@@ -273,36 +273,75 @@ static void splice_device_list(struct list_head *seed_devices,
273273 list_splice (seed_devices , all_devices );
274274}
275275
276- static void print_filesystem_info (char * label , char uuidbuf [BTRFS_UUID_UNPARSED_SIZE ],
277- u64 bytes_used , u64 num_devices ,
278- unsigned unit_mode )
276+ static const struct rowspec filesystem_show_data_rowspec [] = {
277+ { .key = "label" , .fmt = "%s" , .out_json = "label" },
278+ { .key = "uuid" , .fmt = "%s" , .out_json = "uuid" },
279+ { .key = "num_devices" , .fmt = "%llu" , .out_json = "total_devices" },
280+ { .key = "used" , .fmt = "%llu" , .out_json = "used" },
281+ /* device list */
282+ { .key = "devid" , .fmt = "%llu" , .out_json = "devid" },
283+ { .key = "size" , .fmt = "%llu" , .out_json = "size" },
284+ { .key = "used" , .fmt = "%llu" , .out_json = "used" },
285+ { .key = "path" , .fmt = "%s" , .out_json = "path" },
286+ { .key = "missing" , .fmt = "bool" , .out_json = "missing" },
287+ ROWSPEC_END
288+ };
289+
290+ static void print_filesystem_info (struct format_ctx * fctx ,
291+ char * label , char uuidbuf [BTRFS_UUID_UNPARSED_SIZE ],
292+ u64 bytes_used , u64 num_devices ,
293+ unsigned unit_mode )
279294{
280- if (label )
281- pr_verbose (LOG_DEFAULT , "Label: '%s' " , label );
282- else
283- pr_verbose (LOG_DEFAULT , "Label: none " );
284-
285- pr_verbose (LOG_DEFAULT , " uuid: %s\n\tTotal devices %llu FS bytes used %s\n" , uuidbuf ,
286- num_devices ,
287- pretty_size_mode (bytes_used ,
288- unit_mode ));
295+ if (bconf .output_format == CMD_FORMAT_JSON ) {
296+ if (label )
297+ fmt_print (fctx , "label" , label );
298+ else
299+ fmt_print (fctx , "label" , "none" );
300+
301+ fmt_print (fctx , "uuid" , uuidbuf );
302+ fmt_print (fctx , "num_devices" , num_devices );
303+ fmt_print (fctx , "used" , bytes_used );
304+ } else {
305+ if (label )
306+ pr_verbose (LOG_DEFAULT , "Label: '%s' " , label );
307+ else
308+ pr_verbose (LOG_DEFAULT , "Label: none " );
309+
310+ pr_verbose (LOG_DEFAULT , " uuid: %s\n\tTotal devices %llu FS bytes used %s\n" , uuidbuf ,
311+ num_devices ,
312+ pretty_size_mode (bytes_used ,
313+ unit_mode ));
314+ }
289315}
290316
291- static void print_filesystem_device (u64 devid , u64 total_bytes , u64 bytes_used ,
317+ static void print_filesystem_device (struct format_ctx * fctx ,
318+ u64 devid , u64 total_bytes , u64 bytes_used ,
292319 char * path ,
293320 bool missing ,
294321 unsigned unit_mode )
295322{
296- pr_verbose (LOG_DEFAULT , "\tdevid %4llu size %s used %s path %s%s\n" ,
297- devid ,
298- pretty_size_mode (total_bytes , unit_mode ),
299- pretty_size_mode (bytes_used , unit_mode ),
300- path ,
301- missing ? " MISSING" : "" );
323+ if (bconf .output_format == CMD_FORMAT_JSON ) {
324+ fmt_print_start_group (fctx , NULL , JSON_TYPE_MAP );
325+ fmt_print (fctx , "devid" , devid );
326+ fmt_print (fctx , "size" , 0 );
327+ fmt_print (fctx , "used" , 0 );
328+ fmt_print (fctx , "path" , path );
329+ if (missing )
330+ fmt_print (fctx , "missing" , 0 );
331+ fmt_print_end_group (fctx , NULL );
332+ } else {
333+ pr_verbose (LOG_DEFAULT , "\tdevid %4llu size %s used %s path %s%s\n" ,
334+ devid ,
335+ pretty_size_mode (total_bytes , unit_mode ),
336+ pretty_size_mode (bytes_used , unit_mode ),
337+ path ,
338+ missing ? " MISSING" : "" );
339+ }
302340}
303341
304342static void print_devices (struct btrfs_fs_devices * fs_devices ,
305- u64 * devs_found , unsigned unit_mode )
343+ u64 * devs_found , unsigned unit_mode ,
344+ struct format_ctx * fctx )
306345{
307346 struct btrfs_device * device ;
308347 struct btrfs_fs_devices * cur_fs ;
@@ -318,16 +357,17 @@ static void print_devices(struct btrfs_fs_devices *fs_devices,
318357
319358 list_sort (NULL , all_devices , cmp_device_id );
320359 list_for_each_entry (device , all_devices , dev_list ) {
321- print_filesystem_device (device -> devid ,
322- device -> total_bytes , device -> bytes_used ,
323- device -> name ,
324- false,
325- unit_mode );
360+ print_filesystem_device (fctx , device -> devid ,
361+ device -> total_bytes , device -> bytes_used ,
362+ device -> name ,
363+ false,
364+ unit_mode );
326365 (* devs_found )++ ;
327366 }
328367}
329368
330- static void print_one_uuid (struct btrfs_fs_devices * fs_devices ,
369+ static void print_one_uuid (struct format_ctx * fctx ,
370+ struct btrfs_fs_devices * fs_devices ,
331371 unsigned unit_mode )
332372{
333373 char uuidbuf [BTRFS_UUID_UNPARSED_SIZE ];
@@ -343,16 +383,28 @@ static void print_one_uuid(struct btrfs_fs_devices *fs_devices,
343383 dev_list );
344384 total = device -> total_devs ;
345385
346- print_filesystem_info (device -> label && device -> label [0 ] ? device -> label : NULL , uuidbuf ,
347- device -> super_bytes_used , total ,
348- unit_mode );
386+ if (bconf .output_format == CMD_FORMAT_JSON )
387+ fmt_print_start_group (fctx , NULL , JSON_TYPE_MAP );
388+
389+ print_filesystem_info (fctx , device -> label && device -> label [0 ] ? device -> label : NULL , uuidbuf ,
390+ device -> super_bytes_used , total ,
391+ unit_mode );
349392
350- print_devices (fs_devices , & devs_found , unit_mode );
393+ if (bconf .output_format == CMD_FORMAT_JSON )
394+ fmt_print_start_group (fctx , "device-list" , JSON_TYPE_ARRAY );
351395
352- if (devs_found < total ) {
353- pr_verbose (LOG_DEFAULT , "\t*** Some devices missing\n" );
396+ print_devices (fs_devices , & devs_found , unit_mode , fctx );
397+
398+ // TODO: global missing option?
399+ if (bconf .output_format == CMD_FORMAT_JSON ) {
400+ fmt_print_end_group (fctx , NULL );
401+ fmt_print_end_group (fctx , "device-list" );
402+ } else {
403+ if (devs_found < total ) {
404+ pr_verbose (LOG_DEFAULT , "\t*** Some devices missing\n" );
405+ }
406+ pr_verbose (LOG_DEFAULT , "\n" );
354407 }
355- pr_verbose (LOG_DEFAULT , "\n" );
356408}
357409
358410/* adds up all the used spaces as reported by the space info ioctl
@@ -366,7 +418,8 @@ static u64 calc_used_bytes(struct btrfs_ioctl_space_args *si)
366418 return ret ;
367419}
368420
369- static int print_one_fs (struct btrfs_ioctl_fs_info_args * fs_info ,
421+ static int print_one_fs (struct format_ctx * fctx ,
422+ struct btrfs_ioctl_fs_info_args * fs_info ,
370423 struct btrfs_ioctl_dev_info_args * dev_info ,
371424 struct btrfs_ioctl_space_args * space_info ,
372425 char * label , unsigned unit_mode )
@@ -383,10 +436,16 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
383436 else if (ret )
384437 return ret ;
385438
439+ if (bconf .output_format == CMD_FORMAT_JSON )
440+ fmt_print_start_group (fctx , NULL , JSON_TYPE_MAP );
441+
386442 uuid_unparse (fs_info -> fsid , uuidbuf );
387- print_filesystem_info (label && * label ? label : NULL , uuidbuf ,
388- calc_used_bytes (space_info ), fs_info -> num_devices ,
389- unit_mode );
443+ print_filesystem_info (fctx , label && * label ? label : NULL , uuidbuf ,
444+ calc_used_bytes (space_info ), fs_info -> num_devices ,
445+ unit_mode );
446+
447+ if (bconf .output_format == CMD_FORMAT_JSON )
448+ fmt_print_start_group (fctx , "device-list" , JSON_TYPE_ARRAY );
390449
391450 for (i = 0 ; i < fs_info -> num_devices ; i ++ ) {
392451 char * canonical_path ;
@@ -396,7 +455,8 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
396455 /* Add check for missing devices even mounted */
397456 fd = open ((char * )tmp_dev_info -> path , O_RDONLY );
398457 if (fd < 0 ) {
399- print_filesystem_device (tmp_dev_info -> devid ,
458+ print_filesystem_device (fctx ,
459+ tmp_dev_info -> devid ,
400460 0 , 0 ,
401461 (char * )tmp_dev_info -> path ,
402462 true,
@@ -405,20 +465,25 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
405465 }
406466 close (fd );
407467 canonical_path = path_canonicalize ((char * )tmp_dev_info -> path );
408- print_filesystem_device (tmp_dev_info -> devid ,
409- tmp_dev_info -> total_bytes , tmp_dev_info -> bytes_used ,
410- canonical_path ,
411- false,
412- unit_mode );
468+ print_filesystem_device (fctx , tmp_dev_info -> devid ,
469+ tmp_dev_info -> total_bytes , tmp_dev_info -> bytes_used ,
470+ canonical_path ,
471+ false,
472+ unit_mode );
413473
414474 free (canonical_path );
415475 }
416476
417- pr_verbose (LOG_DEFAULT , "\n" );
477+ if (bconf .output_format == CMD_FORMAT_JSON ) {
478+ fmt_print_end_group (fctx , "device-list" );
479+ fmt_print_end_group (fctx , NULL );
480+ } else {
481+ pr_verbose (LOG_DEFAULT , "\n" );
482+ }
418483 return 0 ;
419484}
420485
421- static int btrfs_scan_kernel (void * search , unsigned unit_mode )
486+ static int btrfs_scan_kernel (struct format_ctx * fctx , void * search , unsigned unit_mode )
422487{
423488 int ret = 0 , fd ;
424489 int found = 0 ;
@@ -464,7 +529,7 @@ static int btrfs_scan_kernel(void *search, unsigned unit_mode)
464529
465530 fd = open (mnt -> mnt_dir , O_RDONLY );
466531 if ((fd != -1 ) && !get_df (fd , & space_info_arg )) {
467- print_one_fs (& fs_info_arg , dev_info_arg ,
532+ print_one_fs (fctx , & fs_info_arg , dev_info_arg ,
468533 space_info_arg , label , unit_mode );
469534 free (space_info_arg );
470535 memset (label , 0 , sizeof (label ));
@@ -728,6 +793,7 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
728793 LIST_HEAD (all_uuids );
729794 struct btrfs_fs_devices * fs_devices ;
730795 struct btrfs_root * root = NULL ;
796+ struct format_ctx fctx ;
731797 char * search = NULL ;
732798 char * canon_path = NULL ;
733799 int ret ;
@@ -770,6 +836,11 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
770836 if (check_argc_max (argc , optind + 1 ))
771837 return 1 ;
772838
839+ if (bconf .output_format == CMD_FORMAT_JSON ) {
840+ fmt_start (& fctx , filesystem_show_data_rowspec , 1 , 0 );
841+ fmt_print_start_group (& fctx , "filesystem-list" , JSON_TYPE_ARRAY );
842+ }
843+
773844 if (argc > optind ) {
774845 search = argv [optind ];
775846 if (* search == 0 )
@@ -822,7 +893,7 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
822893 }
823894
824895 /* show mounted btrfs */
825- ret = btrfs_scan_kernel (search , unit_mode );
896+ ret = btrfs_scan_kernel (& fctx , search , unit_mode );
826897 if (search && !ret ) {
827898 /* since search is found we are done */
828899 goto out ;
@@ -866,7 +937,7 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
866937 }
867938
868939 list_for_each_entry (fs_devices , & all_uuids , fs_list )
869- print_one_uuid (fs_devices , unit_mode );
940+ print_one_uuid (& fctx , fs_devices , unit_mode );
870941
871942 if (search && !found ) {
872943 error ("not a valid btrfs filesystem: %s" , search );
@@ -878,13 +949,21 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
878949 free_fs_devices (fs_devices );
879950 }
880951out :
952+ if (bconf .output_format == CMD_FORMAT_JSON ) {
953+ fmt_print_end_group (& fctx , "filesystem-list" );
954+ fmt_end (& fctx );
955+ }
881956 free (canon_path );
882957 if (root )
883958 close_ctree (root );
884959 free_seen_fsid (seen_fsid_hash );
885960 return !!ret ;
886961}
887- static DEFINE_SIMPLE_COMMAND (filesystem_show , "show ") ;
962+ #if EXPERIMENTAL
963+ static DEFINE_COMMAND_WITH_FLAGS (filesystem_show , "show" , CMD_FORMAT_JSON );
964+ #else
965+ DEFINE_SIMPLE_COMMAND (filesystem_show , "show" );
966+ #endif
888967
889968static const char * const cmd_filesystem_sync_usage [] = {
890969 "btrfs filesystem sync <path>" ,
0 commit comments