@@ -310,8 +310,9 @@ get_usage(zfs_help_t idx)
310
310
return (gettext ("\tupgrade [-v]\n"
311
311
"\tupgrade [-r] [-V version] <-a | filesystem ...>\n" ));
312
312
case HELP_LIST :
313
- return (gettext ("\tlist [-Hp] [-r|-d max] [-o property[,...]] "
314
- "[-s property]...\n\t [-S property]... [-t type[,...]] "
313
+ return (gettext ("\tlist [-Hp] [-j [--json-int]] [-r|-d max] "
314
+ "[-o property[,...]] [-s property]...\n\t "
315
+ "[-S property]... [-t type[,...]] "
315
316
"[filesystem|volume|snapshot] ...\n" ));
316
317
case HELP_MOUNT :
317
318
return (gettext ("\tmount\n"
@@ -3609,6 +3610,9 @@ typedef struct list_cbdata {
3609
3610
boolean_t cb_literal ;
3610
3611
boolean_t cb_scripted ;
3611
3612
zprop_list_t * cb_proplist ;
3613
+ boolean_t cb_json ;
3614
+ nvlist_t * cb_jsobj ;
3615
+ boolean_t cb_json_as_int ;
3612
3616
} list_cbdata_t ;
3613
3617
3614
3618
/*
@@ -3679,10 +3683,11 @@ zfs_list_avail_color(zfs_handle_t *zhp)
3679
3683
3680
3684
/*
3681
3685
* Given a dataset and a list of fields, print out all the properties according
3682
- * to the described layout.
3686
+ * to the described layout, or return an nvlist containing all the fields, later
3687
+ * to be printed out as JSON object.
3683
3688
*/
3684
3689
static void
3685
- print_dataset (zfs_handle_t * zhp , list_cbdata_t * cb )
3690
+ collect_dataset (zfs_handle_t * zhp , list_cbdata_t * cb )
3686
3691
{
3687
3692
zprop_list_t * pl = cb -> cb_proplist ;
3688
3693
boolean_t first = B_TRUE ;
@@ -3691,9 +3696,23 @@ print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
3691
3696
nvlist_t * propval ;
3692
3697
const char * propstr ;
3693
3698
boolean_t right_justify ;
3699
+ nvlist_t * item , * d , * props ;
3700
+ item = d = props = NULL ;
3701
+ zprop_source_t sourcetype = ZPROP_SRC_NONE ;
3702
+ char source [ZFS_MAX_DATASET_NAME_LEN ];
3703
+ if (cb -> cb_json ) {
3704
+ d = fnvlist_lookup_nvlist (cb -> cb_jsobj , "datasets" );
3705
+ if (d == NULL ) {
3706
+ fprintf (stderr , "datasets obj not found.\n" );
3707
+ exit (1 );
3708
+ }
3709
+ item = fnvlist_alloc ();
3710
+ props = fnvlist_alloc ();
3711
+ fill_dataset_info (item , zhp , cb -> cb_json_as_int );
3712
+ }
3694
3713
3695
3714
for (; pl != NULL ; pl = pl -> pl_next ) {
3696
- if (!first ) {
3715
+ if (!cb -> cb_json && ! first ) {
3697
3716
if (cb -> cb_scripted )
3698
3717
(void ) putchar ('\t' );
3699
3718
else
@@ -3709,69 +3728,112 @@ print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
3709
3728
right_justify = zfs_prop_align_right (pl -> pl_prop );
3710
3729
} else if (pl -> pl_prop != ZPROP_USERPROP ) {
3711
3730
if (zfs_prop_get (zhp , pl -> pl_prop , property ,
3712
- sizeof (property ), NULL , NULL , 0 ,
3713
- cb -> cb_literal ) != 0 )
3731
+ sizeof (property ), & sourcetype , source ,
3732
+ sizeof ( source ), cb -> cb_literal ) != 0 )
3714
3733
propstr = "-" ;
3715
3734
else
3716
3735
propstr = property ;
3717
3736
right_justify = zfs_prop_align_right (pl -> pl_prop );
3718
3737
} else if (zfs_prop_userquota (pl -> pl_user_prop )) {
3738
+ sourcetype = ZPROP_SRC_LOCAL ;
3719
3739
if (zfs_prop_get_userquota (zhp , pl -> pl_user_prop ,
3720
- property , sizeof (property ), cb -> cb_literal ) != 0 )
3740
+ property , sizeof (property ), cb -> cb_literal ) != 0 ) {
3741
+ sourcetype = ZPROP_SRC_NONE ;
3721
3742
propstr = "-" ;
3722
- else
3743
+ } else {
3723
3744
propstr = property ;
3745
+ }
3724
3746
right_justify = B_TRUE ;
3725
3747
} else if (zfs_prop_written (pl -> pl_user_prop )) {
3748
+ sourcetype = ZPROP_SRC_LOCAL ;
3726
3749
if (zfs_prop_get_written (zhp , pl -> pl_user_prop ,
3727
- property , sizeof (property ), cb -> cb_literal ) != 0 )
3750
+ property , sizeof (property ), cb -> cb_literal ) != 0 ) {
3751
+ sourcetype = ZPROP_SRC_NONE ;
3728
3752
propstr = "-" ;
3729
- else
3753
+ } else {
3730
3754
propstr = property ;
3755
+ }
3731
3756
right_justify = B_TRUE ;
3732
3757
} else {
3733
3758
if (nvlist_lookup_nvlist (userprops ,
3734
- pl -> pl_user_prop , & propval ) != 0 )
3759
+ pl -> pl_user_prop , & propval ) != 0 ) {
3735
3760
propstr = "-" ;
3736
- else
3761
+ } else {
3737
3762
propstr = fnvlist_lookup_string (propval ,
3738
3763
ZPROP_VALUE );
3764
+ strlcpy (source ,
3765
+ fnvlist_lookup_string (propval ,
3766
+ ZPROP_SOURCE ), ZFS_MAX_DATASET_NAME_LEN );
3767
+ if (strcmp (source ,
3768
+ zfs_get_name (zhp )) == 0 ) {
3769
+ sourcetype = ZPROP_SRC_LOCAL ;
3770
+ } else if (strcmp (source ,
3771
+ ZPROP_SOURCE_VAL_RECVD ) == 0 ) {
3772
+ sourcetype = ZPROP_SRC_RECEIVED ;
3773
+ } else {
3774
+ sourcetype = ZPROP_SRC_INHERITED ;
3775
+ }
3776
+ }
3739
3777
right_justify = B_FALSE ;
3740
3778
}
3741
3779
3742
- /*
3743
- * zfs_list_avail_color() needs ZFS_PROP_AVAILABLE + USED
3744
- * - so we need another for() search for the USED part
3745
- * - when no colors wanted, we can skip the whole thing
3746
- */
3747
- if (use_color () && pl -> pl_prop == ZFS_PROP_AVAILABLE ) {
3748
- zprop_list_t * pl2 = cb -> cb_proplist ;
3749
- for (; pl2 != NULL ; pl2 = pl2 -> pl_next ) {
3750
- if (pl2 -> pl_prop == ZFS_PROP_USED ) {
3751
- color_start (zfs_list_avail_color (zhp ));
3752
- /* found it, no need for more loops */
3753
- break ;
3780
+ if (cb -> cb_json ) {
3781
+ if (pl -> pl_prop == ZFS_PROP_NAME )
3782
+ continue ;
3783
+ if (zprop_nvlist_one_property (
3784
+ zfs_prop_to_name (pl -> pl_prop ), propstr ,
3785
+ sourcetype , source , NULL , props ,
3786
+ cb -> cb_json_as_int ) != 0 )
3787
+ nomem ();
3788
+ } else {
3789
+ /*
3790
+ * zfs_list_avail_color() needs
3791
+ * ZFS_PROP_AVAILABLE + USED, so we need another
3792
+ * for() search for the USED part when no colors
3793
+ * wanted, we can skip the whole thing
3794
+ */
3795
+ if (use_color () && pl -> pl_prop == ZFS_PROP_AVAILABLE ) {
3796
+ zprop_list_t * pl2 = cb -> cb_proplist ;
3797
+ for (; pl2 != NULL ; pl2 = pl2 -> pl_next ) {
3798
+ if (pl2 -> pl_prop == ZFS_PROP_USED ) {
3799
+ color_start (
3800
+ zfs_list_avail_color (zhp ));
3801
+ /*
3802
+ * found it, no need for more
3803
+ * loops
3804
+ */
3805
+ break ;
3806
+ }
3754
3807
}
3755
3808
}
3756
- }
3757
3809
3758
- /*
3759
- * If this is being called in scripted mode, or if this is the
3760
- * last column and it is left-justified, don't include a width
3761
- * format specifier.
3762
- */
3763
- if (cb -> cb_scripted || (pl -> pl_next == NULL && !right_justify ))
3764
- (void ) fputs (propstr , stdout );
3765
- else if (right_justify )
3766
- (void ) printf ("%*s" , (int )pl -> pl_width , propstr );
3767
- else
3768
- (void ) printf ("%-*s" , (int )pl -> pl_width , propstr );
3810
+ /*
3811
+ * If this is being called in scripted mode, or if
3812
+ * this is the last column and it is left-justified,
3813
+ * don't include a width format specifier.
3814
+ */
3815
+ if (cb -> cb_scripted || (pl -> pl_next == NULL &&
3816
+ !right_justify ))
3817
+ (void ) fputs (propstr , stdout );
3818
+ else if (right_justify ) {
3819
+ (void ) printf ("%*s" , (int )pl -> pl_width ,
3820
+ propstr );
3821
+ } else {
3822
+ (void ) printf ("%-*s" , (int )pl -> pl_width ,
3823
+ propstr );
3824
+ }
3769
3825
3770
- if (pl -> pl_prop == ZFS_PROP_AVAILABLE )
3771
- color_end ();
3826
+ if (pl -> pl_prop == ZFS_PROP_AVAILABLE )
3827
+ color_end ();
3828
+ }
3772
3829
}
3773
-
3774
- (void ) putchar ('\n' );
3830
+ if (cb -> cb_json ) {
3831
+ fnvlist_add_nvlist (item , "properties" , props );
3832
+ fnvlist_add_nvlist (d , zfs_get_name (zhp ), item );
3833
+ fnvlist_free (props );
3834
+ fnvlist_free (item );
3835
+ } else
3836
+ (void ) putchar ('\n' );
3775
3837
}
3776
3838
3777
3839
/*
@@ -3783,12 +3845,12 @@ list_callback(zfs_handle_t *zhp, void *data)
3783
3845
list_cbdata_t * cbp = data ;
3784
3846
3785
3847
if (cbp -> cb_first ) {
3786
- if (!cbp -> cb_scripted )
3848
+ if (!cbp -> cb_scripted && ! cbp -> cb_json )
3787
3849
print_header (cbp );
3788
3850
cbp -> cb_first = B_FALSE ;
3789
3851
}
3790
3852
3791
- print_dataset (zhp , cbp );
3853
+ collect_dataset (zhp , cbp );
3792
3854
3793
3855
return (0 );
3794
3856
}
@@ -3807,9 +3869,16 @@ zfs_do_list(int argc, char **argv)
3807
3869
int ret = 0 ;
3808
3870
zfs_sort_column_t * sortcol = NULL ;
3809
3871
int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS ;
3872
+ nvlist_t * data = NULL ;
3873
+
3874
+ struct option long_options [] = {
3875
+ {"json-int" , no_argument , NULL , ZFS_OPTION_JSON_NUMS_AS_INT },
3876
+ {0 , 0 , 0 , 0 }
3877
+ };
3810
3878
3811
3879
/* check options */
3812
- while ((c = getopt (argc , argv , "HS:d:o:prs:t:" )) != -1 ) {
3880
+ while ((c = getopt_long (argc , argv , "jHS:d:o:prs:t:" , long_options ,
3881
+ NULL )) != -1 ) {
3813
3882
switch (c ) {
3814
3883
case 'o' :
3815
3884
fields = optarg ;
@@ -3824,6 +3893,17 @@ zfs_do_list(int argc, char **argv)
3824
3893
case 'r' :
3825
3894
flags |= ZFS_ITER_RECURSE ;
3826
3895
break ;
3896
+ case 'j' :
3897
+ cb .cb_json = B_TRUE ;
3898
+ cb .cb_jsobj = zfs_json_schema (0 , 1 );
3899
+ data = fnvlist_alloc ();
3900
+ fnvlist_add_nvlist (cb .cb_jsobj , "datasets" , data );
3901
+ fnvlist_free (data );
3902
+ break ;
3903
+ case ZFS_OPTION_JSON_NUMS_AS_INT :
3904
+ cb .cb_json_as_int = B_TRUE ;
3905
+ cb .cb_literal = B_TRUE ;
3906
+ break ;
3827
3907
case 'H' :
3828
3908
cb .cb_scripted = B_TRUE ;
3829
3909
break ;
@@ -3897,6 +3977,12 @@ found3:;
3897
3977
argc -= optind ;
3898
3978
argv += optind ;
3899
3979
3980
+ if (!cb .cb_json && cb .cb_json_as_int ) {
3981
+ (void ) fprintf (stderr , gettext ("'--json-int' only works with"
3982
+ " '-j' option\n" ));
3983
+ usage (B_FALSE );
3984
+ }
3985
+
3900
3986
/*
3901
3987
* If "-o space" and no types were specified, don't display snapshots.
3902
3988
*/
@@ -3936,6 +4022,11 @@ found3:;
3936
4022
ret = zfs_for_each (argc , argv , flags , types , sortcol , & cb .cb_proplist ,
3937
4023
limit , list_callback , & cb );
3938
4024
4025
+ if (ret == 0 && cb .cb_json )
4026
+ zcmd_print_json (cb .cb_jsobj );
4027
+ else if (ret != 0 && cb .cb_json )
4028
+ nvlist_free (cb .cb_jsobj );
4029
+
3939
4030
zprop_free_list (cb .cb_proplist );
3940
4031
zfs_free_sort_columns (sortcol );
3941
4032
0 commit comments