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
This commit is contained in:
Chris Williamson
2015-07-06 01:11:09 +02:00
committed by Brian Behlendorf
parent f5f087eb88
commit 23de906c72
5 changed files with 198 additions and 92 deletions
+50 -34
View File
@@ -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':