Skip to content

Commit 23de906

Browse files
cwillbehlendorf
authored andcommitted
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 illumos/illumos-gate@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
1 parent f5f087e commit 23de906

File tree

5 files changed

+193
-87
lines changed

5 files changed

+193
-87
lines changed

cmd/zfs/zfs_main.c

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ get_usage(zfs_help_t idx)
263263
"\tsend [-Le] [-i snapshot|bookmark] "
264264
"<filesystem|volume|snapshot>\n"));
265265
case HELP_SET:
266-
return (gettext("\tset <property=value> "
266+
return (gettext("\tset <property=value> ... "
267267
"<filesystem|volume|snapshot> ...\n"));
268268
case HELP_SHARE:
269269
return (gettext("\tshare <-a | filesystem>\n"));
@@ -478,15 +478,18 @@ usage(boolean_t requested)
478478
exit(requested ? 0 : 2);
479479
}
480480

481+
/*
482+
* Take a property=value argument string and add it to the given nvlist.
483+
* Modifies the argument inplace.
484+
*/
481485
static int
482-
parseprop(nvlist_t *props)
486+
parseprop(nvlist_t *props, char *propname)
483487
{
484-
char *propname = optarg;
485488
char *propval, *strval;
486489

487490
if ((propval = strchr(propname, '=')) == NULL) {
488491
(void) fprintf(stderr, gettext("missing "
489-
"'=' for -o option\n"));
492+
"'=' for property=value argument\n"));
490493
return (-1);
491494
}
492495
*propval = '\0';
@@ -647,7 +650,7 @@ zfs_do_clone(int argc, char **argv)
647650
while ((c = getopt(argc, argv, "o:p")) != -1) {
648651
switch (c) {
649652
case 'o':
650-
if (parseprop(props))
653+
if (parseprop(props, optarg) != 0)
651654
return (1);
652655
break;
653656
case 'p':
@@ -789,7 +792,7 @@ zfs_do_create(int argc, char **argv)
789792
nomem();
790793
break;
791794
case 'o':
792-
if (parseprop(props))
795+
if (parseprop(props, optarg))
793796
goto error;
794797
break;
795798
case 's':
@@ -3472,21 +3475,17 @@ zfs_do_rollback(int argc, char **argv)
34723475
}
34733476

34743477
/*
3475-
* zfs set property=value { fs | snap | vol } ...
3478+
* zfs set property=value ... { fs | snap | vol } ...
34763479
*
3477-
* Sets the given property for all datasets specified on the command line.
3480+
* Sets the given properties for all datasets specified on the command line.
34783481
*/
3479-
typedef struct set_cbdata {
3480-
char *cb_propname;
3481-
char *cb_value;
3482-
} set_cbdata_t;
34833482

34843483
static int
34853484
set_callback(zfs_handle_t *zhp, void *data)
34863485
{
3487-
set_cbdata_t *cbp = data;
3486+
nvlist_t *props = data;
34883487

3489-
if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) {
3488+
if (zfs_prop_set_list(zhp, props) != 0) {
34903489
switch (libzfs_errno(g_zfs)) {
34913490
case EZFS_MOUNTFAILED:
34923491
(void) fprintf(stderr, gettext("property may be set "
@@ -3505,8 +3504,10 @@ set_callback(zfs_handle_t *zhp, void *data)
35053504
static int
35063505
zfs_do_set(int argc, char **argv)
35073506
{
3508-
set_cbdata_t cb;
3507+
nvlist_t *props = NULL;
3508+
int ds_start = -1; /* argv idx of first dataset arg */
35093509
int ret = 0;
3510+
int i;
35103511

35113512
/* check for options */
35123513
if (argc > 1 && argv[1][0] == '-') {
@@ -3517,36 +3518,51 @@ zfs_do_set(int argc, char **argv)
35173518

35183519
/* check number of arguments */
35193520
if (argc < 2) {
3520-
(void) fprintf(stderr, gettext("missing property=value "
3521-
"argument\n"));
3521+
(void) fprintf(stderr, gettext("missing arguments\n"));
35223522
usage(B_FALSE);
35233523
}
35243524
if (argc < 3) {
3525-
(void) fprintf(stderr, gettext("missing dataset name\n"));
3525+
if (strchr(argv[1], '=') == NULL) {
3526+
(void) fprintf(stderr, gettext("missing property=value "
3527+
"argument(s)\n"));
3528+
} else {
3529+
(void) fprintf(stderr, gettext("missing dataset "
3530+
"name(s)\n"));
3531+
}
35263532
usage(B_FALSE);
35273533
}
35283534

3529-
/* validate property=value argument */
3530-
cb.cb_propname = argv[1];
3531-
if (((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) ||
3532-
(cb.cb_value[1] == '\0')) {
3533-
(void) fprintf(stderr, gettext("missing value in "
3534-
"property=value argument\n"));
3535+
/* validate argument order: prop=val args followed by dataset args */
3536+
for (i = 1; i < argc; i++) {
3537+
if (strchr(argv[i], '=') != NULL) {
3538+
if (ds_start > 0) {
3539+
/* out-of-order prop=val argument */
3540+
(void) fprintf(stderr, gettext("invalid "
3541+
"argument order\n"));
3542+
usage(B_FALSE);
3543+
}
3544+
} else if (ds_start < 0) {
3545+
ds_start = i;
3546+
}
3547+
}
3548+
if (ds_start < 0) {
3549+
(void) fprintf(stderr, gettext("missing dataset name(s)\n"));
35353550
usage(B_FALSE);
35363551
}
35373552

3538-
*cb.cb_value = '\0';
3539-
cb.cb_value++;
3540-
3541-
if (*cb.cb_propname == '\0') {
3542-
(void) fprintf(stderr,
3543-
gettext("missing property in property=value argument\n"));
3544-
usage(B_FALSE);
3553+
/* Populate a list of property settings */
3554+
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
3555+
nomem();
3556+
for (i = 1; i < ds_start; i++) {
3557+
if ((ret = parseprop(props, argv[i])) != 0)
3558+
goto error;
35453559
}
35463560

3547-
ret = zfs_for_each(argc - 2, argv + 2, 0,
3548-
ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb);
3561+
ret = zfs_for_each(argc - ds_start, argv + ds_start, 0,
3562+
ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, props);
35493563

3564+
error:
3565+
nvlist_free(props);
35503566
return (ret);
35513567
}
35523568

@@ -3606,7 +3622,7 @@ zfs_do_snapshot(int argc, char **argv)
36063622
while ((c = getopt(argc, argv, "ro:")) != -1) {
36073623
switch (c) {
36083624
case 'o':
3609-
if (parseprop(props))
3625+
if (parseprop(props, optarg))
36103626
return (1);
36113627
break;
36123628
case 'r':

include/libzfs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
/*
2323
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24-
* Copyright (c) 2013 by Delphix. All rights reserved.
24+
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
2525
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
2626
* Copyright (c) 2013 Steven Hartland. All rights reserved.
2727
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
@@ -452,6 +452,7 @@ extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t,
452452

453453
extern const char *zfs_prop_to_name(zfs_prop_t);
454454
extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
455+
extern int zfs_prop_set_list(zfs_handle_t *, nvlist_t *);
455456
extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
456457
zprop_source_t *, char *, size_t, boolean_t);
457458
extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t,

0 commit comments

Comments
 (0)