/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
* Copyright (c) 2012 by Cyril Plisko. All rights reserved.
+ * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
*/
#include <assert.h>
#include <sys/stat.h>
#include <sys/fm/util.h>
#include <sys/fm/protocol.h>
+#include <sys/zfs_ioctl.h>
#include <libzfs.h>
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
-zpool_command_t *current_command;
+static zpool_command_t *current_command;
static char history_str[HIS_MAX_RECORD_LEN];
-
+static boolean_t log_history = B_TRUE;
static uint_t timestamp_fmt = NODATE;
static const char *
case HELP_DETACH:
return (gettext("\tdetach <pool> <device>\n"));
case HELP_EXPORT:
- return (gettext("\texport [-f] <pool> ...\n"));
+ return (gettext("\texport [-af] <pool> ...\n"));
case HELP_HISTORY:
return (gettext("\thistory [-il] [<pool>] ...\n"));
case HELP_IMPORT:
"[-R root] [-F [-n]]\n"
"\t <pool | id> [newpool]\n"));
case HELP_IOSTAT:
- return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
- "[count]]\n"));
+ return (gettext("\tiostat [-v] [-T d|u] [-y] [pool] ... "
+ "[interval [count]]\n"));
case HELP_LABELCLEAR:
return (gettext("\tlabelclear [-f] <vdev>\n"));
case HELP_LIST:
case HELP_ONLINE:
return (gettext("\tonline <pool> <device> ...\n"));
case HELP_REPLACE:
- return (gettext("\treplace [-f] <pool> <device> "
- "[new-device]\n"));
+ return (gettext("\treplace [-f] [-o property=value] "
+ "<pool> <device> [new-device]\n"));
case HELP_REMOVE:
return (gettext("\tremove <pool> <device> ...\n"));
case HELP_REOPEN:
case HELP_SCRUB:
return (gettext("\tscrub [-s] <pool> ...\n"));
case HELP_STATUS:
- return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
+ return (gettext("\tstatus [-vxD] [-T d|u] [pool] ... [interval "
"[count]]\n"));
case HELP_UPGRADE:
return (gettext("\tupgrade\n"
case HELP_EVENTS:
return (gettext("\tevents [-vHfc]\n"));
case HELP_GET:
- return (gettext("\tget <\"all\" | property[,...]> "
+ return (gettext("\tget [-pH] <\"all\" | property[,...]> "
"<pool> ...\n"));
case HELP_SET:
return (gettext("\tset <property=value> <pool> \n"));
return (0);
}
+/*
+ * Set a default property pair (name, string-value) in a property nvlist
+ */
+static int
+add_prop_list_default(const char *propname, char *propval, nvlist_t **props,
+ boolean_t poolprop)
+{
+ char *pval;
+
+ if (nvlist_lookup_string(*props, propname, &pval) == 0)
+ return (0);
+
+ return (add_prop_list(propname, propval, props, B_TRUE));
+}
+
/*
* zpool add [-fn] [-o property=value] <pool> <vdev> ...
*
if (dryrun) {
nvlist_t *poolnvroot;
+ nvlist_t **l2child;
+ uint_t l2children, c;
+ char *vname;
+ boolean_t hadcache = B_FALSE;
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
&poolnvroot) == 0);
print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
}
+ /* Do the same for the caches */
+ if (nvlist_lookup_nvlist_array(poolnvroot, ZPOOL_CONFIG_L2CACHE,
+ &l2child, &l2children) == 0 && l2children) {
+ hadcache = B_TRUE;
+ (void) printf(gettext("\tcache\n"));
+ for (c = 0; c < l2children; c++) {
+ vname = zpool_vdev_name(g_zfs, NULL,
+ l2child[c], B_FALSE);
+ (void) printf("\t %s\n", vname);
+ free(vname);
+ }
+ }
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+ &l2child, &l2children) == 0 && l2children) {
+ if (!hadcache)
+ (void) printf(gettext("\tcache\n"));
+ for (c = 0; c < l2children; c++) {
+ vname = zpool_vdev_name(g_zfs, NULL,
+ l2child[c], B_FALSE);
+ (void) printf("\t %s\n", vname);
+ free(vname);
+ }
+ }
+
ret = 0;
} else {
ret = (zpool_add(zhp, nvroot) != 0);
int c;
nvlist_t *nvroot = NULL;
char *poolname;
+ char *tname = NULL;
int ret = 1;
char *altroot = NULL;
char *mountpoint = NULL;
char *propval;
/* check options */
- while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) {
+ while ((c = getopt(argc, argv, ":fndR:m:o:O:t:")) != -1) {
switch (c) {
case 'f':
force = B_TRUE;
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(
+ if (add_prop_list_default(zpool_prop_to_name(
ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
goto errout;
break;
case 'm':
+ /* Equivalent to -O mountpoint=optarg */
mountpoint = optarg;
break;
case 'o':
*propval = '\0';
propval++;
- if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
+ /*
+ * Mountpoints are checked and then added later.
+ * Uniquely among properties, they can be specified
+ * more than once, to avoid conflict with -m.
+ */
+ if (0 == strcmp(optarg,
+ zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) {
+ mountpoint = propval;
+ } else if (add_prop_list(optarg, propval, &fsprops,
+ B_FALSE)) {
+ goto errout;
+ }
+ break;
+ case 't':
+ /*
+ * Sanity check temporary pool name.
+ */
+ if (strchr(optarg, '/') != NULL) {
+ (void) fprintf(stderr, gettext("cannot create "
+ "'%s': invalid character '/' in temporary "
+ "name\n"), optarg);
+ (void) fprintf(stderr, gettext("use 'zfs "
+ "create' to create a dataset\n"));
+ goto errout;
+ }
+
+ if (add_prop_list(zpool_prop_to_name(
+ ZPOOL_PROP_TNAME), optarg, &props, B_TRUE))
+ goto errout;
+ if (add_prop_list_default(zpool_prop_to_name(
+ ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
goto errout;
+ tname = optarg;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
}
}
+ /*
+ * Now that the mountpoint's validity has been checked, ensure that
+ * the property is set appropriately prior to creating the pool.
+ */
+ if (mountpoint != NULL) {
+ ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
+ mountpoint, &fsprops, B_FALSE);
+ if (ret != 0)
+ goto errout;
+ }
+
+ ret = 1;
if (dryrun) {
/*
* For a dry run invocation, print out a basic message and run
* Hand off to libzfs.
*/
if (enable_all_pool_feat) {
- int i;
+ spa_feature_t i;
for (i = 0; i < SPA_FEATURES; i++) {
char propname[MAXPATHLEN];
zfeature_info_t *feat = &spa_feature_table[i];
if (nvlist_exists(props, propname))
continue;
- if (add_prop_list(propname, ZFS_FEATURE_ENABLED,
- &props, B_TRUE) != 0)
+ ret = add_prop_list(propname,
+ ZFS_FEATURE_ENABLED, &props, B_TRUE);
+ if (ret != 0)
goto errout;
}
}
+
+ ret = 1;
if (zpool_create(g_zfs, poolname,
nvroot, props, fsprops) == 0) {
- zfs_handle_t *pool = zfs_open(g_zfs, poolname,
- ZFS_TYPE_FILESYSTEM);
+ zfs_handle_t *pool = zfs_open(g_zfs,
+ tname ? tname : poolname, ZFS_TYPE_FILESYSTEM);
if (pool != NULL) {
- if (mountpoint != NULL)
- verify(zfs_prop_set(pool,
- zfs_prop_to_name(
- ZFS_PROP_MOUNTPOINT),
- mountpoint) == 0);
if (zfs_mount(pool, NULL, 0) == 0)
ret = zfs_shareall(pool);
zfs_close(pool);
return (1);
}
- ret = (zpool_destroy(zhp) != 0);
+ /* The history must be logged as part of the export */
+ log_history = B_FALSE;
+
+ ret = (zpool_destroy(zhp, history_str) != 0);
zpool_close(zhp);
return (ret);
}
+typedef struct export_cbdata {
+ boolean_t force;
+ boolean_t hardforce;
+} export_cbdata_t;
+
+/*
+ * Export one pool
+ */
+int
+zpool_export_one(zpool_handle_t *zhp, void *data)
+{
+ export_cbdata_t *cb = data;
+
+ if (zpool_disable_datasets(zhp, cb->force) != 0)
+ return (1);
+
+ /* The history must be logged as part of the export */
+ log_history = B_FALSE;
+
+ if (cb->hardforce) {
+ if (zpool_export_force(zhp, history_str) != 0)
+ return (1);
+ } else if (zpool_export(zhp, cb->force, history_str) != 0) {
+ return (1);
+ }
+
+ return (0);
+}
+
/*
* zpool export [-f] <pool> ...
*
+ * -a Export all pools
* -f Forcefully unmount datasets
*
* Export the given pools. By default, the command will attempt to cleanly
int
zpool_do_export(int argc, char **argv)
{
+ export_cbdata_t cb;
+ boolean_t do_all = B_FALSE;
boolean_t force = B_FALSE;
boolean_t hardforce = B_FALSE;
- int c;
- zpool_handle_t *zhp;
- int ret;
- int i;
+ int c, ret;
/* check options */
- while ((c = getopt(argc, argv, "fF")) != -1) {
+ while ((c = getopt(argc, argv, "afF")) != -1) {
switch (c) {
+ case 'a':
+ do_all = B_TRUE;
+ break;
case 'f':
force = B_TRUE;
break;
}
}
+ cb.force = force;
+ cb.hardforce = hardforce;
argc -= optind;
argv += optind;
+ if (do_all) {
+ if (argc != 0) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ return (for_each_pool(argc, argv, B_TRUE, NULL,
+ zpool_export_one, &cb));
+ }
+
/* check arguments */
if (argc < 1) {
(void) fprintf(stderr, gettext("missing pool argument\n"));
usage(B_FALSE);
}
- ret = 0;
- for (i = 0; i < argc; i++) {
- if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
- ret = 1;
- continue;
- }
-
- if (zpool_disable_datasets(zhp, force) != 0) {
- ret = 1;
- zpool_close(zhp);
- continue;
- }
-
- if (hardforce) {
- if (zpool_export_force(zhp) != 0)
- ret = 1;
- } else if (zpool_export(zhp, force) != 0) {
- ret = 1;
- }
-
- zpool_close(zhp);
- }
+ ret = for_each_pool(argc, argv, B_TRUE, NULL, zpool_export_one, &cb);
return (ret);
}
uint64_t guid;
char *msgid;
nvlist_t *nvroot;
- int reason;
+ zpool_status_t reason;
+ zpool_errata_t errata;
const char *health;
uint_t vsc;
int namewidth;
(uint64_t **)&vs, &vsc) == 0);
health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
- reason = zpool_import_status(config, &msgid);
+ reason = zpool_import_status(config, &msgid, &errata);
(void) printf(gettext(" pool: %s\n"), name);
(void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
"resilvered.\n"));
break;
+ case ZPOOL_STATUS_ERRATA:
+ (void) printf(gettext(" status: Errata #%d detected.\n"),
+ errata);
+ break;
+
default:
/*
* No other status can be seen when importing pools.
(void) printf(gettext(" action: The pool can be "
"imported using its name or numeric "
"identifier and\n\tthe '-f' flag.\n"));
+ } else if (reason == ZPOOL_STATUS_ERRATA) {
+ switch (errata) {
+ case ZPOOL_ERRATA_NONE:
+ break;
+
+ case ZPOOL_ERRATA_ZOL_2094_SCRUB:
+ (void) printf(gettext(" action: The pool can "
+ "be imported using its name or numeric "
+ "identifier,\n\thowever there is a compat"
+ "ibility issue which should be corrected"
+ "\n\tby running 'zpool scrub'\n"));
+ break;
+
+ case ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY:
+ (void) printf(gettext(" action: The pool can"
+ "not be imported with this version of ZFS "
+ "due to\n\tan active asynchronous destroy. "
+ "Revert to an earlier version\n\tand "
+ "allow the destroy to complete before "
+ "updating.\n"));
+ break;
+
+ default:
+ /*
+ * All errata must contain an action message.
+ */
+ assert(0);
+ }
} else {
(void) printf(gettext(" action: The pool can be "
"imported using its name or numeric "
return (1);
} else if (state != POOL_STATE_EXPORTED &&
!(flags & ZFS_IMPORT_ANY_HOST)) {
- uint64_t hostid;
-
- if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
- &hostid) == 0) {
- unsigned long system_hostid = gethostid() & 0xffffffff;
-
- if ((unsigned long)hostid != system_hostid) {
- char *hostname;
- uint64_t timestamp;
- time_t t;
-
- verify(nvlist_lookup_string(config,
- ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
- verify(nvlist_lookup_uint64(config,
- ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0);
- t = timestamp;
- (void) fprintf(stderr, gettext("cannot import "
- "'%s': pool may be in use from other "
- "system, it was last accessed by %s "
- "(hostid: 0x%lx) on %s"), name, hostname,
- (unsigned long)hostid,
- asctime(localtime(&t)));
- (void) fprintf(stderr, gettext("use '-f' to "
- "import anyway\n"));
- return (1);
- }
- } else {
- (void) fprintf(stderr, gettext("cannot import '%s': "
- "pool may be in use from other system\n"), name);
- (void) fprintf(stderr, gettext("use '-f' to import "
- "anyway\n"));
+ uint64_t hostid = 0;
+ unsigned long system_hostid = get_system_hostid();
+
+ (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
+ &hostid);
+
+ if (hostid != 0 && (unsigned long)hostid != system_hostid) {
+ char *hostname;
+ uint64_t timestamp;
+ time_t t;
+
+ verify(nvlist_lookup_string(config,
+ ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
+ verify(nvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0);
+ t = timestamp;
+ (void) fprintf(stderr, gettext("cannot import "
+ "'%s': pool may be in use from other "
+ "system, it was last accessed by %s "
+ "(hostid: 0x%lx) on %s"), name, hostname,
+ (unsigned long)hostid,
+ asctime(localtime(&t)));
+ (void) fprintf(stderr, gettext("use '-f' to "
+ "import anyway\n"));
return (1);
}
}
char *endptr;
/* check options */
- while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
+ while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:R:tT:VX")) != -1) {
switch (c) {
case 'a':
do_all = B_TRUE;
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(
+ if (add_prop_list_default(zpool_prop_to_name(
+ ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+ goto error;
+ break;
+ case 't':
+ flags |= ZFS_IMPORT_TEMP_NAME;
+ if (add_prop_list_default(zpool_prop_to_name(
ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
goto error;
break;
+
case 'T':
errno = 0;
- txg = strtoull(optarg, &endptr, 10);
+ txg = strtoull(optarg, &endptr, 0);
if (errno != 0 || *endptr != '\0') {
(void) fprintf(stderr,
gettext("invalid txg value\n"));
errno = 0;
searchguid = strtoull(argv[0], &endptr, 10);
- if (errno != 0 || *endptr != '\0')
+ if (errno != 0 || *endptr != '\0') {
searchname = argv[0];
+ searchguid = 0;
+ }
found_config = NULL;
/*
columns = 999;
}
- return columns;
+ return (columns);
}
int
unsigned long interval = 0, count = 0;
zpool_list_t *list;
boolean_t verbose = B_FALSE;
+ boolean_t omit_since_boot = B_FALSE;
iostat_cbdata_t cb;
/* check options */
- while ((c = getopt(argc, argv, "T:v")) != -1) {
+ while ((c = getopt(argc, argv, "T:vy")) != -1) {
switch (c) {
case 'T':
get_timestamp_arg(*optarg);
case 'v':
verbose = B_TRUE;
break;
+ case 'y':
+ omit_since_boot = B_TRUE;
+ break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
cb.cb_namewidth = 0;
for (;;) {
- pool_list_update(list);
-
if ((npools = pool_list_count(list)) == 0)
(void) fprintf(stderr, gettext("no pools available\n"));
else {
+ /*
+ * If this is the first iteration and -y was supplied
+ * we skip any printing.
+ */
+ boolean_t skip = (omit_since_boot &&
+ cb.cb_iteration == 0);
+
/*
* Refresh all statistics. This is done as an
* explicit step before calculating the maximum name
print_timestamp(timestamp_fmt);
/*
- * If it's the first time, or verbose mode, print the
- * header.
+ * If it's the first time and we're not skipping it,
+ * or either skip or verbose mode, print the header.
*/
- if (++cb.cb_iteration == 1 || verbose)
+ if ((++cb.cb_iteration == 1 && !skip) ||
+ (skip != verbose))
print_iostat_header(&cb);
+ if (skip) {
+ (void) sleep(interval);
+ continue;
+ }
+
(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
/*
right_justify = B_FALSE;
if (pl->pl_prop != ZPROP_INVAL) {
- if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ &&
- zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0)
- propstr = "-";
- else if (zpool_get_prop(zhp, pl->pl_prop, property,
+ if (zpool_get_prop(zhp, pl->pl_prop, property,
sizeof (property), NULL) != 0)
propstr = "-";
else
}
static void
-print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted)
+print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
+ boolean_t valid)
{
char propval[64];
boolean_t fixed;
size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
- zfs_nicenum(value, propval, sizeof (propval));
+ switch (prop) {
+ case ZPOOL_PROP_EXPANDSZ:
+ if (value == 0)
+ (void) strlcpy(propval, "-", sizeof (propval));
+ else
+ zfs_nicenum(value, propval, sizeof (propval));
+ break;
+ case ZPOOL_PROP_FRAGMENTATION:
+ if (value == ZFS_FRAG_INVALID) {
+ (void) strlcpy(propval, "-", sizeof (propval));
+ } else {
+ (void) snprintf(propval, sizeof (propval), "%llu%%",
+ (unsigned long long)value);
+ }
+ break;
+ case ZPOOL_PROP_CAPACITY:
+ (void) snprintf(propval, sizeof (propval), "%llu%%",
+ (unsigned long long)value);
+ break;
+ default:
+ zfs_nicenum(value, propval, sizeof (propval));
+ }
- if (prop == ZPOOL_PROP_EXPANDSZ && value == 0)
+ if (!valid)
(void) strlcpy(propval, "-", sizeof (propval));
if (scripted)
(uint64_t **)&vs, &c) == 0);
if (name != NULL) {
+ boolean_t toplevel = (vs->vs_space != 0);
+ uint64_t cap;
+
if (scripted)
(void) printf("\t%s", name);
else if (strlen(name) + depth > cb->cb_namewidth)
(void) printf("%*s%s%*s", depth, "", name,
(int)(cb->cb_namewidth - strlen(name) - depth), "");
- /* only toplevel vdevs have capacity stats */
- if (vs->vs_space == 0) {
- if (scripted)
- (void) printf("\t-\t-\t-");
- else
- (void) printf(" - - -");
- } else {
- print_one_column(ZPOOL_PROP_SIZE, vs->vs_space,
- scripted);
- print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc,
- scripted);
- print_one_column(ZPOOL_PROP_FREE,
- vs->vs_space - vs->vs_alloc, scripted);
- }
- print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize,
- scripted);
+ /*
+ * Print the properties for the individual vdevs. Some
+ * properties are only applicable to toplevel vdevs. The
+ * 'toplevel' boolean value is passed to the print_one_column()
+ * to indicate that the value is valid.
+ */
+ print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted,
+ toplevel);
+ print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted,
+ toplevel);
+ print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
+ scripted, toplevel);
+ print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted,
+ B_TRUE);
+ print_one_column(ZPOOL_PROP_FRAGMENTATION,
+ vs->vs_fragmentation, scripted,
+ (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel));
+ cap = (vs->vs_space == 0) ? 0 :
+ (vs->vs_alloc * 100 / vs->vs_space);
+ print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel);
(void) printf("\n");
}
* -H Scripted mode. Don't display headers, and separate properties
* by a single tab.
* -o List of properties to display. Defaults to
- * "name,size,allocated,free,capacity,health,altroot"
+ * "name,size,allocated,free,expandsize,fragmentation,capacity,"
+ * "dedupratio,health,altroot"
* -T Display a timestamp in date(1) or Unix format
*
* List all pools in the system, whether or not they're healthy. Output space
int ret = 0;
list_cbdata_t cb = { 0 };
static char default_props[] =
- "name,size,allocated,free,capacity,dedupratio,"
- "health,altroot";
+ "name,size,allocated,free,expandsize,fragmentation,capacity,"
+ "dedupratio,health,altroot";
char *props = default_props;
unsigned long interval = 0, count = 0;
zpool_list_t *list;
if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
usage(B_FALSE);
- if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL)
- return (1);
-
- if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
- (void) printf(gettext("no pools available\n"));
- zprop_free_list(cb.cb_proplist);
- return (0);
- }
-
for (;;) {
- pool_list_update(list);
+ if ((list = pool_list_get(argc, argv, &cb.cb_proplist,
+ &ret)) == NULL)
+ return (1);
if (pool_list_count(list) == 0)
break;
if (count != 0 && --count == 0)
break;
+ pool_list_free(list);
(void) sleep(interval);
}
+ if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
+ (void) printf(gettext("no pools available\n"));
+ ret = 0;
+ }
+
+ pool_list_free(list);
zprop_free_list(cb.cb_proplist);
return (ret);
}
status_cbdata_t *cbp = data;
nvlist_t *config, *nvroot;
char *msgid;
- int reason;
+ zpool_status_t reason;
+ zpool_errata_t errata;
const char *health;
uint_t c;
vdev_stat_t *vs;
config = zpool_get_config(zhp, NULL);
- reason = zpool_get_status(zhp, &msgid);
+ reason = zpool_get_status(zhp, &msgid, &errata);
cbp->cb_count++;
"'zpool clear'.\n"));
break;
+ case ZPOOL_STATUS_HOSTID_MISMATCH:
+ (void) printf(gettext("status: Mismatch between pool hostid "
+ "and system hostid on imported pool.\n\tThis pool was "
+ "previously imported into a system with a different "
+ "hostid,\n\tand then was verbatim imported into this "
+ "system.\n"));
+ (void) printf(gettext("action: Export this pool on all systems "
+ "on which it is imported.\n"
+ "\tThen import it to correct the mismatch.\n"));
+ break;
+
+ case ZPOOL_STATUS_ERRATA:
+ (void) printf(gettext("status: Errata #%d detected.\n"),
+ errata);
+
+ switch (errata) {
+ case ZPOOL_ERRATA_NONE:
+ break;
+
+ case ZPOOL_ERRATA_ZOL_2094_SCRUB:
+ (void) printf(gettext("action: To correct the issue "
+ "run 'zpool scrub'.\n"));
+ break;
+
+ default:
+ /*
+ * All errata which allow the pool to be imported
+ * must contain an action message.
+ */
+ assert(0);
+ }
+ break;
+
default:
/*
* The remaining errors can't actually be generated, yet.
char **cb_argv;
} upgrade_cbdata_t;
+static int
+check_unsupp_fs(zfs_handle_t *zhp, void *unsupp_fs)
+{
+ int zfs_version = (int) zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+ int *count = (int *)unsupp_fs;
+
+ if (zfs_version > ZPL_VERSION) {
+ (void) printf(gettext("%s (v%d) is not supported by this "
+ "implementation of ZFS.\n"),
+ zfs_get_name(zhp), zfs_version);
+ (*count)++;
+ }
+
+ zfs_iter_filesystems(zhp, check_unsupp_fs, unsupp_fs);
+
+ zfs_close(zhp);
+
+ return (0);
+}
+
static int
upgrade_version(zpool_handle_t *zhp, uint64_t version)
{
int ret;
nvlist_t *config;
uint64_t oldversion;
+ int unsupp_fs = 0;
config = zpool_get_config(zhp, NULL);
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
assert(SPA_VERSION_IS_SUPPORTED(oldversion));
assert(oldversion < version);
+ ret = zfs_iter_root(zpool_get_handle(zhp), check_unsupp_fs, &unsupp_fs);
+ if (ret != 0)
+ return (ret);
+
+ if (unsupp_fs) {
+ (void) fprintf(stderr, gettext("Upgrade not performed due "
+ "to %d unsupported filesystems (max v%d).\n"),
+ unsupp_fs, (int) ZPL_VERSION);
+ return (1);
+ }
+
ret = zpool_upgrade(zhp, version);
if (ret != 0)
return (ret);
return (ret);
printnl = B_TRUE;
-#if 0
- /*
- * XXX: This code can be enabled when Illumos commit
- * 4445fffbbb1ea25fd0e9ea68b9380dd7a6709025 is merged.
- * It reworks the history logging among other things.
- */
-
/*
* If they did "zpool upgrade -a", then we could
* be doing ioctls to different pools. We need
*/
(void) zpool_log_history(g_zfs, history_str);
log_history = B_FALSE;
-#endif
}
if (cbp->cb_version >= SPA_VERSION_FEATURES) {
(void) printf(gettext(" %s\n"), fname);
}
+ /*
+ * If they did "zpool upgrade -a", then we could
+ * be doing ioctls to different pools. We need
+ * to log this history once to each pool, and bypass
+ * the normal history logging that happens in main().
+ */
+ (void) zpool_log_history(g_zfs, history_str);
+ log_history = B_FALSE;
}
}
int ret;
if (strcmp("log", zpool_get_name(zhp)) == 0) {
- (void) printf(gettext("'log' is now a reserved word\n"
+ (void) fprintf(stderr, gettext("'log' is now a reserved word\n"
"Pool 'log' must be renamed using export and import"
" to upgrade.\n"));
return (1);
typedef struct hist_cbdata {
boolean_t first;
- int longfmt;
- int internal;
+ boolean_t longfmt;
+ boolean_t internal;
} hist_cbdata_t;
/*
nvlist_t *nvhis;
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;
cb->first = B_FALSE;
verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
&records, &numrecords) == 0);
for (i = 0; i < numrecords; i++) {
- if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
- &dst_time) != 0)
- continue;
+ nvlist_t *rec = records[i];
+ char tbuf[30] = "";
- /* 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_exists(rec, ZPOOL_HIST_TIME)) {
+ time_t tsec;
+ struct tm t;
+
+ tsec = fnvlist_lookup_uint64(records[i],
+ ZPOOL_HIST_TIME);
+ (void) localtime_r(&tsec, &t);
+ (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
+ }
- if (nvlist_lookup_uint64(records[i],
- ZPOOL_HIST_INT_EVENT, &ievent) != 0)
+ if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
+ (void) printf("%s %s", tbuf,
+ fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
+ } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
+ int ievent =
+ fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
+ if (!cb->internal)
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)
+ if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
+ (void) printf("%s unrecognized record:\n",
+ tbuf);
+ dump_nvlist(rec, 4);
+ continue;
+ }
+ (void) printf("%s [internal %s txg:%lld] %s", tbuf,
+ zfs_history_event_names[ievent],
+ (longlong_t) fnvlist_lookup_uint64(
+ rec, ZPOOL_HIST_TXG),
+ fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
+ } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
+ if (!cb->internal)
+ continue;
+ (void) printf("%s [txg:%lld] %s", tbuf,
+ (longlong_t) fnvlist_lookup_uint64(
+ rec, ZPOOL_HIST_TXG),
+ fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
+ if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
+ (void) printf(" %s (%llu)",
+ fnvlist_lookup_string(rec,
+ ZPOOL_HIST_DSNAME),
+ (u_longlong_t)fnvlist_lookup_uint64(rec,
+ ZPOOL_HIST_DSID));
+ }
+ (void) printf(" %s", fnvlist_lookup_string(rec,
+ ZPOOL_HIST_INT_STR));
+ } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
+ if (!cb->internal)
continue;
- (void) snprintf(internalstr,
- sizeof (internalstr),
- "[internal %s txg:%llu] %s",
- zfs_history_event_names[ievent], (u_longlong_t)txg,
- pathstr);
- cmdstr = internalstr;
+ (void) printf("%s ioctl %s\n", tbuf,
+ fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
+ if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
+ (void) printf(" input:\n");
+ dump_nvlist(fnvlist_lookup_nvlist(rec,
+ ZPOOL_HIST_INPUT_NVL), 8);
+ }
+ if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
+ (void) printf(" output:\n");
+ dump_nvlist(fnvlist_lookup_nvlist(rec,
+ ZPOOL_HIST_OUTPUT_NVL), 8);
+ }
+ } else {
+ if (!cb->internal)
+ continue;
+ (void) printf("%s unrecognized record:\n", tbuf);
+ dump_nvlist(rec, 4);
}
- 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_exists(rec, ZPOOL_HIST_WHO)) {
+ uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
+ struct passwd *pwd = getpwuid(who);
+ (void) printf("user %d ", (int)who);
+ if (pwd != NULL)
+ (void) printf("(%s) ", pwd->pw_name);
}
- if (nvlist_lookup_string(records[i],
- ZPOOL_HIST_HOST, &hostname) == 0) {
- (void) printf(" %s", hostname);
+ if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
+ (void) printf("on %s",
+ fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
}
- if (nvlist_lookup_string(records[i],
- ZPOOL_HIST_ZONE, &zonename) == 0) {
- (void) printf(":%s", zonename);
+ if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
+ (void) printf(":%s",
+ fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
}
(void) printf("]");
*
* Displays the history of commands that modified pools.
*/
-
-
int
zpool_do_history(int argc, char **argv)
{
while ((c = getopt(argc, argv, "li")) != -1) {
switch (c) {
case 'l':
- cbdata.longfmt = 1;
+ cbdata.longfmt = B_TRUE;
break;
case 'i':
- cbdata.internal = 1;
+ cbdata.internal = B_TRUE;
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
verify(nvlist_lookup_int64_array(nvl, FM_EREPORT_TIME, &tv, &n) == 0);
memset(str, ' ', 32);
(void) ctime_r((const time_t *)&tv[0], ctime_str);
- (void) strncpy(str, ctime_str+4, 6); /* 'Jun 30' */
- (void) strncpy(str+7, ctime_str+20, 4); /* '1993' */
- (void) strncpy(str+12, ctime_str+11, 8); /* '21:49:08' */
- (void) sprintf(str+20, ".%09lld", (longlong_t)tv[1]);/* '.123456789' */
+ (void) strncpy(str, ctime_str+4, 6); /* 'Jun 30' */
+ (void) strncpy(str+7, ctime_str+20, 4); /* '1993' */
+ (void) strncpy(str+12, ctime_str+11, 8); /* '21:49:08' */
+ (void) sprintf(str+20, ".%09lld", (longlong_t)tv[1]); /* '.123456789' */
(void) printf(gettext("%s "), str);
verify(nvlist_lookup_string(nvl, FM_CLASS, &ptr) == 0);
printf(gettext("(%d embedded nvlists)\n"), nelem);
for (i = 0; i < nelem; i++) {
printf(gettext("%*s%s[%d] = %s\n"),
- depth, "", name, i, "(embedded nvlist)");
+ depth, "", name, i, "(embedded nvlist)");
zpool_do_events_nvprint(val[i], depth + 8);
printf(gettext("%*s(end %s[%i])\n"),
- depth, "", name, i);
+ depth, "", name, i);
}
printf(gettext("%*s(end %s)\n"), depth, "", name);
}
(void) nvpair_value_int64_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
- printf(gettext("0x%llx "), (u_longlong_t)val[i]);
+ printf(gettext("0x%llx "),
+ (u_longlong_t)val[i]);
break;
}
(void) nvpair_value_uint64_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
- printf(gettext("0x%llx "), (u_longlong_t)val[i]);
+ printf(gettext("0x%llx "),
+ (u_longlong_t)val[i]);
+
+ break;
+ }
+
+ case DATA_TYPE_STRING_ARRAY: {
+ char **str;
+ uint_t i, nelem;
+
+ (void) nvpair_value_string_array(nvp, &str, &nelem);
+ for (i = 0; i < nelem; i++)
+ printf(gettext("\"%s\" "),
+ str[i] ? str[i] : "<NULL>");
break;
}
- case DATA_TYPE_STRING_ARRAY:
case DATA_TYPE_BOOLEAN_ARRAY:
case DATA_TYPE_BYTE_ARRAY:
case DATA_TYPE_DOUBLE:
zpool_do_events_next(ev_opts_t *opts)
{
nvlist_t *nvl;
- int cleanup_fd, ret, dropped;
+ int zevent_fd, ret, dropped;
- cleanup_fd = open(ZFS_DEV, O_RDWR);
- VERIFY(cleanup_fd >= 0);
+ zevent_fd = open(ZFS_DEV, O_RDWR);
+ VERIFY(zevent_fd >= 0);
if (!opts->scripted)
(void) printf(gettext("%-30s %s\n"), "TIME", "CLASS");
while (1) {
ret = zpool_events_next(g_zfs, &nvl, &dropped,
- !!opts->follow, cleanup_fd);
+ (opts->follow ? ZEVENT_NONE : ZEVENT_NONBLOCK), zevent_fd);
if (ret || nvl == NULL)
break;
nvlist_free(nvl);
}
- VERIFY(0 == close(cleanup_fd));
+ VERIFY(0 == close(zevent_fd));
return (ret);
}
else
ret = zpool_do_events_next(&opts);
- return ret;
+ return (ret);
}
static int
NULL, NULL);
}
} else {
- if (zpool_get_prop(zhp, pl->pl_prop, value,
- sizeof (value), &srctype) != 0)
+ if (zpool_get_prop_literal(zhp, pl->pl_prop, value,
+ sizeof (value), &srctype, cbp->cb_literal) != 0)
continue;
zprop_print_one_property(zpool_get_name(zhp), cbp,
{
zprop_get_cbdata_t cb = { 0 };
zprop_list_t fake_name = { 0 };
- int ret;
+ int c, ret;
- if (argc < 2) {
+ /* check options */
+ while ((c = getopt(argc, argv, "pH")) != -1) {
+ switch (c) {
+ case 'p':
+ cb.cb_literal = B_TRUE;
+ break;
+
+ case 'H':
+ cb.cb_scripted = B_TRUE;
+ break;
+
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
(void) fprintf(stderr, gettext("missing property "
"argument\n"));
usage(B_FALSE);
cb.cb_columns[3] = GET_COL_SOURCE;
cb.cb_type = ZFS_TYPE_POOL;
- if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
- ZFS_TYPE_POOL) != 0)
+ if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
usage(B_FALSE);
+ argc--;
+ argv++;
+
if (cb.cb_proplist != NULL) {
fake_name.pl_prop = ZPOOL_PROP_NAME;
fake_name.pl_width = strlen(gettext("NAME"));
cb.cb_proplist = &fake_name;
}
- ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
+ ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
get_callback, &cb);
if (cb.cb_proplist == &fake_name)
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
+ dprintf_setup(&argc, argv);
+
opterr = 0;
/*
/*
* Special case '-?'
*/
- if ((strcmp(cmdname, "-?") == 0) ||
- strcmp(cmdname, "--help") == 0)
+ if ((strcmp(cmdname, "-?") == 0) || strcmp(cmdname, "--help") == 0)
usage(B_TRUE);
- if ((g_zfs = libzfs_init()) == NULL)
+ if ((g_zfs = libzfs_init()) == NULL) {
+ (void) fprintf(stderr, "%s", libzfs_error_init(errno));
return (1);
+ }
libzfs_print_on_error(g_zfs, B_TRUE);
- zpool_set_history_str("zpool", argc, argv, history_str);
- verify(zpool_stage_history(g_zfs, history_str) == 0);
+ zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
/*
* Run the appropriate command.
ret = 1;
}
+ if (ret == 0 && log_history)
+ (void) zpool_log_history(g_zfs, history_str);
+
libzfs_fini(g_zfs);
/*