diff options
Diffstat (limited to 'cmd/zfs/zfs_main.c')
| -rw-r--r-- | cmd/zfs/zfs_main.c | 2885 |
1 files changed, 213 insertions, 2672 deletions
diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 1fd27c5677d8..9516697390ef 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -21,10 +21,6 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. - * Copyright 2012 Milan Jurik. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #include <assert.h> @@ -45,7 +41,6 @@ #include <grp.h> #include <pwd.h> #include <signal.h> -#include <sys/list.h> #include <sys/mkdev.h> #include <sys/mntent.h> #include <sys/mnttab.h> @@ -56,12 +51,7 @@ #include <time.h> #include <libzfs.h> -#include <libzfs_core.h> -#include <zfs_prop.h> -#include <zfs_deleg.h> #include <libuutil.h> -#include <aclutils.h> -#include <directory.h> #include "zfs_iter.h" #include "zfs_util.h" @@ -71,7 +61,7 @@ libzfs_handle_t *g_zfs; static FILE *mnttab_file; static char history_str[HIS_MAX_RECORD_LEN]; -static boolean_t log_history = B_TRUE; +const char *pypath = "/usr/lib/zfs/pyzfs.py"; static int zfs_do_clone(int argc, char **argv); static int zfs_do_create(int argc, char **argv); @@ -92,10 +82,8 @@ static int zfs_do_send(int argc, char **argv); static int zfs_do_receive(int argc, char **argv); static int zfs_do_promote(int argc, char **argv); static int zfs_do_userspace(int argc, char **argv); -static int zfs_do_allow(int argc, char **argv); -static int zfs_do_unallow(int argc, char **argv); +static int zfs_do_python(int argc, char **argv); static int zfs_do_hold(int argc, char **argv); -static int zfs_do_holds(int argc, char **argv); static int zfs_do_release(int argc, char **argv); static int zfs_do_diff(int argc, char **argv); @@ -143,7 +131,7 @@ typedef enum { HELP_HOLD, HELP_HOLDS, HELP_RELEASE, - HELP_DIFF, + HELP_DIFF } zfs_help_t; typedef struct zfs_command { @@ -188,12 +176,12 @@ static zfs_command_t command_table[] = { { "send", zfs_do_send, HELP_SEND }, { "receive", zfs_do_receive, HELP_RECEIVE }, { NULL }, - { "allow", zfs_do_allow, HELP_ALLOW }, + { "allow", zfs_do_python, HELP_ALLOW }, { NULL }, - { "unallow", zfs_do_unallow, HELP_UNALLOW }, + { "unallow", zfs_do_python, HELP_UNALLOW }, { NULL }, { "hold", zfs_do_hold, HELP_HOLD }, - { "holds", zfs_do_holds, HELP_HOLDS }, + { "holds", zfs_do_python, HELP_HOLDS }, { "release", zfs_do_release, HELP_RELEASE }, { "diff", zfs_do_diff, HELP_DIFF }, }; @@ -215,13 +203,11 @@ get_usage(zfs_help_t idx) "\tcreate [-ps] [-b blocksize] [-o property=value] ... " "-V <size> <volume>\n")); case HELP_DESTROY: - return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n" - "\tdestroy [-dnpRrv] " - "<filesystem|volume>@<snap>[%<snap>][,...]\n")); + return (gettext("\tdestroy [-rRf] <filesystem|volume>\n" + "\tdestroy [-rRd] <snapshot>\n")); case HELP_GET: return (gettext("\tget [-rHp] [-d max] " - "[-o \"all\" | field[,...]] [-t type[,...]] " - "[-s source[,...]]\n" + "[-o \"all\" | field[,...]] [-s source[,...]]\n" "\t <\"all\" | property[,...]> " "[filesystem|volume|snapshot] ...\n")); case HELP_INHERIT: @@ -245,15 +231,14 @@ get_usage(zfs_help_t idx) "snapshot>\n" "\treceive [-vnFu] [-d | -e] <filesystem>\n")); case HELP_RENAME: - return (gettext("\trename [-f] <filesystem|volume|snapshot> " + return (gettext("\trename <filesystem|volume|snapshot> " "<filesystem|volume|snapshot>\n" - "\trename [-f] -p <filesystem|volume> <filesystem|volume>\n" + "\trename -p <filesystem|volume> <filesystem|volume>\n" "\trename -r <snapshot> <snapshot>")); case HELP_ROLLBACK: return (gettext("\trollback [-rRf] <snapshot>\n")); case HELP_SEND: - return (gettext("\tsend [-DnPpRrv] [-[iI] snapshot] " - "<snapshot>\n")); + return (gettext("\tsend [-RDp] [-[iI] snapshot] <snapshot>\n")); case HELP_SET: return (gettext("\tset <property=value> " "<filesystem|volume|snapshot> ...\n")); @@ -261,7 +246,7 @@ get_usage(zfs_help_t idx) return (gettext("\tshare <-a | filesystem>\n")); case HELP_SNAPSHOT: return (gettext("\tsnapshot [-r] [-o property=value] ... " - "<filesystem@snapname|volume@snapname> ...\n")); + "<filesystem@snapname|volume@snapname>\n")); case HELP_UNMOUNT: return (gettext("\tunmount [-f] " "<-a | filesystem|mountpoint>\n")); @@ -432,8 +417,6 @@ usage(boolean_t requested) (void) fprintf(fp, "YES NO <size> | none\n"); (void) fprintf(fp, "\t%-15s ", "groupquota@..."); (void) fprintf(fp, "YES NO <size> | none\n"); - (void) fprintf(fp, "\t%-15s ", "written@<snap>"); - (void) fprintf(fp, " NO NO <size>\n"); (void) fprintf(fp, gettext("\nSizes are specified in bytes " "with standard units such as K, M, G, etc.\n")); @@ -579,7 +562,7 @@ zfs_do_clone(int argc, char **argv) zfs_handle_t *zhp = NULL; boolean_t parents = B_FALSE; nvlist_t *props; - int ret = 0; + int ret; int c; if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) @@ -746,6 +729,7 @@ zfs_do_create(int argc, char **argv) (void) fprintf(stderr, gettext("missing size " "argument\n")); goto badusage; + break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); @@ -878,23 +862,15 @@ badusage: */ typedef struct destroy_cbdata { boolean_t cb_first; - boolean_t cb_force; - boolean_t cb_recurse; - boolean_t cb_error; - boolean_t cb_doclones; + int cb_force; + int cb_recurse; + int cb_error; + int cb_needforce; + int cb_doclones; + boolean_t cb_closezhp; zfs_handle_t *cb_target; + char *cb_snapname; boolean_t cb_defer_destroy; - boolean_t cb_verbose; - boolean_t cb_parsable; - boolean_t cb_dryrun; - nvlist_t *cb_nvl; - - /* first snap in contiguous run */ - char *cb_firstsnap; - /* previous snap in contiguous run */ - char *cb_prevsnap; - int64_t cb_snapused; - char *cb_snapspec; } destroy_cbdata_t; /* @@ -924,7 +900,7 @@ destroy_check_dependent(zfs_handle_t *zhp, void *data) (void) fprintf(stderr, gettext("use '-r' to destroy " "the following datasets:\n")); cbp->cb_first = B_FALSE; - cbp->cb_error = B_TRUE; + cbp->cb_error = 1; } (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); @@ -945,8 +921,7 @@ destroy_check_dependent(zfs_handle_t *zhp, void *data) (void) fprintf(stderr, gettext("use '-R' to destroy " "the following datasets:\n")); cbp->cb_first = B_FALSE; - cbp->cb_error = B_TRUE; - cbp->cb_dryrun = B_TRUE; + cbp->cb_error = 1; } (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); @@ -960,20 +935,7 @@ out: static int destroy_callback(zfs_handle_t *zhp, void *data) { - destroy_cbdata_t *cb = data; - const char *name = zfs_get_name(zhp); - - if (cb->cb_verbose) { - if (cb->cb_parsable) { - (void) printf("destroy\t%s\n", name); - } else if (cb->cb_dryrun) { - (void) printf(gettext("would destroy %s\n"), - name); - } else { - (void) printf(gettext("will destroy %s\n"), - name); - } - } + destroy_cbdata_t *cbp = data; /* * Ignore pools (which we've already flagged as an error before getting @@ -985,12 +947,13 @@ destroy_callback(zfs_handle_t *zhp, void *data) return (0); } - if (!cb->cb_dryrun) { - if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 || - zfs_destroy(zhp, cb->cb_defer_destroy) != 0) { - zfs_close(zhp); - return (-1); - } + /* + * Bail out on the first error. + */ + if (zfs_unmount(zhp, NULL, cbp->cb_force ? MS_FORCE : 0) != 0 || + zfs_destroy(zhp, cbp->cb_defer_destroy) != 0) { + zfs_close(zhp); + return (-1); } zfs_close(zhp); @@ -998,144 +961,39 @@ destroy_callback(zfs_handle_t *zhp, void *data) } static int -destroy_print_cb(zfs_handle_t *zhp, void *arg) +destroy_snap_clones(zfs_handle_t *zhp, void *arg) { - destroy_cbdata_t *cb = arg; - const char *name = zfs_get_name(zhp); - int err = 0; + destroy_cbdata_t *cbp = arg; + char thissnap[MAXPATHLEN]; + zfs_handle_t *szhp; + boolean_t closezhp = cbp->cb_closezhp; + int rv; - if (nvlist_exists(cb->cb_nvl, name)) { - if (cb->cb_firstsnap == NULL) - cb->cb_firstsnap = strdup(name); - if (cb->cb_prevsnap != NULL) - free(cb->cb_prevsnap); - /* this snap continues the current range */ - cb->cb_prevsnap = strdup(name); - if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL) - nomem(); - if (cb->cb_verbose) { - if (cb->cb_parsable) { - (void) printf("destroy\t%s\n", name); - } else if (cb->cb_dryrun) { - (void) printf(gettext("would destroy %s\n"), - name); - } else { - (void) printf(gettext("will destroy %s\n"), - name); - } - } - } else if (cb->cb_firstsnap != NULL) { - /* end of this range */ - uint64_t used = 0; - err = lzc_snaprange_space(cb->cb_firstsnap, - cb->cb_prevsnap, &used); - cb->cb_snapused += used; - free(cb->cb_firstsnap); - cb->cb_firstsnap = NULL; - free(cb->cb_prevsnap); - cb->cb_prevsnap = NULL; - } - zfs_close(zhp); - return (err); -} + (void) snprintf(thissnap, sizeof (thissnap), + "%s@%s", zfs_get_name(zhp), cbp->cb_snapname); -static int -destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb) -{ - int err = 0; - assert(cb->cb_firstsnap == NULL); - assert(cb->cb_prevsnap == NULL); - err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb); - if (cb->cb_firstsnap != NULL) { - uint64_t used = 0; - if (err == 0) { - err = lzc_snaprange_space(cb->cb_firstsnap, - cb->cb_prevsnap, &used); + libzfs_print_on_error(g_zfs, B_FALSE); + szhp = zfs_open(g_zfs, thissnap, ZFS_TYPE_SNAPSHOT); + libzfs_print_on_error(g_zfs, B_TRUE); + if (szhp) { + /* + * Destroy any clones of this snapshot + */ + if (zfs_iter_dependents(szhp, B_FALSE, destroy_callback, + cbp) != 0) { + zfs_close(szhp); + if (closezhp) + zfs_close(zhp); + return (-1); } - cb->cb_snapused += used; - free(cb->cb_firstsnap); - cb->cb_firstsnap = NULL; - free(cb->cb_prevsnap); - cb->cb_prevsnap = NULL; - } - return (err); -} - -static int -snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg) -{ - destroy_cbdata_t *cb = arg; - int err = 0; - - /* Check for clones. */ - if (!cb->cb_doclones && !cb->cb_defer_destroy) { - cb->cb_target = zhp; - cb->cb_first = B_TRUE; - err = zfs_iter_dependents(zhp, B_TRUE, - destroy_check_dependent, cb); - } - - if (err == 0) { - if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp))) - nomem(); - } - zfs_close(zhp); - return (err); -} - -static int -gather_snapshots(zfs_handle_t *zhp, void *arg) -{ - destroy_cbdata_t *cb = arg; - int err = 0; - - err = zfs_iter_snapspec(zhp, cb->cb_snapspec, snapshot_to_nvl_cb, cb); - if (err == ENOENT) - err = 0; - if (err != 0) - goto out; - - if (cb->cb_verbose) { - err = destroy_print_snapshots(zhp, cb); - if (err != 0) - goto out; + zfs_close(szhp); } - if (cb->cb_recurse) - err = zfs_iter_filesystems(zhp, gather_snapshots, cb); - -out: - zfs_close(zhp); - return (err); -} - -static int -destroy_clones(destroy_cbdata_t *cb) -{ - nvpair_t *pair; - for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL); - pair != NULL; - pair = nvlist_next_nvpair(cb->cb_nvl, pair)) { - zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair), - ZFS_TYPE_SNAPSHOT); - if (zhp != NULL) { - boolean_t defer = cb->cb_defer_destroy; - int err = 0; - - /* - * We can't defer destroy non-snapshots, so set it to - * false while destroying the clones. - */ - cb->cb_defer_destroy = B_FALSE; - err = zfs_iter_dependents(zhp, B_FALSE, - destroy_callback, cb); - cb->cb_defer_destroy = defer; - zfs_close(zhp); - if (err != 0) - return (err); - } - } - return (0); + cbp->cb_closezhp = B_TRUE; + rv = zfs_iter_filesystems(zhp, destroy_snap_clones, arg); + if (closezhp) + zfs_close(zhp); + return (rv); } static int @@ -1144,35 +1002,25 @@ zfs_do_destroy(int argc, char **argv) destroy_cbdata_t cb = { 0 }; int c; zfs_handle_t *zhp; - char *at; + char *cp; zfs_type_t type = ZFS_TYPE_DATASET; /* check options */ - while ((c = getopt(argc, argv, "vpndfrR")) != -1) { + while ((c = getopt(argc, argv, "dfrR")) != -1) { switch (c) { - case 'v': - cb.cb_verbose = B_TRUE; - break; - case 'p': - cb.cb_verbose = B_TRUE; - cb.cb_parsable = B_TRUE; - break; - case 'n': - cb.cb_dryrun = B_TRUE; - break; case 'd': cb.cb_defer_destroy = B_TRUE; type = ZFS_TYPE_SNAPSHOT; break; case 'f': - cb.cb_force = B_TRUE; + cb.cb_force = 1; break; case 'r': - cb.cb_recurse = B_TRUE; + cb.cb_recurse = 1; break; case 'R': - cb.cb_recurse = B_TRUE; - cb.cb_doclones = B_TRUE; + cb.cb_recurse = 1; + cb.cb_doclones = 1; break; case '?': default: @@ -1187,7 +1035,7 @@ zfs_do_destroy(int argc, char **argv) /* check number of arguments */ if (argc == 0) { - (void) fprintf(stderr, gettext("missing dataset argument\n")); + (void) fprintf(stderr, gettext("missing path argument\n")); usage(B_FALSE); } if (argc > 1) { @@ -1195,117 +1043,91 @@ zfs_do_destroy(int argc, char **argv) usage(B_FALSE); } - at = strchr(argv[0], '@'); - if (at != NULL) { - int err = 0; - - /* Build the list of snaps to destroy in cb_nvl. */ - if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0) - nomem(); - - *at = '\0'; - zhp = zfs_open(g_zfs, argv[0], - ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); - if (zhp == NULL) - return (1); + /* + * If we are doing recursive destroy of a snapshot, then the + * named snapshot may not exist. Go straight to libzfs. + */ + if (cb.cb_recurse && (cp = strchr(argv[0], '@'))) { + int ret; - cb.cb_snapspec = at + 1; - if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 || - cb.cb_error) { - zfs_close(zhp); - nvlist_free(cb.cb_nvl); + *cp = '\0'; + if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL) return (1); - } + *cp = '@'; + cp++; - if (nvlist_empty(cb.cb_nvl)) { - (void) fprintf(stderr, gettext("could not find any " - "snapshots to destroy; check snapshot names.\n")); - zfs_close(zhp); - nvlist_free(cb.cb_nvl); - return (1); - } + if (cb.cb_doclones) { + boolean_t defer = cb.cb_defer_destroy; - if (cb.cb_verbose) { - char buf[16]; - zfs_nicenum(cb.cb_snapused, buf, sizeof (buf)); - if (cb.cb_parsable) { - (void) printf("reclaim\t%llu\n", - cb.cb_snapused); - } else if (cb.cb_dryrun) { - (void) printf(gettext("would reclaim %s\n"), - buf); - } else { - (void) printf(gettext("will reclaim %s\n"), - buf); + /* + * Temporarily ignore the defer_destroy setting since + * it's not supported for clones. + */ + cb.cb_defer_destroy = B_FALSE; + cb.cb_snapname = cp; + if (destroy_snap_clones(zhp, &cb) != 0) { + zfs_close(zhp); + return (1); } + cb.cb_defer_destroy = defer; } - if (!cb.cb_dryrun) { - if (cb.cb_doclones) - err = destroy_clones(&cb); - if (err == 0) { - err = zfs_destroy_snaps_nvl(zhp, cb.cb_nvl, - cb.cb_defer_destroy); - } + ret = zfs_destroy_snaps(zhp, cp, cb.cb_defer_destroy); + zfs_close(zhp); + if (ret) { + (void) fprintf(stderr, + gettext("no snapshots destroyed\n")); } + return (ret != 0); + } - zfs_close(zhp); - nvlist_free(cb.cb_nvl); - if (err != 0) - return (1); - } else { - /* Open the given dataset */ - if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL) - return (1); + /* Open the given dataset */ + if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL) + return (1); - cb.cb_target = zhp; + cb.cb_target = zhp; - /* - * Perform an explicit check for pools before going any further. - */ - if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL && - zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { - (void) fprintf(stderr, gettext("cannot destroy '%s': " - "operation does not apply to pools\n"), - zfs_get_name(zhp)); - (void) fprintf(stderr, gettext("use 'zfs destroy -r " - "%s' to destroy all datasets in the pool\n"), - zfs_get_name(zhp)); - (void) fprintf(stderr, gettext("use 'zpool destroy %s' " - "to destroy the pool itself\n"), zfs_get_name(zhp)); - zfs_close(zhp); - return (1); - } + /* + * Perform an explicit check for pools before going any further. + */ + if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL && + zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { + (void) fprintf(stderr, gettext("cannot destroy '%s': " + "operation does not apply to pools\n"), + zfs_get_name(zhp)); + (void) fprintf(stderr, gettext("use 'zfs destroy -r " + "%s' to destroy all datasets in the pool\n"), + zfs_get_name(zhp)); + (void) fprintf(stderr, gettext("use 'zpool destroy %s' " + "to destroy the pool itself\n"), zfs_get_name(zhp)); + zfs_close(zhp); + return (1); + } - /* - * Check for any dependents and/or clones. - */ - cb.cb_first = B_TRUE; - if (!cb.cb_doclones && - zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent, - &cb) != 0) { - zfs_close(zhp); - return (1); - } + /* + * Check for any dependents and/or clones. + */ + cb.cb_first = B_TRUE; + if (!cb.cb_doclones && !cb.cb_defer_destroy && + zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent, + &cb) != 0) { + zfs_close(zhp); + return (1); + } - if (cb.cb_error) { - zfs_close(zhp); - return (1); - } + if (cb.cb_error || (!cb.cb_defer_destroy && + (zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) != 0))) { + zfs_close(zhp); + return (1); + } - if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback, - &cb) != 0) { - zfs_close(zhp); - return (1); - } + /* + * Do the real thing. The callback will close the handle regardless of + * whether it succeeds or not. + */ - /* - * Do the real thing. The callback will close the - * handle regardless of whether it succeeds or not. - */ - if (destroy_callback(zhp, &cb) != 0) - return (1); - } + if (destroy_callback(zhp, &cb) != 0) + return (1); return (0); } @@ -1407,17 +1229,6 @@ get_callback(zfs_handle_t *zhp, void *data) zprop_print_one_property(zfs_get_name(zhp), cbp, pl->pl_user_prop, buf, sourcetype, source, NULL); - } else if (zfs_prop_written(pl->pl_user_prop)) { - sourcetype = ZPROP_SRC_LOCAL; - - if (zfs_prop_get_written(zhp, pl->pl_user_prop, - buf, sizeof (buf), cbp->cb_literal) != 0) { - sourcetype = ZPROP_SRC_NONE; - (void) strlcpy(buf, "-", sizeof (buf)); - } - - zprop_print_one_property(zfs_get_name(zhp), cbp, - pl->pl_user_prop, buf, sourcetype, source, NULL); } else { if (nvlist_lookup_nvlist(user_props, pl->pl_user_prop, &propval) != 0) { @@ -1462,10 +1273,9 @@ static int zfs_do_get(int argc, char **argv) { zprop_get_cbdata_t cb = { 0 }; - int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS; - int types = ZFS_TYPE_DATASET; + int i, c, flags = 0; char *value, *fields; - int ret = 0; + int ret; int limit = 0; zprop_list_t fake_name = { 0 }; @@ -1480,7 +1290,7 @@ zfs_do_get(int argc, char **argv) cb.cb_type = ZFS_TYPE_DATASET; /* check options */ - while ((c = getopt(argc, argv, ":d:o:s:rt:Hp")) != -1) { + while ((c = getopt(argc, argv, ":d:o:s:rHp")) != -1) { switch (c) { case 'p': cb.cb_literal = B_TRUE; @@ -1598,37 +1408,6 @@ zfs_do_get(int argc, char **argv) } break; - case 't': - types = 0; - flags &= ~ZFS_ITER_PROP_LISTSNAPS; - while (*optarg != '\0') { - static char *type_subopts[] = { "filesystem", - "volume", "snapshot", "all", NULL }; - - switch (getsubopt(&optarg, type_subopts, - &value)) { - case 0: - types |= ZFS_TYPE_FILESYSTEM; - break; - case 1: - types |= ZFS_TYPE_VOLUME; - break; - case 2: - types |= ZFS_TYPE_SNAPSHOT; - break; - case 3: - types = ZFS_TYPE_DATASET; - break; - - default: - (void) fprintf(stderr, - gettext("invalid type '%s'\n"), - value); - usage(B_FALSE); - } - } - break; - case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); @@ -1672,7 +1451,7 @@ zfs_do_get(int argc, char **argv) cb.cb_first = B_TRUE; /* run for each object */ - ret = zfs_for_each(argc, argv, flags, types, NULL, + ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET, NULL, &cb.cb_proplist, limit, get_callback, &cb); if (cb.cb_proplist == &fake_name) @@ -1733,7 +1512,7 @@ zfs_do_inherit(int argc, char **argv) zfs_prop_t prop; inherit_cbdata_t cb = { 0 }; char *propname; - int ret = 0; + int ret; int flags = 0; boolean_t received = B_FALSE; @@ -1908,11 +1687,9 @@ upgrade_set_callback(zfs_handle_t *zhp, void *data) /* * If they did "zfs upgrade -a", then we could * be doing ioctls to different pools. We need - * to log this history once to each pool, and bypass - * the normal history logging that happens in main(). + * to log this history once to each pool. */ - (void) zpool_log_history(g_zfs, history_str); - log_history = B_FALSE; + verify(zpool_stage_history(g_zfs, history_str) == 0); } if (zfs_prop_set(zhp, "version", verstr) == 0) cb->cb_numupgraded++; @@ -1941,7 +1718,7 @@ zfs_do_upgrade(int argc, char **argv) { boolean_t all = B_FALSE; boolean_t showversions = B_FALSE; - int ret = 0; + int ret; upgrade_cbdata_t cb = { 0 }; char c; int flags = ZFS_ITER_ARGS_CAN_BE_PATHS; @@ -1996,8 +1773,8 @@ zfs_do_upgrade(int argc, char **argv) "---------------\n"); (void) printf(gettext(" 1 Initial ZFS filesystem version\n")); (void) printf(gettext(" 2 Enhanced directory entries\n")); - (void) printf(gettext(" 3 Case insensitive and filesystem " - "user identifier (FUID)\n")); + (void) printf(gettext(" 3 Case insensitive and File system " + "unique identifier (FUID)\n")); (void) printf(gettext(" 4 userquota, groupquota " "properties\n")); (void) printf(gettext(" 5 System attributes\n")); @@ -2046,721 +1823,81 @@ zfs_do_upgrade(int argc, char **argv) return (ret); } -#define USTYPE_USR_BIT (0) -#define USTYPE_GRP_BIT (1) -#define USTYPE_PSX_BIT (2) -#define USTYPE_SMB_BIT (3) - -#define USTYPE_USR (1 << USTYPE_USR_BIT) -#define USTYPE_GRP (1 << USTYPE_GRP_BIT) - -#define USTYPE_PSX (1 << USTYPE_PSX_BIT) -#define USTYPE_SMB (1 << USTYPE_SMB_BIT) - -#define USTYPE_PSX_USR (USTYPE_PSX | USTYPE_USR) -#define USTYPE_SMB_USR (USTYPE_SMB | USTYPE_USR) -#define USTYPE_PSX_GRP (USTYPE_PSX | USTYPE_GRP) -#define USTYPE_SMB_GRP (USTYPE_SMB | USTYPE_GRP) -#define USTYPE_ALL (USTYPE_PSX_USR | USTYPE_SMB_USR \ - | USTYPE_PSX_GRP | USTYPE_SMB_GRP) - - -#define USPROP_USED_BIT (0) -#define USPROP_QUOTA_BIT (1) - -#define USPROP_USED (1 << USPROP_USED_BIT) -#define USPROP_QUOTA (1 << USPROP_QUOTA_BIT) - -typedef struct us_node { - nvlist_t *usn_nvl; - uu_avl_node_t usn_avlnode; - uu_list_node_t usn_listnode; -} us_node_t; - -typedef struct us_cbdata { - nvlist_t **cb_nvlp; - uu_avl_pool_t *cb_avl_pool; - uu_avl_t *cb_avl; - boolean_t cb_numname; - boolean_t cb_nicenum; - boolean_t cb_sid2posix; - zfs_userquota_prop_t cb_prop; - zfs_sort_column_t *cb_sortcol; - size_t cb_max_typelen; - size_t cb_max_namelen; - size_t cb_max_usedlen; - size_t cb_max_quotalen; -} us_cbdata_t; - -typedef struct { - zfs_sort_column_t *si_sortcol; - boolean_t si_num_name; - boolean_t si_parsable; -} us_sort_info_t; - -static int -us_compare(const void *larg, const void *rarg, void *unused) -{ - const us_node_t *l = larg; - const us_node_t *r = rarg; - int rc = 0; - us_sort_info_t *si = (us_sort_info_t *)unused; - zfs_sort_column_t *sortcol = si->si_sortcol; - boolean_t num_name = si->si_num_name; - nvlist_t *lnvl = l->usn_nvl; - nvlist_t *rnvl = r->usn_nvl; - - for (; sortcol != NULL; sortcol = sortcol->sc_next) { - char *lvstr = ""; - char *rvstr = ""; - uint32_t lv32 = 0; - uint32_t rv32 = 0; - uint64_t lv64 = 0; - uint64_t rv64 = 0; - zfs_prop_t prop = sortcol->sc_prop; - const char *propname = NULL; - boolean_t reverse = sortcol->sc_reverse; - - switch (prop) { - case ZFS_PROP_TYPE: - propname = "type"; - (void) nvlist_lookup_uint32(lnvl, propname, &lv32); - (void) nvlist_lookup_uint32(rnvl, propname, &rv32); - if (rv32 != lv32) - rc = (rv32 > lv32) ? 1 : -1; - break; - case ZFS_PROP_NAME: - propname = "name"; - if (num_name) { - (void) nvlist_lookup_uint32(lnvl, propname, - &lv32); - (void) nvlist_lookup_uint32(rnvl, propname, - &rv32); - if (rv32 != lv32) - rc = (rv32 > lv32) ? 1 : -1; - } else { - (void) nvlist_lookup_string(lnvl, propname, - &lvstr); - (void) nvlist_lookup_string(rnvl, propname, - &rvstr); - rc = strcmp(lvstr, rvstr); - } - break; - - case ZFS_PROP_USED: - case ZFS_PROP_QUOTA: - if (ZFS_PROP_USED == prop) - propname = "used"; - else - propname = "quota"; - (void) nvlist_lookup_uint64(lnvl, propname, &lv64); - (void) nvlist_lookup_uint64(rnvl, propname, &rv64); - if (rv64 != lv64) - rc = (rv64 > lv64) ? 1 : -1; - } - - if (rc) - if (rc < 0) - return (reverse ? 1 : -1); - else - return (reverse ? -1 : 1); - } - - return (rc); -} - -static inline const char * -us_type2str(unsigned field_type) -{ - switch (field_type) { - case USTYPE_PSX_USR: - return ("POSIX User"); - case USTYPE_PSX_GRP: - return ("POSIX Group"); - case USTYPE_SMB_USR: - return ("SMB User"); - case USTYPE_SMB_GRP: - return ("SMB Group"); - default: - return ("Undefined"); - } -} - /* * zfs userspace */ static int userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space) { - us_cbdata_t *cb = (us_cbdata_t *)arg; - zfs_userquota_prop_t prop = cb->cb_prop; + zfs_userquota_prop_t *typep = arg; + zfs_userquota_prop_t p = *typep; char *name = NULL; - char *propname; + char *ug, *propname; char namebuf[32]; char sizebuf[32]; - us_node_t *node; - uu_avl_pool_t *avl_pool = cb->cb_avl_pool; - uu_avl_t *avl = cb->cb_avl; - uu_avl_index_t idx; - nvlist_t *props; - us_node_t *n; - zfs_sort_column_t *sortcol = cb->cb_sortcol; - unsigned type; - const char *typestr; - size_t namelen; - size_t typelen; - size_t sizelen; - us_sort_info_t sortinfo = { sortcol, cb->cb_numname }; if (domain == NULL || domain[0] == '\0') { - /* POSIX */ - if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) { - type = USTYPE_PSX_GRP; + if (p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA) { struct group *g = getgrgid(rid); if (g) name = g->gr_name; } else { - type = USTYPE_PSX_USR; struct passwd *p = getpwuid(rid); if (p) name = p->pw_name; } - } else { - char sid[ZFS_MAXNAMELEN+32]; - uid_t id; - uint64_t classes; - int err = 0; - directory_error_t e; - - (void) snprintf(sid, sizeof (sid), "%s-%u", domain, rid); - /* SMB */ - if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) { - type = USTYPE_SMB_GRP; - err = sid_to_id(sid, B_FALSE, &id); - } else { - type = USTYPE_SMB_USR; - err = sid_to_id(sid, B_TRUE, &id); - } - - if (err == 0) { - rid = id; - - e = directory_name_from_sid(NULL, sid, &name, &classes); - if (e != NULL) { - directory_error_free(e); - return (NULL); - } - - if (name == NULL) - name = sid; - } } -/* - * if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) - * ug = "group"; - * else - * ug = "user"; - */ + if (p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA) + ug = "group"; + else + ug = "user"; - if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED) + if (p == ZFS_PROP_USERUSED || p == ZFS_PROP_GROUPUSED) propname = "used"; else propname = "quota"; - (void) snprintf(namebuf, sizeof (namebuf), "%u", rid); - if (name == NULL) + if (name == NULL) { + (void) snprintf(namebuf, sizeof (namebuf), + "%llu", (longlong_t)rid); name = namebuf; - - if (cb->cb_nicenum) - zfs_nicenum(space, sizebuf, sizeof (sizebuf)); - else - (void) sprintf(sizebuf, "%llu", space); - - node = safe_malloc(sizeof (us_node_t)); - uu_avl_node_init(node, &node->usn_avlnode, avl_pool); - - if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { - free(node); - return (-1); - } - - if (nvlist_add_uint32(props, "type", type) != 0) - nomem(); - - if (cb->cb_numname) { - if (nvlist_add_uint32(props, "name", rid) != 0) - nomem(); - namelen = strlen(namebuf); - } else { - if (nvlist_add_string(props, "name", name) != 0) - nomem(); - namelen = strlen(name); - } - - typestr = us_type2str(type); - typelen = strlen(gettext(typestr)); - if (typelen > cb->cb_max_typelen) - cb->cb_max_typelen = typelen; - - if (namelen > cb->cb_max_namelen) - cb->cb_max_namelen = namelen; - - sizelen = strlen(sizebuf); - if (0 == strcmp(propname, "used")) { - if (sizelen > cb->cb_max_usedlen) - cb->cb_max_usedlen = sizelen; - } else { - if (sizelen > cb->cb_max_quotalen) - cb->cb_max_quotalen = sizelen; - } - - node->usn_nvl = props; - - n = uu_avl_find(avl, node, &sortinfo, &idx); - if (n == NULL) - uu_avl_insert(avl, node, idx); - else { - nvlist_free(props); - free(node); - node = n; - props = node->usn_nvl; } + zfs_nicenum(space, sizebuf, sizeof (sizebuf)); - if (nvlist_add_uint64(props, propname, space) != 0) - nomem(); + (void) printf("%s %s %s%c%s %s\n", propname, ug, domain, + domain[0] ? '-' : ' ', name, sizebuf); return (0); } -static inline boolean_t -usprop_check(zfs_userquota_prop_t p, unsigned types, unsigned props) -{ - unsigned type; - unsigned prop; - - switch (p) { - case ZFS_PROP_USERUSED: - type = USTYPE_USR; - prop = USPROP_USED; - break; - case ZFS_PROP_USERQUOTA: - type = USTYPE_USR; - prop = USPROP_QUOTA; - break; - case ZFS_PROP_GROUPUSED: - type = USTYPE_GRP; - prop = USPROP_USED; - break; - case ZFS_PROP_GROUPQUOTA: - type = USTYPE_GRP; - prop = USPROP_QUOTA; - break; - default: /* ALL */ - return (B_TRUE); - }; - - return (type & types && prop & props); -} - -#define USFIELD_TYPE (1 << 0) -#define USFIELD_NAME (1 << 1) -#define USFIELD_USED (1 << 2) -#define USFIELD_QUOTA (1 << 3) -#define USFIELD_ALL (USFIELD_TYPE | USFIELD_NAME | USFIELD_USED | USFIELD_QUOTA) - -static int -parsefields(unsigned *fieldsp, char **names, unsigned *bits, size_t len) -{ - char *field = optarg; - char *delim; - - do { - int i; - boolean_t found = B_FALSE; - delim = strchr(field, ','); - if (delim != NULL) - *delim = '\0'; - - for (i = 0; i < len; i++) - if (0 == strcmp(field, names[i])) { - found = B_TRUE; - *fieldsp |= bits[i]; - break; - } - - if (!found) { - (void) fprintf(stderr, gettext("invalid type '%s'" - "for -t option\n"), field); - return (-1); - } - - field = delim + 1; - } while (delim); - - return (0); -} - - -static char *type_names[] = { "posixuser", "smbuser", "posixgroup", "smbgroup", - "all" }; -static unsigned type_bits[] = { - USTYPE_PSX_USR, - USTYPE_SMB_USR, - USTYPE_PSX_GRP, - USTYPE_SMB_GRP, - USTYPE_ALL -}; - -static char *us_field_names[] = { "type", "name", "used", "quota" }; -static unsigned us_field_bits[] = { - USFIELD_TYPE, - USFIELD_NAME, - USFIELD_USED, - USFIELD_QUOTA -}; - -static void -print_us_node(boolean_t scripted, boolean_t parseable, unsigned fields, - size_t type_width, size_t name_width, size_t used_width, - size_t quota_width, us_node_t *node) -{ - nvlist_t *nvl = node->usn_nvl; - nvpair_t *nvp = NULL; - char valstr[ZFS_MAXNAMELEN]; - boolean_t first = B_TRUE; - boolean_t quota_found = B_FALSE; - - if (fields & USFIELD_QUOTA && !nvlist_exists(nvl, "quota")) - if (nvlist_add_string(nvl, "quota", "none") != 0) - nomem(); - - while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { - char *pname = nvpair_name(nvp); - data_type_t type = nvpair_type(nvp); - uint32_t val32 = 0; - uint64_t val64 = 0; - char *strval = NULL; - unsigned field = 0; - unsigned width = 0; - int i; - for (i = 0; i < 4; i++) { - if (0 == strcmp(pname, us_field_names[i])) { - field = us_field_bits[i]; - break; - } - } - - if (!(field & fields)) - continue; - - switch (type) { - case DATA_TYPE_UINT32: - (void) nvpair_value_uint32(nvp, &val32); - break; - case DATA_TYPE_UINT64: - (void) nvpair_value_uint64(nvp, &val64); - break; - case DATA_TYPE_STRING: - (void) nvpair_value_string(nvp, &strval); - break; - default: - (void) fprintf(stderr, "Invalid data type\n"); - } - - if (!first) - if (scripted) - (void) printf("\t"); - else - (void) printf(" "); - - switch (field) { - case USFIELD_TYPE: - strval = (char *)us_type2str(val32); - width = type_width; - break; - case USFIELD_NAME: - if (type == DATA_TYPE_UINT64) { - (void) sprintf(valstr, "%llu", val64); - strval = valstr; - } - width = name_width; - break; - case USFIELD_USED: - case USFIELD_QUOTA: - if (type == DATA_TYPE_UINT64) { - (void) nvpair_value_uint64(nvp, &val64); - if (parseable) - (void) sprintf(valstr, "%llu", val64); - else - zfs_nicenum(val64, valstr, - sizeof (valstr)); - strval = valstr; - } - - if (field == USFIELD_USED) - width = used_width; - else { - quota_found = B_FALSE; - width = quota_width; - } - - break; - } - - if (field == USFIELD_QUOTA && !quota_found) - (void) printf("%*s", width, strval); - else { - if (type == DATA_TYPE_STRING) - (void) printf("%-*s", width, strval); - else - (void) printf("%*s", width, strval); - } - - first = B_FALSE; - - } - - (void) printf("\n"); -} - -static void -print_us(boolean_t scripted, boolean_t parsable, unsigned fields, - unsigned type_width, unsigned name_width, unsigned used_width, - unsigned quota_width, boolean_t rmnode, uu_avl_t *avl) -{ - static char *us_field_hdr[] = { "TYPE", "NAME", "USED", "QUOTA" }; - us_node_t *node; - const char *col; - int i; - size_t width[4] = { type_width, name_width, used_width, quota_width }; - - if (!scripted) { - boolean_t first = B_TRUE; - for (i = 0; i < 4; i++) { - unsigned field = us_field_bits[i]; - if (!(field & fields)) - continue; - - col = gettext(us_field_hdr[i]); - if (field == USFIELD_TYPE || field == USFIELD_NAME) - (void) printf(first?"%-*s":" %-*s", width[i], - col); - else - (void) printf(first?"%*s":" %*s", width[i], - col); - first = B_FALSE; - } - (void) printf("\n"); - } - - for (node = uu_avl_first(avl); node != NULL; - node = uu_avl_next(avl, node)) { - print_us_node(scripted, parsable, fields, type_width, - name_width, used_width, used_width, node); - if (rmnode) - nvlist_free(node->usn_nvl); - } -} - static int zfs_do_userspace(int argc, char **argv) { zfs_handle_t *zhp; zfs_userquota_prop_t p; - uu_avl_pool_t *avl_pool; - uu_avl_t *avl_tree; - uu_avl_walk_t *walk; - - char *cmd; - boolean_t scripted = B_FALSE; - boolean_t prtnum = B_FALSE; - boolean_t parseable = B_FALSE; - boolean_t sid2posix = B_FALSE; - int error = 0; - int c; - zfs_sort_column_t *default_sortcol = NULL; - zfs_sort_column_t *sortcol = NULL; - unsigned types = USTYPE_PSX_USR | USTYPE_SMB_USR; - unsigned fields = 0; - unsigned props = USPROP_USED | USPROP_QUOTA; - us_cbdata_t cb; - us_node_t *node; - boolean_t resort_avl = B_FALSE; - - if (argc < 2) - usage(B_FALSE); - - cmd = argv[0]; - if (0 == strcmp(cmd, "groupspace")) - /* toggle default group types */ - types = USTYPE_PSX_GRP | USTYPE_SMB_GRP; - - /* check options */ - while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) { - switch (c) { - case 'n': - prtnum = B_TRUE; - break; - case 'H': - scripted = B_TRUE; - break; - case 'p': - parseable = B_TRUE; - break; - case 'o': - if (parsefields(&fields, us_field_names, us_field_bits, - 4) != 0) - return (1); - break; - case 's': - if (zfs_add_sort_column(&sortcol, optarg, - B_FALSE) != 0) { - (void) fprintf(stderr, - gettext("invalid property '%s'\n"), optarg); - usage(B_FALSE); - } - break; - case 'S': - if (zfs_add_sort_column(&sortcol, optarg, - B_TRUE) != 0) { - (void) fprintf(stderr, - gettext("invalid property '%s'\n"), optarg); - usage(B_FALSE); - } - break; - case 't': - if (parsefields(&types, type_names, type_bits, 5)) - return (1); - break; - case 'i': - sid2posix = B_TRUE; - break; - case ':': - (void) fprintf(stderr, gettext("missing argument for " - "'%c' option\n"), optopt); - usage(B_FALSE); - break; - case '?': - (void) fprintf(stderr, gettext("invalid option '%c'\n"), - optopt); - usage(B_FALSE); - } - } - - argc -= optind; - argv += optind; + int error; - /* ok, now we have sorted by default colums (type,name) avl tree */ - if (sortcol) { - zfs_sort_column_t *sc; - for (sc = sortcol; sc; sc = sc->sc_next) { - if (sc->sc_prop == ZFS_PROP_QUOTA) { - resort_avl = B_TRUE; - break; - } - } - } + /* + * Try the python version. If the execv fails, we'll continue + * and do a simplistic implementation. + */ + (void) execv(pypath, argv-1); - if (!fields) - fields = USFIELD_ALL; + (void) printf("internal error: %s not found\n" + "falling back on built-in implementation, " + "some features will not work\n", pypath); if ((zhp = zfs_open(g_zfs, argv[argc-1], ZFS_TYPE_DATASET)) == NULL) return (1); - if ((avl_pool = uu_avl_pool_create("us_avl_pool", sizeof (us_node_t), - offsetof(us_node_t, usn_avlnode), - us_compare, UU_DEFAULT)) == NULL) - nomem(); - if ((avl_tree = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) - nomem(); - - if (sortcol && !resort_avl) - cb.cb_sortcol = sortcol; - else { - (void) zfs_add_sort_column(&default_sortcol, "type", B_FALSE); - (void) zfs_add_sort_column(&default_sortcol, "name", B_FALSE); - cb.cb_sortcol = default_sortcol; - } - cb.cb_numname = prtnum; - cb.cb_nicenum = !parseable; - cb.cb_avl_pool = avl_pool; - cb.cb_avl = avl_tree; - cb.cb_sid2posix = sid2posix; - cb.cb_max_typelen = strlen(gettext("TYPE")); - cb.cb_max_namelen = strlen(gettext("NAME")); - cb.cb_max_usedlen = strlen(gettext("USED")); - cb.cb_max_quotalen = strlen(gettext("QUOTA")); + (void) printf("PROP TYPE NAME VALUE\n"); for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) { - if (!usprop_check(p, types, props)) - continue; - - cb.cb_prop = p; - error = zfs_userspace(zhp, p, userspace_cb, &cb); + error = zfs_userspace(zhp, p, userspace_cb, &p); if (error) break; } - - - if (resort_avl) { - us_node_t *node; - us_node_t *rmnode; - uu_list_pool_t *listpool; - uu_list_t *list; - uu_avl_index_t idx = 0; - uu_list_index_t idx2 = 0; - listpool = uu_list_pool_create("tmplist", sizeof (us_node_t), - offsetof(us_node_t, usn_listnode), NULL, - UU_DEFAULT); - list = uu_list_create(listpool, NULL, UU_DEFAULT); - - node = uu_avl_first(avl_tree); - uu_list_node_init(node, &node->usn_listnode, listpool); - while (node != NULL) { - rmnode = node; - node = uu_avl_next(avl_tree, node); - uu_avl_remove(avl_tree, rmnode); - if (uu_list_find(list, rmnode, NULL, &idx2) == NULL) { - uu_list_insert(list, rmnode, idx2); - } - } - - for (node = uu_list_first(list); node != NULL; - node = uu_list_next(list, node)) { - us_sort_info_t sortinfo = { sortcol, cb.cb_numname }; - if (uu_avl_find(avl_tree, node, &sortinfo, &idx) == - NULL) - uu_avl_insert(avl_tree, node, idx); - } - - uu_list_destroy(list); - } - - /* print & free node`s nvlist memory */ - print_us(scripted, parseable, fields, cb.cb_max_typelen, - cb.cb_max_namelen, cb.cb_max_usedlen, - cb.cb_max_quotalen, B_TRUE, cb.cb_avl); - - if (sortcol) - zfs_free_sort_columns(sortcol); - zfs_free_sort_columns(default_sortcol); - - /* - * Finally, clean up the AVL tree. - */ - if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL) - nomem(); - - while ((node = uu_avl_walk_next(walk)) != NULL) { - uu_avl_remove(cb.cb_avl, node); - free(node); - } - - uu_avl_walk_end(walk); - uu_avl_destroy(avl_tree); - uu_avl_pool_destroy(avl_pool); - return (error); } @@ -2868,13 +2005,6 @@ print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted) else propstr = property; right_justify = B_TRUE; - } else if (zfs_prop_written(pl->pl_user_prop)) { - if (zfs_prop_get_written(zhp, pl->pl_user_prop, - property, sizeof (property), B_FALSE) != 0) - propstr = "-"; - else - propstr = property; - right_justify = B_TRUE; } else { if (nvlist_lookup_nvlist(userprops, pl->pl_user_prop, &propval) != 0) @@ -2935,7 +2065,7 @@ zfs_do_list(int argc, char **argv) list_cbdata_t cb = { 0 }; char *value; int limit = 0; - int ret = 0; + int ret; zfs_sort_column_t *sortcol = NULL; int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS; @@ -3050,8 +2180,8 @@ zfs_do_list(int argc, char **argv) } /* - * zfs rename [-f] <fs | snap | vol> <fs | snap | vol> - * zfs rename [-f] -p <fs | vol> <fs | vol> + * zfs rename <fs | snap | vol> <fs | snap | vol> + * zfs rename -p <fs | vol> <fs | vol> * zfs rename -r <snap> <snap> * * Renames the given dataset to another of the same type. @@ -3064,13 +2194,12 @@ zfs_do_rename(int argc, char **argv) { zfs_handle_t *zhp; int c; - int ret = 0; + int ret; boolean_t recurse = B_FALSE; boolean_t parents = B_FALSE; - boolean_t force_unmount = B_FALSE; /* check options */ - while ((c = getopt(argc, argv, "prf")) != -1) { + while ((c = getopt(argc, argv, "pr")) != -1) { switch (c) { case 'p': parents = B_TRUE; @@ -3078,9 +2207,6 @@ zfs_do_rename(int argc, char **argv) case 'r': recurse = B_TRUE; break; - case 'f': - force_unmount = B_TRUE; - break; case '?': default: (void) fprintf(stderr, gettext("invalid option '%c'\n"), @@ -3131,7 +2257,7 @@ zfs_do_rename(int argc, char **argv) return (1); } - ret = (zfs_rename(zhp, argv[1], recurse, force_unmount) != 0); + ret = (zfs_rename(zhp, argv[1], recurse) != 0); zfs_close(zhp); return (ret); @@ -3147,7 +2273,7 @@ static int zfs_do_promote(int argc, char **argv) { zfs_handle_t *zhp; - int ret = 0; + int ret; /* check options */ if (argc > 1 && argv[1][0] == '-') { @@ -3268,7 +2394,7 @@ rollback_check(zfs_handle_t *zhp, void *data) static int zfs_do_rollback(int argc, char **argv) { - int ret = 0; + int ret; int c; boolean_t force = B_FALSE; rollback_cbdata_t cb = { 0 }; @@ -3386,7 +2512,7 @@ static int zfs_do_set(int argc, char **argv) { set_cbdata_t cb; - int ret = 0; + int ret; /* check for options */ if (argc > 1 && argv[1][0] == '-') { @@ -3430,32 +2556,6 @@ zfs_do_set(int argc, char **argv) return (ret); } -typedef struct snap_cbdata { - nvlist_t *sd_nvl; - boolean_t sd_recursive; - const char *sd_snapname; -} snap_cbdata_t; - -static int -zfs_snapshot_cb(zfs_handle_t *zhp, void *arg) -{ - snap_cbdata_t *sd = arg; - char *name; - int rv = 0; - int error; - - error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname); - if (error == -1) - nomem(); - fnvlist_add_boolean(sd->sd_nvl, name); - free(name); - - if (sd->sd_recursive) - rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd); - zfs_close(zhp); - return (rv); -} - /* * zfs snapshot [-r] [-o prop=value] ... <fs@snap> * @@ -3465,16 +2565,13 @@ zfs_snapshot_cb(zfs_handle_t *zhp, void *arg) static int zfs_do_snapshot(int argc, char **argv) { - int ret = 0; + boolean_t recursive = B_FALSE; + int ret; char c; nvlist_t *props; - snap_cbdata_t sd = { 0 }; - boolean_t multiple_snaps = B_FALSE; if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) nomem(); - if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0) - nomem(); /* check options */ while ((c = getopt(argc, argv, "ro:")) != -1) { @@ -3484,8 +2581,7 @@ zfs_do_snapshot(int argc, char **argv) return (1); break; case 'r': - sd.sd_recursive = B_TRUE; - multiple_snaps = B_TRUE; + recursive = B_TRUE; break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), @@ -3502,41 +2598,27 @@ zfs_do_snapshot(int argc, char **argv) (void) fprintf(stderr, gettext("missing snapshot argument\n")); goto usage; } - - if (argc > 1) - multiple_snaps = B_TRUE; - for (; argc > 0; argc--, argv++) { - char *atp; - zfs_handle_t *zhp; - - atp = strchr(argv[0], '@'); - if (atp == NULL) - goto usage; - *atp = '\0'; - sd.sd_snapname = atp + 1; - zhp = zfs_open(g_zfs, argv[0], - ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); - if (zhp == NULL) - goto usage; - if (zfs_snapshot_cb(zhp, &sd) != 0) - goto usage; + if (argc > 1) { + (void) fprintf(stderr, gettext("too many arguments\n")); + goto usage; } - ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props); - nvlist_free(sd.sd_nvl); + ret = zfs_snapshot(g_zfs, argv[0], recursive, props); nvlist_free(props); - if (ret != 0 && multiple_snaps) + if (ret && recursive) (void) fprintf(stderr, gettext("no snapshots were created\n")); return (ret != 0); usage: - nvlist_free(sd.sd_nvl); nvlist_free(props); usage(B_FALSE); return (-1); } /* + * zfs send [-vDp] -R [-i|-I <@snap>] <fs@snap> + * zfs send [-vDp] [-i|-I <@snap>] <fs@snap> + * * Send a backup stream to stdout. */ static int @@ -3548,11 +2630,11 @@ zfs_do_send(int argc, char **argv) zfs_handle_t *zhp; sendflags_t flags = { 0 }; int c, err; - nvlist_t *dbgnv = NULL; + nvlist_t *dbgnv; boolean_t extraverbose = B_FALSE; /* check options */ - while ((c = getopt(argc, argv, ":i:I:RDpvnP")) != -1) { + while ((c = getopt(argc, argv, ":i:I:RDpv")) != -1) { switch (c) { case 'i': if (fromname) @@ -3571,22 +2653,14 @@ zfs_do_send(int argc, char **argv) case 'p': flags.props = B_TRUE; break; - case 'P': - flags.parsable = B_TRUE; - flags.verbose = B_TRUE; - break; case 'v': if (flags.verbose) extraverbose = B_TRUE; flags.verbose = B_TRUE; - flags.progress = B_TRUE; break; case 'D': flags.dedup = B_TRUE; break; - case 'n': - flags.dryrun = B_TRUE; - break; case ':': (void) fprintf(stderr, gettext("missing argument for " "'%c' option\n"), optopt); @@ -3612,7 +2686,7 @@ zfs_do_send(int argc, char **argv) usage(B_FALSE); } - if (!flags.dryrun && isatty(STDOUT_FILENO)) { + if (isatty(STDOUT_FILENO)) { (void) fprintf(stderr, gettext("Error: Stream can not be written to a terminal.\n" "You must redirect standard output.\n")); @@ -3666,10 +2740,10 @@ zfs_do_send(int argc, char **argv) if (flags.replicate && fromname == NULL) flags.doall = B_TRUE; - err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO, NULL, 0, + err = zfs_send(zhp, fromname, toname, flags, STDOUT_FILENO, NULL, 0, extraverbose ? &dbgnv : NULL); - if (extraverbose && dbgnv != NULL) { + if (extraverbose) { /* * dump_nvlist prints to stdout, but that's been * redirected to a file. Make it print to stderr @@ -3750,1357 +2824,11 @@ zfs_do_receive(int argc, char **argv) return (1); } - err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, NULL); + err = zfs_receive(g_zfs, argv[0], flags, STDIN_FILENO, NULL); return (err != 0); } -/* - * allow/unallow stuff - */ -/* copied from zfs/sys/dsl_deleg.h */ -#define ZFS_DELEG_PERM_CREATE "create" -#define ZFS_DELEG_PERM_DESTROY "destroy" -#define ZFS_DELEG_PERM_SNAPSHOT "snapshot" -#define ZFS_DELEG_PERM_ROLLBACK "rollback" -#define ZFS_DELEG_PERM_CLONE "clone" -#define ZFS_DELEG_PERM_PROMOTE "promote" -#define ZFS_DELEG_PERM_RENAME "rename" -#define ZFS_DELEG_PERM_MOUNT "mount" -#define ZFS_DELEG_PERM_SHARE "share" -#define ZFS_DELEG_PERM_SEND "send" -#define ZFS_DELEG_PERM_RECEIVE "receive" -#define ZFS_DELEG_PERM_ALLOW "allow" -#define ZFS_DELEG_PERM_USERPROP "userprop" -#define ZFS_DELEG_PERM_VSCAN "vscan" /* ??? */ -#define ZFS_DELEG_PERM_USERQUOTA "userquota" -#define ZFS_DELEG_PERM_GROUPQUOTA "groupquota" -#define ZFS_DELEG_PERM_USERUSED "userused" -#define ZFS_DELEG_PERM_GROUPUSED "groupused" -#define ZFS_DELEG_PERM_HOLD "hold" -#define ZFS_DELEG_PERM_RELEASE "release" -#define ZFS_DELEG_PERM_DIFF "diff" - -#define ZFS_NUM_DELEG_NOTES ZFS_DELEG_NOTE_NONE - -static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = { - { ZFS_DELEG_PERM_ALLOW, ZFS_DELEG_NOTE_ALLOW }, - { ZFS_DELEG_PERM_CLONE, ZFS_DELEG_NOTE_CLONE }, - { ZFS_DELEG_PERM_CREATE, ZFS_DELEG_NOTE_CREATE }, - { ZFS_DELEG_PERM_DESTROY, ZFS_DELEG_NOTE_DESTROY }, - { ZFS_DELEG_PERM_DIFF, ZFS_DELEG_NOTE_DIFF}, - { ZFS_DELEG_PERM_HOLD, ZFS_DELEG_NOTE_HOLD }, - { ZFS_DELEG_PERM_MOUNT, ZFS_DELEG_NOTE_MOUNT }, - { ZFS_DELEG_PERM_PROMOTE, ZFS_DELEG_NOTE_PROMOTE }, - { ZFS_DELEG_PERM_RECEIVE, ZFS_DELEG_NOTE_RECEIVE }, - { ZFS_DELEG_PERM_RELEASE, ZFS_DELEG_NOTE_RELEASE }, - { ZFS_DELEG_PERM_RENAME, ZFS_DELEG_NOTE_RENAME }, - { ZFS_DELEG_PERM_ROLLBACK, ZFS_DELEG_NOTE_ROLLBACK }, - { ZFS_DELEG_PERM_SEND, ZFS_DELEG_NOTE_SEND }, - { ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE }, - { ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT }, - - { ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA }, - { ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED }, - { ZFS_DELEG_PERM_USERPROP, ZFS_DELEG_NOTE_USERPROP }, - { ZFS_DELEG_PERM_USERQUOTA, ZFS_DELEG_NOTE_USERQUOTA }, - { ZFS_DELEG_PERM_USERUSED, ZFS_DELEG_NOTE_USERUSED }, - { NULL, ZFS_DELEG_NOTE_NONE } -}; - -/* permission structure */ -typedef struct deleg_perm { - zfs_deleg_who_type_t dp_who_type; - const char *dp_name; - boolean_t dp_local; - boolean_t dp_descend; -} deleg_perm_t; - -/* */ -typedef struct deleg_perm_node { - deleg_perm_t dpn_perm; - - uu_avl_node_t dpn_avl_node; -} deleg_perm_node_t; - -typedef struct fs_perm fs_perm_t; - -/* permissions set */ -typedef struct who_perm { - zfs_deleg_who_type_t who_type; - const char *who_name; /* id */ - char who_ug_name[256]; /* user/group name */ - fs_perm_t *who_fsperm; /* uplink */ - - uu_avl_t *who_deleg_perm_avl; /* permissions */ -} who_perm_t; - -/* */ -typedef struct who_perm_node { - who_perm_t who_perm; - uu_avl_node_t who_avl_node; -} who_perm_node_t; - -typedef struct fs_perm_set fs_perm_set_t; -/* fs permissions */ -struct fs_perm { - const char *fsp_name; - - uu_avl_t *fsp_sc_avl; /* sets,create */ - uu_avl_t *fsp_uge_avl; /* user,group,everyone */ - - fs_perm_set_t *fsp_set; /* uplink */ -}; - -/* */ -typedef struct fs_perm_node { - fs_perm_t fspn_fsperm; - uu_avl_t *fspn_avl; - - uu_list_node_t fspn_list_node; -} fs_perm_node_t; - -/* top level structure */ -struct fs_perm_set { - uu_list_pool_t *fsps_list_pool; - uu_list_t *fsps_list; /* list of fs_perms */ - - uu_avl_pool_t *fsps_named_set_avl_pool; - uu_avl_pool_t *fsps_who_perm_avl_pool; - uu_avl_pool_t *fsps_deleg_perm_avl_pool; -}; - -static inline const char * -deleg_perm_type(zfs_deleg_note_t note) -{ - /* subcommands */ - switch (note) { - /* SUBCOMMANDS */ - /* OTHER */ - case ZFS_DELEG_NOTE_GROUPQUOTA: - case ZFS_DELEG_NOTE_GROUPUSED: - case ZFS_DELEG_NOTE_USERPROP: - case ZFS_DELEG_NOTE_USERQUOTA: - case ZFS_DELEG_NOTE_USERUSED: - /* other */ - return (gettext("other")); - default: - return (gettext("subcommand")); - } -} - -static int inline -who_type2weight(zfs_deleg_who_type_t who_type) -{ - int res; - switch (who_type) { - case ZFS_DELEG_NAMED_SET_SETS: - case ZFS_DELEG_NAMED_SET: - res = 0; - break; - case ZFS_DELEG_CREATE_SETS: - case ZFS_DELEG_CREATE: - res = 1; - break; - case ZFS_DELEG_USER_SETS: - case ZFS_DELEG_USER: - res = 2; - break; - case ZFS_DELEG_GROUP_SETS: - case ZFS_DELEG_GROUP: - res = 3; - break; - case ZFS_DELEG_EVERYONE_SETS: - case ZFS_DELEG_EVERYONE: - res = 4; - break; - default: - res = -1; - } - - return (res); -} - -/* ARGSUSED */ -static int -who_perm_compare(const void *larg, const void *rarg, void *unused) -{ - const who_perm_node_t *l = larg; - const who_perm_node_t *r = rarg; - zfs_deleg_who_type_t ltype = l->who_perm.who_type; - zfs_deleg_who_type_t rtype = r->who_perm.who_type; - int lweight = who_type2weight(ltype); - int rweight = who_type2weight(rtype); - int res = lweight - rweight; - if (res == 0) - res = strncmp(l->who_perm.who_name, r->who_perm.who_name, - ZFS_MAX_DELEG_NAME-1); - - if (res == 0) - return (0); - if (res > 0) - return (1); - else - return (-1); -} - -/* ARGSUSED */ -static int -deleg_perm_compare(const void *larg, const void *rarg, void *unused) -{ - const deleg_perm_node_t *l = larg; - const deleg_perm_node_t *r = rarg; - int res = strncmp(l->dpn_perm.dp_name, r->dpn_perm.dp_name, - ZFS_MAX_DELEG_NAME-1); - - if (res == 0) - return (0); - - if (res > 0) - return (1); - else - return (-1); -} - -static inline void -fs_perm_set_init(fs_perm_set_t *fspset) -{ - bzero(fspset, sizeof (fs_perm_set_t)); - - if ((fspset->fsps_list_pool = uu_list_pool_create("fsps_list_pool", - sizeof (fs_perm_node_t), offsetof(fs_perm_node_t, fspn_list_node), - NULL, UU_DEFAULT)) == NULL) - nomem(); - if ((fspset->fsps_list = uu_list_create(fspset->fsps_list_pool, NULL, - UU_DEFAULT)) == NULL) - nomem(); - - if ((fspset->fsps_named_set_avl_pool = uu_avl_pool_create( - "named_set_avl_pool", sizeof (who_perm_node_t), offsetof( - who_perm_node_t, who_avl_node), who_perm_compare, - UU_DEFAULT)) == NULL) - nomem(); - - if ((fspset->fsps_who_perm_avl_pool = uu_avl_pool_create( - "who_perm_avl_pool", sizeof (who_perm_node_t), offsetof( - who_perm_node_t, who_avl_node), who_perm_compare, - UU_DEFAULT)) == NULL) - nomem(); - - if ((fspset->fsps_deleg_perm_avl_pool = uu_avl_pool_create( - "deleg_perm_avl_pool", sizeof (deleg_perm_node_t), offsetof( - deleg_perm_node_t, dpn_avl_node), deleg_perm_compare, UU_DEFAULT)) - == NULL) - nomem(); -} - -static inline void fs_perm_fini(fs_perm_t *); -static inline void who_perm_fini(who_perm_t *); - -static inline void -fs_perm_set_fini(fs_perm_set_t *fspset) -{ - fs_perm_node_t *node = uu_list_first(fspset->fsps_list); - - while (node != NULL) { - fs_perm_node_t *next_node = - uu_list_next(fspset->fsps_list, node); - fs_perm_t *fsperm = &node->fspn_fsperm; - fs_perm_fini(fsperm); - uu_list_remove(fspset->fsps_list, node); - free(node); - node = next_node; - } - - uu_avl_pool_destroy(fspset->fsps_named_set_avl_pool); - uu_avl_pool_destroy(fspset->fsps_who_perm_avl_pool); - uu_avl_pool_destroy(fspset->fsps_deleg_perm_avl_pool); -} - -static inline void -deleg_perm_init(deleg_perm_t *deleg_perm, zfs_deleg_who_type_t type, - const char *name) -{ - deleg_perm->dp_who_type = type; - deleg_perm->dp_name = name; -} - -static inline void -who_perm_init(who_perm_t *who_perm, fs_perm_t *fsperm, - zfs_deleg_who_type_t type, const char *name) -{ - uu_avl_pool_t *pool; - pool = fsperm->fsp_set->fsps_deleg_perm_avl_pool; - - bzero(who_perm, sizeof (who_perm_t)); - - if ((who_perm->who_deleg_perm_avl = uu_avl_create(pool, NULL, - UU_DEFAULT)) == NULL) - nomem(); - - who_perm->who_type = type; - who_perm->who_name = name; - who_perm->who_fsperm = fsperm; -} - -static inline void -who_perm_fini(who_perm_t *who_perm) -{ - deleg_perm_node_t *node = uu_avl_first(who_perm->who_deleg_perm_avl); - - while (node != NULL) { - deleg_perm_node_t *next_node = - uu_avl_next(who_perm->who_deleg_perm_avl, node); - - uu_avl_remove(who_perm->who_deleg_perm_avl, node); - free(node); - node = next_node; - } - - uu_avl_destroy(who_perm->who_deleg_perm_avl); -} - -static inline void -fs_perm_init(fs_perm_t *fsperm, fs_perm_set_t *fspset, const char *fsname) -{ - uu_avl_pool_t *nset_pool = fspset->fsps_named_set_avl_pool; - uu_avl_pool_t *who_pool = fspset->fsps_who_perm_avl_pool; - - bzero(fsperm, sizeof (fs_perm_t)); - - if ((fsperm->fsp_sc_avl = uu_avl_create(nset_pool, NULL, UU_DEFAULT)) - == NULL) - nomem(); - - if ((fsperm->fsp_uge_avl = uu_avl_create(who_pool, NULL, UU_DEFAULT)) - == NULL) - nomem(); - - fsperm->fsp_set = fspset; - fsperm->fsp_name = fsname; -} - -static inline void -fs_perm_fini(fs_perm_t *fsperm) -{ - who_perm_node_t *node = uu_avl_first(fsperm->fsp_sc_avl); - while (node != NULL) { - who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_sc_avl, - node); - who_perm_t *who_perm = &node->who_perm; - who_perm_fini(who_perm); - uu_avl_remove(fsperm->fsp_sc_avl, node); - free(node); - node = next_node; - } - - node = uu_avl_first(fsperm->fsp_uge_avl); - while (node != NULL) { - who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_uge_avl, - node); - who_perm_t *who_perm = &node->who_perm; - who_perm_fini(who_perm); - uu_avl_remove(fsperm->fsp_uge_avl, node); - free(node); - node = next_node; - } - - uu_avl_destroy(fsperm->fsp_sc_avl); - uu_avl_destroy(fsperm->fsp_uge_avl); -} - -static void inline -set_deleg_perm_node(uu_avl_t *avl, deleg_perm_node_t *node, - zfs_deleg_who_type_t who_type, const char *name, char locality) -{ - uu_avl_index_t idx = 0; - - deleg_perm_node_t *found_node = NULL; - deleg_perm_t *deleg_perm = &node->dpn_perm; - - deleg_perm_init(deleg_perm, who_type, name); - - if ((found_node = uu_avl_find(avl, node, NULL, &idx)) - == NULL) - uu_avl_insert(avl, node, idx); - else { - node = found_node; - deleg_perm = &node->dpn_perm; - } - - - switch (locality) { - case ZFS_DELEG_LOCAL: - deleg_perm->dp_local = B_TRUE; - break; - case ZFS_DELEG_DESCENDENT: - deleg_perm->dp_descend = B_TRUE; - break; - case ZFS_DELEG_NA: - break; - default: - assert(B_FALSE); /* invalid locality */ - } -} - -static inline int -parse_who_perm(who_perm_t *who_perm, nvlist_t *nvl, char locality) -{ - nvpair_t *nvp = NULL; - fs_perm_set_t *fspset = who_perm->who_fsperm->fsp_set; - uu_avl_t *avl = who_perm->who_deleg_perm_avl; - zfs_deleg_who_type_t who_type = who_perm->who_type; - - while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { - const char *name = nvpair_name(nvp); - data_type_t type = nvpair_type(nvp); - uu_avl_pool_t *avl_pool = fspset->fsps_deleg_perm_avl_pool; - deleg_perm_node_t *node = - safe_malloc(sizeof (deleg_perm_node_t)); - - assert(type == DATA_TYPE_BOOLEAN); - - uu_avl_node_init(node, &node->dpn_avl_node, avl_pool); - set_deleg_perm_node(avl, node, who_type, name, locality); - } - - return (0); -} - -static inline int -parse_fs_perm(fs_perm_t *fsperm, nvlist_t *nvl) -{ - nvpair_t *nvp = NULL; - fs_perm_set_t *fspset = fsperm->fsp_set; - - while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { - nvlist_t *nvl2 = NULL; - const char *name = nvpair_name(nvp); - uu_avl_t *avl = NULL; - uu_avl_pool_t *avl_pool; - zfs_deleg_who_type_t perm_type = name[0]; - char perm_locality = name[1]; - const char *perm_name = name + 3; - boolean_t is_set = B_TRUE; - who_perm_t *who_perm = NULL; - - assert('$' == name[2]); - - if (nvpair_value_nvlist(nvp, &nvl2) != 0) - return (-1); - - switch (perm_type) { - case ZFS_DELEG_CREATE: - case ZFS_DELEG_CREATE_SETS: - case ZFS_DELEG_NAMED_SET: - case ZFS_DELEG_NAMED_SET_SETS: - avl_pool = fspset->fsps_named_set_avl_pool; - avl = fsperm->fsp_sc_avl; - break; - case ZFS_DELEG_USER: - case ZFS_DELEG_USER_SETS: - case ZFS_DELEG_GROUP: - case ZFS_DELEG_GROUP_SETS: - case ZFS_DELEG_EVERYONE: - case ZFS_DELEG_EVERYONE_SETS: - avl_pool = fspset->fsps_who_perm_avl_pool; - avl = fsperm->fsp_uge_avl; - break; - } - - if (is_set) { - who_perm_node_t *found_node = NULL; - who_perm_node_t *node = safe_malloc( - sizeof (who_perm_node_t)); - who_perm = &node->who_perm; - uu_avl_index_t idx = 0; - - uu_avl_node_init(node, &node->who_avl_node, avl_pool); - who_perm_init(who_perm, fsperm, perm_type, perm_name); - - if ((found_node = uu_avl_find(avl, node, NULL, &idx)) - == NULL) { - if (avl == fsperm->fsp_uge_avl) { - uid_t rid = 0; - struct passwd *p = NULL; - struct group *g = NULL; - const char *nice_name = NULL; - - switch (perm_type) { - case ZFS_DELEG_USER_SETS: - case ZFS_DELEG_USER: - rid = atoi(perm_name); - p = getpwuid(rid); - if (p) - nice_name = p->pw_name; - break; - case ZFS_DELEG_GROUP_SETS: - case ZFS_DELEG_GROUP: - rid = atoi(perm_name); - g = getgrgid(rid); - if (g) - nice_name = g->gr_name; - break; - } - - if (nice_name != NULL) - (void) strlcpy( - node->who_perm.who_ug_name, - nice_name, 256); - } - - uu_avl_insert(avl, node, idx); - } else { - node = found_node; - who_perm = &node->who_perm; - } - } - - (void) parse_who_perm(who_perm, nvl2, perm_locality); - } - - return (0); -} - -static inline int -parse_fs_perm_set(fs_perm_set_t *fspset, nvlist_t *nvl) -{ - nvpair_t *nvp = NULL; - uu_avl_index_t idx = 0; - - while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { - nvlist_t *nvl2 = NULL; - const char *fsname = nvpair_name(nvp); - data_type_t type = nvpair_type(nvp); - fs_perm_t *fsperm = NULL; - fs_perm_node_t *node = safe_malloc(sizeof (fs_perm_node_t)); - if (node == NULL) - nomem(); - - fsperm = &node->fspn_fsperm; - - assert(DATA_TYPE_NVLIST == type); - - uu_list_node_init(node, &node->fspn_list_node, - fspset->fsps_list_pool); - - idx = uu_list_numnodes(fspset->fsps_list); - fs_perm_init(fsperm, fspset, fsname); - - if (nvpair_value_nvlist(nvp, &nvl2) != 0) - return (-1); - - (void) parse_fs_perm(fsperm, nvl2); - - uu_list_insert(fspset->fsps_list, node, idx); - } - - return (0); -} - -static inline const char * -deleg_perm_comment(zfs_deleg_note_t note) -{ - const char *str = ""; - - /* subcommands */ - switch (note) { - /* SUBCOMMANDS */ - case ZFS_DELEG_NOTE_ALLOW: - str = gettext("Must also have the permission that is being" - "\n\t\t\t\tallowed"); - break; - case ZFS_DELEG_NOTE_CLONE: - str = gettext("Must also have the 'create' ability and 'mount'" - "\n\t\t\t\tability in the origin file system"); - break; - case ZFS_DELEG_NOTE_CREATE: - str = gettext("Must also have the 'mount' ability"); - break; - case ZFS_DELEG_NOTE_DESTROY: - str = gettext("Must also have the 'mount' ability"); - break; - case ZFS_DELEG_NOTE_DIFF: - str = gettext("Allows lookup of paths within a dataset;" - "\n\t\t\t\tgiven an object number. Ordinary users need this" - "\n\t\t\t\tin order to use zfs diff"); - break; - case ZFS_DELEG_NOTE_HOLD: - str = gettext("Allows adding a user hold to a snapshot"); - break; - case ZFS_DELEG_NOTE_MOUNT: - str = gettext("Allows mount/umount of ZFS datasets"); - break; - case ZFS_DELEG_NOTE_PROMOTE: - str = gettext("Must also have the 'mount'\n\t\t\t\tand" - " 'promote' ability in the origin file system"); - break; - case ZFS_DELEG_NOTE_RECEIVE: - str = gettext("Must also have the 'mount' and 'create'" - " ability"); - break; - case ZFS_DELEG_NOTE_RELEASE: - str = gettext("Allows releasing a user hold which\n\t\t\t\t" - "might destroy the snapshot"); - break; - case ZFS_DELEG_NOTE_RENAME: - str = gettext("Must also have the 'mount' and 'create'" - "\n\t\t\t\tability in the new parent"); - break; - case ZFS_DELEG_NOTE_ROLLBACK: - str = gettext(""); - break; - case ZFS_DELEG_NOTE_SEND: - str = gettext(""); - break; - case ZFS_DELEG_NOTE_SHARE: - str = gettext("Allows sharing file systems over NFS or SMB" - "\n\t\t\t\tprotocols"); - break; - case ZFS_DELEG_NOTE_SNAPSHOT: - str = gettext(""); - break; -/* - * case ZFS_DELEG_NOTE_VSCAN: - * str = gettext(""); - * break; - */ - /* OTHER */ - case ZFS_DELEG_NOTE_GROUPQUOTA: - str = gettext("Allows accessing any groupquota@... property"); - break; - case ZFS_DELEG_NOTE_GROUPUSED: - str = gettext("Allows reading any groupused@... property"); - break; - case ZFS_DELEG_NOTE_USERPROP: - str = gettext("Allows changing any user property"); - break; - case ZFS_DELEG_NOTE_USERQUOTA: - str = gettext("Allows accessing any userquota@... property"); - break; - case ZFS_DELEG_NOTE_USERUSED: - str = gettext("Allows reading any userused@... property"); - break; - /* other */ - default: - str = ""; - } - - return (str); -} - -struct allow_opts { - boolean_t local; - boolean_t descend; - boolean_t user; - boolean_t group; - boolean_t everyone; - boolean_t create; - boolean_t set; - boolean_t recursive; /* unallow only */ - boolean_t prt_usage; - - boolean_t prt_perms; - char *who; - char *perms; - const char *dataset; -}; - -static inline int -prop_cmp(const void *a, const void *b) -{ - const char *str1 = *(const char **)a; - const char *str2 = *(const char **)b; - return (strcmp(str1, str2)); -} - -static void -allow_usage(boolean_t un, boolean_t requested, const char *msg) -{ - const char *opt_desc[] = { - "-h", gettext("show this help message and exit"), - "-l", gettext("set permission locally"), - "-d", gettext("set permission for descents"), - "-u", gettext("set permission for user"), - "-g", gettext("set permission for group"), - "-e", gettext("set permission for everyone"), - "-c", gettext("set create time permission"), - "-s", gettext("define permission set"), - /* unallow only */ - "-r", gettext("remove permissions recursively"), - }; - size_t unallow_size = sizeof (opt_desc) / sizeof (char *); - size_t allow_size = unallow_size - 2; - const char *props[ZFS_NUM_PROPS]; - int i; - size_t count = 0; - FILE *fp = requested ? stdout : stderr; - zprop_desc_t *pdtbl = zfs_prop_get_table(); - const char *fmt = gettext("%-16s %-14s\t%s\n"); - - (void) fprintf(fp, gettext("Usage: %s\n"), get_usage(un ? HELP_UNALLOW : - HELP_ALLOW)); - (void) fprintf(fp, gettext("Options:\n")); - for (int i = 0; i < (un ? unallow_size : allow_size); i++) { - const char *opt = opt_desc[i++]; - const char *optdsc = opt_desc[i]; - (void) fprintf(fp, gettext(" %-10s %s\n"), opt, optdsc); - } - - (void) fprintf(fp, gettext("\nThe following permissions are " - "supported:\n\n")); - (void) fprintf(fp, fmt, gettext("NAME"), gettext("TYPE"), - gettext("NOTES")); - for (i = 0; i < ZFS_NUM_DELEG_NOTES; i++) { - const char *perm_name = zfs_deleg_perm_tbl[i].z_perm; - zfs_deleg_note_t perm_note = zfs_deleg_perm_tbl[i].z_note; - const char *perm_type = deleg_perm_type(perm_note); - const char *perm_comment = deleg_perm_comment(perm_note); - (void) fprintf(fp, fmt, perm_name, perm_type, perm_comment); - } - - for (i = 0; i < ZFS_NUM_PROPS; i++) { - zprop_desc_t *pd = &pdtbl[i]; - if (pd->pd_visible != B_TRUE) - continue; - - if (pd->pd_attr == PROP_READONLY) - continue; - - props[count++] = pd->pd_name; - } - props[count] = NULL; - - qsort(props, count, sizeof (char *), prop_cmp); - - for (i = 0; i < count; i++) - (void) fprintf(fp, fmt, props[i], gettext("property"), ""); - - if (msg != NULL) - (void) fprintf(fp, gettext("\nzfs: error: %s"), msg); - - exit(requested ? 0 : 2); -} - -static inline const char * -munge_args(int argc, char **argv, boolean_t un, size_t expected_argc, - char **permsp) -{ - if (un && argc == expected_argc - 1) - *permsp = NULL; - else if (argc == expected_argc) - *permsp = argv[argc - 2]; - else - allow_usage(un, B_FALSE, - gettext("wrong number of parameters\n")); - - return (argv[argc - 1]); -} - -static void -parse_allow_args(int argc, char **argv, boolean_t un, struct allow_opts *opts) -{ - int uge_sum = opts->user + opts->group + opts->everyone; - int csuge_sum = opts->create + opts->set + uge_sum; - int ldcsuge_sum = csuge_sum + opts->local + opts->descend; - int all_sum = un ? ldcsuge_sum + opts->recursive : ldcsuge_sum; - - if (uge_sum > 1) - allow_usage(un, B_FALSE, - gettext("-u, -g, and -e are mutually exclusive\n")); - - if (opts->prt_usage) - if (argc == 0 && all_sum == 0) - allow_usage(un, B_TRUE, NULL); - else - usage(B_FALSE); - - if (opts->set) { - if (csuge_sum > 1) - allow_usage(un, B_FALSE, - gettext("invalid options combined with -s\n")); - - opts->dataset = munge_args(argc, argv, un, 3, &opts->perms); - if (argv[0][0] != '@') - allow_usage(un, B_FALSE, - gettext("invalid set name: missing '@' prefix\n")); - opts->who = argv[0]; - } else if (opts->create) { - if (ldcsuge_sum > 1) - allow_usage(un, B_FALSE, - gettext("invalid options combined with -c\n")); - opts->dataset = munge_args(argc, argv, un, 2, &opts->perms); - } else if (opts->everyone) { - if (csuge_sum > 1) - allow_usage(un, B_FALSE, - gettext("invalid options combined with -e\n")); - opts->dataset = munge_args(argc, argv, un, 2, &opts->perms); - } else if (uge_sum == 0 && argc > 0 && strcmp(argv[0], "everyone") - == 0) { - opts->everyone = B_TRUE; - argc--; - argv++; - opts->dataset = munge_args(argc, argv, un, 2, &opts->perms); - } else if (argc == 1 && !un) { - opts->prt_perms = B_TRUE; - opts->dataset = argv[argc-1]; - } else { - opts->dataset = munge_args(argc, argv, un, 3, &opts->perms); - opts->who = argv[0]; - } - - if (!opts->local && !opts->descend) { - opts->local = B_TRUE; - opts->descend = B_TRUE; - } -} - -static void -store_allow_perm(zfs_deleg_who_type_t type, boolean_t local, boolean_t descend, - const char *who, char *perms, nvlist_t *top_nvl) -{ - int i; - char ld[2] = { '\0', '\0' }; - char who_buf[ZFS_MAXNAMELEN+32]; - char base_type; - char set_type; - nvlist_t *base_nvl = NULL; - nvlist_t *set_nvl = NULL; - nvlist_t *nvl; - - if (nvlist_alloc(&base_nvl, NV_UNIQUE_NAME, 0) != 0) - nomem(); - if (nvlist_alloc(&set_nvl, NV_UNIQUE_NAME, 0) != 0) - nomem(); - - switch (type) { - case ZFS_DELEG_NAMED_SET_SETS: - case ZFS_DELEG_NAMED_SET: - set_type = ZFS_DELEG_NAMED_SET_SETS; - base_type = ZFS_DELEG_NAMED_SET; - ld[0] = ZFS_DELEG_NA; - break; - case ZFS_DELEG_CREATE_SETS: - case ZFS_DELEG_CREATE: - set_type = ZFS_DELEG_CREATE_SETS; - base_type = ZFS_DELEG_CREATE; - ld[0] = ZFS_DELEG_NA; - break; - case ZFS_DELEG_USER_SETS: - case ZFS_DELEG_USER: - set_type = ZFS_DELEG_USER_SETS; - base_type = ZFS_DELEG_USER; - if (local) - ld[0] = ZFS_DELEG_LOCAL; - if (descend) - ld[1] = ZFS_DELEG_DESCENDENT; - break; - case ZFS_DELEG_GROUP_SETS: - case ZFS_DELEG_GROUP: - set_type = ZFS_DELEG_GROUP_SETS; - base_type = ZFS_DELEG_GROUP; - if (local) - ld[0] = ZFS_DELEG_LOCAL; - if (descend) - ld[1] = ZFS_DELEG_DESCENDENT; - break; - case ZFS_DELEG_EVERYONE_SETS: - case ZFS_DELEG_EVERYONE: - set_type = ZFS_DELEG_EVERYONE_SETS; - base_type = ZFS_DELEG_EVERYONE; - if (local) - ld[0] = ZFS_DELEG_LOCAL; - if (descend) - ld[1] = ZFS_DELEG_DESCENDENT; - } - - if (perms != NULL) { - char *curr = perms; - char *end = curr + strlen(perms); - - while (curr < end) { - char *delim = strchr(curr, ','); - if (delim == NULL) - delim = end; - else - *delim = '\0'; - - if (curr[0] == '@') - nvl = set_nvl; - else - nvl = base_nvl; - - (void) nvlist_add_boolean(nvl, curr); - if (delim != end) - *delim = ','; - curr = delim + 1; - } - - for (i = 0; i < 2; i++) { - char locality = ld[i]; - if (locality == 0) - continue; - - if (!nvlist_empty(base_nvl)) { - if (who != NULL) - (void) snprintf(who_buf, - sizeof (who_buf), "%c%c$%s", - base_type, locality, who); - else - (void) snprintf(who_buf, - sizeof (who_buf), "%c%c$", - base_type, locality); - - (void) nvlist_add_nvlist(top_nvl, who_buf, - base_nvl); - } - - - if (!nvlist_empty(set_nvl)) { - if (who != NULL) - (void) snprintf(who_buf, - sizeof (who_buf), "%c%c$%s", - set_type, locality, who); - else - (void) snprintf(who_buf, - sizeof (who_buf), "%c%c$", - set_type, locality); - - (void) nvlist_add_nvlist(top_nvl, who_buf, - set_nvl); - } - } - } else { - for (i = 0; i < 2; i++) { - char locality = ld[i]; - if (locality == 0) - continue; - - if (who != NULL) - (void) snprintf(who_buf, sizeof (who_buf), - "%c%c$%s", base_type, locality, who); - else - (void) snprintf(who_buf, sizeof (who_buf), - "%c%c$", base_type, locality); - (void) nvlist_add_boolean(top_nvl, who_buf); - - if (who != NULL) - (void) snprintf(who_buf, sizeof (who_buf), - "%c%c$%s", set_type, locality, who); - else - (void) snprintf(who_buf, sizeof (who_buf), - "%c%c$", set_type, locality); - (void) nvlist_add_boolean(top_nvl, who_buf); - } - } -} - -static int -construct_fsacl_list(boolean_t un, struct allow_opts *opts, nvlist_t **nvlp) -{ - if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) - nomem(); - - if (opts->set) { - store_allow_perm(ZFS_DELEG_NAMED_SET, opts->local, - opts->descend, opts->who, opts->perms, *nvlp); - } else if (opts->create) { - store_allow_perm(ZFS_DELEG_CREATE, opts->local, - opts->descend, NULL, opts->perms, *nvlp); - } else if (opts->everyone) { - store_allow_perm(ZFS_DELEG_EVERYONE, opts->local, - opts->descend, NULL, opts->perms, *nvlp); - } else { - char *curr = opts->who; - char *end = curr + strlen(curr); - - while (curr < end) { - const char *who; - zfs_deleg_who_type_t who_type; - char *endch; - char *delim = strchr(curr, ','); - char errbuf[256]; - char id[64]; - struct passwd *p = NULL; - struct group *g = NULL; - - uid_t rid; - if (delim == NULL) - delim = end; - else - *delim = '\0'; - - rid = (uid_t)strtol(curr, &endch, 0); - if (opts->user) { - who_type = ZFS_DELEG_USER; - if (*endch != '\0') - p = getpwnam(curr); - else - p = getpwuid(rid); - - if (p != NULL) - rid = p->pw_uid; - else { - (void) snprintf(errbuf, 256, gettext( - "invalid user %s"), curr); - allow_usage(un, B_TRUE, errbuf); - } - } else if (opts->group) { - who_type = ZFS_DELEG_GROUP; - if (*endch != '\0') - g = getgrnam(curr); - else - g = getgrgid(rid); - - if (g != NULL) - rid = g->gr_gid; - else { - (void) snprintf(errbuf, 256, gettext( - "invalid group %s"), curr); - allow_usage(un, B_TRUE, errbuf); - } - } else { - if (*endch != '\0') { - p = getpwnam(curr); - } else { - p = getpwuid(rid); - } - - if (p == NULL) - if (*endch != '\0') { - g = getgrnam(curr); - } else { - g = getgrgid(rid); - } - - if (p != NULL) { - who_type = ZFS_DELEG_USER; - rid = p->pw_uid; - } else if (g != NULL) { - who_type = ZFS_DELEG_GROUP; - rid = g->gr_gid; - } else { - (void) snprintf(errbuf, 256, gettext( - "invalid user/group %s"), curr); - allow_usage(un, B_TRUE, errbuf); - } - } - - (void) sprintf(id, "%u", rid); - who = id; - - store_allow_perm(who_type, opts->local, - opts->descend, who, opts->perms, *nvlp); - curr = delim + 1; - } - } - - return (0); -} - -static void -print_set_creat_perms(uu_avl_t *who_avl) -{ - const char *sc_title[] = { - gettext("Permission sets:\n"), - gettext("Create time permissions:\n"), - NULL - }; - const char **title_ptr = sc_title; - who_perm_node_t *who_node = NULL; - int prev_weight = -1; - - for (who_node = uu_avl_first(who_avl); who_node != NULL; - who_node = uu_avl_next(who_avl, who_node)) { - uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl; - zfs_deleg_who_type_t who_type = who_node->who_perm.who_type; - const char *who_name = who_node->who_perm.who_name; - int weight = who_type2weight(who_type); - boolean_t first = B_TRUE; - deleg_perm_node_t *deleg_node; - - if (prev_weight != weight) { - (void) printf(*title_ptr++); - prev_weight = weight; - } - - if (who_name == NULL || strnlen(who_name, 1) == 0) - (void) printf("\t"); - else - (void) printf("\t%s ", who_name); - - for (deleg_node = uu_avl_first(avl); deleg_node != NULL; - deleg_node = uu_avl_next(avl, deleg_node)) { - if (first) { - (void) printf("%s", - deleg_node->dpn_perm.dp_name); - first = B_FALSE; - } else - (void) printf(",%s", - deleg_node->dpn_perm.dp_name); - } - - (void) printf("\n"); - } -} - -static void inline -print_uge_deleg_perms(uu_avl_t *who_avl, boolean_t local, boolean_t descend, - const char *title) -{ - who_perm_node_t *who_node = NULL; - boolean_t prt_title = B_TRUE; - uu_avl_walk_t *walk; - - if ((walk = uu_avl_walk_start(who_avl, UU_WALK_ROBUST)) == NULL) - nomem(); - - while ((who_node = uu_avl_walk_next(walk)) != NULL) { - const char *who_name = who_node->who_perm.who_name; - const char *nice_who_name = who_node->who_perm.who_ug_name; - uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl; - zfs_deleg_who_type_t who_type = who_node->who_perm.who_type; - char delim = ' '; - deleg_perm_node_t *deleg_node; - boolean_t prt_who = B_TRUE; - - for (deleg_node = uu_avl_first(avl); - deleg_node != NULL; - deleg_node = uu_avl_next(avl, deleg_node)) { - if (local != deleg_node->dpn_perm.dp_local || - descend != deleg_node->dpn_perm.dp_descend) - continue; - - if (prt_who) { - const char *who = NULL; - if (prt_title) { - prt_title = B_FALSE; - (void) printf(title); - } - - switch (who_type) { - case ZFS_DELEG_USER_SETS: - case ZFS_DELEG_USER: - who = gettext("user"); - if (nice_who_name) - who_name = nice_who_name; - break; - case ZFS_DELEG_GROUP_SETS: - case ZFS_DELEG_GROUP: - who = gettext("group"); - if (nice_who_name) - who_name = nice_who_name; - break; - case ZFS_DELEG_EVERYONE_SETS: - case ZFS_DELEG_EVERYONE: - who = gettext("everyone"); - who_name = NULL; - } - - prt_who = B_FALSE; - if (who_name == NULL) - (void) printf("\t%s", who); - else - (void) printf("\t%s %s", who, who_name); - } - - (void) printf("%c%s", delim, - deleg_node->dpn_perm.dp_name); - delim = ','; - } - - if (!prt_who) - (void) printf("\n"); - } - - uu_avl_walk_end(walk); -} - -static void -print_fs_perms(fs_perm_set_t *fspset) -{ - fs_perm_node_t *node = NULL; - char buf[ZFS_MAXNAMELEN+32]; - const char *dsname = buf; - - for (node = uu_list_first(fspset->fsps_list); node != NULL; - node = uu_list_next(fspset->fsps_list, node)) { - uu_avl_t *sc_avl = node->fspn_fsperm.fsp_sc_avl; - uu_avl_t *uge_avl = node->fspn_fsperm.fsp_uge_avl; - int left = 0; - - (void) snprintf(buf, ZFS_MAXNAMELEN+32, - gettext("---- Permissions on %s "), - node->fspn_fsperm.fsp_name); - (void) printf(dsname); - left = 70 - strlen(buf); - while (left-- > 0) - (void) printf("-"); - (void) printf("\n"); - - print_set_creat_perms(sc_avl); - print_uge_deleg_perms(uge_avl, B_TRUE, B_FALSE, - gettext("Local permissions:\n")); - print_uge_deleg_perms(uge_avl, B_FALSE, B_TRUE, - gettext("Descendent permissions:\n")); - print_uge_deleg_perms(uge_avl, B_TRUE, B_TRUE, - gettext("Local+Descendent permissions:\n")); - } -} - -static fs_perm_set_t fs_perm_set = { NULL, NULL, NULL, NULL }; - -struct deleg_perms { - boolean_t un; - nvlist_t *nvl; -}; - -static int -set_deleg_perms(zfs_handle_t *zhp, void *data) -{ - struct deleg_perms *perms = (struct deleg_perms *)data; - zfs_type_t zfs_type = zfs_get_type(zhp); - - if (zfs_type != ZFS_TYPE_FILESYSTEM && zfs_type != ZFS_TYPE_VOLUME) - return (0); - - return (zfs_set_fsacl(zhp, perms->un, perms->nvl)); -} - -static int -zfs_do_allow_unallow_impl(int argc, char **argv, boolean_t un) -{ - zfs_handle_t *zhp; - nvlist_t *perm_nvl = NULL; - nvlist_t *update_perm_nvl = NULL; - int error = 1; - int c; - struct allow_opts opts = { 0 }; - - const char *optstr = un ? "ldugecsrh" : "ldugecsh"; - - /* check opts */ - while ((c = getopt(argc, argv, optstr)) != -1) { - switch (c) { - case 'l': - opts.local = B_TRUE; - break; - case 'd': - opts.descend = B_TRUE; - break; - case 'u': - opts.user = B_TRUE; - break; - case 'g': - opts.group = B_TRUE; - break; - case 'e': - opts.everyone = B_TRUE; - break; - case 's': - opts.set = B_TRUE; - break; - case 'c': - opts.create = B_TRUE; - break; - case 'r': - opts.recursive = B_TRUE; - break; - case ':': - (void) fprintf(stderr, gettext("missing argument for " - "'%c' option\n"), optopt); - usage(B_FALSE); - break; - case 'h': - opts.prt_usage = B_TRUE; - break; - case '?': - (void) fprintf(stderr, gettext("invalid option '%c'\n"), - optopt); - usage(B_FALSE); - } - } - - argc -= optind; - argv += optind; - - /* check arguments */ - parse_allow_args(argc, argv, un, &opts); - - /* try to open the dataset */ - if ((zhp = zfs_open(g_zfs, opts.dataset, ZFS_TYPE_FILESYSTEM | - ZFS_TYPE_VOLUME)) == NULL) { - (void) fprintf(stderr, "Failed to open dataset: %s\n", - opts.dataset); - return (-1); - } - - if (zfs_get_fsacl(zhp, &perm_nvl) != 0) - goto cleanup2; - - fs_perm_set_init(&fs_perm_set); - if (parse_fs_perm_set(&fs_perm_set, perm_nvl) != 0) { - (void) fprintf(stderr, "Failed to parse fsacl permissions\n"); - goto cleanup1; - } - - if (opts.prt_perms) - print_fs_perms(&fs_perm_set); - else { - (void) construct_fsacl_list(un, &opts, &update_perm_nvl); - if (zfs_set_fsacl(zhp, un, update_perm_nvl) != 0) - goto cleanup0; - - if (un && opts.recursive) { - struct deleg_perms data = { un, update_perm_nvl }; - if (zfs_iter_filesystems(zhp, set_deleg_perms, - &data) != 0) - goto cleanup0; - } - } - - error = 0; - -cleanup0: - nvlist_free(perm_nvl); - if (update_perm_nvl != NULL) - nvlist_free(update_perm_nvl); -cleanup1: - fs_perm_set_fini(&fs_perm_set); -cleanup2: - zfs_close(zhp); - - return (error); -} - -/* - * zfs allow [-r] [-t] <tag> <snap> ... - * - * -r Recursively hold - * -t Temporary hold (hidden option) - * - * Apply a user-hold with the given tag to the list of snapshots. - */ -static int -zfs_do_allow(int argc, char **argv) -{ - return (zfs_do_allow_unallow_impl(argc, argv, B_FALSE)); -} - -/* - * zfs unallow [-r] [-t] <tag> <snap> ... - * - * -r Recursively hold - * -t Temporary hold (hidden option) - * - * Apply a user-hold with the given tag to the list of snapshots. - */ -static int -zfs_do_unallow(int argc, char **argv) -{ - return (zfs_do_allow_unallow_impl(argc, argv, B_TRUE)); -} - static int zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding) { @@ -5208,200 +2936,6 @@ zfs_do_release(int argc, char **argv) return (zfs_do_hold_rele_impl(argc, argv, B_FALSE)); } -typedef struct holds_cbdata { - boolean_t cb_recursive; - const char *cb_snapname; - nvlist_t **cb_nvlp; - size_t cb_max_namelen; - size_t cb_max_taglen; -} holds_cbdata_t; - -#define STRFTIME_FMT_STR "%a %b %e %k:%M %Y" -#define DATETIME_BUF_LEN (32) -/* - * - */ -static void -print_holds(boolean_t scripted, size_t nwidth, size_t tagwidth, nvlist_t *nvl) -{ - int i; - nvpair_t *nvp = NULL; - char *hdr_cols[] = { "NAME", "TAG", "TIMESTAMP" }; - const char *col; - - if (!scripted) { - for (i = 0; i < 3; i++) { - col = gettext(hdr_cols[i]); - if (i < 2) - (void) printf("%-*s ", i ? tagwidth : nwidth, - col); - else - (void) printf("%s\n", col); - } - } - - while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { - char *zname = nvpair_name(nvp); - nvlist_t *nvl2; - nvpair_t *nvp2 = NULL; - (void) nvpair_value_nvlist(nvp, &nvl2); - while ((nvp2 = nvlist_next_nvpair(nvl2, nvp2)) != NULL) { - char tsbuf[DATETIME_BUF_LEN]; - char *tagname = nvpair_name(nvp2); - uint64_t val = 0; - time_t time; - struct tm t; - char sep = scripted ? '\t' : ' '; - size_t sepnum = scripted ? 1 : 2; - - (void) nvpair_value_uint64(nvp2, &val); - time = (time_t)val; - (void) localtime_r(&time, &t); - (void) strftime(tsbuf, DATETIME_BUF_LEN, - gettext(STRFTIME_FMT_STR), &t); - - (void) printf("%-*s%*c%-*s%*c%s\n", nwidth, zname, - sepnum, sep, tagwidth, tagname, sepnum, sep, tsbuf); - } - } -} - -/* - * Generic callback function to list a dataset or snapshot. - */ -static int -holds_callback(zfs_handle_t *zhp, void *data) -{ - holds_cbdata_t *cbp = data; - nvlist_t *top_nvl = *cbp->cb_nvlp; - nvlist_t *nvl = NULL; - nvpair_t *nvp = NULL; - const char *zname = zfs_get_name(zhp); - size_t znamelen = strnlen(zname, ZFS_MAXNAMELEN); - - if (cbp->cb_recursive) { - const char *snapname; - char *delim = strchr(zname, '@'); - if (delim == NULL) - return (0); - - snapname = delim + 1; - if (strcmp(cbp->cb_snapname, snapname)) - return (0); - } - - if (zfs_get_holds(zhp, &nvl) != 0) - return (-1); - - if (znamelen > cbp->cb_max_namelen) - cbp->cb_max_namelen = znamelen; - - while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { - const char *tag = nvpair_name(nvp); - size_t taglen = strnlen(tag, MAXNAMELEN); - if (taglen > cbp->cb_max_taglen) - cbp->cb_max_taglen = taglen; - } - - return (nvlist_add_nvlist(top_nvl, zname, nvl)); -} - -/* - * zfs holds [-r] <snap> ... - * - * -r Recursively hold - */ -static int -zfs_do_holds(int argc, char **argv) -{ - int errors = 0; - int c; - int i; - boolean_t scripted = B_FALSE; - boolean_t recursive = B_FALSE; - const char *opts = "rH"; - nvlist_t *nvl; - - int types = ZFS_TYPE_SNAPSHOT; - holds_cbdata_t cb = { 0 }; - - int limit = 0; - int ret = 0; - int flags = 0; - - /* check options */ - while ((c = getopt(argc, argv, opts)) != -1) { - switch (c) { - case 'r': - recursive = B_TRUE; - break; - case 'H': - scripted = B_TRUE; - break; - case '?': - (void) fprintf(stderr, gettext("invalid option '%c'\n"), - optopt); - usage(B_FALSE); - } - } - - if (recursive) { - types |= ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME; - flags |= ZFS_ITER_RECURSE; - } - - argc -= optind; - argv += optind; - - /* check number of arguments */ - if (argc < 1) - usage(B_FALSE); - - if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) - nomem(); - - for (i = 0; i < argc; ++i) { - char *snapshot = argv[i]; - const char *delim; - const char *snapname; - - delim = strchr(snapshot, '@'); - if (delim == NULL) { - (void) fprintf(stderr, - gettext("'%s' is not a snapshot\n"), snapshot); - ++errors; - continue; - } - snapname = delim + 1; - if (recursive) - snapshot[delim - snapshot] = '\0'; - - cb.cb_recursive = recursive; - cb.cb_snapname = snapname; - cb.cb_nvlp = &nvl; - - /* - * 1. collect holds data, set format options - */ - ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit, - holds_callback, &cb); - if (ret != 0) - ++errors; - } - - /* - * 2. print holds data - */ - print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl); - - if (nvlist_empty(nvl)) - (void) printf(gettext("no datasets available\n")); - - nvlist_free(nvl); - - return (0 != errors); -} - #define CHECK_SPINNER 30 #define SPINNER_TIME 3 /* seconds */ #define MOUNT_TIME 5 /* seconds */ @@ -5903,7 +3437,7 @@ static int unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) { zfs_handle_t *zhp; - int ret = 0; + int ret; struct stat64 statbuf; struct extmnttab entry; const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount"; @@ -6286,6 +3820,15 @@ zfs_do_unshare(int argc, char **argv) return (unshare_unmount(OP_SHARE, argc, argv)); } +/* ARGSUSED */ +static int +zfs_do_python(int argc, char **argv) +{ + (void) execv(pypath, argv-1); + (void) printf("internal error: %s not found\n", pypath); + return (-1); +} + /* * Called when invoked as /etc/fs/zfs/mount. Do the mount if the mountpoint is * 'legacy'. Otherwise, complain that use should be using 'zfs mount'. @@ -6296,7 +3839,7 @@ manual_mount(int argc, char **argv) zfs_handle_t *zhp; char mountpoint[ZFS_MAXPROPLEN]; char mntopts[MNT_LINE_MAX] = { '\0' }; - int ret = 0; + int ret; int c; int flags = 0; char *dataset, *path; @@ -6446,7 +3989,7 @@ zfs_do_diff(int argc, char **argv) char *tosnap = NULL; char *fromsnap = NULL; char *atp, *copy; - int err = 0; + int err; int c; while ((c = getopt(argc, argv, "FHt")) != -1) { @@ -6516,7 +4059,7 @@ zfs_do_diff(int argc, char **argv) int main(int argc, char **argv) { - int ret = 0; + int ret; int i; char *progname; char *cmdname; @@ -6532,7 +4075,8 @@ main(int argc, char **argv) return (1); } - zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); + zpool_set_history_str("zfs", argc, argv, history_str); + verify(zpool_stage_history(g_zfs, history_str) == 0); libzfs_print_on_error(g_zfs, B_TRUE); @@ -6601,9 +4145,6 @@ main(int argc, char **argv) (void) fclose(mnttab_file); - if (ret == 0 && log_history) - (void) zpool_log_history(g_zfs, history_str); - libzfs_fini(g_zfs); /* |
