aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/zfs/zfs_main.c
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2010-05-28 13:45:14 -0700
committerBrian Behlendorf <[email protected]>2010-05-28 13:45:14 -0700
commit428870ff734fdaccc342b33fc53cf94724409a46 (patch)
tree164e83c0ceda52a843795ed7cd9e95637d02c177 /cmd/zfs/zfs_main.c
parent6119cb885a976e175a6e827894accf657ff1984f (diff)
Update core ZFS code from build 121 to build 141.
Diffstat (limited to 'cmd/zfs/zfs_main.c')
-rw-r--r--cmd/zfs/zfs_main.c687
1 files changed, 351 insertions, 336 deletions
diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c
index 1fbd8bc65..353fd4fa6 100644
--- a/cmd/zfs/zfs_main.c
+++ b/cmd/zfs/zfs_main.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <assert.h>
@@ -47,12 +46,15 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/fs/zfs.h>
+#include <sys/types.h>
+#include <time.h>
#include <libzfs.h>
#include <libuutil.h>
#include "zfs_iter.h"
#include "zfs_util.h"
+#include "zfs_comutil.h"
libzfs_handle_t *g_zfs;
@@ -157,7 +159,7 @@ static zfs_command_t command_table[] = {
{ "list", zfs_do_list, HELP_LIST },
{ NULL },
{ "set", zfs_do_set, HELP_SET },
- { "get", zfs_do_get, HELP_GET },
+ { "get", zfs_do_get, HELP_GET },
{ "inherit", zfs_do_inherit, HELP_INHERIT },
{ "upgrade", zfs_do_upgrade, HELP_UPGRADE },
{ "userspace", zfs_do_userspace, HELP_USERSPACE },
@@ -197,16 +199,15 @@ get_usage(zfs_help_t idx)
"\tcreate [-ps] [-b blocksize] [-o property=value] ... "
"-V <size> <volume>\n"));
case HELP_DESTROY:
- return (gettext("\tdestroy [-rRf] "
- "<filesystem|volume|snapshot>\n"
- "\tdestroy -d [-r] <filesystem|volume|snapshot>\n"));
+ return (gettext("\tdestroy [-rRf] <filesystem|volume>\n"
+ "\tdestroy [-rRd] <snapshot>\n"));
case HELP_GET:
return (gettext("\tget [-rHp] [-d max] "
- "[-o field[,...]] [-s source[,...]]\n"
+ "[-o \"all\" | field[,...]] [-s source[,...]]\n"
"\t <\"all\" | property[,...]> "
"[filesystem|volume|snapshot] ...\n"));
case HELP_INHERIT:
- return (gettext("\tinherit [-r] <property> "
+ return (gettext("\tinherit [-rS] <property> "
"<filesystem|volume|snapshot> ...\n"));
case HELP_UPGRADE:
return (gettext("\tupgrade [-v]\n"
@@ -222,9 +223,9 @@ get_usage(zfs_help_t idx)
case HELP_PROMOTE:
return (gettext("\tpromote <clone-filesystem>\n"));
case HELP_RECEIVE:
- return (gettext("\treceive [-vnF] <filesystem|volume|"
+ return (gettext("\treceive [-vnFu] <filesystem|volume|"
"snapshot>\n"
- "\treceive [-vnF] -d <filesystem>\n"));
+ "\treceive [-vnFu] [-d | -e] <filesystem>\n"));
case HELP_RENAME:
return (gettext("\trename <filesystem|volume|snapshot> "
"<filesystem|volume|snapshot>\n"
@@ -233,7 +234,7 @@ get_usage(zfs_help_t idx)
case HELP_ROLLBACK:
return (gettext("\trollback [-rRf] <snapshot>\n"));
case HELP_SEND:
- return (gettext("\tsend [-R] [-[iI] snapshot] <snapshot>\n"));
+ return (gettext("\tsend [-RDp] [-[iI] snapshot] <snapshot>\n"));
case HELP_SET:
return (gettext("\tset <property=value> "
"<filesystem|volume|snapshot> ...\n"));
@@ -288,22 +289,39 @@ get_usage(zfs_help_t idx)
/* NOTREACHED */
}
+void
+nomem(void)
+{
+ (void) fprintf(stderr, gettext("internal error: out of memory\n"));
+ exit(1);
+}
+
/*
* Utility function to guarantee malloc() success.
*/
+
void *
safe_malloc(size_t size)
{
void *data;
- if ((data = calloc(1, size)) == NULL) {
- (void) fprintf(stderr, "internal error: out of memory\n");
- exit(1);
- }
+ if ((data = calloc(1, size)) == NULL)
+ nomem();
return (data);
}
+static char *
+safe_strdup(char *str)
+{
+ char *dupstr = strdup(str);
+
+ if (dupstr == NULL)
+ nomem();
+
+ return (dupstr);
+}
+
/*
* Callback routine that will print out information for each of
* the properties.
@@ -442,11 +460,8 @@ parseprop(nvlist_t *props)
"specified multiple times\n"), propname);
return (-1);
}
- if (nvlist_add_string(props, propname, propval) != 0) {
- (void) fprintf(stderr, gettext("internal "
- "error: out of memory\n"));
- return (-1);
- }
+ if (nvlist_add_string(props, propname, propval) != 0)
+ nomem();
return (0);
}
@@ -471,6 +486,59 @@ parse_depth(char *opt, int *flags)
return (depth);
}
+#define PROGRESS_DELAY 2 /* seconds */
+
+static char *pt_reverse = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+static time_t pt_begin;
+static char *pt_header = NULL;
+static boolean_t pt_shown;
+
+static void
+start_progress_timer(void)
+{
+ pt_begin = time(NULL) + PROGRESS_DELAY;
+ pt_shown = B_FALSE;
+}
+
+static void
+set_progress_header(char *header)
+{
+ assert(pt_header == NULL);
+ pt_header = safe_strdup(header);
+ if (pt_shown) {
+ (void) printf("%s: ", header);
+ (void) fflush(stdout);
+ }
+}
+
+static void
+update_progress(char *update)
+{
+ if (!pt_shown && time(NULL) > pt_begin) {
+ int len = strlen(update);
+
+ (void) printf("%s: %s%*.*s", pt_header, update, len, len,
+ pt_reverse);
+ (void) fflush(stdout);
+ pt_shown = B_TRUE;
+ } else if (pt_shown) {
+ int len = strlen(update);
+
+ (void) printf("%s%*.*s", update, len, len, pt_reverse);
+ (void) fflush(stdout);
+ }
+}
+
+static void
+finish_progress(char *done)
+{
+ if (pt_shown) {
+ (void) printf("%s\n", done);
+ (void) fflush(stdout);
+ }
+ free(pt_header);
+ pt_header = NULL;
+}
/*
* zfs clone [-p] [-o prop=value] ... <snap> <fs | vol>
*
@@ -490,11 +558,8 @@ zfs_do_clone(int argc, char **argv)
int ret;
int c;
- if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
- (void) fprintf(stderr, gettext("internal error: "
- "out of memory\n"));
- return (1);
- }
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
/* check options */
while ((c = getopt(argc, argv, "o:p")) != -1) {
@@ -608,11 +673,8 @@ zfs_do_create(int argc, char **argv)
uint64_t intval;
int canmount;
- if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
- (void) fprintf(stderr, gettext("internal error: "
- "out of memory\n"));
- return (1);
- }
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
/* check options */
while ((c = getopt(argc, argv, ":V:b:so:p")) != -1) {
@@ -627,12 +689,8 @@ zfs_do_create(int argc, char **argv)
}
if (nvlist_add_uint64(props,
- zfs_prop_to_name(ZFS_PROP_VOLSIZE),
- intval) != 0) {
- (void) fprintf(stderr, gettext("internal "
- "error: out of memory\n"));
- goto error;
- }
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE), intval) != 0)
+ nomem();
volsize = intval;
break;
case 'p':
@@ -649,11 +707,8 @@ zfs_do_create(int argc, char **argv)
if (nvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
- intval) != 0) {
- (void) fprintf(stderr, gettext("internal "
- "error: out of memory\n"));
- goto error;
- }
+ intval) != 0)
+ nomem();
break;
case 'o':
if (parseprop(props))
@@ -715,15 +770,14 @@ zfs_do_create(int argc, char **argv)
resv_prop = ZFS_PROP_REFRESERVATION;
else
resv_prop = ZFS_PROP_RESERVATION;
+ volsize = zvol_volsize_to_reservation(volsize, props);
if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
&strval) != 0) {
if (nvlist_add_uint64(props,
zfs_prop_to_name(resv_prop), volsize) != 0) {
- (void) fprintf(stderr, gettext("internal "
- "error: out of memory\n"));
nvlist_free(props);
- return (1);
+ nomem();
}
}
}
@@ -785,12 +839,12 @@ badusage:
}
/*
- * zfs destroy [-rRf] <fs, snap, vol>
- * zfs destroy -d [-r] <fs, snap, vol>
+ * zfs destroy [-rRf] <fs, vol>
+ * zfs destroy [-rRd] <snap>
*
- * -r Recursively destroy all children
- * -R Recursively destroy all dependents, including clones
- * -f Force unmounting of any dependents
+ * -r Recursively destroy all children
+ * -R Recursively destroy all dependents, including clones
+ * -f Force unmounting of any dependents
* -d If we can't destroy now, mark for deferred destruction
*
* Destroys the given dataset. By default, it will unmount any filesystems,
@@ -876,7 +930,7 @@ destroy_callback(zfs_handle_t *zhp, void *data)
/*
* Ignore pools (which we've already flagged as an error before getting
- * here.
+ * here).
*/
if (strchr(zfs_get_name(zhp), '/') == NULL &&
zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
@@ -940,12 +994,14 @@ zfs_do_destroy(int argc, char **argv)
int c;
zfs_handle_t *zhp;
char *cp;
+ zfs_type_t type = ZFS_TYPE_DATASET;
/* check options */
while ((c = getopt(argc, argv, "dfrR")) != -1) {
switch (c) {
case 'd':
cb.cb_defer_destroy = B_TRUE;
+ type = ZFS_TYPE_SNAPSHOT;
break;
case 'f':
cb.cb_force = 1;
@@ -978,9 +1034,6 @@ zfs_do_destroy(int argc, char **argv)
usage(B_FALSE);
}
- if (cb.cb_defer_destroy && cb.cb_doclones)
- usage(B_FALSE);
-
/*
* If we are doing recursive destroy of a snapshot, then the
* named snapshot may not exist. Go straight to libzfs.
@@ -995,11 +1048,19 @@ zfs_do_destroy(int argc, char **argv)
cp++;
if (cb.cb_doclones) {
+ boolean_t defer = cb.cb_defer_destroy;
+
+ /*
+ * 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;
}
ret = zfs_destroy_snaps(zhp, cp, cb.cb_defer_destroy);
@@ -1012,7 +1073,7 @@ zfs_do_destroy(int argc, char **argv)
}
/* Open the given dataset */
- if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
+ if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
return (1);
cb.cb_target = zhp;
@@ -1062,18 +1123,32 @@ zfs_do_destroy(int argc, char **argv)
return (0);
}
+static boolean_t
+is_recvd_column(zprop_get_cbdata_t *cbp)
+{
+ int i;
+ zfs_get_column_t col;
+
+ for (i = 0; i < ZFS_GET_NCOLS &&
+ (col = cbp->cb_columns[i]) != GET_COL_NONE; i++)
+ if (col == GET_COL_RECVD)
+ return (B_TRUE);
+ return (B_FALSE);
+}
+
/*
- * zfs get [-rHp] [-o field[,field]...] [-s source[,source]...]
- * < all | property[,property]... > < fs | snap | vol > ...
+ * zfs get [-rHp] [-o all | field[,field]...] [-s source[,source]...]
+ * < all | property[,property]... > < fs | snap | vol > ...
*
* -r recurse over any child datasets
* -H scripted mode. Headers are stripped, and fields are separated
* by tabs instead of spaces.
- * -o Set of fields to display. One of "name,property,value,source".
- * Default is all four.
+ * -o Set of fields to display. One of "name,property,value,
+ * received,source". Default is "name,property,value,source".
+ * "all" is an alias for all five.
* -s Set of sources to allow. One of
- * "local,default,inherited,temporary,none". Default is all
- * five.
+ * "local,default,inherited,received,temporary,none". Default is
+ * all six.
* -p Display values in parsable (literal) format.
*
* Prints properties for the given datasets. The user can control which
@@ -1087,16 +1162,19 @@ static int
get_callback(zfs_handle_t *zhp, void *data)
{
char buf[ZFS_MAXPROPLEN];
+ char rbuf[ZFS_MAXPROPLEN];
zprop_source_t sourcetype;
char source[ZFS_MAXNAMELEN];
zprop_get_cbdata_t *cbp = data;
- nvlist_t *userprop = zfs_get_user_props(zhp);
+ nvlist_t *user_props = zfs_get_user_props(zhp);
zprop_list_t *pl = cbp->cb_proplist;
nvlist_t *propval;
char *strval;
char *sourceval;
+ boolean_t received = is_recvd_column(cbp);
for (; pl != NULL; pl = pl->pl_next) {
+ char *recvdval = NULL;
/*
* Skip the special fake placeholder. This will also skip over
* the name property when 'all' is specified.
@@ -1123,9 +1201,14 @@ get_callback(zfs_handle_t *zhp, void *data)
(void) strlcpy(buf, "-", sizeof (buf));
}
+ if (received && (zfs_prop_get_recvd(zhp,
+ zfs_prop_to_name(pl->pl_prop), rbuf, sizeof (rbuf),
+ cbp->cb_literal) == 0))
+ recvdval = rbuf;
+
zprop_print_one_property(zfs_get_name(zhp), cbp,
zfs_prop_to_name(pl->pl_prop),
- buf, sourcetype, source);
+ buf, sourcetype, source, recvdval);
} else if (zfs_prop_userquota(pl->pl_user_prop)) {
sourcetype = ZPROP_SRC_LOCAL;
@@ -1136,9 +1219,9 @@ get_callback(zfs_handle_t *zhp, void *data)
}
zprop_print_one_property(zfs_get_name(zhp), cbp,
- pl->pl_user_prop, buf, sourcetype, source);
+ pl->pl_user_prop, buf, sourcetype, source, NULL);
} else {
- if (nvlist_lookup_nvlist(userprop,
+ if (nvlist_lookup_nvlist(user_props,
pl->pl_user_prop, &propval) != 0) {
if (pl->pl_all)
continue;
@@ -1153,6 +1236,9 @@ get_callback(zfs_handle_t *zhp, void *data)
if (strcmp(sourceval,
zfs_get_name(zhp)) == 0) {
sourcetype = ZPROP_SRC_LOCAL;
+ } else if (strcmp(sourceval,
+ ZPROP_SOURCE_VAL_RECVD) == 0) {
+ sourcetype = ZPROP_SRC_RECEIVED;
} else {
sourcetype = ZPROP_SRC_INHERITED;
(void) strlcpy(source,
@@ -1160,9 +1246,14 @@ get_callback(zfs_handle_t *zhp, void *data)
}
}
+ if (received && (zfs_prop_get_recvd(zhp,
+ pl->pl_user_prop, rbuf, sizeof (rbuf),
+ cbp->cb_literal) == 0))
+ recvdval = rbuf;
+
zprop_print_one_property(zfs_get_name(zhp), cbp,
pl->pl_user_prop, strval, sourcetype,
- source);
+ source, recvdval);
}
}
@@ -1218,10 +1309,10 @@ zfs_do_get(int argc, char **argv)
i = 0;
while (*optarg != '\0') {
static char *col_subopts[] =
- { "name", "property", "value", "source",
- NULL };
+ { "name", "property", "value", "received",
+ "source", "all", NULL };
- if (i == 4) {
+ if (i == ZFS_GET_NCOLS) {
(void) fprintf(stderr, gettext("too "
"many fields given to -o "
"option\n"));
@@ -1240,8 +1331,28 @@ zfs_do_get(int argc, char **argv)
cb.cb_columns[i++] = GET_COL_VALUE;
break;
case 3:
+ cb.cb_columns[i++] = GET_COL_RECVD;
+ flags |= ZFS_ITER_RECVD_PROPS;
+ break;
+ case 4:
cb.cb_columns[i++] = GET_COL_SOURCE;
break;
+ case 5:
+ if (i > 0) {
+ (void) fprintf(stderr,
+ gettext("\"all\" conflicts "
+ "with specific fields "
+ "given to -o option\n"));
+ usage(B_FALSE);
+ }
+ cb.cb_columns[0] = GET_COL_NAME;
+ cb.cb_columns[1] = GET_COL_PROPERTY;
+ cb.cb_columns[2] = GET_COL_VALUE;
+ cb.cb_columns[3] = GET_COL_RECVD;
+ cb.cb_columns[4] = GET_COL_SOURCE;
+ flags |= ZFS_ITER_RECVD_PROPS;
+ i = ZFS_GET_NCOLS;
+ break;
default:
(void) fprintf(stderr,
gettext("invalid column name "
@@ -1256,7 +1367,8 @@ zfs_do_get(int argc, char **argv)
while (*optarg != '\0') {
static char *source_subopts[] = {
"local", "default", "inherited",
- "temporary", "none", NULL };
+ "received", "temporary", "none",
+ NULL };
switch (getsubopt(&optarg, source_subopts,
&value)) {
@@ -1270,9 +1382,12 @@ zfs_do_get(int argc, char **argv)
cb.cb_sources |= ZPROP_SRC_INHERITED;
break;
case 3:
- cb.cb_sources |= ZPROP_SRC_TEMPORARY;
+ cb.cb_sources |= ZPROP_SRC_RECEIVED;
break;
case 4:
+ cb.cb_sources |= ZPROP_SRC_TEMPORARY;
+ break;
+ case 5:
cb.cb_sources |= ZPROP_SRC_NONE;
break;
default:
@@ -1339,9 +1454,10 @@ zfs_do_get(int argc, char **argv)
}
/*
- * inherit [-r] <property> <fs|vol> ...
+ * inherit [-rS] <property> <fs|vol> ...
*
- * -r Recurse over all children
+ * -r Recurse over all children
+ * -S Revert to received value, if any
*
* For each dataset specified on the command line, inherit the given property
* from its parent. Inheriting a property at the pool level will cause it to
@@ -1350,11 +1466,16 @@ zfs_do_get(int argc, char **argv)
* local modifications for each dataset.
*/
+typedef struct inherit_cbdata {
+ const char *cb_propname;
+ boolean_t cb_received;
+} inherit_cbdata_t;
+
static int
inherit_recurse_cb(zfs_handle_t *zhp, void *data)
{
- char *propname = data;
- zfs_prop_t prop = zfs_name_to_prop(propname);
+ inherit_cbdata_t *cb = data;
+ zfs_prop_t prop = zfs_name_to_prop(cb->cb_propname);
/*
* If we're doing it recursively, then ignore properties that
@@ -1364,15 +1485,15 @@ inherit_recurse_cb(zfs_handle_t *zhp, void *data)
!zfs_prop_valid_for_type(prop, zfs_get_type(zhp)))
return (0);
- return (zfs_prop_inherit(zhp, propname) != 0);
+ return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
}
static int
inherit_cb(zfs_handle_t *zhp, void *data)
{
- char *propname = data;
+ inherit_cbdata_t *cb = data;
- return (zfs_prop_inherit(zhp, propname) != 0);
+ return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
}
static int
@@ -1380,16 +1501,21 @@ zfs_do_inherit(int argc, char **argv)
{
int c;
zfs_prop_t prop;
+ inherit_cbdata_t cb = { 0 };
char *propname;
int ret;
int flags = 0;
+ boolean_t received = B_FALSE;
/* check options */
- while ((c = getopt(argc, argv, "r")) != -1) {
+ while ((c = getopt(argc, argv, "rS")) != -1) {
switch (c) {
case 'r':
flags |= ZFS_ITER_RECURSE;
break;
+ case 'S':
+ received = B_TRUE;
+ break;
case '?':
default:
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
@@ -1422,7 +1548,7 @@ zfs_do_inherit(int argc, char **argv)
propname);
return (1);
}
- if (!zfs_prop_inheritable(prop)) {
+ if (!zfs_prop_inheritable(prop) && !received) {
(void) fprintf(stderr, gettext("'%s' property cannot "
"be inherited\n"), propname);
if (prop == ZFS_PROP_QUOTA ||
@@ -1433,18 +1559,27 @@ zfs_do_inherit(int argc, char **argv)
"%s=none' to clear\n"), propname);
return (1);
}
+ if (received && (prop == ZFS_PROP_VOLSIZE ||
+ prop == ZFS_PROP_VERSION)) {
+ (void) fprintf(stderr, gettext("'%s' property cannot "
+ "be reverted to a received value\n"), propname);
+ return (1);
+ }
} else if (!zfs_prop_user(propname)) {
(void) fprintf(stderr, gettext("invalid property '%s'\n"),
propname);
usage(B_FALSE);
}
+ cb.cb_propname = propname;
+ cb.cb_received = received;
+
if (flags & ZFS_ITER_RECURSE) {
ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
- NULL, NULL, 0, inherit_recurse_cb, propname);
+ NULL, NULL, 0, inherit_recurse_cb, &cb);
} else {
ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
- NULL, NULL, 0, inherit_cb, propname);
+ NULL, NULL, 0, inherit_cb, &cb);
}
return (ret);
@@ -1513,31 +1648,25 @@ upgrade_set_callback(zfs_handle_t *zhp, void *data)
{
upgrade_cbdata_t *cb = data;
int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
- int i;
- static struct { int zplver; int spaver; } table[] = {
- {ZPL_VERSION_FUID, SPA_VERSION_FUID},
- {ZPL_VERSION_USERSPACE, SPA_VERSION_USERSPACE},
- {0, 0}
- };
-
-
- for (i = 0; table[i].zplver; i++) {
- if (cb->cb_version >= table[i].zplver) {
- int spa_version;
-
- if (zfs_spa_version(zhp, &spa_version) < 0)
- return (-1);
-
- if (spa_version < table[i].spaver) {
- /* can't upgrade */
- (void) printf(gettext("%s: can not be "
- "upgraded; the pool version needs to first "
- "be upgraded\nto version %d\n\n"),
- zfs_get_name(zhp), table[i].spaver);
- cb->cb_numfailed++;
- return (0);
- }
- }
+ int needed_spa_version;
+ int spa_version;
+
+ if (zfs_spa_version(zhp, &spa_version) < 0)
+ return (-1);
+
+ needed_spa_version = zfs_spa_version_map(cb->cb_version);
+
+ if (needed_spa_version < 0)
+ return (-1);
+
+ if (spa_version < needed_spa_version) {
+ /* can't upgrade */
+ (void) printf(gettext("%s: can not be "
+ "upgraded; the pool version needs to first "
+ "be upgraded\nto version %d\n\n"),
+ zfs_get_name(zhp), needed_spa_version);
+ cb->cb_numfailed++;
+ return (0);
}
/* upgrade */
@@ -1639,11 +1768,10 @@ zfs_do_upgrade(int argc, char **argv)
"unique identifier (FUID)\n"));
(void) printf(gettext(" 4 userquota, groupquota "
"properties\n"));
+ (void) printf(gettext(" 5 System attributes\n"));
(void) printf(gettext("\nFor more information on a particular "
- "version, including supported releases, see:\n\n"));
- (void) printf("http://www.opensolaris.org/os/community/zfs/"
- "version/zpl/N\n\n");
- (void) printf(gettext("Where 'N' is the version number.\n"));
+ "version, including supported releases,\n"));
+ (void) printf("see the ZFS Administration Guide.\n\n");
ret = 0;
} else if (argc || all) {
/* Upgrade filesystems */
@@ -1769,11 +1897,11 @@ zfs_do_userspace(int argc, char **argv)
* [-s property [-s property]...] [-S property [-S property]...]
* <dataset> ...
*
- * -r Recurse over all children
- * -d Limit recursion by depth.
- * -H Scripted mode; elide headers and separate columns by tabs
- * -o Control which fields to display.
- * -t Control which object types to display.
+ * -r Recurse over all children
+ * -d Limit recursion by depth.
+ * -H Scripted mode; elide headers and separate columns by tabs
+ * -o Control which fields to display.
+ * -t Control which object types to display.
* -s Specify sort columns, descending order.
* -S Specify sort columns, ascending order.
*
@@ -2170,9 +2298,9 @@ zfs_do_promote(int argc, char **argv)
/*
* zfs rollback [-rRf] <snapshot>
*
- * -r Delete any intervening snapshots before doing rollback
- * -R Delete any snapshots and their clones
- * -f ignored for backwards compatability
+ * -r Delete any intervening snapshots before doing rollback
+ * -R Delete any snapshots and their clones
+ * -f ignored for backwards compatability
*
* Given a filesystem, rollback to a specific snapshot, discarding any changes
* since then and making it the active dataset. If more recent snapshots exist,
@@ -2433,11 +2561,8 @@ zfs_do_snapshot(int argc, char **argv)
char c;
nvlist_t *props;
- if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
- (void) fprintf(stderr, gettext("internal error: "
- "out of memory\n"));
- return (1);
- }
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
/* check options */
while ((c = getopt(argc, argv, "ro:")) != -1) {
@@ -2482,8 +2607,8 @@ usage:
}
/*
- * zfs send [-v] -R [-i|-I <@snap>] <fs@snap>
- * zfs send [-v] [-i|-I <@snap>] <fs@snap>
+ * zfs send [-vDp] -R [-i|-I <@snap>] <fs@snap>
+ * zfs send [-vDp] [-i|-I <@snap>] <fs@snap>
*
* Send a backup stream to stdout.
*/
@@ -2494,14 +2619,13 @@ zfs_do_send(int argc, char **argv)
char *toname = NULL;
char *cp;
zfs_handle_t *zhp;
- boolean_t doall = B_FALSE;
- boolean_t replicate = B_FALSE;
- boolean_t fromorigin = B_FALSE;
- boolean_t verbose = B_FALSE;
+ sendflags_t flags = { 0 };
int c, err;
+ nvlist_t *dbgnv;
+ boolean_t extraverbose = B_FALSE;
/* check options */
- while ((c = getopt(argc, argv, ":i:I:Rv")) != -1) {
+ while ((c = getopt(argc, argv, ":i:I:RDpv")) != -1) {
switch (c) {
case 'i':
if (fromname)
@@ -2512,13 +2636,21 @@ zfs_do_send(int argc, char **argv)
if (fromname)
usage(B_FALSE);
fromname = optarg;
- doall = B_TRUE;
+ flags.doall = B_TRUE;
break;
case 'R':
- replicate = B_TRUE;
+ flags.replicate = B_TRUE;
+ break;
+ case 'p':
+ flags.props = B_TRUE;
break;
case 'v':
- verbose = B_TRUE;
+ if (flags.verbose)
+ extraverbose = B_TRUE;
+ flags.verbose = B_TRUE;
+ break;
+ case 'D':
+ flags.dedup = B_TRUE;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
@@ -2578,7 +2710,7 @@ zfs_do_send(int argc, char **argv)
if (strcmp(origin, fromname) == 0) {
fromname = NULL;
- fromorigin = B_TRUE;
+ flags.fromorigin = B_TRUE;
} else {
*cp = '\0';
if (cp != fromname && strcmp(argv[0], fromname)) {
@@ -2596,18 +2728,29 @@ zfs_do_send(int argc, char **argv)
}
}
- if (replicate && fromname == NULL)
- doall = B_TRUE;
+ if (flags.replicate && fromname == NULL)
+ flags.doall = B_TRUE;
+
+ err = zfs_send(zhp, fromname, toname, flags, STDOUT_FILENO, NULL, 0,
+ extraverbose ? &dbgnv : NULL);
- err = zfs_send(zhp, fromname, toname, replicate, doall, fromorigin,
- verbose, STDOUT_FILENO);
+ if (extraverbose) {
+ /*
+ * dump_nvlist prints to stdout, but that's been
+ * redirected to a file. Make it print to stderr
+ * instead.
+ */
+ (void) dup2(STDERR_FILENO, STDOUT_FILENO);
+ dump_nvlist(dbgnv, 0);
+ nvlist_free(dbgnv);
+ }
zfs_close(zhp);
return (err != 0);
}
/*
- * zfs receive [-dnvF] <fs@snap>
+ * zfs receive [-vnFu] [-d | -e] <fs@snap>
*
* Restore a backup stream from stdin.
*/
@@ -2615,15 +2758,18 @@ static int
zfs_do_receive(int argc, char **argv)
{
int c, err;
- recvflags_t flags;
+ recvflags_t flags = { 0 };
- bzero(&flags, sizeof (recvflags_t));
/* check options */
- while ((c = getopt(argc, argv, ":dnuvF")) != -1) {
+ while ((c = getopt(argc, argv, ":denuvF")) != -1) {
switch (c) {
case 'd':
flags.isprefix = B_TRUE;
break;
+ case 'e':
+ flags.isprefix = B_TRUE;
+ flags.istail = B_TRUE;
+ break;
case 'n':
flags.dryrun = B_TRUE;
break;
@@ -2681,15 +2827,19 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
int i;
const char *tag;
boolean_t recursive = B_FALSE;
+ boolean_t temphold = B_FALSE;
+ const char *opts = holding ? "rt" : "r";
int c;
- int (*func)(zfs_handle_t *, const char *, const char *, boolean_t);
/* check options */
- while ((c = getopt(argc, argv, "r")) != -1) {
+ while ((c = getopt(argc, argv, opts)) != -1) {
switch (c) {
case 'r':
recursive = B_TRUE;
break;
+ case 't':
+ temphold = B_TRUE;
+ break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
@@ -2708,16 +2858,10 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
--argc;
++argv;
- if (holding) {
- if (tag[0] == '.') {
- /* tags starting with '.' are reserved for libzfs */
- (void) fprintf(stderr,
- gettext("tag may not start with '.'\n"));
- usage(B_FALSE);
- }
- func = zfs_hold;
- } else {
- func = zfs_release;
+ if (holding && tag[0] == '.') {
+ /* tags starting with '.' are reserved for libzfs */
+ (void) fprintf(stderr, gettext("tag may not start with '.'\n"));
+ usage(B_FALSE);
}
for (i = 0; i < argc; ++i) {
@@ -2742,8 +2886,14 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
++errors;
continue;
}
- if (func(zhp, delim+1, tag, recursive) != 0)
- ++errors;
+ if (holding) {
+ if (zfs_hold(zhp, delim+1, tag, recursive,
+ temphold, B_FALSE) != 0)
+ ++errors;
+ } else {
+ if (zfs_release(zhp, delim+1, tag, recursive) != 0)
+ ++errors;
+ }
zfs_close(zhp);
}
@@ -2751,9 +2901,10 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
}
/*
- * zfs hold [-r] <tag> <snap> ...
+ * zfs hold [-r] [-t] <tag> <snap> ...
*
- * -r Recursively hold
+ * -r Recursively hold
+ * -t Temporary hold (hidden option)
*
* Apply a user-hold with the given tag to the list of snapshots.
*/
@@ -2766,7 +2917,7 @@ zfs_do_hold(int argc, char **argv)
/*
* zfs release [-r] <tag> <snap> ...
*
- * -r Recursively release
+ * -r Recursively release
*
* Release a user-hold with the given tag from the list of snapshots.
*/
@@ -2791,7 +2942,7 @@ typedef struct get_all_cbdata {
static int
get_one_dataset(zfs_handle_t *zhp, void *data)
{
- static char spin[] = { '-', '\\', '|', '/' };
+ static char *spin[] = { "-", "\\", "|", "/" };
static int spinval = 0;
static int spincheck = 0;
static time_t last_spin_time = (time_t)0;
@@ -2802,8 +2953,7 @@ get_one_dataset(zfs_handle_t *zhp, void *data)
if (--spincheck < 0) {
time_t now = time(NULL);
if (last_spin_time + SPINNER_TIME < now) {
- (void) printf("\b%c", spin[spinval++ % 4]);
- (void) fflush(stdout);
+ update_progress(spin[spinval++ % 4]);
last_spin_time = now;
}
spincheck = CHECK_SPINNER;
@@ -2859,19 +3009,16 @@ get_all_datasets(uint_t types, zfs_handle_t ***dslist, size_t *count,
cb.cb_types = types;
cb.cb_verbose = verbose;
- if (verbose) {
- (void) printf("%s: *", gettext("Reading ZFS config"));
- (void) fflush(stdout);
- }
+ if (verbose)
+ set_progress_header(gettext("Reading ZFS config"));
(void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
*dslist = cb.cb_handles;
*count = cb.cb_used;
- if (verbose) {
- (void) printf("\b%s\n", gettext("done."));
- }
+ if (verbose)
+ finish_progress(gettext("done."));
}
static int
@@ -3098,42 +3245,9 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
return (1);
break;
}
- } else {
+ } else
assert(op == OP_SHARE);
- /*
- * Ignore any volumes that aren't shared.
- */
- verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts,
- sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
-
- if (strcmp(shareopts, "off") == 0) {
- if (!explicit)
- return (0);
-
- (void) fprintf(stderr, gettext("cannot share '%s': "
- "'shareiscsi' property not set\n"),
- zfs_get_name(zhp));
- (void) fprintf(stderr, gettext("set 'shareiscsi' "
- "property or use iscsitadm(1M) to share this "
- "volume\n"));
- return (1);
- }
-
- if (zfs_is_shared_iscsi(zhp)) {
- if (!explicit)
- return (0);
-
- (void) fprintf(stderr, gettext("cannot share "
- "'%s': volume already shared\n"),
- zfs_get_name(zhp));
- return (1);
- }
-
- if (zfs_share_iscsi(zhp) != 0)
- return (1);
- }
-
return (0);
}
@@ -3143,19 +3257,16 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
static void
report_mount_progress(int current, int total)
{
- static int len;
- static char *reverse = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
- "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
- static time_t last_progress_time;
+ static time_t last_progress_time = 0;
time_t now = time(NULL);
+ char info[32];
/* report 1..n instead of 0..n-1 */
++current;
/* display header if we're here for the first time */
if (current == 1) {
- (void) printf(gettext("Mounting ZFS filesystems: "));
- len = 0;
+ set_progress_header(gettext("Mounting ZFS filesystems"));
} else if (current != total && last_progress_time + MOUNT_TIME >= now) {
/* too soon to report again */
return;
@@ -3163,13 +3274,12 @@ report_mount_progress(int current, int total)
last_progress_time = now;
- /* back up to prepare for overwriting */
- if (len)
- (void) printf("%*.*s", len, len, reverse);
+ (void) sprintf(info, "(%d/%d)", current, total);
- /* We put a newline at the end if this is the last one. */
- len = printf("(%d/%d)%s", current, total, current == total ? "\n" : "");
- (void) fflush(stdout);
+ if (current == total)
+ finish_progress(info);
+ else
+ update_progress(info);
}
static void
@@ -3254,11 +3364,9 @@ share_mount(int op, int argc, char **argv)
if (strcmp(argv[0], "nfs") == 0 ||
strcmp(argv[0], "smb") == 0) {
types = ZFS_TYPE_FILESYSTEM;
- } else if (strcmp(argv[0], "iscsi") == 0) {
- types = ZFS_TYPE_VOLUME;
} else {
(void) fprintf(stderr, gettext("share type "
- "must be 'nfs', 'smb' or 'iscsi'\n"));
+ "must be 'nfs' or 'smb'\n"));
usage(B_FALSE);
}
protocol = argv[0];
@@ -3273,6 +3381,7 @@ share_mount(int op, int argc, char **argv)
usage(B_FALSE);
}
+ start_progress_timer();
get_all_datasets(types, &dslist, &count, verbose);
if (count == 0)
@@ -3341,7 +3450,7 @@ share_mount(int op, int argc, char **argv)
}
/*
- * zfs mount -a [nfs | iscsi]
+ * zfs mount -a [nfs]
* zfs mount filesystem
*
* Mount all filesystems, or mount the given filesystem.
@@ -3353,7 +3462,7 @@ zfs_do_mount(int argc, char **argv)
}
/*
- * zfs share -a [nfs | iscsi | smb]
+ * zfs share -a [nfs | smb]
* zfs share filesystem
*
* Share all filesystems, or share the given filesystem.
@@ -3509,7 +3618,7 @@ unshare_unmount(int op, int argc, char **argv)
int ret = 0;
int types, c;
zfs_handle_t *zhp;
- char nfsiscsi_mnt_prop[ZFS_MAXPROPLEN];
+ char nfs_mnt_prop[ZFS_MAXPROPLEN];
char sharesmb[ZFS_MAXPROPLEN];
/* check options */
@@ -3558,21 +3667,12 @@ unshare_unmount(int op, int argc, char **argv)
usage(B_FALSE);
}
- if ((pool = uu_avl_pool_create("unmount_pool",
+ if (((pool = uu_avl_pool_create("unmount_pool",
sizeof (unshare_unmount_node_t),
offsetof(unshare_unmount_node_t, un_avlnode),
- unshare_unmount_compare,
- UU_DEFAULT)) == NULL) {
- (void) fprintf(stderr, gettext("internal error: "
- "out of memory\n"));
- exit(1);
- }
-
- if ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL) {
- (void) fprintf(stderr, gettext("internal error: "
- "out of memory\n"));
- exit(1);
- }
+ unshare_unmount_compare, UU_DEFAULT)) == NULL) ||
+ ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL))
+ nomem();
rewind(mnttab_file);
while (getmntent(mnttab_file, &entry) == 0) {
@@ -3594,25 +3694,25 @@ unshare_unmount(int op, int argc, char **argv)
switch (op) {
case OP_SHARE:
verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
- nfsiscsi_mnt_prop,
- sizeof (nfsiscsi_mnt_prop),
+ nfs_mnt_prop,
+ sizeof (nfs_mnt_prop),
NULL, NULL, 0, B_FALSE) == 0);
- if (strcmp(nfsiscsi_mnt_prop, "off") != 0)
+ if (strcmp(nfs_mnt_prop, "off") != 0)
break;
verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
- nfsiscsi_mnt_prop,
- sizeof (nfsiscsi_mnt_prop),
+ nfs_mnt_prop,
+ sizeof (nfs_mnt_prop),
NULL, NULL, 0, B_FALSE) == 0);
- if (strcmp(nfsiscsi_mnt_prop, "off") == 0)
+ if (strcmp(nfs_mnt_prop, "off") == 0)
continue;
break;
case OP_MOUNT:
/* Ignore legacy mounts */
verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
- nfsiscsi_mnt_prop,
- sizeof (nfsiscsi_mnt_prop),
+ nfs_mnt_prop,
+ sizeof (nfs_mnt_prop),
NULL, NULL, 0, B_FALSE) == 0);
- if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0)
+ if (strcmp(nfs_mnt_prop, "legacy") == 0)
continue;
/* Ignore canmount=noauto mounts */
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
@@ -3624,13 +3724,7 @@ unshare_unmount(int op, int argc, char **argv)
node = safe_malloc(sizeof (unshare_unmount_node_t));
node->un_zhp = zhp;
-
- if ((node->un_mountp = strdup(entry.mnt_mountp)) ==
- NULL) {
- (void) fprintf(stderr, gettext("internal error:"
- " out of memory\n"));
- exit(1);
- }
+ node->un_mountp = safe_strdup(entry.mnt_mountp);
uu_avl_node_init(node, &node->un_avlnode, pool);
@@ -3648,11 +3742,8 @@ unshare_unmount(int op, int argc, char **argv)
* removing it from the AVL tree in the process.
*/
if ((walk = uu_avl_walk_start(tree,
- UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL) {
- (void) fprintf(stderr,
- gettext("internal error: out of memory"));
- exit(1);
- }
+ UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL)
+ nomem();
while ((node = uu_avl_walk_next(walk)) != NULL) {
uu_avl_remove(tree, node);
@@ -3680,29 +3771,6 @@ unshare_unmount(int op, int argc, char **argv)
uu_avl_destroy(tree);
uu_avl_pool_destroy(pool);
- if (op == OP_SHARE) {
- /*
- * Finally, unshare any volumes shared via iSCSI.
- */
- zfs_handle_t **dslist = NULL;
- size_t i, count = 0;
-
- get_all_datasets(ZFS_TYPE_VOLUME, &dslist, &count,
- B_FALSE);
-
- if (count != 0) {
- qsort(dslist, count, sizeof (void *),
- dataset_cmp);
-
- for (i = 0; i < count; i++) {
- if (zfs_unshare_iscsi(dslist[i]) != 0)
- ret = 1;
- zfs_close(dslist[i]);
- }
-
- free(dslist);
- }
- }
} else {
if (argc != 1) {
if (argc == 0)
@@ -3734,20 +3802,20 @@ unshare_unmount(int op, int argc, char **argv)
if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
verify(zfs_prop_get(zhp, op == OP_SHARE ?
ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
- nfsiscsi_mnt_prop, sizeof (nfsiscsi_mnt_prop), NULL,
+ nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL,
NULL, 0, B_FALSE) == 0);
switch (op) {
case OP_SHARE:
verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
- nfsiscsi_mnt_prop,
- sizeof (nfsiscsi_mnt_prop),
+ nfs_mnt_prop,
+ sizeof (nfs_mnt_prop),
NULL, NULL, 0, B_FALSE) == 0);
verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
sharesmb, sizeof (sharesmb), NULL, NULL,
0, B_FALSE) == 0);
- if (strcmp(nfsiscsi_mnt_prop, "off") == 0 &&
+ if (strcmp(nfs_mnt_prop, "off") == 0 &&
strcmp(sharesmb, "off") == 0) {
(void) fprintf(stderr, gettext("cannot "
"unshare '%s': legacy share\n"),
@@ -3767,7 +3835,7 @@ unshare_unmount(int op, int argc, char **argv)
break;
case OP_MOUNT:
- if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0) {
+ if (strcmp(nfs_mnt_prop, "legacy") == 0) {
(void) fprintf(stderr, gettext("cannot "
"unmount '%s': legacy "
"mountpoint\n"), zfs_get_name(zhp));
@@ -3786,29 +3854,6 @@ unshare_unmount(int op, int argc, char **argv)
}
break;
}
- } else {
- assert(op == OP_SHARE);
-
- verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI,
- nfsiscsi_mnt_prop, sizeof (nfsiscsi_mnt_prop),
- NULL, NULL, 0, B_FALSE) == 0);
-
- if (strcmp(nfsiscsi_mnt_prop, "off") == 0) {
- (void) fprintf(stderr, gettext("cannot unshare "
- "'%s': 'shareiscsi' property not set\n"),
- zfs_get_name(zhp));
- (void) fprintf(stderr, gettext("set "
- "'shareiscsi' property or use "
- "iscsitadm(1M) to share this volume\n"));
- ret = 1;
- } else if (!zfs_is_shared_iscsi(zhp)) {
- (void) fprintf(stderr, gettext("cannot "
- "unshare '%s': not currently shared\n"),
- zfs_get_name(zhp));
- ret = 1;
- } else if (zfs_unshare_iscsi(zhp) != 0) {
- ret = 1;
- }
}
zfs_close(zhp);
@@ -3986,27 +4031,6 @@ manual_unmount(int argc, char **argv)
}
static int
-volcheck(zpool_handle_t *zhp, void *data)
-{
- boolean_t isinit = *((boolean_t *)data);
-
- if (isinit)
- return (zpool_create_zvol_links(zhp));
- else
- return (zpool_remove_zvol_links(zhp));
-}
-
-/*
- * Iterate over all pools in the system and either create or destroy /dev/zvol
- * links, depending on the value of 'isinit'.
- */
-static int
-do_volcheck(boolean_t isinit)
-{
- return (zpool_iter(g_zfs, volcheck, &isinit) ? 1 : 0);
-}
-
-static int
find_command_idx(char *command, int *idx)
{
int i;
@@ -4092,15 +4116,6 @@ main(int argc, char **argv)
usage(B_TRUE);
/*
- * 'volinit' and 'volfini' do not appear in the usage message,
- * so we have to special case them here.
- */
- if (strcmp(cmdname, "volinit") == 0)
- return (do_volcheck(B_TRUE));
- else if (strcmp(cmdname, "volfini") == 0)
- return (do_volcheck(B_FALSE));
-
- /*
* Run the appropriate command.
*/
libzfs_mnttab_cache(g_zfs, B_TRUE);