Skip to content

Commit

Permalink
Illumos 5745 - zfs set allows only one dataset property to be set at …
Browse files Browse the repository at this point in the history
…a time

5745 zfs set allows only one dataset property to be set at a time
Reviewed by: Christopher Siden <[email protected]>
Reviewed by: George Wilson <[email protected]>
Reviewed by: Matthew Ahrens <[email protected]>
Reviewed by: Bayard Bell <[email protected]>
Reviewed by: Richard PALO <[email protected]>
Reviewed by: Steven Hartland <[email protected]>
Approved by: Rich Lowe <[email protected]>

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 [email protected]
Signed-off-by: Brian Behlendorf <[email protected]>
Closes openzfs#3574
  • Loading branch information
cwill authored and behlendorf committed Dec 30, 2015
1 parent f5f087e commit 23de906
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 87 deletions.
84 changes: 50 additions & 34 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -3472,21 +3475,17 @@ zfs_do_rollback(int argc, char **argv)
}

/*
* 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 "
Expand All @@ -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] == '-') {
Expand All @@ -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);
}

Expand Down Expand Up @@ -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':
Expand Down
3 changes: 2 additions & 1 deletion include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

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

extern const char *zfs_prop_to_name(zfs_prop_t);
extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
extern int zfs_prop_set_list(zfs_handle_t *, nvlist_t *);
extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
zprop_source_t *, char *, size_t, boolean_t);
extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t,
Expand Down
Loading

0 comments on commit 23de906

Please sign in to comment.