From 23de906c72946da56a54f75238693e186d44d6e2 Mon Sep 17 00:00:00 2001 From: Chris Williamson <chris.williamson@delphix.com> Date: Mon, 6 Jul 2015 01:11:09 +0200 Subject: Illumos 5745 - zfs set allows only one dataset property to be set at a time 5745 zfs set allows only one dataset property to be set at a time Reviewed by: Christopher Siden <christopher.siden@delphix.com> Reviewed by: George Wilson <george@delphix.com> Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: Bayard Bell <buffer.g.overflow@gmail.com> Reviewed by: Richard PALO <richard@NetBSD.org> Reviewed by: Steven Hartland <killing@multiplay.co.uk> Approved by: Rich Lowe <richlowe@richlowe.net> References: https://www.illumos.org/issues/5745 https://github.com/illumos/illumos-gate/commit/3092556 Porting notes: - Fix the missing braces around initializer, zfs_cmd_t zc = {"\0"}; - Remove extra format argument in zfs_do_set() - Declare at the top: - zfs_prop_t prop; - nvpair_t *elem; - nvpair_t *next; - int i; - Additionally initialize: - int added_resv = 0; - zfs_prop_t prop = 0; - Assign 0 install of NULL for uint64_t types. - zc->zc_nvlist_conf = '\0'; - zc->zc_nvlist_src = '\0'; - zc->zc_nvlist_dst = '\0'; Ported-by: kernelOfTruth kerneloftruth@gmail.com Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #3574 --- cmd/zfs/zfs_main.c | 84 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 34 deletions(-) (limited to 'cmd/zfs') diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 6fb35595c..356bf9aae 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -263,7 +263,7 @@ get_usage(zfs_help_t idx) "\tsend [-Le] [-i snapshot|bookmark] " "<filesystem|volume|snapshot>\n")); case HELP_SET: - return (gettext("\tset <property=value> " + return (gettext("\tset <property=value> ... " "<filesystem|volume|snapshot> ...\n")); case HELP_SHARE: return (gettext("\tshare <-a | filesystem>\n")); @@ -478,15 +478,18 @@ usage(boolean_t requested) exit(requested ? 0 : 2); } +/* + * Take a property=value argument string and add it to the given nvlist. + * Modifies the argument inplace. + */ static int -parseprop(nvlist_t *props) +parseprop(nvlist_t *props, char *propname) { - char *propname = optarg; char *propval, *strval; if ((propval = strchr(propname, '=')) == NULL) { (void) fprintf(stderr, gettext("missing " - "'=' for -o option\n")); + "'=' for property=value argument\n")); return (-1); } *propval = '\0'; @@ -647,7 +650,7 @@ zfs_do_clone(int argc, char **argv) while ((c = getopt(argc, argv, "o:p")) != -1) { switch (c) { case 'o': - if (parseprop(props)) + if (parseprop(props, optarg) != 0) return (1); break; case 'p': @@ -789,7 +792,7 @@ zfs_do_create(int argc, char **argv) nomem(); break; case 'o': - if (parseprop(props)) + if (parseprop(props, optarg)) goto error; break; case 's': @@ -3472,21 +3475,17 @@ out: } /* - * zfs set property=value { fs | snap | vol } ... + * zfs set property=value ... { fs | snap | vol } ... * - * Sets the given property for all datasets specified on the command line. + * Sets the given properties for all datasets specified on the command line. */ -typedef struct set_cbdata { - char *cb_propname; - char *cb_value; -} set_cbdata_t; static int set_callback(zfs_handle_t *zhp, void *data) { - set_cbdata_t *cbp = data; + nvlist_t *props = data; - if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) { + if (zfs_prop_set_list(zhp, props) != 0) { switch (libzfs_errno(g_zfs)) { case EZFS_MOUNTFAILED: (void) fprintf(stderr, gettext("property may be set " @@ -3505,8 +3504,10 @@ set_callback(zfs_handle_t *zhp, void *data) static int zfs_do_set(int argc, char **argv) { - set_cbdata_t cb; + nvlist_t *props = NULL; + int ds_start = -1; /* argv idx of first dataset arg */ int ret = 0; + int i; /* check for options */ if (argc > 1 && argv[1][0] == '-') { @@ -3517,36 +3518,51 @@ zfs_do_set(int argc, char **argv) /* check number of arguments */ if (argc < 2) { - (void) fprintf(stderr, gettext("missing property=value " - "argument\n")); + (void) fprintf(stderr, gettext("missing arguments\n")); usage(B_FALSE); } if (argc < 3) { - (void) fprintf(stderr, gettext("missing dataset name\n")); + if (strchr(argv[1], '=') == NULL) { + (void) fprintf(stderr, gettext("missing property=value " + "argument(s)\n")); + } else { + (void) fprintf(stderr, gettext("missing dataset " + "name(s)\n")); + } usage(B_FALSE); } - /* validate property=value argument */ - cb.cb_propname = argv[1]; - if (((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) || - (cb.cb_value[1] == '\0')) { - (void) fprintf(stderr, gettext("missing value in " - "property=value argument\n")); + /* validate argument order: prop=val args followed by dataset args */ + for (i = 1; i < argc; i++) { + if (strchr(argv[i], '=') != NULL) { + if (ds_start > 0) { + /* out-of-order prop=val argument */ + (void) fprintf(stderr, gettext("invalid " + "argument order\n")); + usage(B_FALSE); + } + } else if (ds_start < 0) { + ds_start = i; + } + } + if (ds_start < 0) { + (void) fprintf(stderr, gettext("missing dataset name(s)\n")); usage(B_FALSE); } - *cb.cb_value = '\0'; - cb.cb_value++; - - if (*cb.cb_propname == '\0') { - (void) fprintf(stderr, - gettext("missing property in property=value argument\n")); - usage(B_FALSE); + /* Populate a list of property settings */ + if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) + nomem(); + for (i = 1; i < ds_start; i++) { + if ((ret = parseprop(props, argv[i])) != 0) + goto error; } - ret = zfs_for_each(argc - 2, argv + 2, 0, - ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb); + ret = zfs_for_each(argc - ds_start, argv + ds_start, 0, + ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, props); +error: + nvlist_free(props); return (ret); } @@ -3606,7 +3622,7 @@ zfs_do_snapshot(int argc, char **argv) while ((c = getopt(argc, argv, "ro:")) != -1) { switch (c) { case 'o': - if (parseprop(props)) + if (parseprop(props, optarg)) return (1); break; case 'r': -- cgit v1.2.3