@@ -272,36 +272,75 @@ static void splice_device_list(struct list_head *seed_devices,
272272 list_splice (seed_devices , all_devices );
273273}
274274
275- static void print_filesystem_info (char * label , char uuidbuf [BTRFS_UUID_UNPARSED_SIZE ],
276- u64 bytes_used , u64 num_devices ,
277- unsigned unit_mode )
275+ static const struct rowspec filesystem_show_data_rowspec [] = {
276+ { .key = "label" , .fmt = "%s" , .out_json = "label" },
277+ { .key = "uuid" , .fmt = "%s" , .out_json = "uuid" },
278+ { .key = "num_devices" , .fmt = "%llu" , .out_json = "total_devices" },
279+ { .key = "used" , .fmt = "%llu" , .out_json = "used" },
280+ /* device list */
281+ { .key = "devid" , .fmt = "%llu" , .out_json = "devid" },
282+ { .key = "size" , .fmt = "%llu" , .out_json = "size" },
283+ { .key = "used" , .fmt = "%llu" , .out_json = "used" },
284+ { .key = "path" , .fmt = "%s" , .out_json = "path" },
285+ { .key = "missing" , .fmt = "bool" , .out_json = "missing" },
286+ ROWSPEC_END
287+ };
288+
289+ static void print_filesystem_info (struct format_ctx * fctx ,
290+ char * label , char uuidbuf [BTRFS_UUID_UNPARSED_SIZE ],
291+ u64 bytes_used , u64 num_devices ,
292+ unsigned unit_mode )
278293{
279- if (label )
280- pr_verbose (LOG_DEFAULT , "Label: '%s' " , label );
281- else
282- pr_verbose (LOG_DEFAULT , "Label: none " );
283-
284- pr_verbose (LOG_DEFAULT , " uuid: %s\n\tTotal devices %llu FS bytes used %s\n" , uuidbuf ,
285- num_devices ,
286- pretty_size_mode (bytes_used ,
287- unit_mode ));
294+ if (bconf .output_format == CMD_FORMAT_JSON ) {
295+ if (label )
296+ fmt_print (fctx , "label" , label );
297+ else
298+ fmt_print (fctx , "label" , "none" );
299+
300+ fmt_print (fctx , "uuid" , uuidbuf );
301+ fmt_print (fctx , "num_devices" , num_devices );
302+ fmt_print (fctx , "used" , bytes_used );
303+ } else {
304+ if (label )
305+ pr_verbose (LOG_DEFAULT , "Label: '%s' " , label );
306+ else
307+ pr_verbose (LOG_DEFAULT , "Label: none " );
308+
309+ pr_verbose (LOG_DEFAULT , " uuid: %s\n\tTotal devices %llu FS bytes used %s\n" , uuidbuf ,
310+ num_devices ,
311+ pretty_size_mode (bytes_used ,
312+ unit_mode ));
313+ }
288314}
289315
290- static void print_filesystem_device (u64 devid , u64 total_bytes , u64 bytes_used ,
316+ static void print_filesystem_device (struct format_ctx * fctx ,
317+ u64 devid , u64 total_bytes , u64 bytes_used ,
291318 char * path ,
292319 bool missing ,
293320 unsigned unit_mode )
294321{
295- pr_verbose (LOG_DEFAULT , "\tdevid %4llu size %s used %s path %s%s\n" ,
296- devid ,
297- pretty_size_mode (total_bytes , unit_mode ),
298- pretty_size_mode (bytes_used , unit_mode ),
299- path ,
300- missing ? " MISSING" : "" );
322+ if (bconf .output_format == CMD_FORMAT_JSON ) {
323+ fmt_print_start_group (fctx , NULL , JSON_TYPE_MAP );
324+ fmt_print (fctx , "devid" , devid );
325+ fmt_print (fctx , "size" , 0 );
326+ fmt_print (fctx , "used" , 0 );
327+ fmt_print (fctx , "path" , path );
328+ if (missing )
329+ fmt_print (fctx , "missing" , 0 );
330+ fmt_print_end_group (fctx , NULL );
331+ } else {
332+ pr_verbose (LOG_DEFAULT , "\tdevid %4llu size %s used %s path %s%s\n" ,
333+ devid ,
334+ pretty_size_mode (total_bytes , unit_mode ),
335+ pretty_size_mode (bytes_used , unit_mode ),
336+ path ,
337+ missing ? " MISSING" : "" );
338+ }
301339}
302340
303341static void print_devices (struct btrfs_fs_devices * fs_devices ,
304- u64 * devs_found , unsigned unit_mode )
342+ u64 * devs_found , unsigned unit_mode ,
343+ struct format_ctx * fctx )
305344{
306345 struct btrfs_device * device ;
307346 struct btrfs_fs_devices * cur_fs ;
@@ -317,16 +356,17 @@ static void print_devices(struct btrfs_fs_devices *fs_devices,
317356
318357 list_sort (NULL , all_devices , cmp_device_id );
319358 list_for_each_entry (device , all_devices , dev_list ) {
320- print_filesystem_device (device -> devid ,
321- device -> total_bytes , device -> bytes_used ,
322- device -> name ,
323- false,
324- unit_mode );
359+ print_filesystem_device (fctx , device -> devid ,
360+ device -> total_bytes , device -> bytes_used ,
361+ device -> name ,
362+ false,
363+ unit_mode );
325364 (* devs_found )++ ;
326365 }
327366}
328367
329- static void print_one_uuid (struct btrfs_fs_devices * fs_devices ,
368+ static void print_one_uuid (struct format_ctx * fctx ,
369+ struct btrfs_fs_devices * fs_devices ,
330370 unsigned unit_mode )
331371{
332372 char uuidbuf [BTRFS_UUID_UNPARSED_SIZE ];
@@ -342,16 +382,28 @@ static void print_one_uuid(struct btrfs_fs_devices *fs_devices,
342382 dev_list );
343383 total = device -> total_devs ;
344384
345- print_filesystem_info (device -> label && device -> label [0 ] ? device -> label : NULL , uuidbuf ,
346- device -> super_bytes_used , total ,
347- unit_mode );
385+ if (bconf .output_format == CMD_FORMAT_JSON )
386+ fmt_print_start_group (fctx , NULL , JSON_TYPE_MAP );
387+
388+ print_filesystem_info (fctx , device -> label && device -> label [0 ] ? device -> label : NULL , uuidbuf ,
389+ device -> super_bytes_used , total ,
390+ unit_mode );
348391
349- print_devices (fs_devices , & devs_found , unit_mode );
392+ if (bconf .output_format == CMD_FORMAT_JSON )
393+ fmt_print_start_group (fctx , "device-list" , JSON_TYPE_ARRAY );
350394
351- if (devs_found < total ) {
352- pr_verbose (LOG_DEFAULT , "\t*** Some devices missing\n" );
395+ print_devices (fs_devices , & devs_found , unit_mode , fctx );
396+
397+ // TODO: global missing option?
398+ if (bconf .output_format == CMD_FORMAT_JSON ) {
399+ fmt_print_end_group (fctx , NULL );
400+ fmt_print_end_group (fctx , "device-list" );
401+ } else {
402+ if (devs_found < total ) {
403+ pr_verbose (LOG_DEFAULT , "\t*** Some devices missing\n" );
404+ }
405+ pr_verbose (LOG_DEFAULT , "\n" );
353406 }
354- pr_verbose (LOG_DEFAULT , "\n" );
355407}
356408
357409/* adds up all the used spaces as reported by the space info ioctl
@@ -365,7 +417,8 @@ static u64 calc_used_bytes(struct btrfs_ioctl_space_args *si)
365417 return ret ;
366418}
367419
368- static int print_one_fs (struct btrfs_ioctl_fs_info_args * fs_info ,
420+ static int print_one_fs (struct format_ctx * fctx ,
421+ struct btrfs_ioctl_fs_info_args * fs_info ,
369422 struct btrfs_ioctl_dev_info_args * dev_info ,
370423 struct btrfs_ioctl_space_args * space_info ,
371424 char * label , unsigned unit_mode )
@@ -382,10 +435,16 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
382435 else if (ret )
383436 return ret ;
384437
438+ if (bconf .output_format == CMD_FORMAT_JSON )
439+ fmt_print_start_group (fctx , NULL , JSON_TYPE_MAP );
440+
385441 uuid_unparse (fs_info -> fsid , uuidbuf );
386- print_filesystem_info (label && * label ? label : NULL , uuidbuf ,
387- calc_used_bytes (space_info ), fs_info -> num_devices ,
388- unit_mode );
442+ print_filesystem_info (fctx , label && * label ? label : NULL , uuidbuf ,
443+ calc_used_bytes (space_info ), fs_info -> num_devices ,
444+ unit_mode );
445+
446+ if (bconf .output_format == CMD_FORMAT_JSON )
447+ fmt_print_start_group (fctx , "device-list" , JSON_TYPE_ARRAY );
389448
390449 for (i = 0 ; i < fs_info -> num_devices ; i ++ ) {
391450 char * canonical_path ;
@@ -395,7 +454,8 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
395454 /* Add check for missing devices even mounted */
396455 fd = open ((char * )tmp_dev_info -> path , O_RDONLY );
397456 if (fd < 0 ) {
398- print_filesystem_device (tmp_dev_info -> devid ,
457+ print_filesystem_device (fctx ,
458+ tmp_dev_info -> devid ,
399459 0 , 0 ,
400460 (char * )tmp_dev_info -> path ,
401461 true,
@@ -404,20 +464,25 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
404464 }
405465 close (fd );
406466 canonical_path = path_canonicalize ((char * )tmp_dev_info -> path );
407- print_filesystem_device (tmp_dev_info -> devid ,
408- tmp_dev_info -> total_bytes , tmp_dev_info -> bytes_used ,
409- canonical_path ,
410- false,
411- unit_mode );
467+ print_filesystem_device (fctx , tmp_dev_info -> devid ,
468+ tmp_dev_info -> total_bytes , tmp_dev_info -> bytes_used ,
469+ canonical_path ,
470+ false,
471+ unit_mode );
412472
413473 free (canonical_path );
414474 }
415475
416- pr_verbose (LOG_DEFAULT , "\n" );
476+ if (bconf .output_format == CMD_FORMAT_JSON ) {
477+ fmt_print_end_group (fctx , "device-list" );
478+ fmt_print_end_group (fctx , NULL );
479+ } else {
480+ pr_verbose (LOG_DEFAULT , "\n" );
481+ }
417482 return 0 ;
418483}
419484
420- static int btrfs_scan_kernel (void * search , unsigned unit_mode )
485+ static int btrfs_scan_kernel (struct format_ctx * fctx , void * search , unsigned unit_mode )
421486{
422487 int ret = 0 , fd ;
423488 int found = 0 ;
@@ -463,7 +528,7 @@ static int btrfs_scan_kernel(void *search, unsigned unit_mode)
463528
464529 fd = open (mnt -> mnt_dir , O_RDONLY );
465530 if ((fd != -1 ) && !get_df (fd , & space_info_arg )) {
466- print_one_fs (& fs_info_arg , dev_info_arg ,
531+ print_one_fs (fctx , & fs_info_arg , dev_info_arg ,
467532 space_info_arg , label , unit_mode );
468533 free (space_info_arg );
469534 memset (label , 0 , sizeof (label ));
@@ -727,6 +792,7 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
727792 LIST_HEAD (all_uuids );
728793 struct btrfs_fs_devices * fs_devices ;
729794 struct btrfs_root * root = NULL ;
795+ struct format_ctx fctx ;
730796 char * search = NULL ;
731797 char * canon_path = NULL ;
732798 int ret ;
@@ -769,6 +835,11 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
769835 if (check_argc_max (argc , optind + 1 ))
770836 return 1 ;
771837
838+ if (bconf .output_format == CMD_FORMAT_JSON ) {
839+ fmt_start (& fctx , filesystem_show_data_rowspec , 1 , 0 );
840+ fmt_print_start_group (& fctx , "filesystem-list" , JSON_TYPE_ARRAY );
841+ }
842+
772843 if (argc > optind ) {
773844 search = argv [optind ];
774845 if (* search == 0 )
@@ -821,7 +892,7 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
821892 }
822893
823894 /* show mounted btrfs */
824- ret = btrfs_scan_kernel (search , unit_mode );
895+ ret = btrfs_scan_kernel (& fctx , search , unit_mode );
825896 if (search && !ret ) {
826897 /* since search is found we are done */
827898 goto out ;
@@ -865,7 +936,7 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
865936 }
866937
867938 list_for_each_entry (fs_devices , & all_uuids , fs_list )
868- print_one_uuid (fs_devices , unit_mode );
939+ print_one_uuid (& fctx , fs_devices , unit_mode );
869940
870941 if (search && !found ) {
871942 error ("not a valid btrfs filesystem: %s" , search );
@@ -877,13 +948,21 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
877948 free_fs_devices (fs_devices );
878949 }
879950out :
951+ if (bconf .output_format == CMD_FORMAT_JSON ) {
952+ fmt_print_end_group (& fctx , "filesystem-list" );
953+ fmt_end (& fctx );
954+ }
880955 free (canon_path );
881956 if (root )
882957 close_ctree (root );
883958 free_seen_fsid (seen_fsid_hash );
884959 return !!ret ;
885960}
886- static DEFINE_SIMPLE_COMMAND (filesystem_show , "show ") ;
961+ #if EXPERIMENTAL
962+ static DEFINE_COMMAND_WITH_FLAGS (filesystem_show , "show" , CMD_FORMAT_JSON );
963+ #else
964+ DEFINE_SIMPLE_COMMAND (filesystem_show , "show" );
965+ #endif
887966
888967static const char * const cmd_filesystem_sync_usage [] = {
889968 "btrfs filesystem sync <path>" ,
0 commit comments