summaryrefslogtreecommitdiffstats
path: root/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'cddl/contrib/opensolaris/cmd/zpool/zpool_main.c')
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_main.c1338
1 files changed, 843 insertions, 495 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
index 5b1d856..2388df9 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <solaris.h>
#include <assert.h>
#include <ctype.h>
@@ -42,6 +40,8 @@
#include <strings.h>
#include <unistd.h>
#include <priv.h>
+#include <pwd.h>
+#include <zone.h>
#include <sys/time.h>
#include <sys/fs/zfs.h>
@@ -50,6 +50,7 @@
#include <libzfs.h>
#include "zpool_util.h"
+#include "zfs_comutil.h"
static int zpool_do_create(int, char **);
static int zpool_do_destroy(int, char **);
@@ -85,6 +86,8 @@ static int zpool_do_set(int, char **);
* These libumem hooks provide a reasonable set of defaults for the allocator's
* debugging facilities.
*/
+
+#ifdef DEBUG
const char *
_umem_debug_init(void)
{
@@ -96,6 +99,7 @@ _umem_logging_init(void)
{
return ("fail,contents"); /* $UMEM_LOGGING setting */
}
+#endif
typedef enum {
HELP_ADD,
@@ -169,6 +173,7 @@ static zpool_command_t command_table[] = {
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
zpool_command_t *current_command;
+static char history_str[HIS_MAX_RECORD_LEN];
static const char *
get_usage(zpool_help_t idx) {
@@ -177,12 +182,13 @@ get_usage(zpool_help_t idx) {
return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
case HELP_ATTACH:
return (gettext("\tattach [-f] <pool> <device> "
- "<new_device>\n"));
+ "<new-device>\n"));
case HELP_CLEAR:
return (gettext("\tclear <pool> [device]\n"));
case HELP_CREATE:
- return (gettext("\tcreate [-fn] [-R root] [-m mountpoint] "
- "<pool> <vdev> ...\n"));
+ return (gettext("\tcreate [-fn] [-o property=value] ... \n"
+ "\t [-O file-system-property=value] ... \n"
+ "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
case HELP_DESTROY:
return (gettext("\tdestroy [-f] <pool>\n"));
case HELP_DETACH:
@@ -190,17 +196,19 @@ get_usage(zpool_help_t idx) {
case HELP_EXPORT:
return (gettext("\texport [-f] <pool> ...\n"));
case HELP_HISTORY:
- return (gettext("\thistory [<pool>]\n"));
+ return (gettext("\thistory [-il] [<pool>] ...\n"));
case HELP_IMPORT:
return (gettext("\timport [-d dir] [-D]\n"
- "\timport [-d dir] [-D] [-f] [-o opts] [-R root] -a\n"
- "\timport [-d dir] [-D] [-f] [-o opts] [-R root ]"
- " <pool | id> [newpool]\n"));
+ "\timport [-o mntopts] [-o property=value] ... \n"
+ "\t [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n"
+ "\timport [-o mntopts] [-o property=value] ... \n"
+ "\t [-d dir | -c cachefile] [-D] [-f] [-R root] "
+ "<pool | id> [newpool]\n"));
case HELP_IOSTAT:
return (gettext("\tiostat [-v] [pool] ... [interval "
"[count]]\n"));
case HELP_LIST:
- return (gettext("\tlist [-H] [-o field[,field]*] "
+ return (gettext("\tlist [-H] [-o property[,...]] "
"[pool] ...\n"));
case HELP_OFFLINE:
return (gettext("\toffline [-t] <pool> <device> ...\n"));
@@ -208,9 +216,9 @@ get_usage(zpool_help_t idx) {
return (gettext("\tonline <pool> <device> ...\n"));
case HELP_REPLACE:
return (gettext("\treplace [-f] <pool> <device> "
- "[new_device]\n"));
+ "[new-device]\n"));
case HELP_REMOVE:
- return (gettext("\tremove <pool> <device>\n"));
+ return (gettext("\tremove <pool> <device> ...\n"));
case HELP_SCRUB:
return (gettext("\tscrub [-s] <pool> ...\n"));
case HELP_STATUS:
@@ -218,9 +226,9 @@ get_usage(zpool_help_t idx) {
case HELP_UPGRADE:
return (gettext("\tupgrade\n"
"\tupgrade -v\n"
- "\tupgrade <-a | pool>\n"));
+ "\tupgrade [-V version] <-a | pool ...>\n"));
case HELP_GET:
- return (gettext("\tget <all | property[,property]...> "
+ return (gettext("\tget <\"all\" | property[,...]> "
"<pool> ...\n"));
case HELP_SET:
return (gettext("\tset <property=value> <pool> \n"));
@@ -230,67 +238,28 @@ get_usage(zpool_help_t idx) {
/* NOTREACHED */
}
-/*
- * Fields available for 'zpool list'.
- */
-typedef enum {
- ZPOOL_FIELD_NAME,
- ZPOOL_FIELD_SIZE,
- ZPOOL_FIELD_USED,
- ZPOOL_FIELD_AVAILABLE,
- ZPOOL_FIELD_CAPACITY,
- ZPOOL_FIELD_HEALTH,
- ZPOOL_FIELD_ROOT
-} zpool_field_t;
-
-#define MAX_FIELDS 10
-
-typedef struct column_def {
- const char *cd_title;
- size_t cd_width;
- enum {
- left_justify,
- right_justify
- } cd_justify;
-} column_def_t;
-
-static column_def_t column_table[] = {
- { "NAME", 20, left_justify },
- { "SIZE", 6, right_justify },
- { "USED", 6, right_justify },
- { "AVAIL", 6, right_justify },
- { "CAP", 5, right_justify },
- { "HEALTH", 9, left_justify },
- { "ALTROOT", 15, left_justify }
-};
-
-static char *column_subopts[] = {
- "name",
- "size",
- "used",
- "available",
- "capacity",
- "health",
- "root",
- NULL
-};
/*
* Callback routine that will print out a pool property value.
*/
-static zpool_prop_t
-print_prop_cb(zpool_prop_t prop, void *cb)
+static int
+print_prop_cb(int prop, void *cb)
{
FILE *fp = cb;
(void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop));
+ if (zpool_prop_readonly(prop))
+ (void) fprintf(fp, " NO ");
+ else
+ (void) fprintf(fp, " YES ");
+
if (zpool_prop_values(prop) == NULL)
(void) fprintf(fp, "-\n");
else
(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
- return (ZFS_PROP_CONT);
+ return (ZPROP_CONT);
}
/*
@@ -301,7 +270,6 @@ print_prop_cb(zpool_prop_t prop, void *cb)
void
usage(boolean_t requested)
{
- int i;
FILE *fp = requested ? stdout : stderr;
if (current_command == NULL) {
@@ -321,28 +289,22 @@ usage(boolean_t requested)
} else {
(void) fprintf(fp, gettext("usage:\n"));
(void) fprintf(fp, "%s", get_usage(current_command->usage));
-
- if (strcmp(current_command->name, "list") == 0) {
- (void) fprintf(fp, gettext("\nwhere 'field' is one "
- "of the following:\n\n"));
-
- for (i = 0; column_subopts[i] != NULL; i++)
- (void) fprintf(fp, "\t%s\n", column_subopts[i]);
- }
}
if (current_command != NULL &&
((strcmp(current_command->name, "set") == 0) ||
- (strcmp(current_command->name, "get") == 0))) {
+ (strcmp(current_command->name, "get") == 0) ||
+ (strcmp(current_command->name, "list") == 0))) {
(void) fprintf(fp,
gettext("\nthe following properties are supported:\n"));
- (void) fprintf(fp, "\n\t%-13s %s\n\n",
- "PROPERTY", "VALUES");
+ (void) fprintf(fp, "\n\t%-13s %s %s\n\n",
+ "PROPERTY", "EDIT", "VALUES");
/* Iterate over all properties */
- (void) zpool_prop_iter(print_prop_cb, fp, B_FALSE);
+ (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
+ ZFS_TYPE_POOL);
}
/*
@@ -356,46 +318,9 @@ usage(boolean_t requested)
exit(requested ? 0 : 2);
}
-const char *
-state_to_health(int vs_state)
-{
- switch (vs_state) {
- case VDEV_STATE_CLOSED:
- case VDEV_STATE_CANT_OPEN:
- case VDEV_STATE_OFFLINE:
- return (dgettext(TEXT_DOMAIN, "FAULTED"));
- case VDEV_STATE_DEGRADED:
- return (dgettext(TEXT_DOMAIN, "DEGRADED"));
- case VDEV_STATE_HEALTHY:
- return (dgettext(TEXT_DOMAIN, "ONLINE"));
- }
-
- return (dgettext(TEXT_DOMAIN, "UNKNOWN"));
-}
-
-const char *
-state_to_name(vdev_stat_t *vs)
-{
- switch (vs->vs_state) {
- case VDEV_STATE_CLOSED:
- case VDEV_STATE_CANT_OPEN:
- if (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
- return (gettext("FAULTED"));
- else
- return (gettext("UNAVAIL"));
- case VDEV_STATE_OFFLINE:
- return (gettext("OFFLINE"));
- case VDEV_STATE_DEGRADED:
- return (gettext("DEGRADED"));
- case VDEV_STATE_HEALTHY:
- return (gettext("ONLINE"));
- }
-
- return (gettext("UNKNOWN"));
-}
-
void
-print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent)
+print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
+ boolean_t print_logs)
{
nvlist_t **child;
uint_t c, children;
@@ -409,13 +334,75 @@ print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent)
return;
for (c = 0; c < children; c++) {
+ uint64_t is_log = B_FALSE;
+
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &is_log);
+ if ((is_log && !print_logs) || (!is_log && print_logs))
+ continue;
+
vname = zpool_vdev_name(g_zfs, zhp, child[c]);
- print_vdev_tree(zhp, vname, child[c], indent + 2);
+ print_vdev_tree(zhp, vname, child[c], indent + 2,
+ B_FALSE);
free(vname);
}
}
/*
+ * Add a property pair (name, string-value) into a property nvlist.
+ */
+static int
+add_prop_list(const char *propname, char *propval, nvlist_t **props,
+ boolean_t poolprop)
+{
+ zpool_prop_t prop = ZPROP_INVAL;
+ zfs_prop_t fprop;
+ nvlist_t *proplist;
+ const char *normnm;
+ char *strval;
+
+ if (*props == NULL &&
+ nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
+ (void) fprintf(stderr,
+ gettext("internal error: out of memory\n"));
+ return (1);
+ }
+
+ proplist = *props;
+
+ if (poolprop) {
+ if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
+ (void) fprintf(stderr, gettext("property '%s' is "
+ "not a valid pool property\n"), propname);
+ return (2);
+ }
+ normnm = zpool_prop_to_name(prop);
+ } else {
+ if ((fprop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
+ (void) fprintf(stderr, gettext("property '%s' is "
+ "not a valid file system property\n"), propname);
+ return (2);
+ }
+ normnm = zfs_prop_to_name(fprop);
+ }
+
+ if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
+ prop != ZPOOL_PROP_CACHEFILE) {
+ (void) fprintf(stderr, gettext("property '%s' "
+ "specified multiple times\n"), propname);
+ return (2);
+ }
+
+ if (nvlist_add_string(proplist, normnm, propval) != 0) {
+ (void) fprintf(stderr, gettext("internal "
+ "error: out of memory\n"));
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
* zpool add [-fn] <pool> <vdev> ...
*
* -f Force addition of devices, even if they appear in use
@@ -483,7 +470,8 @@ zpool_do_add(int argc, char **argv)
}
/* pass off to get_vdev_spec for processing */
- nvroot = make_root_vdev(config, force, !force, B_FALSE, argc, argv);
+ nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
+ argc, argv);
if (nvroot == NULL) {
zpool_close(zhp);
return (1);
@@ -498,16 +486,21 @@ zpool_do_add(int argc, char **argv)
(void) printf(gettext("would update '%s' to the following "
"configuration:\n"), zpool_get_name(zhp));
- print_vdev_tree(zhp, poolname, poolnvroot, 0);
- print_vdev_tree(zhp, NULL, nvroot, 0);
+ /* print original main pool and new tree */
+ print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
+ print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
+
+ /* Do the same for the logs */
+ if (num_logs(poolnvroot) > 0) {
+ print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
+ print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
+ } else if (num_logs(nvroot) > 0) {
+ print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
+ }
ret = 0;
} else {
ret = (zpool_add(zhp, nvroot) != 0);
- if (!ret) {
- zpool_log_history(g_zfs, argc + 1 + optind,
- argv - 1 - optind, poolname, B_TRUE, B_FALSE);
- }
}
nvlist_free(nvroot);
@@ -517,17 +510,17 @@ zpool_do_add(int argc, char **argv)
}
/*
- * zpool remove <pool> <vdev>
+ * zpool remove <pool> <vdev> ...
*
* Removes the given vdev from the pool. Currently, this only supports removing
- * spares from the pool. Eventually, we'll want to support removing leaf vdevs
- * (as an alias for 'detach') as well as toplevel vdevs.
+ * spares and cache devices from the pool. Eventually, we'll want to support
+ * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
*/
int
zpool_do_remove(int argc, char **argv)
{
char *poolname;
- int ret;
+ int i, ret = 0;
zpool_handle_t *zhp;
argc--;
@@ -548,17 +541,18 @@ zpool_do_remove(int argc, char **argv)
if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
return (1);
- ret = (zpool_vdev_remove(zhp, argv[1]) != 0);
- if (!ret) {
- zpool_log_history(g_zfs, ++argc, --argv, poolname, B_TRUE,
- B_FALSE);
+ for (i = 1; i < argc; i++) {
+ if (zpool_vdev_remove(zhp, argv[i]) != 0)
+ ret = 1;
}
return (ret);
}
/*
- * zpool create [-fn] [-R root] [-m mountpoint] <pool> <dev> ...
+ * zpool create [-fn] [-o property=value] ...
+ * [-O file-system-property=value] ...
+ * [-R root] [-m mountpoint] <pool> <dev> ...
*
* -f Force creation, even if devices appear in use
* -n Do not create the pool, but display the resulting layout if it
@@ -566,6 +560,8 @@ zpool_do_remove(int argc, char **argv)
* -R Create a pool under an alternate root
* -m Set default mountpoint for the root dataset. By default it's
* '/<pool>'
+ * -o Set property=value.
+ * -O Set fsproperty=value in the pool's root file system
*
* Creates the named pool according to the given vdev specification. The
* bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once
@@ -578,16 +574,17 @@ zpool_do_create(int argc, char **argv)
boolean_t force = B_FALSE;
boolean_t dryrun = B_FALSE;
int c;
- nvlist_t *nvroot;
+ nvlist_t *nvroot = NULL;
char *poolname;
- int ret;
+ int ret = 1;
char *altroot = NULL;
char *mountpoint = NULL;
- nvlist_t **child;
- uint_t children;
+ nvlist_t *fsprops = NULL;
+ nvlist_t *props = NULL;
+ char *propval;
/* check options */
- while ((c = getopt(argc, argv, ":fnR:m:")) != -1) {
+ while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
switch (c) {
case 'f':
force = B_TRUE;
@@ -597,19 +594,52 @@ zpool_do_create(int argc, char **argv)
break;
case 'R':
altroot = optarg;
+ if (add_prop_list(zpool_prop_to_name(
+ ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
+ goto errout;
+ if (nvlist_lookup_string(props,
+ zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
+ &propval) == 0)
+ break;
+ if (add_prop_list(zpool_prop_to_name(
+ ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+ goto errout;
break;
case 'm':
mountpoint = optarg;
break;
+ case 'o':
+ if ((propval = strchr(optarg, '=')) == NULL) {
+ (void) fprintf(stderr, gettext("missing "
+ "'=' for -o option\n"));
+ goto errout;
+ }
+ *propval = '\0';
+ propval++;
+
+ if (add_prop_list(optarg, propval, &props, B_TRUE))
+ goto errout;
+ break;
+ case 'O':
+ if ((propval = strchr(optarg, '=')) == NULL) {
+ (void) fprintf(stderr, gettext("missing "
+ "'=' for -O option\n"));
+ goto errout;
+ }
+ *propval = '\0';
+ propval++;
+
+ if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
+ goto errout;
+ break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
- usage(B_FALSE);
- break;
+ goto badusage;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
- usage(B_FALSE);
+ goto badusage;
}
}
@@ -619,11 +649,11 @@ zpool_do_create(int argc, char **argv)
/* get pool name and check number of arguments */
if (argc < 1) {
(void) fprintf(stderr, gettext("missing pool name argument\n"));
- usage(B_FALSE);
+ goto badusage;
}
if (argc < 2) {
(void) fprintf(stderr, gettext("missing vdev specification\n"));
- usage(B_FALSE);
+ goto badusage;
}
poolname = argv[0];
@@ -637,31 +667,28 @@ zpool_do_create(int argc, char **argv)
"character '/' in pool name\n"), poolname);
(void) fprintf(stderr, gettext("use 'zfs create' to "
"create a dataset\n"));
- return (1);
+ goto errout;
}
/* pass off to get_vdev_spec for bulk processing */
- nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1,
- argv + 1);
+ nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
+ argc - 1, argv + 1);
if (nvroot == NULL)
- return (1);
+ goto errout;
/* make_root_vdev() allows 0 toplevel children if there are spares */
- verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
- &child, &children) == 0);
- if (children == 0) {
+ if (!zfs_allocatable_devs(nvroot)) {
(void) fprintf(stderr, gettext("invalid vdev "
"specification: at least one toplevel vdev must be "
"specified\n"));
- return (1);
+ goto errout;
}
if (altroot != NULL && altroot[0] != '/') {
(void) fprintf(stderr, gettext("invalid alternate root '%s': "
"must be an absolute path\n"), altroot);
- nvlist_free(nvroot);
- return (1);
+ goto errout;
}
/*
@@ -672,14 +699,13 @@ zpool_do_create(int argc, char **argv)
(strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
char buf[MAXPATHLEN];
- struct stat64 statbuf;
+ DIR *dirp;
if (mountpoint && mountpoint[0] != '/') {
(void) fprintf(stderr, gettext("invalid mountpoint "
"'%s': must be an absolute path, 'legacy', or "
"'none'\n"), mountpoint);
- nvlist_free(nvroot);
- return (1);
+ goto errout;
}
if (mountpoint == NULL) {
@@ -698,23 +724,30 @@ zpool_do_create(int argc, char **argv)
mountpoint);
}
- if (stat64(buf, &statbuf) == 0 &&
- statbuf.st_nlink != 2) {
- if (mountpoint == NULL)
- (void) fprintf(stderr, gettext("default "
- "mountpoint '%s' exists and is not "
- "empty\n"), buf);
- else
- (void) fprintf(stderr, gettext("mountpoint "
- "'%s' exists and is not empty\n"), buf);
+ if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
+ (void) fprintf(stderr, gettext("mountpoint '%s' : "
+ "%s\n"), buf, strerror(errno));
(void) fprintf(stderr, gettext("use '-m' "
"option to provide a different default\n"));
- nvlist_free(nvroot);
- return (1);
+ goto errout;
+ } else if (dirp) {
+ int count = 0;
+
+ while (count < 3 && readdir(dirp) != NULL)
+ count++;
+ (void) closedir(dirp);
+
+ if (count > 2) {
+ (void) fprintf(stderr, gettext("mountpoint "
+ "'%s' exists and is not empty\n"), buf);
+ (void) fprintf(stderr, gettext("use '-m' "
+ "option to provide a "
+ "different default\n"));
+ goto errout;
+ }
}
}
-
if (dryrun) {
/*
* For a dry run invocation, print out a basic message and run
@@ -724,15 +757,17 @@ zpool_do_create(int argc, char **argv)
(void) printf(gettext("would create '%s' with the "
"following layout:\n\n"), poolname);
- print_vdev_tree(NULL, poolname, nvroot, 0);
+ print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
+ if (num_logs(nvroot) > 0)
+ print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
ret = 0;
} else {
- ret = 1;
/*
* Hand off to libzfs.
*/
- if (zpool_create(g_zfs, poolname, nvroot, altroot) == 0) {
+ if (zpool_create(g_zfs, poolname,
+ nvroot, props, fsprops) == 0) {
zfs_handle_t *pool = zfs_open(g_zfs, poolname,
ZFS_TYPE_FILESYSTEM);
if (pool != NULL) {
@@ -742,20 +777,25 @@ zpool_do_create(int argc, char **argv)
ZFS_PROP_MOUNTPOINT),
mountpoint) == 0);
if (zfs_mount(pool, NULL, 0) == 0)
- ret = zfs_share_nfs(pool);
+ ret = zfs_shareall(pool);
zfs_close(pool);
}
- zpool_log_history(g_zfs, argc + optind, argv - optind,
- poolname, B_TRUE, B_TRUE);
} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
(void) fprintf(stderr, gettext("pool name may have "
"been omitted\n"));
}
}
+errout:
nvlist_free(nvroot);
-
+ nvlist_free(fsprops);
+ nvlist_free(props);
return (ret);
+badusage:
+ nvlist_free(fsprops);
+ nvlist_free(props);
+ usage(B_FALSE);
+ return (2);
}
/*
@@ -819,9 +859,6 @@ zpool_do_destroy(int argc, char **argv)
return (1);
}
- zpool_log_history(g_zfs, argc + optind, argv - optind, pool, B_TRUE,
- B_FALSE);
-
ret = (zpool_destroy(zhp) != 0);
zpool_close(zhp);
@@ -882,10 +919,7 @@ zpool_do_export(int argc, char **argv)
continue;
}
- zpool_log_history(g_zfs, argc + optind, argv - optind, argv[i],
- B_TRUE, B_FALSE);
-
- if (zpool_export(zhp) != 0)
+ if (zpool_export(zhp, force) != 0)
ret = 1;
zpool_close(zhp);
@@ -919,6 +953,14 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
max = ret;
}
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+ &child, &children) == 0) {
+ for (c = 0; c < children; c++)
+ if ((ret = max_width(zhp, child[c], depth + 2,
+ max)) > max)
+ max = ret;
+ }
+
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
&child, &children) == 0) {
for (c = 0; c < children; c++)
@@ -937,7 +979,8 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
* pool, printing out the name and status for each one.
*/
void
-print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
+print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
+ boolean_t print_logs)
{
nvlist_t **child;
uint_t c, children;
@@ -952,9 +995,10 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
(uint64_t **)&vs, &c) == 0);
(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
+ (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
if (vs->vs_aux != 0) {
- (void) printf(" %-8s ", state_to_name(vs));
+ (void) printf(" ");
switch (vs->vs_aux) {
case VDEV_AUX_OPEN_FAILED:
@@ -973,12 +1017,14 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
(void) printf(gettext("newer version"));
break;
+ case VDEV_AUX_ERR_EXCEEDED:
+ (void) printf(gettext("too many errors"));
+ break;
+
default:
(void) printf(gettext("corrupted data"));
break;
}
- } else {
- (void) printf(" %s", state_to_name(vs));
}
(void) printf("\n");
@@ -987,21 +1033,37 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
return;
for (c = 0; c < children; c++) {
+ uint64_t is_log = B_FALSE;
+
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &is_log);
+ if ((is_log && !print_logs) || (!is_log && print_logs))
+ continue;
+
vname = zpool_vdev_name(g_zfs, NULL, child[c]);
print_import_config(vname, child[c],
- namewidth, depth + 2);
+ namewidth, depth + 2, B_FALSE);
free(vname);
}
- if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
- &child, &children) != 0)
- return;
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+ &child, &children) == 0) {
+ (void) printf(gettext("\tcache\n"));
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, NULL, child[c]);
+ (void) printf("\t %s\n", vname);
+ free(vname);
+ }
+ }
- (void) printf(gettext("\tspares\n"));
- for (c = 0; c < children; c++) {
- vname = zpool_vdev_name(g_zfs, NULL, child[c]);
- (void) printf("\t %s\n", vname);
- free(vname);
+ if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+ &child, &children) == 0) {
+ (void) printf(gettext("\tspares\n"));
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, NULL, child[c]);
+ (void) printf("\t %s\n", vname);
+ free(vname);
+ }
}
}
@@ -1033,7 +1095,7 @@ show_import(nvlist_t *config)
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
(uint64_t **)&vs, &vsc) == 0);
- health = state_to_health(vs->vs_state);
+ health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
reason = zpool_import_status(config, &msgid);
@@ -1086,6 +1148,18 @@ show_import(nvlist_t *config)
(void) printf(gettext("status: The pool was last accessed by "
"another system.\n"));
break;
+
+ case ZPOOL_STATUS_FAULTED_DEV_R:
+ case ZPOOL_STATUS_FAULTED_DEV_NR:
+ (void) printf(gettext("status: One or more devices are "
+ "faulted.\n"));
+ break;
+
+ case ZPOOL_STATUS_BAD_LOG:
+ (void) printf(gettext("status: An intent log record cannot be "
+ "read.\n"));
+ break;
+
default:
/*
* No other status can be seen when importing pools.
@@ -1147,7 +1221,7 @@ show_import(nvlist_t *config)
"but can be imported using the '-Df' flags.\n"));
else if (pool_state != POOL_STATE_EXPORTED)
(void) printf(gettext("\tThe pool may be active on "
- "on another system, but can be imported using\n\t"
+ "another system, but can be imported using\n\t"
"the '-f' flag.\n"));
}
@@ -1160,7 +1234,12 @@ show_import(nvlist_t *config)
namewidth = max_width(NULL, nvroot, 0, 0);
if (namewidth < 10)
namewidth = 10;
- print_import_config(name, nvroot, namewidth, 0);
+
+ print_import_config(name, nvroot, namewidth, 0, B_FALSE);
+ if (num_logs(nvroot) > 0) {
+ (void) printf(gettext("\tlogs\n"));
+ print_import_config(name, nvroot, namewidth, 0, B_TRUE);
+ }
if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
(void) printf(gettext("\n\tAdditional devices are known to "
@@ -1171,17 +1250,18 @@ show_import(nvlist_t *config)
/*
* Perform the import for the given configuration. This passes the heavy
- * lifting off to zpool_import(), and then mounts the datasets contained within
- * the pool.
+ * lifting off to zpool_import_props(), and then mounts the datasets contained
+ * within the pool.
*/
static int
do_import(nvlist_t *config, const char *newname, const char *mntopts,
- const char *altroot, int force, int argc, char **argv)
+ int force, nvlist_t *props, boolean_t allowfaulted)
{
zpool_handle_t *zhp;
char *name;
uint64_t state;
uint64_t version;
+ int error = 0;
verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
&name) == 0);
@@ -1190,7 +1270,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
ZPOOL_CONFIG_POOL_STATE, &state) == 0);
verify(nvlist_lookup_uint64(config,
ZPOOL_CONFIG_VERSION, &version) == 0);
- if (version > ZFS_VERSION) {
+ if (version > SPA_VERSION) {
(void) fprintf(stderr, gettext("cannot import '%s': pool "
"is formatted using a newer ZFS version\n"), name);
return (1);
@@ -1228,15 +1308,14 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
}
}
- if (zpool_import(g_zfs, config, newname, altroot) != 0)
+ if (zpool_import_props(g_zfs, config, newname, props,
+ allowfaulted) != 0)
return (1);
if (newname != NULL)
name = (char *)newname;
- zpool_log_history(g_zfs, argc, argv, name, B_TRUE, B_FALSE);
-
- verify((zhp = zpool_open(g_zfs, name)) != NULL);
+ verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
zpool_close(zhp);
@@ -1244,13 +1323,18 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
}
zpool_close(zhp);
- return (0);
+ return (error);
}
/*
* zpool import [-d dir] [-D]
- * import [-R root] [-D] [-d dir] [-f] -a
- * import [-R root] [-D] [-d dir] [-f] <pool | id> [newpool]
+ * import [-o mntopts] [-o prop=value] ... [-R root] [-D]
+ * [-d dir | -c cachefile] [-f] -a
+ * import [-o mntopts] [-o prop=value] ... [-R root] [-D]
+ * [-d dir | -c cachefile] [-f] <pool | id> [newpool]
+ *
+ * -c Read pool information from a cachefile instead of searching
+ * devices.
*
* -d Scan in a specific directory, other than /dev/dsk. More than
* one directory can be specified using multiple '-d' options.
@@ -1264,8 +1348,15 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
*
* -f Force import, even if it appears that the pool is active.
*
+ * -F Import even in the presence of faulted vdevs. This is an
+ * intentionally undocumented option for testing purposes, and
+ * treats the pool configuration as complete, leaving any bad
+ * vdevs in the FAULTED state.
+ *
* -a Import all pools found.
*
+ * -o Set property=value and/or temporary mount options (without '=').
+ *
* The import command scans for pools to import, and import pools based on pool
* name and GUID. The pool can also be renamed as part of the import process.
*/
@@ -1276,26 +1367,32 @@ zpool_do_import(int argc, char **argv)
int nsearch = 0;
int c;
int err;
- nvlist_t *pools;
+ nvlist_t *pools = NULL;
boolean_t do_all = B_FALSE;
boolean_t do_destroyed = B_FALSE;
- char *altroot = NULL;
char *mntopts = NULL;
boolean_t do_force = B_FALSE;
nvpair_t *elem;
nvlist_t *config;
- uint64_t searchguid;
- char *searchname;
+ uint64_t searchguid = 0;
+ char *searchname = NULL;
+ char *propval;
nvlist_t *found_config;
+ nvlist_t *props = NULL;
boolean_t first;
+ boolean_t allow_faulted = B_FALSE;
uint64_t pool_state;
+ char *cachefile = NULL;
/* check options */
- while ((c = getopt(argc, argv, ":Dfd:R:ao:")) != -1) {
+ while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
switch (c) {
case 'a':
do_all = B_TRUE;
break;
+ case 'c':
+ cachefile = optarg;
+ break;
case 'd':
if (searchdirs == NULL) {
searchdirs = safe_malloc(sizeof (char *));
@@ -1315,11 +1412,31 @@ zpool_do_import(int argc, char **argv)
case 'f':
do_force = B_TRUE;
break;
+ case 'F':
+ allow_faulted = B_TRUE;
+ break;
case 'o':
- mntopts = optarg;
+ if ((propval = strchr(optarg, '=')) != NULL) {
+ *propval = '\0';
+ propval++;
+ if (add_prop_list(optarg, propval,
+ &props, B_TRUE))
+ goto error;
+ } else {
+ mntopts = optarg;
+ }
break;
case 'R':
- altroot = optarg;
+ if (add_prop_list(zpool_prop_to_name(
+ ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
+ goto error;
+ if (nvlist_lookup_string(props,
+ zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
+ &propval) == 0)
+ break;
+ if (add_prop_list(zpool_prop_to_name(
+ ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+ goto error;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
@@ -1336,9 +1453,14 @@ zpool_do_import(int argc, char **argv)
argc -= optind;
argv += optind;
+ if (cachefile && nsearch != 0) {
+ (void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
+ usage(B_FALSE);
+ }
+
if (searchdirs == NULL) {
searchdirs = safe_malloc(sizeof (char *));
- searchdirs[0] = "/dev";
+ searchdirs[0] = "/dev/dsk";
nsearch = 1;
}
@@ -1367,13 +1489,7 @@ zpool_do_import(int argc, char **argv)
}
}
- if ((pools = zpool_find_import(g_zfs, nsearch, searchdirs)) == NULL) {
- free(searchdirs);
- return (1);
- }
-
/*
- * We now have a list of all available pools in the given directories.
* Depending on the arguments given, we do one of the following:
*
* <none> Iterate through all pools and display information about
@@ -1393,11 +1509,38 @@ zpool_do_import(int argc, char **argv)
searchguid = strtoull(argv[0], &endptr, 10);
if (errno != 0 || *endptr != '\0')
searchname = argv[0];
- else
- searchname = NULL;
found_config = NULL;
}
+ if (cachefile) {
+ pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
+ searchguid);
+ } else if (searchname != NULL) {
+ pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
+ searchname);
+ } else {
+ /*
+ * It's OK to search by guid even if searchguid is 0.
+ */
+ pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
+ searchguid);
+ }
+
+ if (pools == NULL) {
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("cannot import '%s': "
+ "no such pool available\n"), argv[0]);
+ }
+ free(searchdirs);
+ return (1);
+ }
+
+ /*
+ * At this point we have a list of import candidate configs. Even if
+ * we were searching by pool name or guid, we still need to
+ * post-process the list to deal with pool state and possible
+ * duplicate names.
+ */
err = 0;
elem = NULL;
first = B_TRUE;
@@ -1420,8 +1563,7 @@ zpool_do_import(int argc, char **argv)
if (do_all)
err |= do_import(config, NULL, mntopts,
- altroot, do_force, argc + optind,
- argv - optind);
+ do_force, props, allow_faulted);
else
show_import(config);
} else if (searchname != NULL) {
@@ -1469,8 +1611,7 @@ zpool_do_import(int argc, char **argv)
err = B_TRUE;
} else {
err |= do_import(found_config, argc == 1 ? NULL :
- argv[1], mntopts, altroot, do_force, argc + optind,
- argv - optind);
+ argv[1], mntopts, do_force, props, allow_faulted);
}
}
@@ -1482,6 +1623,8 @@ zpool_do_import(int argc, char **argv)
(void) fprintf(stderr,
gettext("no pools available to import\n"));
+error:
+ nvlist_free(props);
nvlist_free(pools);
free(searchdirs);
@@ -1518,7 +1661,7 @@ print_iostat_header(iostat_cbdata_t *cb)
/*
* Display a single statistic.
*/
-void
+static void
print_one_stat(uint64_t value)
{
char buf[64];
@@ -1606,6 +1749,28 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
newchild[c], cb, depth + 2);
free(vname);
}
+
+ /*
+ * Include level 2 ARC devices in iostat output
+ */
+ if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
+ &newchild, &children) != 0)
+ return;
+
+ if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
+ &oldchild, &c) != 0)
+ return;
+
+ if (children > 0) {
+ (void) printf("%-*s - - - - - "
+ "-\n", cb->cb_namewidth, "cache");
+ for (c = 0; c < children; c++) {
+ vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
+ print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
+ newchild[c], cb, depth + 2);
+ free(vname);
+ }
+ }
}
static int
@@ -1870,160 +2035,122 @@ zpool_do_iostat(int argc, char **argv)
typedef struct list_cbdata {
boolean_t cb_scripted;
boolean_t cb_first;
- int cb_fields[MAX_FIELDS];
- int cb_fieldcount;
+ zprop_list_t *cb_proplist;
} list_cbdata_t;
/*
* Given a list of columns to display, output appropriate headers for each one.
*/
-void
-print_header(int *fields, size_t count)
+static void
+print_header(zprop_list_t *pl)
{
- int i;
- column_def_t *col;
- const char *fmt;
+ const char *header;
+ boolean_t first = B_TRUE;
+ boolean_t right_justify;
- for (i = 0; i < count; i++) {
- col = &column_table[fields[i]];
- if (i != 0)
+ for (; pl != NULL; pl = pl->pl_next) {
+ if (pl->pl_prop == ZPROP_INVAL)
+ continue;
+
+ if (!first)
(void) printf(" ");
- if (col->cd_justify == left_justify)
- fmt = "%-*s";
else
- fmt = "%*s";
+ first = B_FALSE;
+
+ header = zpool_prop_column_name(pl->pl_prop);
+ right_justify = zpool_prop_align_right(pl->pl_prop);
- (void) printf(fmt, i == count - 1 ? strlen(col->cd_title) :
- col->cd_width, col->cd_title);
+ if (pl->pl_next == NULL && !right_justify)
+ (void) printf("%s", header);
+ else if (right_justify)
+ (void) printf("%*s", pl->pl_width, header);
+ else
+ (void) printf("%-*s", pl->pl_width, header);
}
(void) printf("\n");
}
-int
-list_callback(zpool_handle_t *zhp, void *data)
+/*
+ * Given a pool and a list of properties, print out all the properties according
+ * to the described layout.
+ */
+static void
+print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
{
- list_cbdata_t *cbp = data;
- nvlist_t *config;
- int i;
- char buf[ZPOOL_MAXNAMELEN];
- uint64_t total;
- uint64_t used;
- const char *fmt;
- column_def_t *col;
-
- if (cbp->cb_first) {
- if (!cbp->cb_scripted)
- print_header(cbp->cb_fields, cbp->cb_fieldcount);
- cbp->cb_first = B_FALSE;
- }
-
- if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
- config = NULL;
- } else {
- config = zpool_get_config(zhp, NULL);
- total = zpool_get_space_total(zhp);
- used = zpool_get_space_used(zhp);
- }
-
- for (i = 0; i < cbp->cb_fieldcount; i++) {
- if (i != 0) {
- if (cbp->cb_scripted)
+ boolean_t first = B_TRUE;
+ char property[ZPOOL_MAXPROPLEN];
+ char *propstr;
+ boolean_t right_justify;
+ int width;
+
+ for (; pl != NULL; pl = pl->pl_next) {
+ if (!first) {
+ if (scripted)
(void) printf("\t");
else
(void) printf(" ");
+ } else {
+ first = B_FALSE;
}
- col = &column_table[cbp->cb_fields[i]];
-
- switch (cbp->cb_fields[i]) {
- case ZPOOL_FIELD_NAME:
- (void) strlcpy(buf, zpool_get_name(zhp), sizeof (buf));
- break;
-
- case ZPOOL_FIELD_SIZE:
- if (config == NULL)
- (void) strlcpy(buf, "-", sizeof (buf));
- else
- zfs_nicenum(total, buf, sizeof (buf));
- break;
-
- case ZPOOL_FIELD_USED:
- if (config == NULL)
- (void) strlcpy(buf, "-", sizeof (buf));
+ right_justify = B_FALSE;
+ if (pl->pl_prop != ZPROP_INVAL) {
+ if (zpool_get_prop(zhp, pl->pl_prop, property,
+ sizeof (property), NULL) != 0)
+ propstr = "-";
else
- zfs_nicenum(used, buf, sizeof (buf));
- break;
+ propstr = property;
- case ZPOOL_FIELD_AVAILABLE:
- if (config == NULL)
- (void) strlcpy(buf, "-", sizeof (buf));
- else
- zfs_nicenum(total - used, buf, sizeof (buf));
- break;
+ right_justify = zpool_prop_align_right(pl->pl_prop);
+ } else {
+ propstr = "-";
+ }
- case ZPOOL_FIELD_CAPACITY:
- if (config == NULL) {
- (void) strlcpy(buf, "-", sizeof (buf));
- } else {
- uint64_t capacity = (total == 0 ? 0 :
- (used * 100 / total));
- (void) snprintf(buf, sizeof (buf), "%llu%%",
- (u_longlong_t)capacity);
- }
- break;
+ width = pl->pl_width;
- case ZPOOL_FIELD_HEALTH:
- if (config == NULL) {
- (void) strlcpy(buf, "FAULTED", sizeof (buf));
- } else {
- nvlist_t *nvroot;
- vdev_stat_t *vs;
- uint_t vsc;
-
- verify(nvlist_lookup_nvlist(config,
- ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
- verify(nvlist_lookup_uint64_array(nvroot,
- ZPOOL_CONFIG_STATS, (uint64_t **)&vs,
- &vsc) == 0);
- (void) strlcpy(buf, state_to_name(vs),
- sizeof (buf));
- }
- break;
+ /*
+ * If this is being called in scripted mode, or if this is the
+ * last column and it is left-justified, don't include a width
+ * format specifier.
+ */
+ if (scripted || (pl->pl_next == NULL && !right_justify))
+ (void) printf("%s", propstr);
+ else if (right_justify)
+ (void) printf("%*s", width, propstr);
+ else
+ (void) printf("%-*s", width, propstr);
+ }
- case ZPOOL_FIELD_ROOT:
- if (config == NULL)
- (void) strlcpy(buf, "-", sizeof (buf));
- else if (zpool_get_root(zhp, buf, sizeof (buf)) != 0)
- (void) strlcpy(buf, "-", sizeof (buf));
- break;
- }
+ (void) printf("\n");
+}
- if (cbp->cb_scripted)
- (void) printf("%s", buf);
- else {
- if (col->cd_justify == left_justify)
- fmt = "%-*s";
- else
- fmt = "%*s";
+/*
+ * Generic callback function to list a pool.
+ */
+int
+list_callback(zpool_handle_t *zhp, void *data)
+{
+ list_cbdata_t *cbp = data;
- (void) printf(fmt, i == cbp->cb_fieldcount - 1 ?
- strlen(buf) : col->cd_width, buf);
- }
+ if (cbp->cb_first) {
+ if (!cbp->cb_scripted)
+ print_header(cbp->cb_proplist);
+ cbp->cb_first = B_FALSE;
}
- (void) printf("\n");
+ print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
return (0);
}
/*
- * zpool list [-H] [-o field[,field]*] [pool] ...
+ * zpool list [-H] [-o prop[,prop]*] [pool] ...
*
- * -H Scripted mode. Don't display headers, and separate fields by
- * a single tab.
- * -o List of fields to display. Defaults to all fields, or
- * "name,size,used,available,capacity,health,root"
+ * -H Scripted mode. Don't display headers, and separate properties
+ * by a single tab.
+ * -o List of properties to display. Defaults to
+ * "name,size,used,available,capacity,health,altroot"
*
* List all pools in the system, whether or not they're healthy. Output space
* statistics for each one, as well as health status summary.
@@ -2034,10 +2161,9 @@ zpool_do_list(int argc, char **argv)
int c;
int ret;
list_cbdata_t cb = { 0 };
- static char default_fields[] =
- "name,size,used,available,capacity,health,root";
- char *fields = default_fields;
- char *value;
+ static char default_props[] =
+ "name,size,used,available,capacity,health,altroot";
+ char *props = default_props;
/* check options */
while ((c = getopt(argc, argv, ":Ho:")) != -1) {
@@ -2046,7 +2172,7 @@ zpool_do_list(int argc, char **argv)
cb.cb_scripted = B_TRUE;
break;
case 'o':
- fields = optarg;
+ props = optarg;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
@@ -2063,29 +2189,17 @@ zpool_do_list(int argc, char **argv)
argc -= optind;
argv += optind;
- while (*fields != '\0') {
- if (cb.cb_fieldcount == MAX_FIELDS) {
- (void) fprintf(stderr, gettext("too many "
- "properties given to -o option\n"));
- usage(B_FALSE);
- }
-
- if ((cb.cb_fields[cb.cb_fieldcount] = getsubopt(&fields,
- column_subopts, &value)) == -1) {
- (void) fprintf(stderr, gettext("invalid property "
- "'%s'\n"), value);
- usage(B_FALSE);
- }
-
- cb.cb_fieldcount++;
- }
-
+ if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
+ usage(B_FALSE);
cb.cb_first = B_TRUE;
- ret = for_each_pool(argc, argv, B_TRUE, NULL, list_callback, &cb);
+ ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
+ list_callback, &cb);
- if (argc == 0 && cb.cb_first) {
+ zprop_free_list(cb.cb_proplist);
+
+ if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
(void) printf(gettext("no pools available\n"));
return (0);
}
@@ -2128,10 +2242,7 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
nvlist_t *nvroot;
char *poolname, *old_disk, *new_disk;
zpool_handle_t *zhp;
- nvlist_t *config;
int ret;
- int log_argc;
- char **log_argv;
/* check options */
while ((c = getopt(argc, argv, "f")) != -1) {
@@ -2146,8 +2257,6 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
}
}
- log_argc = argc;
- log_argv = argv;
argc -= optind;
argv += optind;
@@ -2190,14 +2299,15 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
return (1);
- if ((config = zpool_get_config(zhp, NULL)) == NULL) {
+ if (zpool_get_config(zhp, NULL) == NULL) {
(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
poolname);
zpool_close(zhp);
return (1);
}
- nvroot = make_root_vdev(config, force, B_FALSE, replacing, argc, argv);
+ nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
+ argc, argv);
if (nvroot == NULL) {
zpool_close(zhp);
return (1);
@@ -2205,11 +2315,6 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
- if (!ret) {
- zpool_log_history(g_zfs, log_argc, log_argv, poolname, B_TRUE,
- B_FALSE);
- }
-
nvlist_free(nvroot);
zpool_close(zhp);
@@ -2299,10 +2404,6 @@ zpool_do_detach(int argc, char **argv)
ret = zpool_vdev_detach(zhp, path);
- if (!ret) {
- zpool_log_history(g_zfs, argc + optind, argv - optind, poolname,
- B_TRUE, B_FALSE);
- }
zpool_close(zhp);
return (ret);
@@ -2311,7 +2412,6 @@ zpool_do_detach(int argc, char **argv)
/*
* zpool online <pool> <device> ...
*/
-/* ARGSUSED */
int
zpool_do_online(int argc, char **argv)
{
@@ -2319,6 +2419,7 @@ zpool_do_online(int argc, char **argv)
char *poolname;
zpool_handle_t *zhp;
int ret = 0;
+ vdev_state_t newstate;
/* check options */
while ((c = getopt(argc, argv, "t")) != -1) {
@@ -2349,17 +2450,26 @@ zpool_do_online(int argc, char **argv)
if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
return (1);
- for (i = 1; i < argc; i++)
- if (zpool_vdev_online(zhp, argv[i]) == 0)
- (void) printf(gettext("Bringing device %s online\n"),
- argv[i]);
- else
+ for (i = 1; i < argc; i++) {
+ if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
+ if (newstate != VDEV_STATE_HEALTHY) {
+ (void) printf(gettext("warning: device '%s' "
+ "onlined, but remains in faulted state\n"),
+ argv[i]);
+ if (newstate == VDEV_STATE_FAULTED)
+ (void) printf(gettext("use 'zpool "
+ "clear' to restore a faulted "
+ "device\n"));
+ else
+ (void) printf(gettext("use 'zpool "
+ "replace' to replace devices "
+ "that are no longer present\n"));
+ }
+ } else {
ret = 1;
-
- if (!ret) {
- zpool_log_history(g_zfs, argc + optind, argv - optind, poolname,
- B_TRUE, B_FALSE);
+ }
}
+
zpool_close(zhp);
return (ret);
@@ -2417,17 +2527,11 @@ zpool_do_offline(int argc, char **argv)
if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
return (1);
- for (i = 1; i < argc; i++)
- if (zpool_vdev_offline(zhp, argv[i], istmp) == 0)
- (void) printf(gettext("Bringing device %s offline\n"),
- argv[i]);
- else
+ for (i = 1; i < argc; i++) {
+ if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
ret = 1;
-
- if (!ret) {
- zpool_log_history(g_zfs, argc + optind, argv - optind, poolname,
- B_TRUE, B_FALSE);
}
+
zpool_close(zhp);
return (ret);
@@ -2458,14 +2562,12 @@ zpool_do_clear(int argc, char **argv)
pool = argv[1];
device = argc == 3 ? argv[2] : NULL;
- if ((zhp = zpool_open(g_zfs, pool)) == NULL)
+ if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
return (1);
if (zpool_clear(zhp, device) != 0)
ret = 1;
- if (!ret)
- zpool_log_history(g_zfs, argc, argv, pool, B_TRUE, B_FALSE);
zpool_close(zhp);
return (ret);
@@ -2494,11 +2596,6 @@ scrub_callback(zpool_handle_t *zhp, void *data)
err = zpool_scrub(zhp, cb->cb_type);
- if (!err) {
- zpool_log_history(g_zfs, cb->cb_argc, cb->cb_argv,
- zpool_get_name(zhp), B_TRUE, B_FALSE);
- }
-
return (err != 0);
}
@@ -2559,7 +2656,7 @@ print_scrub_status(nvlist_t *nvroot)
uint_t vsc;
time_t start, end, now;
double fraction_done;
- uint64_t examined, total, minutes_left;
+ uint64_t examined, total, minutes_left, minutes_taken;
char *scrub_type;
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
@@ -2583,8 +2680,13 @@ print_scrub_status(nvlist_t *nvroot)
total = vs->vs_alloc;
if (end != 0) {
- (void) printf(gettext("%s %s with %llu errors on %s"),
+ minutes_taken = (uint64_t)((end - start) / 60);
+
+ (void) printf(gettext("%s %s after %lluh%um with %llu errors "
+ "on %s"),
scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
+ (u_longlong_t)(minutes_taken / 60),
+ (uint_t)(minutes_taken % 60),
(u_longlong_t)vs->vs_scrub_errors, ctime(&end));
return;
}
@@ -2597,9 +2699,12 @@ print_scrub_status(nvlist_t *nvroot)
fraction_done = (double)examined / total;
minutes_left = (uint64_t)((now - start) *
(1 - fraction_done) / fraction_done / 60);
+ minutes_taken = (uint64_t)((now - start) / 60);
- (void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"),
- scrub_type, 100 * fraction_done,
+ (void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
+ "%lluh%um to go\n"),
+ scrub_type, (u_longlong_t)(minutes_taken / 60),
+ (uint_t)(minutes_taken % 60), 100 * fraction_done,
(u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
}
@@ -2653,7 +2758,7 @@ find_spare(zpool_handle_t *zhp, void *data)
*/
void
print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
- int namewidth, int depth, boolean_t isspare)
+ int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
{
nvlist_t **child;
uint_t c, children;
@@ -2662,7 +2767,7 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
char *vname;
uint64_t notpresent;
spare_cbdata_t cb;
- const char *state;
+ char *state;
verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
(uint64_t **)&vs, &c) == 0);
@@ -2671,7 +2776,7 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
&child, &children) != 0)
children = 0;
- state = state_to_name(vs);
+ state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
if (isspare) {
/*
* For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
@@ -2736,6 +2841,18 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
}
break;
+ case VDEV_AUX_ERR_EXCEEDED:
+ (void) printf(gettext("too many errors"));
+ break;
+
+ case VDEV_AUX_IO_FAILURE:
+ (void) printf(gettext("experienced I/O failures"));
+ break;
+
+ case VDEV_AUX_BAD_LOG:
+ (void) printf(gettext("bad intent log"));
+ break;
+
default:
(void) printf(gettext("corrupted data"));
break;
@@ -2753,9 +2870,15 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
(void) printf("\n");
for (c = 0; c < children; c++) {
+ uint64_t is_log = B_FALSE;
+
+ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+ &is_log);
+ if ((is_log && !print_logs) || (!is_log && print_logs))
+ continue;
vname = zpool_vdev_name(g_zfs, zhp, child[c]);
print_status_config(zhp, vname, child[c],
- namewidth, depth + 2, isspare);
+ namewidth, depth + 2, isspare, B_FALSE);
free(vname);
}
}
@@ -2763,7 +2886,7 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
static void
print_error_log(zpool_handle_t *zhp)
{
- nvlist_t *nverrlist;
+ nvlist_t *nverrlist = NULL;
nvpair_t *elem;
char *pathname;
size_t len = MAXPATHLEN * 2;
@@ -2810,7 +2933,27 @@ print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
for (i = 0; i < nspares; i++) {
name = zpool_vdev_name(g_zfs, zhp, spares[i]);
print_status_config(zhp, name, spares[i],
- namewidth, 2, B_TRUE);
+ namewidth, 2, B_TRUE, B_FALSE);
+ free(name);
+ }
+}
+
+static void
+print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
+ int namewidth)
+{
+ uint_t i;
+ char *name;
+
+ if (nl2cache == 0)
+ return;
+
+ (void) printf(gettext("\tcache\n"));
+
+ for (i = 0; i < nl2cache; i++) {
+ name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
+ print_status_config(zhp, name, l2cache[i],
+ namewidth, 2, B_FALSE, B_FALSE);
free(name);
}
}
@@ -2869,7 +3012,7 @@ status_callback(zpool_handle_t *zhp, void *data)
&nvroot) == 0);
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
(uint64_t **)&vs, &c) == 0);
- health = state_to_name(vs);
+ health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
(void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp));
(void) printf(gettext(" state: %s\n"), health);
@@ -2972,6 +3115,45 @@ status_callback(zpool_handle_t *zhp, void *data)
"backup.\n"));
break;
+ case ZPOOL_STATUS_FAULTED_DEV_R:
+ (void) printf(gettext("status: One or more devices are "
+ "faulted in response to persistent errors.\n\tSufficient "
+ "replicas exist for the pool to continue functioning "
+ "in a\n\tdegraded state.\n"));
+ (void) printf(gettext("action: Replace the faulted device, "
+ "or use 'zpool clear' to mark the device\n\trepaired.\n"));
+ break;
+
+ case ZPOOL_STATUS_FAULTED_DEV_NR:
+ (void) printf(gettext("status: One or more devices are "
+ "faulted in response to persistent errors. There are "
+ "insufficient replicas for the pool to\n\tcontinue "
+ "functioning.\n"));
+ (void) printf(gettext("action: Destroy and re-create the pool "
+ "from a backup source. Manually marking the device\n"
+ "\trepaired using 'zpool clear' may allow some data "
+ "to be recovered.\n"));
+ break;
+
+ case ZPOOL_STATUS_IO_FAILURE_WAIT:
+ case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
+ (void) printf(gettext("status: One or more devices are "
+ "faulted in response to IO failures.\n"));
+ (void) printf(gettext("action: Make sure the affected devices "
+ "are connected, then run 'zpool clear'.\n"));
+ break;
+
+ case ZPOOL_STATUS_BAD_LOG:
+ (void) printf(gettext("status: An intent log record "
+ "could not be read.\n"
+ "\tWaiting for adminstrator intervention to fix the "
+ "faulted pool.\n"));
+ (void) printf(gettext("action: Either restore the affected "
+ "device(s) and run 'zpool online',\n"
+ "\tor ignore the intent log records by running "
+ "'zpool clear'.\n"));
+ break;
+
default:
/*
* The remaining errors can't actually be generated, yet.
@@ -2986,8 +3168,8 @@ status_callback(zpool_handle_t *zhp, void *data)
if (config != NULL) {
int namewidth;
uint64_t nerr;
- nvlist_t **spares;
- uint_t nspares;
+ nvlist_t **spares, **l2cache;
+ uint_t nspares, nl2cache;
(void) printf(gettext(" scrub: "));
@@ -3001,7 +3183,14 @@ status_callback(zpool_handle_t *zhp, void *data)
(void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth,
"NAME", "STATE", "READ", "WRITE", "CKSUM");
print_status_config(zhp, zpool_get_name(zhp), nvroot,
- namewidth, 0, B_FALSE);
+ namewidth, 0, B_FALSE, B_FALSE);
+ if (num_logs(nvroot) > 0)
+ print_status_config(zhp, "logs", nvroot, namewidth, 0,
+ B_FALSE, B_TRUE);
+
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+ &l2cache, &nl2cache) == 0)
+ print_l2cache(zhp, l2cache, nl2cache, namewidth);
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
&spares, &nspares) == 0)
@@ -3016,7 +3205,7 @@ status_callback(zpool_handle_t *zhp, void *data)
* precise count by fetching the entire log and
* uniquifying the results.
*/
- if (nerr < 100 && !cbp->cb_verbose &&
+ if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
zpool_get_errlog(zhp, &nverrlist) == 0) {
nvpair_t *elem;
@@ -3103,6 +3292,7 @@ typedef struct upgrade_cbdata {
int cb_first;
int cb_newer;
int cb_argc;
+ uint64_t cb_version;
char **cb_argv;
} upgrade_cbdata_t;
@@ -3118,7 +3308,7 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
&version) == 0);
- if (!cbp->cb_newer && version < ZFS_VERSION) {
+ if (!cbp->cb_newer && version < SPA_VERSION) {
if (!cbp->cb_all) {
if (cbp->cb_first) {
(void) printf(gettext("The following pools are "
@@ -3135,16 +3325,13 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
zpool_get_name(zhp));
} else {
cbp->cb_first = B_FALSE;
- ret = zpool_upgrade(zhp);
+ ret = zpool_upgrade(zhp, cbp->cb_version);
if (!ret) {
- zpool_log_history(g_zfs, cbp->cb_argc,
- cbp->cb_argv, zpool_get_name(zhp), B_TRUE,
- B_FALSE);
(void) printf(gettext("Successfully upgraded "
- "'%s'\n"), zpool_get_name(zhp));
+ "'%s'\n\n"), zpool_get_name(zhp));
}
}
- } else if (cbp->cb_newer && version > ZFS_VERSION) {
+ } else if (cbp->cb_newer && version > SPA_VERSION) {
assert(!cbp->cb_all);
if (cbp->cb_first) {
@@ -3168,29 +3355,37 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
static int
upgrade_one(zpool_handle_t *zhp, void *data)
{
- nvlist_t *config;
- uint64_t version;
- int ret;
upgrade_cbdata_t *cbp = data;
+ uint64_t cur_version;
+ int ret;
- config = zpool_get_config(zhp, NULL);
- verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
- &version) == 0);
+ if (strcmp("log", zpool_get_name(zhp)) == 0) {
+ (void) printf(gettext("'log' is now a reserved word\n"
+ "Pool 'log' must be renamed using export and import"
+ " to upgrade.\n"));
+ return (1);
+ }
- if (version == ZFS_VERSION) {
+ cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
+ if (cur_version > cbp->cb_version) {
+ (void) printf(gettext("Pool '%s' is already formatted "
+ "using more current version '%llu'.\n"),
+ zpool_get_name(zhp), cur_version);
+ return (0);
+ }
+ if (cur_version == cbp->cb_version) {
(void) printf(gettext("Pool '%s' is already formatted "
"using the current version.\n"), zpool_get_name(zhp));
return (0);
}
- ret = zpool_upgrade(zhp);
+ ret = zpool_upgrade(zhp, cbp->cb_version);
if (!ret) {
- zpool_log_history(g_zfs, cbp->cb_argc, cbp->cb_argv,
- zpool_get_name(zhp), B_TRUE, B_FALSE);
(void) printf(gettext("Successfully upgraded '%s' "
- "from version %llu to version %llu\n"), zpool_get_name(zhp),
- (u_longlong_t)version, (u_longlong_t)ZFS_VERSION);
+ "from version %llu to version %llu\n\n"),
+ zpool_get_name(zhp), (u_longlong_t)cur_version,
+ (u_longlong_t)cbp->cb_version);
}
return (ret != 0);
@@ -3199,7 +3394,7 @@ upgrade_one(zpool_handle_t *zhp, void *data)
/*
* zpool upgrade
* zpool upgrade -v
- * zpool upgrade <-a | pool>
+ * zpool upgrade [-V version] <-a | pool ...>
*
* With no arguments, display downrev'd ZFS pool available for upgrade.
* Individual pools can be upgraded by specifying the pool, and '-a' will
@@ -3212,9 +3407,11 @@ zpool_do_upgrade(int argc, char **argv)
upgrade_cbdata_t cb = { 0 };
int ret = 0;
boolean_t showversions = B_FALSE;
+ char *end;
+
/* check options */
- while ((c = getopt(argc, argv, "av")) != -1) {
+ while ((c = getopt(argc, argv, "avV:")) != -1) {
switch (c) {
case 'a':
cb.cb_all = B_TRUE;
@@ -3222,6 +3419,15 @@ zpool_do_upgrade(int argc, char **argv)
case 'v':
showversions = B_TRUE;
break;
+ case 'V':
+ cb.cb_version = strtoll(optarg, &end, 10);
+ if (*end != '\0' || cb.cb_version > SPA_VERSION ||
+ cb.cb_version < SPA_VERSION_1) {
+ (void) fprintf(stderr,
+ gettext("invalid version '%s'\n"), optarg);
+ usage(B_FALSE);
+ }
+ break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
@@ -3234,6 +3440,14 @@ zpool_do_upgrade(int argc, char **argv)
argc -= optind;
argv += optind;
+ if (cb.cb_version == 0) {
+ cb.cb_version = SPA_VERSION;
+ } else if (!cb.cb_all && argc == 0) {
+ (void) fprintf(stderr, gettext("-V option is "
+ "incompatible with other arguments\n"));
+ usage(B_FALSE);
+ }
+
if (showversions) {
if (cb.cb_all || argc != 0) {
(void) fprintf(stderr, gettext("-v option is "
@@ -3242,14 +3456,14 @@ zpool_do_upgrade(int argc, char **argv)
}
} else if (cb.cb_all) {
if (argc != 0) {
- (void) fprintf(stderr, gettext("-a option is "
- "incompatible with other arguments\n"));
+ (void) fprintf(stderr, gettext("-a option should not "
+ "be used along with a pool name\n"));
usage(B_FALSE);
}
}
- (void) printf(gettext("This system is currently running ZFS version "
- "%llu.\n\n"), ZFS_VERSION);
+ (void) printf(gettext("This system is currently running "
+ "ZFS pool version %llu.\n\n"), SPA_VERSION);
cb.cb_first = B_TRUE;
if (showversions) {
(void) printf(gettext("The following versions are "
@@ -3265,8 +3479,16 @@ zpool_do_upgrade(int argc, char **argv)
(void) printf(gettext(" 4 zpool history\n"));
(void) printf(gettext(" 5 Compression using the gzip "
"algorithm\n"));
- (void) printf(gettext(" 6 bootfs pool property "));
- (void) printf(gettext("\nFor more information on a particular "
+ (void) printf(gettext(" 6 bootfs pool property\n"));
+ (void) printf(gettext(" 7 Separate intent log devices\n"));
+ (void) printf(gettext(" 8 Delegated administration\n"));
+ (void) printf(gettext(" 9 refquota and refreservation "
+ "properties\n"));
+ (void) printf(gettext(" 10 Cache devices\n"));
+ (void) printf(gettext(" 11 Improved scrub performance\n"));
+ (void) printf(gettext(" 12 Snapshot properties\n"));
+ (void) printf(gettext(" 13 snapused property\n"));
+ (void) printf(gettext("For more information on a particular "
"version, including supported releases, see:\n\n"));
(void) printf("http://www.opensolaris.org/os/community/zfs/"
"version/N\n\n");
@@ -3306,6 +3528,53 @@ zpool_do_upgrade(int argc, char **argv)
return (ret);
}
+typedef struct hist_cbdata {
+ boolean_t first;
+ int longfmt;
+ int internal;
+} hist_cbdata_t;
+
+char *hist_event_table[LOG_END] = {
+ "invalid event",
+ "pool create",
+ "vdev add",
+ "pool remove",
+ "pool destroy",
+ "pool export",
+ "pool import",
+ "vdev attach",
+ "vdev replace",
+ "vdev detach",
+ "vdev online",
+ "vdev offline",
+ "vdev upgrade",
+ "pool clear",
+ "pool scrub",
+ "pool property set",
+ "create",
+ "clone",
+ "destroy",
+ "destroy_begin_sync",
+ "inherit",
+ "property set",
+ "quota set",
+ "permission update",
+ "permission remove",
+ "permission who remove",
+ "promote",
+ "receive",
+ "rename",
+ "reservation set",
+ "replay_inc_sync",
+ "replay_full_sync",
+ "rollback",
+ "snapshot",
+ "filesystem version upgrade",
+ "refquota set",
+ "refreservation set",
+ "pool scrub done",
+};
+
/*
* Print out the command history for a specific pool.
*/
@@ -3316,13 +3585,22 @@ get_history_one(zpool_handle_t *zhp, void *data)
nvlist_t **records;
uint_t numrecords;
char *cmdstr;
+ char *pathstr;
uint64_t dst_time;
time_t tsec;
struct tm t;
char tbuf[30];
int ret, i;
+ uint64_t who;
+ struct passwd *pwd;
+ char *hostname;
+ char *zonename;
+ char internalstr[MAXPATHLEN];
+ hist_cbdata_t *cb = (hist_cbdata_t *)data;
+ uint64_t txg;
+ uint64_t ievent;
- *(boolean_t *)data = B_FALSE;
+ cb->first = B_FALSE;
(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
@@ -3333,14 +3611,65 @@ get_history_one(zpool_handle_t *zhp, void *data)
&records, &numrecords) == 0);
for (i = 0; i < numrecords; i++) {
if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
- &dst_time) == 0) {
- verify(nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
- &cmdstr) == 0);
- tsec = dst_time;
- (void) localtime_r(&tsec, &t);
- (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
- (void) printf("%s %s\n", tbuf, cmdstr);
+ &dst_time) != 0)
+ continue;
+
+ /* is it an internal event or a standard event? */
+ if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
+ &cmdstr) != 0) {
+ if (cb->internal == 0)
+ continue;
+
+ if (nvlist_lookup_uint64(records[i],
+ ZPOOL_HIST_INT_EVENT, &ievent) != 0)
+ continue;
+ verify(nvlist_lookup_uint64(records[i],
+ ZPOOL_HIST_TXG, &txg) == 0);
+ verify(nvlist_lookup_string(records[i],
+ ZPOOL_HIST_INT_STR, &pathstr) == 0);
+ if (ievent >= LOG_END)
+ continue;
+ (void) snprintf(internalstr,
+ sizeof (internalstr),
+ "[internal %s txg:%lld] %s",
+ hist_event_table[ievent], txg,
+ pathstr);
+ cmdstr = internalstr;
+ }
+ tsec = dst_time;
+ (void) localtime_r(&tsec, &t);
+ (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
+ (void) printf("%s %s", tbuf, cmdstr);
+
+ if (!cb->longfmt) {
+ (void) printf("\n");
+ continue;
}
+ (void) printf(" [");
+ if (nvlist_lookup_uint64(records[i],
+ ZPOOL_HIST_WHO, &who) == 0) {
+ pwd = getpwuid((uid_t)who);
+ if (pwd)
+ (void) printf("user %s on",
+ pwd->pw_name);
+ else
+ (void) printf("user %d on",
+ (int)who);
+ } else {
+ (void) printf(gettext("no info]\n"));
+ continue;
+ }
+ if (nvlist_lookup_string(records[i],
+ ZPOOL_HIST_HOST, &hostname) == 0) {
+ (void) printf(" %s", hostname);
+ }
+ if (nvlist_lookup_string(records[i],
+ ZPOOL_HIST_ZONE, &zonename) == 0) {
+ (void) printf(":%s", zonename);
+ }
+
+ (void) printf("]");
+ (void) printf("\n");
}
(void) printf("\n");
nvlist_free(nvhis);
@@ -3353,19 +3682,38 @@ get_history_one(zpool_handle_t *zhp, void *data)
*
* Displays the history of commands that modified pools.
*/
+
+
int
zpool_do_history(int argc, char **argv)
{
- boolean_t first = B_TRUE;
+ hist_cbdata_t cbdata = { 0 };
int ret;
+ int c;
+ cbdata.first = B_TRUE;
+ /* check options */
+ while ((c = getopt(argc, argv, "li")) != -1) {
+ switch (c) {
+ case 'l':
+ cbdata.longfmt = 1;
+ break;
+ case 'i':
+ cbdata.internal = 1;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
argc -= optind;
argv += optind;
ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one,
- &first);
+ &cbdata);
- if (argc == 0 && first == B_TRUE) {
+ if (argc == 0 && cbdata.first == B_TRUE) {
(void) printf(gettext("no pools available\n"));
return (0);
}
@@ -3376,17 +3724,18 @@ zpool_do_history(int argc, char **argv)
static int
get_callback(zpool_handle_t *zhp, void *data)
{
- libzfs_get_cbdata_t *cbp = (libzfs_get_cbdata_t *)data;
+ zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
char value[MAXNAMELEN];
- zfs_source_t srctype;
- zpool_proplist_t *pl;
+ zprop_source_t srctype;
+ zprop_list_t *pl;
for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
/*
- * Skip the special fake placeholder.
+ * Skip the special fake placeholder. This will also skip
+ * over the name property when 'all' is specified.
*/
- if (pl->pl_prop == ZFS_PROP_NAME &&
+ if (pl->pl_prop == ZPOOL_PROP_NAME &&
pl == cbp->cb_proplist)
continue;
@@ -3394,7 +3743,7 @@ get_callback(zpool_handle_t *zhp, void *data)
value, sizeof (value), &srctype) != 0)
continue;
- libzfs_print_one_property(zpool_get_name(zhp), cbp,
+ zprop_print_one_property(zpool_get_name(zhp), cbp,
zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
}
return (0);
@@ -3403,25 +3752,27 @@ get_callback(zpool_handle_t *zhp, void *data)
int
zpool_do_get(int argc, char **argv)
{
- libzfs_get_cbdata_t cb = { 0 };
- zpool_proplist_t fake_name = { 0 };
+ zprop_get_cbdata_t cb = { 0 };
+ zprop_list_t fake_name = { 0 };
int ret;
if (argc < 3)
usage(B_FALSE);
cb.cb_first = B_TRUE;
- cb.cb_sources = ZFS_SRC_ALL;
+ cb.cb_sources = ZPROP_SRC_ALL;
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_SOURCE;
+ cb.cb_type = ZFS_TYPE_POOL;
- if (zpool_get_proplist(g_zfs, argv[1], &cb.cb_proplist) != 0)
+ if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
+ ZFS_TYPE_POOL) != 0)
usage(B_FALSE);
if (cb.cb_proplist != NULL) {
- fake_name.pl_prop = ZFS_PROP_NAME;
+ fake_name.pl_prop = ZPOOL_PROP_NAME;
fake_name.pl_width = strlen(gettext("NAME"));
fake_name.pl_next = cb.cb_proplist;
cb.cb_proplist = &fake_name;
@@ -3431,9 +3782,9 @@ zpool_do_get(int argc, char **argv)
get_callback, &cb);
if (cb.cb_proplist == &fake_name)
- zfs_free_proplist(fake_name.pl_next);
+ zprop_free_list(fake_name.pl_next);
else
- zfs_free_proplist(cb.cb_proplist);
+ zprop_free_list(cb.cb_proplist);
return (ret);
}
@@ -3500,11 +3851,6 @@ zpool_do_set(int argc, char **argv)
error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
set_callback, &cb);
- if (cb.cb_any_successful) {
- *(cb.cb_value - 1) = '=';
- zpool_log_history(g_zfs, argc, argv, argv[2], B_FALSE, B_FALSE);
- }
-
return (error);
}
@@ -3531,7 +3877,6 @@ main(int argc, char **argv)
int ret;
int i;
char *cmdname;
- int found = 0;
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
@@ -3562,26 +3907,29 @@ main(int argc, char **argv)
if (strcmp(cmdname, "-?") == 0)
usage(B_TRUE);
+ zpool_set_history_str("zpool", argc, argv, history_str);
+ verify(zpool_stage_history(g_zfs, history_str) == 0);
+
/*
* Run the appropriate command.
*/
if (find_command_idx(cmdname, &i) == 0) {
current_command = &command_table[i];
ret = command_table[i].func(argc - 1, argv + 1);
- found++;
- }
-
- /*
- * 'freeze' is a vile debugging abomination, so we treat it as such.
- */
- if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
+ } else if (strchr(cmdname, '=')) {
+ verify(find_command_idx("set", &i) == 0);
+ current_command = &command_table[i];
+ ret = command_table[i].func(argc, argv);
+ } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
+ /*
+ * 'freeze' is a vile debugging abomination, so we treat
+ * it as such.
+ */
char buf[16384];
int fd = open(ZFS_DEV, O_RDWR);
(void) strcpy((void *)buf, argv[2]);
return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
- }
-
- if (!found) {
+ } else {
(void) fprintf(stderr, gettext("unrecognized "
"command '%s'\n"), cmdname);
usage(B_FALSE);
OpenPOWER on IntegriCloud