@@ -310,36 +310,75 @@ static void splice_device_list(struct list_head *seed_devices,
310310 list_splice (seed_devices , all_devices );
311311}
312312
313- static void print_filesystem_info (char * label , char uuidbuf [BTRFS_UUID_UNPARSED_SIZE ],
314- u64 bytes_used , u64 num_devices ,
315- unsigned unit_mode )
313+ static const struct rowspec filesystem_show_data_rowspec [] = {
314+ { .key = "label" , .fmt = "%s" , .out_json = "label" },
315+ { .key = "uuid" , .fmt = "%s" , .out_json = "uuid" },
316+ { .key = "num_devices" , .fmt = "%llu" , .out_json = "total_devices" },
317+ { .key = "used" , .fmt = "%llu" , .out_json = "used" },
318+ /* device list */
319+ { .key = "devid" , .fmt = "%llu" , .out_json = "devid" },
320+ { .key = "size" , .fmt = "%llu" , .out_json = "size" },
321+ { .key = "used" , .fmt = "%llu" , .out_json = "used" },
322+ { .key = "path" , .fmt = "%s" , .out_json = "path" },
323+ { .key = "missing" , .fmt = "bool" , .out_json = "missing" },
324+ ROWSPEC_END
325+ };
326+
327+ static void print_filesystem_info (struct format_ctx * fctx ,
328+ char * label , char uuidbuf [BTRFS_UUID_UNPARSED_SIZE ],
329+ u64 bytes_used , u64 num_devices ,
330+ unsigned unit_mode )
316331{
317- if (label )
318- pr_verbose (LOG_DEFAULT , "Label: '%s' " , label );
319- else
320- pr_verbose (LOG_DEFAULT , "Label: none " );
321-
322- pr_verbose (LOG_DEFAULT , " uuid: %s\n\tTotal devices %llu FS bytes used %s\n" , uuidbuf ,
323- num_devices ,
324- pretty_size_mode (bytes_used ,
325- unit_mode ));
332+ if (bconf .output_format == CMD_FORMAT_JSON ) {
333+ if (label )
334+ fmt_print (fctx , "label" , label );
335+ else
336+ fmt_print (fctx , "label" , "none" );
337+
338+ fmt_print (fctx , "uuid" , uuidbuf );
339+ fmt_print (fctx , "num_devices" , num_devices );
340+ fmt_print (fctx , "used" , bytes_used );
341+ } else {
342+ if (label )
343+ pr_verbose (LOG_DEFAULT , "Label: '%s' " , label );
344+ else
345+ pr_verbose (LOG_DEFAULT , "Label: none " );
346+
347+ pr_verbose (LOG_DEFAULT , " uuid: %s\n\tTotal devices %llu FS bytes used %s\n" , uuidbuf ,
348+ num_devices ,
349+ pretty_size_mode (bytes_used ,
350+ unit_mode ));
351+ }
326352}
327353
328- static void print_filesystem_device (u64 devid , u64 total_bytes , u64 bytes_used ,
354+ static void print_filesystem_device (struct format_ctx * fctx ,
355+ u64 devid , u64 total_bytes , u64 bytes_used ,
329356 char * path ,
330357 bool missing ,
331358 unsigned unit_mode )
332359{
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" : "" );
360+ if (bconf .output_format == CMD_FORMAT_JSON ) {
361+ fmt_print_start_group (fctx , NULL , JSON_TYPE_MAP );
362+ fmt_print (fctx , "devid" , devid );
363+ fmt_print (fctx , "size" , 0 );
364+ fmt_print (fctx , "used" , 0 );
365+ fmt_print (fctx , "path" , path );
366+ if (missing )
367+ fmt_print (fctx , "missing" , 0 );
368+ fmt_print_end_group (fctx , NULL );
369+ } else {
370+ pr_verbose (LOG_DEFAULT , "\tdevid %4llu size %s used %s path %s%s\n" ,
371+ devid ,
372+ pretty_size_mode (total_bytes , unit_mode ),
373+ pretty_size_mode (bytes_used , unit_mode ),
374+ path ,
375+ missing ? " MISSING" : "" );
376+ }
339377}
340378
341379static void print_devices (struct btrfs_fs_devices * fs_devices ,
342- u64 * devs_found , unsigned unit_mode )
380+ u64 * devs_found , unsigned unit_mode ,
381+ struct format_ctx * fctx )
343382{
344383 struct btrfs_device * device ;
345384 struct btrfs_fs_devices * cur_fs ;
@@ -355,16 +394,17 @@ static void print_devices(struct btrfs_fs_devices *fs_devices,
355394
356395 list_sort (NULL , all_devices , cmp_device_id );
357396 list_for_each_entry (device , all_devices , dev_list ) {
358- print_filesystem_device (device -> devid ,
359- device -> total_bytes , device -> bytes_used ,
360- device -> name ,
361- false,
362- unit_mode );
397+ print_filesystem_device (fctx , device -> devid ,
398+ device -> total_bytes , device -> bytes_used ,
399+ device -> name ,
400+ false,
401+ unit_mode );
363402 (* devs_found )++ ;
364403 }
365404}
366405
367- static void print_one_uuid (struct btrfs_fs_devices * fs_devices ,
406+ static void print_one_uuid (struct format_ctx * fctx ,
407+ struct btrfs_fs_devices * fs_devices ,
368408 unsigned unit_mode )
369409{
370410 char uuidbuf [BTRFS_UUID_UNPARSED_SIZE ];
@@ -380,14 +420,27 @@ static void print_one_uuid(struct btrfs_fs_devices *fs_devices,
380420 dev_list );
381421 total = device -> total_devs ;
382422
383- print_filesystem_info (device -> label && device -> label [0 ] ? device -> label : NULL , uuidbuf ,
384- device -> super_bytes_used , total ,
385- unit_mode );
423+ if (bconf .output_format == CMD_FORMAT_JSON )
424+ fmt_print_start_group (fctx , NULL , JSON_TYPE_MAP );
425+
426+ print_filesystem_info (fctx , device -> label && device -> label [0 ] ? device -> label : NULL , uuidbuf ,
427+ device -> super_bytes_used , total ,
428+ unit_mode );
386429
387- print_devices (fs_devices , & devs_found , unit_mode );
430+ if (bconf .output_format == CMD_FORMAT_JSON )
431+ fmt_print_start_group (fctx , "device-list" , JSON_TYPE_ARRAY );
388432
389- if (devs_found < total ) {
390- pr_verbose (LOG_DEFAULT , "\t*** Some devices missing\n" );
433+ print_devices (fs_devices , & devs_found , unit_mode , fctx );
434+
435+ // TODO: global missing option?
436+ if (bconf .output_format == CMD_FORMAT_JSON ) {
437+ fmt_print_end_group (fctx , NULL );
438+ fmt_print_end_group (fctx , "device-list" );
439+ } else {
440+ if (devs_found < total ) {
441+ pr_verbose (LOG_DEFAULT , "\t*** Some devices missing\n" );
442+ }
443+ pr_verbose (LOG_DEFAULT , "\n" );
391444 }
392445}
393446
@@ -402,7 +455,8 @@ static u64 calc_used_bytes(struct btrfs_ioctl_space_args *si)
402455 return ret ;
403456}
404457
405- static int print_one_fs (struct btrfs_ioctl_fs_info_args * fs_info ,
458+ static int print_one_fs (struct format_ctx * fctx ,
459+ struct btrfs_ioctl_fs_info_args * fs_info ,
406460 struct btrfs_ioctl_dev_info_args * dev_info ,
407461 struct btrfs_ioctl_space_args * space_info ,
408462 char * label , unsigned unit_mode )
@@ -419,10 +473,16 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
419473 else if (ret )
420474 return ret ;
421475
476+ if (bconf .output_format == CMD_FORMAT_JSON )
477+ fmt_print_start_group (fctx , NULL , JSON_TYPE_MAP );
478+
422479 uuid_unparse (fs_info -> fsid , uuidbuf );
423- print_filesystem_info (label && * label ? label : NULL , uuidbuf ,
424- calc_used_bytes (space_info ), fs_info -> num_devices ,
425- unit_mode );
480+ print_filesystem_info (fctx , label && * label ? label : NULL , uuidbuf ,
481+ calc_used_bytes (space_info ), fs_info -> num_devices ,
482+ unit_mode );
483+
484+ if (bconf .output_format == CMD_FORMAT_JSON )
485+ fmt_print_start_group (fctx , "device-list" , JSON_TYPE_ARRAY );
426486
427487 for (i = 0 ; i < fs_info -> num_devices ; i ++ ) {
428488 char * canonical_path ;
@@ -432,7 +492,8 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
432492 /* Add check for missing devices even mounted */
433493 fd = open ((char * )tmp_dev_info -> path , O_RDONLY );
434494 if (fd < 0 ) {
435- print_filesystem_device (tmp_dev_info -> devid ,
495+ print_filesystem_device (fctx ,
496+ tmp_dev_info -> devid ,
436497 0 , 0 ,
437498 (char * )tmp_dev_info -> path ,
438499 true,
@@ -441,19 +502,24 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
441502 }
442503 close (fd );
443504 canonical_path = path_canonicalize ((char * )tmp_dev_info -> path );
444- print_filesystem_device (tmp_dev_info -> devid ,
445- tmp_dev_info -> total_bytes , tmp_dev_info -> bytes_used ,
446- canonical_path ,
447- false,
448- unit_mode );
505+ print_filesystem_device (fctx , tmp_dev_info -> devid ,
506+ tmp_dev_info -> total_bytes , tmp_dev_info -> bytes_used ,
507+ canonical_path ,
508+ false,
509+ unit_mode );
449510
450511 free (canonical_path );
451512 }
452513
514+ if (bconf .output_format == CMD_FORMAT_JSON ) {
515+ fmt_print_end_group (fctx , "device-list" );
516+ fmt_print_end_group (fctx , NULL );
517+ }
518+
453519 return 0 ;
454520}
455521
456- static int btrfs_scan_kernel (void * search , unsigned unit_mode )
522+ static int btrfs_scan_kernel (struct format_ctx * fctx , void * search , unsigned unit_mode )
457523{
458524 int ret = 0 , fd ;
459525 int found = 0 ;
@@ -500,10 +566,10 @@ static int btrfs_scan_kernel(void *search, unsigned unit_mode)
500566 fd = open (mnt -> mnt_dir , O_RDONLY );
501567 if ((fd != -1 ) && !get_df (fd , & space_info_arg )) {
502568 /* Put space between filesystem entries for readability. */
503- if (found != 0 )
569+ if (found != 0 && bconf . output_format != CMD_FORMAT_JSON )
504570 pr_verbose (LOG_DEFAULT , "\n" );
505571
506- print_one_fs (& fs_info_arg , dev_info_arg ,
572+ print_one_fs (fctx , & fs_info_arg , dev_info_arg ,
507573 space_info_arg , label , unit_mode );
508574 free (space_info_arg );
509575 memset (label , 0 , sizeof (label ));
@@ -767,6 +833,7 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
767833 LIST_HEAD (all_uuids );
768834 struct btrfs_fs_devices * fs_devices ;
769835 struct btrfs_root * root = NULL ;
836+ struct format_ctx fctx ;
770837 char * search = NULL ;
771838 char * canon_path = NULL ;
772839 int ret ;
@@ -810,6 +877,11 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
810877 if (check_argc_max (argc , optind + 1 ))
811878 return 1 ;
812879
880+ if (bconf .output_format == CMD_FORMAT_JSON ) {
881+ fmt_start (& fctx , filesystem_show_data_rowspec , 1 , 0 );
882+ fmt_print_start_group (& fctx , "filesystem-list" , JSON_TYPE_ARRAY );
883+ }
884+
813885 if (argc > optind ) {
814886 search = argv [optind ];
815887 if (* search == 0 )
@@ -862,7 +934,7 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
862934 }
863935
864936 /* show mounted btrfs */
865- ret = btrfs_scan_kernel (search , unit_mode );
937+ ret = btrfs_scan_kernel (& fctx , search , unit_mode );
866938 if (search && !ret ) {
867939 /* since search is found we are done */
868940 goto out ;
@@ -913,10 +985,10 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
913985
914986 list_for_each_entry (fs_devices , & all_uuids , fs_list ) {
915987 /* Put space between filesystem entries for readability. */
916- if (needs_newline )
988+ if (needs_newline && bconf . output_format != CMD_FORMAT_JSON )
917989 pr_verbose (LOG_DEFAULT , "\n" );
918990
919- print_one_uuid (fs_devices , unit_mode );
991+ print_one_uuid (& fctx , fs_devices , unit_mode );
920992 needs_newline = true;
921993 }
922994
@@ -930,13 +1002,21 @@ static int cmd_filesystem_show(const struct cmd_struct *cmd,
9301002 free_fs_devices (fs_devices );
9311003 }
9321004out :
1005+ if (bconf .output_format == CMD_FORMAT_JSON ) {
1006+ fmt_print_end_group (& fctx , "filesystem-list" );
1007+ fmt_end (& fctx );
1008+ }
9331009 free (canon_path );
9341010 if (root )
9351011 close_ctree (root );
9361012 free_seen_fsid (seen_fsid_hash );
9371013 return !!ret ;
9381014}
939- static DEFINE_SIMPLE_COMMAND (filesystem_show , "show ") ;
1015+ #if EXPERIMENTAL
1016+ static DEFINE_COMMAND_WITH_FLAGS (filesystem_show , "show" , CMD_FORMAT_JSON );
1017+ #else
1018+ DEFINE_SIMPLE_COMMAND (filesystem_show , "show" );
1019+ #endif
9401020
9411021static const char * const cmd_filesystem_sync_usage [] = {
9421022 "btrfs filesystem sync <path>" ,
0 commit comments