/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
* Copyright 2016 Nexenta Systems, Inc.
*/
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <libintl.h>
#include <libuutil.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <priv.h>
#include <pwd.h>
#include <zone.h>
#include <zfs_prop.h>
#include <libzfs.h>
#include "zpool_util.h"
#include "zfs_comutil.h"
#include "zfeature_common.h"
#include "statcommon.h"
static int zpool_do_create(int, char **);
static int zpool_do_destroy(int, char **);
static int zpool_do_add(int, char **);
static int zpool_do_remove(int, char **);
static int zpool_do_labelclear(int, char **);
static int zpool_do_list(int, char **);
static int zpool_do_iostat(int, char **);
static int zpool_do_status(int, char **);
static int zpool_do_online(int, char **);
static int zpool_do_offline(int, char **);
static int zpool_do_clear(int, char **);
static int zpool_do_reopen(int, char **);
static int zpool_do_reguid(int, char **);
static int zpool_do_attach(int, char **);
static int zpool_do_detach(int, char **);
static int zpool_do_replace(int, char **);
static int zpool_do_split(int, char **);
static int zpool_do_scrub(int, char **);
static int zpool_do_import(int, char **);
static int zpool_do_export(int, char **);
static int zpool_do_upgrade(int, char **);
static int zpool_do_history(int, char **);
static int zpool_do_get(int, char **);
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)
{
return ("default,verbose"); /* $UMEM_DEBUG setting */
}
const char *
_umem_logging_init(void)
{
return ("fail,contents"); /* $UMEM_LOGGING setting */
}
#endif
typedef enum {
} zpool_help_t;
typedef struct zpool_command {
const char *name;
int (*func)(int, char **);
/*
* Master command table. Each ZFS command has a name, associated function, and
* usage message. The usage messages need to be internationalized, so we have
* to have a function to return the usage message based on a command index.
*
* These commands are organized according to how they are displayed in the usage
* message. An empty command (one with a NULL name) indicates an empty line in
* the generic usage message.
*/
{ NULL },
{ NULL },
{ NULL },
{ NULL },
{ NULL },
{ NULL },
{ NULL },
{ NULL },
};
static const char *
{
switch (idx) {
case HELP_ADD:
return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
case HELP_ATTACH:
return (gettext("\tattach [-f] <pool> <device> "
"<new-device>\n"));
case HELP_CLEAR:
return (gettext("\tclear [-nF] <pool> [device]\n"));
case HELP_CREATE:
return (gettext("\tcreate [-fnd] [-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:
return (gettext("\tdetach <pool> <device>\n"));
case HELP_EXPORT:
return (gettext("\texport [-f] <pool> ...\n"));
case HELP_HISTORY:
return (gettext("\thistory [-il] [<pool>] ...\n"));
case HELP_IMPORT:
return (gettext("\timport [-d dir] [-D]\n"
"\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
"\timport [-o mntopts] [-o property=value] ... \n"
"\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
"[-R root] [-F [-n]] -a\n"
"\timport [-o mntopts] [-o property=value] ... \n"
"\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
"[-R root] [-F [-n]]\n"
"\t <pool | id> [newpool]\n"));
case HELP_IOSTAT:
return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
"[count]]\n"));
case HELP_LABELCLEAR:
return (gettext("\tlabelclear [-f] <vdev>\n"));
case HELP_LIST:
return (gettext("\tlist [-Hp] [-o property[,...]] "
"[-T d|u] [pool] ... [interval [count]]\n"));
case HELP_OFFLINE:
return (gettext("\toffline [-t] <pool> <device> ...\n"));
case HELP_ONLINE:
return (gettext("\tonline <pool> <device> ...\n"));
case HELP_REPLACE:
return (gettext("\treplace [-f] <pool> <device> "
"[new-device]\n"));
case HELP_REMOVE:
return (gettext("\tremove <pool> <device> ...\n"));
case HELP_REOPEN:
return (gettext("\treopen <pool>\n"));
case HELP_SCRUB:
return (gettext("\tscrub [-s] <pool> ...\n"));
case HELP_STATUS:
return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
"[count]]\n"));
case HELP_UPGRADE:
return (gettext("\tupgrade\n"
"\tupgrade -v\n"
"\tupgrade [-V version] <-a | pool ...>\n"));
case HELP_GET:
return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
"<\"all\" | property[,...]> <pool> ...\n"));
case HELP_SET:
return (gettext("\tset <property=value> <pool> \n"));
case HELP_SPLIT:
return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
"\t [-o property=value] <pool> <newpool> "
"[<device> ...]\n"));
case HELP_REGUID:
return (gettext("\treguid <pool>\n"));
}
abort();
/* NOTREACHED */
}
/*
* Callback routine that will print out a pool property value.
*/
static int
{
if (zpool_prop_readonly(prop))
else
else
return (ZPROP_CONT);
}
/*
* Display usage message. If we're inside a command, display only the usage for
* that command. Otherwise, iterate over the entire command table and display
* a complete usage message.
*/
void
{
if (current_command == NULL) {
int i;
gettext("where 'command' is one of the following:\n\n"));
for (i = 0; i < NCOMMAND; i++) {
else
}
} else {
}
if (current_command != NULL &&
gettext("\nthe following properties are supported:\n"));
"PROPERTY", "EDIT", "VALUES");
/* Iterate over all properties */
"appended with a feature name.\nSee zpool-features(5).\n"));
}
/*
* See comments at end of main().
*/
(void) printf("dumping core by request\n");
abort();
}
}
void
{
char *vname;
return;
for (c = 0; c < children; c++) {
&is_log);
continue;
B_FALSE);
}
}
static boolean_t
{
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Add a property pair (name, string-value) into a property nvlist.
*/
static int
{
const char *normnm;
char *strval;
gettext("internal error: out of memory\n"));
return (1);
}
if (poolprop) {
"not a valid pool property\n"), propname);
return (2);
}
/*
* feature@ properties and version should not be specified
* at the same time.
*/
(prop == ZPOOL_PROP_VERSION &&
"'version' properties cannot be specified "
"together\n"));
return (2);
}
if (zpool_prop_feature(propname))
else
} else {
} else {
}
}
prop != ZPOOL_PROP_CACHEFILE) {
"specified multiple times\n"), propname);
return (2);
}
"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
* -n Do not add the devices, but display the resulting layout if
* they were to be added.
*
* Adds the given vdevs to 'pool'. As with create, the bulk of this work is
* handled by get_vdev_spec(), which constructs the nvlist needed to pass to
* libzfs.
*/
int
{
int c;
char *poolname;
int ret;
/* check options */
switch (c) {
case 'f':
break;
case 'n':
break;
case '?':
optopt);
}
}
/* get pool name and check number of arguments */
if (argc < 1) {
}
if (argc < 2) {
}
argc--;
argv++;
return (1);
poolname);
return (1);
}
/* pass off to get_vdev_spec for processing */
return (1);
}
if (dryrun) {
&poolnvroot) == 0);
/* print original main pool and new tree */
/* Do the same for the logs */
if (num_logs(poolnvroot) > 0) {
}
ret = 0;
} else {
}
return (ret);
}
/*
* zpool remove <pool> <vdev> ...
*
* Removes the given vdev from the pool. Currently, this supports removing
* spares, cache, and log devices from the pool.
*/
int
{
char *poolname;
int i, ret = 0;
argc--;
argv++;
/* get pool name and check number of arguments */
if (argc < 1) {
}
if (argc < 2) {
}
return (1);
for (i = 1; i < argc; i++) {
ret = 1;
}
return (ret);
}
/*
* zpool labelclear [-f] <vdev>
*
* -f Force clearing the label for the vdevs which are members of
* the exported or foreign pools.
*
* Verifies that the vdev is not active and zeros out the label information
* on the device.
*/
int
{
/* check options */
switch (c) {
case 'f':
break;
default:
optopt);
}
}
/* get vdev name */
if (argc < 1) {
}
if (argc > 1) {
}
/*
* Check if we were given absolute path and use it as is.
* Otherwise if the provided vdev name doesn't point to a file,
* try prepending dsk path and appending s0.
*/
char *s;
ZFS_DISK_ROOT, argv[0]);
!isdigit(*(s + 1)))
"failed to find device %s, try specifying absolute "
"path instead\n"), argv[0]);
return (1);
}
}
return (1);
}
return (1);
}
if (ret != 0) {
return (1);
}
if (!inuse)
goto wipe_label;
switch (state) {
default:
case POOL_STATE_ACTIVE:
case POOL_STATE_SPARE:
case POOL_STATE_L2CACHE:
"%s is a member (%s) of pool \"%s\"\n"),
ret = 1;
goto errout;
case POOL_STATE_EXPORTED:
if (force)
break;
"use '-f' to override the following error:\n"
"%s is a member of exported pool \"%s\"\n"),
ret = 1;
goto errout;
if (force)
break;
"use '-f' to override the following error:\n"
"%s is a member of potentially active pool \"%s\"\n"),
ret = 1;
goto errout;
case POOL_STATE_DESTROYED:
/* inuse should never be set for a destroyed pool */
assert(0);
break;
}
if (ret != 0) {
}
return (ret);
}
/*
* zpool create [-fnd] [-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
* were to be created.
* -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.
* -d Don't automatically enable all supported pool features
* (individual features can be enabled with -o).
* -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
* we get the nvlist back from get_vdev_spec(), we either print out the contents
* (if '-n' was specified), or pass it to libzfs to do the creation.
*/
int
{
int c;
char *poolname;
char *propval;
/* check options */
switch (c) {
case 'f':
break;
case 'n':
break;
case 'd':
break;
case 'R':
goto errout;
&propval) == 0)
break;
goto errout;
break;
case 'm':
/* Equivalent to -O mountpoint=optarg */
mountpoint = optarg;
break;
case 'o':
"'=' for -o option\n"));
goto errout;
}
*propval = '\0';
propval++;
goto errout;
/*
* If the user is creating a pool that doesn't support
* feature flags, don't enable any features.
*/
char *end;
if (*end == '\0' &&
ver < SPA_VERSION_FEATURES) {
}
}
break;
case 'O':
"'=' for -O option\n"));
goto errout;
}
*propval = '\0';
propval++;
/*
* Mountpoints are checked and then added later.
* Uniquely among properties, they can be specified
* more than once, to avoid conflict with -m.
*/
B_FALSE)) {
goto errout;
}
break;
case ':':
"'%c' option\n"), optopt);
goto badusage;
case '?':
optopt);
goto badusage;
}
}
/* get pool name and check number of arguments */
if (argc < 1) {
goto badusage;
}
if (argc < 2) {
goto badusage;
}
/*
* As a special case, check for use of '/' in the name, and direct the
* user to use 'zfs create' instead.
*/
"character '/' in pool name\n"), poolname);
"create a dataset\n"));
goto errout;
}
/* pass off to get_vdev_spec for bulk processing */
goto errout;
/* make_root_vdev() allows 0 toplevel children if there are spares */
if (!zfs_allocatable_devs(nvroot)) {
"specification: at least one toplevel vdev must be "
"specified\n"));
goto errout;
}
"must be an absolute path\n"), altroot);
goto errout;
}
/*
* Check the validity of the mountpoint and direct the user to use the
* '-m' mountpoint option if it looks like its in use.
*/
if (mountpoint == NULL ||
"'%s': must be an absolute path, 'legacy', or "
"'none'\n"), mountpoint);
goto errout;
}
if (mountpoint == NULL) {
else
poolname);
} else {
else
}
"option to provide a different default\n"));
goto errout;
} else if (dirp) {
int count = 0;
count++;
if (count > 2) {
"'%s' exists and is not empty\n"), buf);
"option to provide a "
"different default\n"));
goto errout;
}
}
}
/*
* Now that the mountpoint's validity has been checked, ensure that
* the property is set appropriately prior to creating the pool.
*/
if (mountpoint != NULL) {
if (ret != 0)
goto errout;
}
ret = 1;
if (dryrun) {
/*
* For a dry run invocation, print out a basic message and run
* through all the vdevs in the list and print out in an
* appropriate hierarchy.
*/
"following layout:\n\n"), poolname);
ret = 0;
} else {
/*
* Hand off to libzfs.
*/
if (enable_all_pool_feat) {
for (i = 0; i < SPA_FEATURES; i++) {
/*
* Skip feature if user specified it manually
* on the command line.
*/
continue;
if (ret != 0)
goto errout;
}
}
ret = 1;
}
"been omitted\n"));
}
}
return (ret);
return (2);
}
/*
* zpool destroy <pool>
*
* -f Forcefully unmount any datasets
*
* Destroy the given pool. Automatically unmounts any datasets in the pool.
*/
int
{
int c;
char *pool;
int ret;
/* check options */
switch (c) {
case 'f':
break;
case '?':
optopt);
}
}
/* check arguments */
if (argc < 1) {
}
if (argc > 1) {
}
/*
* As a special case, check for use of '/' in the name, and
* direct the user to use 'zfs destroy' instead.
*/
"destroy a dataset\n"));
return (1);
}
return (1);
}
/* The history must be logged as part of the export */
return (ret);
}
/*
* zpool export [-f] <pool> ...
*
* -f Forcefully unmount datasets
*
* Export the given pools. By default, the command will attempt to cleanly
* unmount any active datasets within the pool. If the '-f' flag is specified,
* then the datasets will be forcefully unmounted.
*/
int
{
int c;
int ret;
int i;
/* check options */
switch (c) {
case 'f':
break;
case 'F':
break;
case '?':
optopt);
}
}
/* check arguments */
if (argc < 1) {
}
ret = 0;
for (i = 0; i < argc; i++) {
ret = 1;
continue;
}
ret = 1;
continue;
}
/* The history must be logged as part of the export */
if (hardforce) {
ret = 1;
ret = 1;
}
}
return (ret);
}
/*
* Given a vdev configuration, determine the maximum width needed for the device
* name column.
*/
static int
{
int ret;
for (c = 0; c < children; c++)
}
for (c = 0; c < children; c++)
}
for (c = 0; c < children; c++)
}
return (max);
}
typedef struct spare_cbdata {
static boolean_t
{
return (B_TRUE);
for (c = 0; c < children; c++)
return (B_TRUE);
}
return (B_FALSE);
}
static int
{
&nvroot) == 0);
return (1);
}
return (0);
}
/*
* Print out configuration state as requested by status_callback.
*/
void
{
char *vname;
const char *state;
children = 0;
if (isspare) {
/*
* For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
* online drives.
*/
state = "INUSE";
state = "AVAIL";
}
if (!isspare) {
}
¬present) == 0) {
char *path;
(void) printf(" ");
case VDEV_AUX_OPEN_FAILED:
break;
case VDEV_AUX_BAD_GUID_SUM:
break;
case VDEV_AUX_NO_REPLICAS:
break;
case VDEV_AUX_VERSION_NEWER:
break;
case VDEV_AUX_UNSUP_FEAT:
break;
case VDEV_AUX_SPARED:
zpool_get_name(zhp)) == 0)
"use"));
else
"pool '%s'"),
} else {
}
break;
case VDEV_AUX_ERR_EXCEEDED:
break;
case VDEV_AUX_IO_FAILURE:
break;
case VDEV_AUX_BAD_LOG:
break;
case VDEV_AUX_EXTERNAL:
break;
case VDEV_AUX_SPLIT_POOL:
break;
default:
break;
}
}
"resilvering" : "repairing");
}
(void) printf("\n");
for (c = 0; c < children; c++) {
/* Don't print logs or holes here */
&islog);
&ishole);
continue;
}
}
/*
* Print the configuration of an exported pool. Iterate over all vdevs in the
* pool, printing out the name and status for each one.
*/
void
{
return;
(void) printf(" ");
case VDEV_AUX_OPEN_FAILED:
break;
case VDEV_AUX_BAD_GUID_SUM:
break;
case VDEV_AUX_NO_REPLICAS:
break;
case VDEV_AUX_VERSION_NEWER:
break;
case VDEV_AUX_UNSUP_FEAT:
break;
case VDEV_AUX_ERR_EXCEEDED:
break;
default:
break;
}
}
(void) printf("\n");
return;
for (c = 0; c < children; c++) {
&is_log);
if (is_log)
continue;
}
for (c = 0; c < children; c++) {
}
}
for (c = 0; c < children; c++) {
}
}
}
/*
* Print log vdevs.
* Logs are recorded as top level vdevs in the main pool child array
* but with "is_log" set to 1. We use either print_status_config() or
* print_import_config() to print the top level logs then any log
* children (eg mirrored slogs) are printed recursively - which
* works because only the top level vdev is marked "is_log"
*/
static void
{
&children) != 0)
return;
for (c = 0; c < children; c++) {
char *name;
&is_log);
if (!is_log)
continue;
if (verbose)
2, B_FALSE);
else
}
}
/*
* Display the status for the given pool.
*/
static void
{
char *name;
char *msgid;
int reason;
const char *health;
int namewidth;
char *comment;
&name) == 0);
&guid) == 0);
&pool_state) == 0);
&nvroot) == 0);
if (pool_state == POOL_STATE_DESTROYED)
(void) printf("\n");
switch (reason) {
"missing from the system.\n"));
break;
"corrupted data.\n"));
break;
(void) printf(
gettext(" status: The pool data is corrupted.\n"));
break;
case ZPOOL_STATUS_OFFLINE_DEV:
"are offlined.\n"));
break;
"corrupted.\n"));
break;
"legacy on-disk version.\n"));
break;
"incompatible version.\n"));
break;
"not enabled on the pool.\n"));
break;
"feature(s) not supported on this sytem:\n"));
break;
"in read-only mode on this system. It\n\tcannot be "
"accessed in read-write mode because it uses the "
"following\n\tfeature(s) not supported on this system:\n"));
break;
"another system.\n"));
break;
"faulted.\n"));
break;
case ZPOOL_STATUS_BAD_LOG:
"read.\n"));
break;
case ZPOOL_STATUS_RESILVERING:
"resilvered.\n"));
break;
default:
/*
* No other status can be seen when importing pools.
*/
}
/*
* Print out an action according to the overall state of the pool.
*/
if (reason == ZPOOL_STATUS_VERSION_OLDER ||
"imported using its name or numeric identifier, "
"though\n\tsome features will not be available "
"without an explicit 'zpool upgrade'.\n"));
} else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
"imported using its name or numeric "
"identifier and\n\tthe '-f' flag.\n"));
} else {
"imported using its name or numeric "
"identifier.\n"));
}
"despite missing or damaged devices. The\n\tfault "
"tolerance of the pool may be compromised if imported.\n"));
} else {
switch (reason) {
"imported. Access the pool on a system running "
"newer\n\tsoftware, or recreate the pool from "
"backup.\n"));
break;
"imported. Access the pool on a system that "
"supports\n\tthe required feature(s), or recreate "
"the pool from backup.\n"));
break;
"imported in read-write mode. Import the pool "
"with\n"
"\t\"-o readonly=on\", access the pool on a system "
"that supports the\n\trequired feature(s), or "
"recreate the pool from backup.\n"));
break;
"imported. Attach the missing\n\tdevices and try "
"again.\n"));
break;
default:
"imported due to damaged devices or data.\n"));
}
}
/* Print the comment attached to the pool. */
/*
* If the state is "closed" or "can't open", and the aux state
* is "corrupt data":
*/
if (pool_state == POOL_STATE_DESTROYED)
"but can be imported using the '-Df' flags.\n"));
else if (pool_state != POOL_STATE_EXPORTED)
"another system, but can be imported using\n\t"
"the '-f' flag.\n"));
}
msgid);
if (namewidth < 10)
namewidth = 10;
if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
"be part of this pool, though their\n\texact "
"configuration cannot be determined.\n"));
}
}
/*
* Perform the import for the given configuration. This passes the heavy
* lifting off to zpool_import_props(), and then mounts the datasets contained
* within the pool.
*/
static int
{
char *name;
&name) == 0);
ZPOOL_CONFIG_POOL_STATE, &state) == 0);
ZPOOL_CONFIG_VERSION, &version) == 0);
if (!SPA_VERSION_IS_SUPPORTED(version)) {
"is formatted using an unsupported ZFS version\n"), name);
return (1);
} else if (state != POOL_STATE_EXPORTED &&
!(flags & ZFS_IMPORT_ANY_HOST)) {
&hostid) == 0) {
char *hostname;
time_t t;
ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0);
t = timestamp;
"'%s': pool may be in use from other "
"system, it was last accessed by %s "
(unsigned long)hostid,
"import anyway\n"));
return (1);
}
} else {
"pool may be in use from other system\n"), name);
"anyway\n"));
return (1);
}
}
return (1);
return (1);
!(flags & ZFS_IMPORT_ONLY) &&
return (1);
}
return (0);
}
/*
* zpool import [-d dir] [-D]
* 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] [-n] [-F] <pool | id> [newpool]
*
* -c Read pool information from a cachefile instead of searching
* devices.
*
* one directory can be specified using multiple '-d' options.
*
* -D Scan for previously destroyed pools or import all or only
* specified destroyed pools.
*
* -R Temporarily import the pool, with all mountpoints relative to
* the given root. The pool will remain exported when the machine
* is rebooted.
*
* -V 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. In other words, it does verbatim
* import.
*
* -f Force import, even if it appears that the pool is active.
*
* -F Attempt rewind if necessary.
*
* -n See if rewind would work, but don't actually rewind.
*
* -N Import the pool but don't mount datasets.
*
* -T Specify a starting txg to use for import. This option is
* intentionally undocumented option for testing purposes.
*
* -a Import all pools found.
*
*
* 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.
*/
int
{
int nsearch = 0;
int c;
int err = 0;
char *propval;
char *endptr;
/* check options */
switch (c) {
case 'a':
break;
case 'c':
break;
case 'd':
if (searchdirs == NULL) {
searchdirs = safe_malloc(sizeof (char *));
} else {
sizeof (char *));
sizeof (char *));
searchdirs = tmp;
}
break;
case 'D':
break;
case 'f':
break;
case 'F':
break;
case 'm':
break;
case 'n':
break;
case 'N':
flags |= ZFS_IMPORT_ONLY;
break;
case 'o':
*propval = '\0';
propval++;
goto error;
} else {
}
break;
case 'R':
goto error;
&propval) == 0)
break;
goto error;
break;
case 'T':
errno = 0;
gettext("invalid txg value\n"));
}
break;
case 'V':
break;
case 'X':
break;
case ':':
"'%c' option\n"), optopt);
break;
case '?':
optopt);
}
}
}
gettext("-n or -X only meaningful with -F\n"));
}
if (dryrun)
else if (do_rewind)
if (xtreme_rewind)
/* In the future, we can capture further policy and include it here */
goto error;
if (searchdirs == NULL) {
searchdirs = safe_malloc(sizeof (char *));
searchdirs[0] = ZFS_DISK_ROOT;
nsearch = 1;
}
/* check argument count */
if (do_all) {
if (argc != 0) {
}
} else {
if (argc > 2) {
}
/*
* Check for the SYS_CONFIG privilege. We do this explicitly
* here because otherwise any attempt to discover pools will
* silently fail.
*/
"discover pools: permission denied\n"));
return (1);
}
}
/*
* Depending on the arguments given, we do one of the following:
*
* <none> Iterate through all pools and display information about
* each one.
*
* -a Iterate through all pools and try to import each one.
*
* name and import that one.
*
* -D Above options applies only to destroyed pools.
*/
if (argc != 0) {
char *endptr;
errno = 0;
searchname = argv[0];
searchguid = 0;
}
found_config = NULL;
/*
* User specified a name or guid. Ensure it's unique.
*/
}
"a pool with that name already exists\n"),
argv[0]);
"<pool | id> <newpool>' to give it a new name\n"),
"zpool import");
err = 1;
argv[0]);
"with that name were found\n"));
err = 1;
if (argc != 0) {
"no such pool available\n"), argv[0]);
}
err = 1;
}
if (err == 1) {
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;
&pool_state) == 0);
continue;
continue;
policy) == 0);
if (argc == 0) {
if (first)
else if (!do_all)
(void) printf("\n");
if (do_all) {
} else {
}
} else if (searchname != NULL) {
char *name;
/*
* We are searching for a pool based on name.
*/
ZPOOL_CONFIG_POOL_NAME, &name) == 0);
if (found_config != NULL) {
"cannot import '%s': more than "
"one matching pool\n"), searchname);
"import by numeric ID instead\n"));
}
}
} else {
/*
* Search for a pool by guid.
*/
ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
if (guid == searchguid)
}
}
/*
* If we were searching for a specific pool, verify that we found a
* pool, and then do the import.
*/
if (found_config == NULL) {
"no such pool available\n"), argv[0]);
} else {
}
}
/*
* If we were just looking for pools, report an error if none were
* found.
*/
gettext("no pools available to import\n"));
return (err ? 1 : 0);
}
typedef struct iostat_cbdata {
int cb_namewidth;
int cb_iteration;
static void
{
int i = 0;
for (i = 0; i < cb->cb_namewidth; i++)
(void) printf("-");
(void) printf(" ----- ----- ----- ----- ----- -----\n");
}
static void
{
(void) printf("%*s capacity operations bandwidth\n",
(void) printf("%-*s alloc free read write read write\n",
}
/*
* Display a single statistic.
*/
static void
{
}
/*
* Print out all the statistics for the given vdev. This can either be the
* toplevel configuration, or called recursively. If 'name' is NULL, then this
* is a verbose output, and we don't want to display the toplevel pool stats.
*/
void
{
double scale;
char *vname;
} else {
}
else
if (tdelta == 0)
scale = 1.0;
else
/* only toplevel vdevs have capacity stats */
(void) printf(" - -");
} else {
}
(void) printf("\n");
if (!cb->cb_verbose)
return;
return;
&oldchild, &c) != 0)
return;
for (c = 0; c < children; c++) {
&ishole);
&islog);
continue;
}
/*
* Log device section
*/
(void) printf("%-*s - - - - - "
for (c = 0; c < children; c++) {
(void) nvlist_lookup_uint64(newchild[c],
if (islog) {
B_FALSE);
}
}
}
/*
* Include level 2 ARC devices in iostat output
*/
return;
&oldchild, &c) != 0)
return;
if (children > 0) {
(void) printf("%-*s - - - - - "
for (c = 0; c < children; c++) {
B_FALSE);
}
}
}
static int
{
/*
* If the pool has disappeared, remove it from the list and continue.
*/
return (-1);
if (missing)
return (0);
}
/*
* Callback to print out the iostats for the given pool.
*/
int
{
&newnvroot) == 0);
else
&oldnvroot) == 0);
/*
* Print out the statistics for the pool.
*/
if (cb->cb_verbose)
return (0);
}
int
{
&nvroot) == 0);
if (!cb->cb_verbose)
else
cb->cb_namewidth);
}
/*
* The width must fall into the range [10,38]. The upper limit is the
* maximum we can have and still fit in 80 columns.
*/
return (0);
}
/*
* Parse the input string, get the 'interval' and 'count' value if there is one.
*/
static void
unsigned long *cnt)
{
/*
* Determine if the last argument is an integer or a pool name
*/
char *end;
errno = 0;
if (interval == 0) {
"cannot be zero\n"));
}
/*
* Ignore the last parameter
*/
argc--;
} else {
/*
* If this is not a valid number, just plow on. The
* user will get a more informative error message later
* on.
*/
interval = 0;
}
}
/*
* If the last argument is also an integer, then we have both a count
* and an interval.
*/
char *end;
errno = 0;
if (interval == 0) {
"cannot be zero\n"));
}
/*
* Ignore the last parameter
*/
argc--;
} else {
interval = 0;
}
}
}
static void
get_timestamp_arg(char c)
{
if (c == 'u')
else if (c == 'd')
else
}
/*
* zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
*
* -v Display statistics for individual vdevs
* -T Display a timestamp in date(1) or Unix format
*
* This command can be tricky because we want to be able to deal with pool
* creation/destruction as well as vdev configuration changes. The bulk of this
* processing is handled by the pool_list_* routines in zpool_iter.c. We rely
* on pool_list_update() to detect the addition of new pools. Configuration
* changes are all handled within libzfs.
*/
int
{
int c;
int ret;
int npools;
/* check options */
switch (c) {
case 'T':
break;
case 'v':
break;
case '?':
optopt);
}
}
/*
* Construct the list of all interesting pools.
*/
ret = 0;
return (1);
return (1);
}
return (1);
}
/*
* Enter the main iostat loop.
*/
cb.cb_iteration = 0;
cb.cb_namewidth = 0;
for (;;) {
break;
/*
* Refresh all statistics. This is done as an explicit step
* before calculating the maximum name width, so that any
* configuration changes are properly accounted for.
*/
/*
* Iterate over all pools to determine the maximum width
* for the pool / device name column across all pools.
*/
cb.cb_namewidth = 0;
if (timestamp_fmt != NODATE)
/*
* If it's the first time, or verbose mode, print the header.
*/
/*
* If there's more than one pool, and we're not in verbose mode
* (which prints a separator for us), then print a separator.
*/
if (verbose)
(void) printf("\n");
/*
* Flush the output so that redirection to a file isn't buffered
* indefinitely.
*/
if (interval == 0)
break;
break;
}
return (ret);
}
typedef struct list_cbdata {
int cb_namewidth;
/*
* Given a list of columns to display, output appropriate headers for each one.
*/
static void
{
const char *header;
/*
* Reset the width to accommodate the verbose listing
* of devices.
*/
}
if (!first)
(void) printf(" ");
else
} else {
int i;
headerbuf[i] = '\0';
}
else if (right_justify)
else
}
(void) printf("\n");
}
/*
* Given a pool and a list of properties, print out all the properties according
* to the described layout.
*/
static void
{
char *propstr;
/*
* Reset the width to accommodate the verbose listing
* of devices.
*/
}
if (!first) {
if (cb->cb_scripted)
(void) printf("\t");
else
(void) printf(" ");
} else {
}
propstr = "-";
else
sizeof (property)) == 0) {
} else {
propstr = "-";
}
/*
* 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.
*/
else if (right_justify)
else
}
(void) printf("\n");
}
static void
{
switch (prop) {
case ZPOOL_PROP_EXPANDSZ:
if (value == 0)
else
break;
case ZPOOL_PROP_FRAGMENTATION:
if (value == ZFS_FRAG_INVALID) {
} else {
value);
}
break;
case ZPOOL_PROP_CAPACITY:
break;
default:
}
if (!valid)
if (scripted)
else
}
void
{
char *vname;
if (scripted)
else
/*
* 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.
*/
toplevel);
toplevel);
B_TRUE);
(void) printf("\n");
}
return;
for (c = 0; c < children; c++) {
if (nvlist_lookup_uint64(child[c],
continue;
if (nvlist_lookup_uint64(child[c],
continue;
}
}
/* LINTED E_SEC_PRINTF_VAR_FMT */
for (c = 0; c < children; c++) {
continue;
}
}
/* LINTED E_SEC_PRINTF_VAR_FMT */
for (c = 0; c < children; c++) {
}
}
/* LINTED E_SEC_PRINTF_VAR_FMT */
for (c = 0; c < children; c++) {
}
}
}
/*
* Generic callback function to list a pool.
*/
int
{
if (!cbp->cb_verbose)
return (0);
&nvroot) == 0);
return (0);
}
/*
* zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
*
* -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,expandsize,fragmentation,capacity,"
* "dedupratio,health,altroot"
* -p Diplay values in parsable (exact) format.
* -T Display a timestamp in date(1) or Unix format
*
* List all pools in the system, whether or not they're healthy. Output space
* statistics for each one, as well as health status summary.
*/
int
{
int c;
int ret;
static char default_props[] =
"name,size,allocated,free,expandsize,fragmentation,capacity,"
"dedupratio,health,altroot";
/* check options */
switch (c) {
case 'H':
break;
case 'o':
break;
case 'p':
break;
case 'T':
break;
case 'v':
break;
case ':':
"'%c' option\n"), optopt);
break;
case '?':
optopt);
}
}
for (;;) {
return (1);
if (pool_list_count(list) == 0)
break;
cb.cb_namewidth = 0;
if (timestamp_fmt != NODATE)
print_header(&cb);
}
if (interval == 0)
break;
break;
}
ret = 0;
}
return (ret);
}
static int
{
int c;
int ret;
/* check options */
switch (c) {
case 'f':
break;
case '?':
optopt);
}
}
/* get pool name and check number of arguments */
if (argc < 1) {
}
if (argc < 2) {
gettext("missing <device> specification\n"));
}
if (argc < 3) {
if (!replacing) {
gettext("missing <new_device> specification\n"));
}
argc -= 1;
argv += 1;
} else {
argc -= 2;
argv += 2;
}
if (argc > 1) {
}
return (1);
poolname);
return (1);
}
return (1);
}
return (ret);
}
/*
* zpool replace [-f] <pool> <device> <new_device>
*
* -f Force attach, even if <new_device> appears to be in use.
*
* Replace <device> with <new_device>.
*/
/* ARGSUSED */
int
{
}
/*
* zpool attach [-f] <pool> <device> <new_device>
*
* -f Force attach, even if <new_device> appears to be in use.
*
* Attach <new_device> to the mirror containing <device>. If <device> is not
* part of a mirror, then <device> will be transformed into a mirror of
* <device> and <new_device>. In either case, <new_device> will begin life
* with a DTL of [0, now], and will immediately begin to resilver itself.
*/
int
{
}
/*
* zpool detach [-f] <pool> <device>
*
* -f Force detach of <device>, even if DTLs argue against it
* (not supported yet)
*
* Detach a device from a mirror. The operation will be refused if <device>
* is the last device in the mirror, or if the DTLs indicate that this device
* has the only valid copy of some data.
*/
/* ARGSUSED */
int
{
int c;
int ret;
/* check options */
switch (c) {
case 'f':
case '?':
optopt);
}
}
/* get pool name and check number of arguments */
if (argc < 1) {
}
if (argc < 2) {
gettext("missing <device> specification\n"));
}
return (1);
return (ret);
}
/*
* zpool split [-n] [-o prop=val] ...
* [-o mntopt] ...
* [-R altroot] <pool> <newpool> [<device> ...]
*
* -n Do not split the pool, but display the resulting layout if
* it were to be split.
* -o Set property=value, or set mount options.
* -R Mount the split-off pool under an alternate root.
*
* Splits the named pool and gives it the new pool name. Devices to be split
* off may be listed, provided that no more than one device is specified
* per top-level vdev mirror. The newly split pool is left in an exported
* state unless -R is specified.
*
* Restrictions: the top-level of the pool pool must only be made up of
* mirrors; all devices in the pool must be healthy; no device may be
* undergoing a resilvering operation.
*/
int
{
int c, ret = 0;
/* check options */
switch (c) {
case 'R':
if (add_prop_list(
}
break;
case 'n':
break;
case 'o':
*propval = '\0';
propval++;
}
} else {
}
break;
case ':':
"'%c' option\n"), optopt);
break;
case '?':
optopt);
break;
}
}
"valid when importing the pool\n"));
}
if (argc < 1) {
}
if (argc < 2) {
}
argc -= 2;
argv += 2;
return (1);
ret = 1;
} else {
"following layout:\n\n"), newpool);
}
}
return (ret);
/*
* The split was successful. Now we need to open the new
* pool and import it.
*/
return (1);
ret = 1;
"the datasets could not all be mounted\n"));
"different altroot\n"), "zpool import");
}
return (ret);
}
/*
* zpool online <pool> <device> ...
*/
int
{
int c, i;
char *poolname;
int ret = 0;
int flags = 0;
/* check options */
switch (c) {
case 'e':
break;
case 't':
case '?':
optopt);
}
}
/* get pool name and check number of arguments */
if (argc < 1) {
}
if (argc < 2) {
}
return (1);
for (i = 1; i < argc; i++) {
if (newstate != VDEV_STATE_HEALTHY) {
"onlined, but remains in faulted state\n"),
argv[i]);
if (newstate == VDEV_STATE_FAULTED)
"clear' to restore a faulted "
"device\n"));
else
"replace' to replace devices "
"that are no longer present\n"));
}
} else {
ret = 1;
}
}
return (ret);
}
/*
* zpool offline [-ft] <pool> <device> ...
*
* -f Force the device into the offline state, even if doing
* so would appear to compromise pool availability.
* (not supported yet)
*
* -t Only take the device off-line temporarily. The offline
* state will not be persistent across reboots.
*/
/* ARGSUSED */
int
{
int c, i;
char *poolname;
int ret = 0;
/* check options */
switch (c) {
case 't':
break;
case 'f':
case '?':
optopt);
}
}
/* get pool name and check number of arguments */
if (argc < 1) {
}
if (argc < 2) {
}
return (1);
for (i = 1; i < argc; i++) {
ret = 1;
}
return (ret);
}
/*
* zpool clear <pool> [device]
*
* Clear all errors associated with a pool or a particular device.
*/
int
{
int c;
int ret = 0;
/* check options */
switch (c) {
case 'F':
break;
case 'n':
break;
case 'X':
break;
case '?':
optopt);
}
}
if (argc < 1) {
}
if (argc > 2) {
}
gettext("-n or -X only meaningful with -F\n"));
}
if (dryrun)
else if (do_rewind)
if (xtreme_rewind)
/* In future, further rewind policy choices can be passed along here */
return (1);
return (1);
}
ret = 1;
return (ret);
}
/*
* zpool reguid <pool>
*/
int
{
int c;
char *poolname;
int ret = 0;
/* check options */
switch (c) {
case '?':
optopt);
}
}
/* get pool name and check number of arguments */
if (argc < 1) {
}
if (argc > 1) {
}
return (1);
return (ret);
}
/*
* zpool reopen <pool>
*
* Reopen the pool so that the kernel can update the sizes of all vdevs.
*/
int
{
int c;
int ret = 0;
char *pool;
/* check options */
switch (c) {
case '?':
optopt);
}
}
argc--;
argv++;
if (argc < 1) {
}
if (argc > 1) {
}
return (1);
return (ret);
}
typedef struct scrub_cbdata {
int cb_type;
int cb_argc;
char **cb_argv;
int
{
int err;
/*
* Ignore faulted pools.
*/
return (1);
}
return (err != 0);
}
/*
* zpool scrub [-s] <pool> ...
*
* -s Stop. Stops any in-progress scrub.
*/
int
{
int c;
/* check options */
switch (c) {
case 's':
break;
case '?':
optopt);
}
}
if (argc < 1) {
}
}
typedef struct status_cbdata {
int cb_count;
/*
* Print out detailed scrub status.
*/
void
{
double fraction_done;
/* If there's never been a scan, there's not much to say. */
return;
}
/*
* Scan is finished or canceled.
*/
"%llu errors on %s");
"%llu errors on %s");
}
/* LINTED */
return;
}
return;
}
/*
* Scan is in progress.
*/
}
/* elapsed time for this pass */
/*
* do not print estimated time if hours_left is more than 30 days
*/
} else {
", (scan is slow, no estimated time)\n"));
}
}
}
static void
{
char *pathname;
(void) printf("errors: List of errors unavailable "
"(insufficient privileges)\n");
return;
}
(void) printf("errors: Permanent errors have been "
"detected in the following files:\n\n");
&dsobj) == 0);
&obj) == 0);
}
}
static void
int namewidth)
{
uint_t i;
char *name;
if (nspares == 0)
return;
for (i = 0; i < nspares; i++) {
}
}
static void
int namewidth)
{
uint_t i;
char *name;
if (nl2cache == 0)
return;
for (i = 0; i < nl2cache; i++) {
}
}
static void
{
uint_t c;
/*
* If the pool was faulted then we may not have been able to
* obtain the config. Otherwise, if we have anything in the dedup
* table continue processing the stats.
*/
return;
(void) printf("\n");
return;
}
(void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
}
/*
* Display a summary of pool status. Displays a summary such as:
*
* pool: tank
* status: DEGRADED
* reason: One or more devices ...
* config:
* mirror DEGRADED
* c1t0d0 OK
* c2t0d0 UNAVAIL
*
* When given the '-v' option, we print out the complete config. If the '-e'
* option is specified, then we print out error rate information as well.
*/
int
{
char *msgid;
int reason;
const char *health;
uint_t c;
/*
* If we were given 'zpool status -x', only report those pools with
* problems.
*/
if (cbp->cb_explain &&
(reason == ZPOOL_STATUS_OK ||
reason == ZPOOL_STATUS_FEAT_DISABLED)) {
if (!cbp->cb_allpools) {
}
return (0);
}
else
(void) printf("\n");
&nvroot) == 0);
switch (reason) {
"be opened. Sufficient replicas exist for\n\tthe pool to "
"continue functioning in a degraded state.\n"));
"online it using 'zpool online'.\n"));
break;
"be opened. There are insufficient\n\treplicas for the "
"pool to continue functioning.\n"));
"online it using 'zpool online'.\n"));
break;
"be used because the label is missing or\n\tinvalid. "
"Sufficient replicas exist for the pool to continue\n\t"
"functioning in a degraded state.\n"));
"'zpool replace'.\n"));
break;
"be used because the label is missing \n\tor invalid. "
"There are insufficient replicas for the pool to "
"continue\n\tfunctioning.\n"));
break;
case ZPOOL_STATUS_FAILING_DEV:
"experienced an unrecoverable error. An\n\tattempt was "
"made to correct the error. Applications are "
"unaffected.\n"));
"to be replaced, and clear the errors\n\tusing "
"'zpool clear' or replace the device with 'zpool "
"replace'.\n"));
break;
case ZPOOL_STATUS_OFFLINE_DEV:
"been taken offline by the administrator.\n\tSufficient "
"replicas exist for the pool to continue functioning in "
"a\n\tdegraded state.\n"));
"'zpool online' or replace the device with\n\t'zpool "
"replace'.\n"));
break;
case ZPOOL_STATUS_REMOVED_DEV:
"been removed by the administrator.\n\tSufficient "
"replicas exist for the pool to continue functioning in "
"a\n\tdegraded state.\n"));
"'zpool online' or replace the device with\n\t'zpool "
"replace'.\n"));
break;
case ZPOOL_STATUS_RESILVERING:
"currently being resilvered. The pool will\n\tcontinue "
"to function, possibly in a degraded state.\n"));
"complete.\n"));
break;
"experienced an error resulting in data\n\tcorruption. "
"Applications may be affected.\n"));
"if possible. Otherwise restore the\n\tentire pool from "
"backup.\n"));
break;
"and the pool cannot be opened.\n"));
break;
"legacy on-disk format. The pool can\n\tstill be used, "
"but some features are unavailable.\n"));
"upgrade'. Once this is done, the\n\tpool will no longer "
"be accessible on software that does not support feature\n"
"\tflags.\n"));
break;
"newer, incompatible on-disk version.\n\tThe pool cannot "
"be accessed on this system.\n"));
"running more recent software, or\n\trestore the pool from "
"backup.\n"));
break;
"enabled on the pool. The pool can\n\tstill be used, but "
"some features are unavailable.\n"));
"'zpool upgrade'. Once this is done,\n\tthe pool may no "
"longer be accessible by software that does not support\n\t"
"the features. See zpool-features(5) for details.\n"));
break;
"this system because it uses the\n\tfollowing feature(s) "
"not supported on this system:\n"));
(void) printf("\n");
"that supports the required feature(s),\n\tor restore the "
"pool from backup.\n"));
break;
"in read-only mode on this system. It\n\tcannot be "
"accessed in read-write mode because it uses the "
"following\n\tfeature(s) not supported on this system:\n"));
(void) printf("\n");
"read-write mode. Import the pool with\n"
"\t\"-o readonly=on\", access the pool from a system that "
"supports the\n\trequired feature(s), or restore the "
"pool from backup.\n"));
break;
"faulted in response to persistent errors.\n\tSufficient "
"replicas exist for the pool to continue functioning "
"in a\n\tdegraded state.\n"));
"or use 'zpool clear' to mark the device\n\trepaired.\n"));
break;
"faulted in response to persistent errors. There are "
"insufficient replicas for the pool to\n\tcontinue "
"functioning.\n"));
"from a backup source. Manually marking the device\n"
"\trepaired using 'zpool clear' may allow some data "
"to be recovered.\n"));
break;
"faulted in response to IO failures.\n"));
"are connected, then run 'zpool clear'.\n"));
break;
case ZPOOL_STATUS_BAD_LOG:
"could not be read.\n"
"\tWaiting for adminstrator intervention to fix the "
"faulted pool.\n"));
"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.
*/
}
msgid);
int namewidth;
(void) nvlist_lookup_uint64_array(nvroot,
if (namewidth < 10)
namewidth = 10;
"NAME", "STATE", "READ", "WRITE", "CKSUM");
&nerr) == 0) {
/*
* If the approximate error count is small, get a
* precise count by fetching the entire log and
* uniquifying the results.
*/
nerr = 0;
nerr++;
}
}
(void) printf("\n");
if (nerr == 0)
"errors\n"));
else if (!cbp->cb_verbose)
"errors, use '-v' for a list\n"),
(u_longlong_t)nerr);
else
}
if (cbp->cb_dedup_stats)
} else {
"determined.\n"));
}
return (0);
}
/*
* zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
*
* -v Display complete error logs
* -x Display only pools with potential problems
* -D Display dedup status (undocumented)
* -T Display a timestamp in date(1) or Unix format
*
* Describes the health status of all pools or some subset.
*/
int
{
int c;
int ret;
/* check options */
switch (c) {
case 'v':
break;
case 'x':
break;
case 'D':
break;
case 'T':
break;
case '?':
optopt);
}
}
if (argc == 0)
for (;;) {
if (timestamp_fmt != NODATE)
status_callback, &cb);
if (ret != 0)
return (ret);
if (interval == 0)
break;
break;
}
return (0);
}
typedef struct upgrade_cbdata {
int cb_first;
int cb_argc;
char **cb_argv;
static int
{
int ret;
&oldversion) == 0);
if (ret != 0)
return (ret);
if (version >= SPA_VERSION_FEATURES) {
"'%s' from version %llu to feature flags.\n"),
} else {
"'%s' from version %llu to version %llu.\n"),
}
return (0);
}
static int
{
count = 0;
for (i = 0; i < SPA_FEATURES; i++) {
char *propname;
if (ret != 0) {
return (ret);
}
count++;
if (firstff) {
"following features on '%s':\n"),
}
}
}
return (0);
}
static int
{
int ret;
&version) == 0);
if (ret != 0)
return (ret);
/*
* 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().
*/
}
int count;
if (ret != 0)
return (ret);
if (count > 0) {
}
}
if (printnl) {
}
return (0);
}
static int
{
&version) == 0);
if (version < SPA_VERSION_FEATURES) {
"formatted with legacy version numbers and can\n"
"be upgraded to use feature flags. After "
"being upgraded, these pools\nwill no "
"longer be accessible by software that does not "
"support feature\nflags.\n\n"));
}
}
return (0);
}
static int
{
&version) == 0);
if (version >= SPA_VERSION_FEATURES) {
int i;
for (i = 0; i < SPA_FEATURES; i++) {
"supported features are not "
"enabled on the following pools. "
"Once a\nfeature is enabled the "
"pool may become incompatible with "
"software\nthat does not support "
"the feature. See "
"zpool-features(5) for "
"details.\n\n"));
"FEATURE\n"));
"---------\n"));
}
if (poolfirst) {
}
}
}
}
return (0);
}
/* ARGSUSED */
static int
{
int ret;
"Pool 'log' must be renamed using export and import"
" to upgrade.\n"));
return (1);
}
"using more current version '%llu'.\n\n"),
return (0);
}
cbp->cb_version);
return (0);
}
if (ret != 0)
return (ret);
}
int count = 0;
if (ret != 0)
return (ret);
if (count != 0) {
} else if (cur_version == SPA_VERSION) {
"supported features enabled.\n"),
}
}
if (printnl) {
}
return (0);
}
/*
* zpool upgrade
* zpool upgrade -v
* 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
* upgrade all pools.
*/
int
{
int c;
int ret = 0;
char *end;
/* check options */
switch (c) {
case 'a':
upgradeall = B_TRUE;
break;
case 'v':
break;
case 'V':
if (*end != '\0' ||
}
break;
case ':':
"'%c' option\n"), optopt);
break;
case '?':
optopt);
}
}
if (cb.cb_version == 0) {
} else if (!upgradeall && argc == 0) {
"incompatible with other arguments\n"));
}
if (showversions) {
if (upgradeall || argc != 0) {
"incompatible with other arguments\n"));
}
} else if (upgradeall) {
if (argc != 0) {
"be used along with a pool name\n"));
}
}
"flags.\n\n"));
if (showversions) {
int i;
"supported:\n\n"));
(void) printf("----------------------------------------------"
"---------------\n");
for (i = 0; i < SPA_FEATURES; i++) {
const char *ro =
" (read-only compatible)" : "";
}
(void) printf("\n");
"supported:\n\n"));
(void) printf("--- -----------------------------------------"
"---------------\n");
"(replicated metadata)\n"));
"RAID-Z\n"));
"algorithm\n"));
"properties\n"));
"(zero-length encoding)\n"));
"performance\n"));
"performance\n"));
"version, including supported releases,\n"));
} else if (argc == 0 && upgradeall) {
"formatted using feature flags.\n\n"));
"pool already has all supported features "
"enabled.\n"));
} else {
"formatted with version %llu or higher.\n"),
cb.cb_version);
}
}
} else if (argc == 0) {
"using feature flags.\n\n"));
} else {
"for a list of available legacy versions.\n"));
}
"all supported features enabled.\n"));
} else {
}
} else {
upgrade_one, &cb);
}
return (ret);
}
typedef struct hist_cbdata {
/*
* Print out the command history for a specific pool.
*/
static int
{
int ret, i;
return (ret);
&records, &numrecords) == 0);
for (i = 0; i < numrecords; i++) {
struct tm t;
(void) localtime_r(&tsec, &t);
}
int ievent =
continue;
if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
(void) printf("%s unrecognized record:\n",
tbuf);
continue;
}
continue;
(void) printf(" %s (%llu)",
}
continue;
(void) printf(" input:\n");
ZPOOL_HIST_INPUT_NVL), 8);
}
(void) printf(" output:\n");
ZPOOL_HIST_OUTPUT_NVL), 8);
}
} else {
continue;
}
(void) printf("\n");
continue;
}
(void) printf(" [");
}
(void) printf("on %s",
}
(void) printf(":%s",
}
(void) printf("]");
(void) printf("\n");
}
(void) printf("\n");
return (ret);
}
/*
* zpool history <pool>
*
* Displays the history of commands that modified pools.
*/
int
{
int ret;
int c;
/* check options */
switch (c) {
case 'l':
break;
case 'i':
break;
case '?':
optopt);
}
}
&cbdata);
return (0);
}
return (ret);
}
static int
{
/*
* Skip the special fake placeholder. This will also skip
* over the name property when 'all' is specified.
*/
continue;
}
} else {
continue;
}
}
return (0);
}
/*
* zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ...
*
* -H Scripted mode. Don't display headers, and separate properties
* by a single tab.
* -o List of columns to display. Defaults to
* "name,property,value,source".
* -p Diplay values in parsable (exact) format.
*
* Get properties of pools in the system. Output space statistics
* for each one as well as other attributes.
*/
int
{
int ret;
int c, i;
char *value;
/*
* Set up default columns and sources.
*/
/* check options */
switch (c) {
case 'p':
break;
case 'H':
break;
case 'o':
i = 0;
while (*optarg != '\0') {
static char *col_subopts[] =
{ "name", "property", "value", "source",
"all", NULL };
if (i == ZFS_GET_NCOLS) {
"many fields given to -o "
"option\n"));
}
&value)) {
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
if (i > 0) {
gettext("\"all\" conflicts "
"with specific fields "
"given to -o option\n"));
}
i = ZFS_GET_NCOLS;
break;
default:
gettext("invalid column name "
"'%s'\n"), value);
}
}
break;
case '?':
optopt);
}
}
if (argc < 1) {
"argument\n"));
}
ZFS_TYPE_POOL) != 0)
argc--;
argv++;
}
get_callback, &cb);
else
return (ret);
}
typedef struct set_cbdata {
char *cb_propname;
char *cb_value;
} set_cbdata_t;
int
{
int error;
if (!error)
return (error);
}
int
{
int error;
}
if (argc < 2) {
"argument\n"));
}
if (argc < 3) {
}
if (argc > 3) {
}
"property=value argument\n"));
}
set_callback, &cb);
return (error);
}
static int
{
int i;
for (i = 0; i < NCOMMAND; i++) {
continue;
*idx = i;
return (0);
}
}
return (1);
}
int
{
int ret = 0;
int i;
char *cmdname;
(void) textdomain(TEXT_DOMAIN);
"initialize ZFS library\n"));
return (1);
}
opterr = 0;
/*
* Make sure the user has specified some command.
*/
if (argc < 2) {
}
/*
* Special case '-?'
*/
/*
* Run the appropriate command.
*/
if (find_command_idx(cmdname, &i) == 0) {
current_command = &command_table[i];
current_command = &command_table[i];
/*
* 'freeze' is a vile debugging abomination, so we treat
* it as such.
*/
} else {
"command '%s'\n"), cmdname);
}
if (ret == 0 && log_history)
/*
* The 'ZFS_ABORT' environment variable causes us to dump core on exit
* for the purposes of running ::findleaks.
*/
(void) printf("dumping core by request\n");
abort();
}
return (ret);
}