zpool_main.c revision 4c58d71403cebfaa40a572ff12b17668ebd56987
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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 <libzfs.h>
#include "zpool_util.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_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_attach(int, char **);
static int zpool_do_detach(int, char **);
static int zpool_do_replace(int, char **);
static int zpool_do_scrub(int, char **);
static int zpool_do_import(int, char **);
static int zpool_do_export(int, char **);
/*
* These libumem hooks provide a reasonable set of defaults for the allocator's
* debugging facilities.
*/
const char *
{
return ("default,verbose"); /* $UMEM_DEBUG setting */
}
const char *
_umem_logging_init(void)
{
return ("fail,contents"); /* $UMEM_LOGGING setting */
}
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.
*/
static zpool_command_t command_table[] = {
{ 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 <pool> [device]\n"));
case HELP_CREATE:
return (gettext("\tcreate [-fn] [-R root] [-m mountpoint] "
"<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_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"));
case HELP_IOSTAT:
return (gettext("\tiostat [-v] [pool] ... [interval "
"[count]]\n"));
case HELP_LIST:
return (gettext("\tlist [-H] [-o field[,field]*] "
"[pool] ...\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_SCRUB:
return (gettext("\tscrub [-s] <pool> ...\n"));
case HELP_STATUS:
return (gettext("\tstatus [-vx] [pool] ...\n"));
}
abort();
/* NOTREACHED */
}
/*
* Fields available for 'zpool list'.
*/
typedef enum {
#define MAX_FIELDS 10
typedef struct column_def {
const char *cd_title;
enum {
} cd_justify;
} column_def_t;
static column_def_t column_table[] = {
};
static char *column_subopts[] = {
"name",
"size",
"used",
"available",
"capacity",
"health",
"root",
};
/*
* 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
{
int i;
if (current_command == NULL) {
int i;
gettext("where 'command' is one of the following:\n\n"));
for (i = 0; i < NCOMMAND; i++) {
else
}
} else {
"of the following:\n\n"));
for (i = 0; column_subopts[i] != NULL; i++)
}
}
}
const char *
{
case VDEV_STATE_CLOSED:
case VDEV_STATE_CANT_OPEN:
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
{
char *vname;
return;
for (c = 0; c < children; c++) {
}
}
/*
* 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);
ret = 0;
} else {
}
return (ret);
}
/*
* zpool create [-fn] [-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>'
*
* Creates the 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;
int ret;
char *mountpoint = NULL;
/* check options */
switch (c) {
case 'f':
break;
case 'n':
break;
case 'R':
break;
case 'm':
mountpoint = optarg;
break;
case ':':
"'%c' option\n"), optopt);
break;
case '?':
optopt);
}
}
/* get pool name and check number of arguments */
if (argc < 1) {
}
if (argc < 2) {
}
/*
* 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"));
return (1);
}
/* pass off to get_vdev_spec for bulk processing */
return (1);
"must be an absolute path\n"));
return (1);
}
/*
* 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 ||
char buf[MAXPATHLEN];
"'%s': must be an absolute path, 'legacy', or "
"'none'\n"), mountpoint);
return (1);
}
if (mountpoint == NULL) {
else
poolname);
} else {
else
}
if (mountpoint == NULL)
"mountpoint '%s' exists and is not "
"empty\n"), buf);
else
"'%s' exists and is not empty\n"), buf);
"option to provide a different default\n"));
return (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.
*
* XXZFS find out of we can create the pool?
*/
"following layout:\n\n"), poolname);
ret = 0;
} else {
ret = 1;
/*
* Hand off to libzfs.
*/
if (mountpoint != NULL)
mountpoint) == 0);
}
}
}
return (ret);
}
/*
* 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);
}
return (ret);
}
/*
* zpool export [-f] <pool> ...
*
* -f Forcefully unmount datasets
*
* Export the 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 '?':
optopt);
}
}
/* check arguments */
if (argc < 1) {
}
ret = 0;
for (i = 0; i < argc; i++) {
ret = 1;
continue;
}
ret = 1;
continue;
}
if (zpool_export(zhp) != 0)
ret = 1;
}
return (ret);
}
/*
* Given a vdev configuration, determine the maximum width needed for the device
* name column.
*/
static int
{
int ret;
return (max);
for (c = 0; c < children; c++)
return (max);
}
/*
* 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;
case VDEV_AUX_OPEN_FAILED:
break;
case VDEV_AUX_BAD_GUID_SUM:
break;
case VDEV_AUX_NO_REPLICAS:
break;
default:
break;
}
} else {
}
(void) printf("\n");
return;
for (c = 0; c < children; c++) {
}
}
/*
* Display the status for the given pool.
*/
static void
{
char *name;
char *msgid;
int reason;
char *health;
int namewidth;
&name) == 0);
&guid) == 0);
&pool_state) == 0);
&health) == 0);
&nvroot) == 0);
if (pool_state == POOL_STATE_DESTROYED)
(void) printf(" (DESTROYED)");
(void) printf("\n");
switch (reason) {
"from the system.\n"));
break;
"corrupted data.\n"));
break;
break;
case ZPOOL_STATUS_OFFLINE_DEV:
"are offlined.\n"));
break;
"corrupted.\n"));
break;
default:
/*
* No other status can be seen when importing pools.
*/
}
/*
* Print out an action according to the overall state of the pool.
*/
" using its name or numeric identifier."));
if (pool_state == POOL_STATE_DESTROYED)
"but can be imported using the '-Df' flags.\n"));
else if (pool_state != POOL_STATE_EXPORTED)
"on another system, but can be imported using\n\t"
"the '-f' flag.\n"));
else
(void) printf("\n");
"despite missing or damaged devices. The\n\tfault "
"tolerance of the pool may be compromised if imported."));
if (pool_state == POOL_STATE_DESTROYED)
"but can be imported using the '-Df' flags.\n"));
else if (pool_state != POOL_STATE_EXPORTED)
"on another system, but can be imported using\n\t"
"the '-f' flag.\n"));
else
(void) printf("\n");
} else {
if (reason == ZPOOL_STATUS_MISSING_DEV_R ||
"imported. Attach the missing\n\tdevices and try "
"again.\n"));
else
"imported due to damaged devices or data.\n"));
}
msgid);
if (namewidth < 10)
namewidth = 10;
if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
(void) printf("\n\tAdditional devices are known to "
"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(), and then mounts the datasets contained within
* the pool.
*/
static int
{
char *name;
&name) == 0);
ZPOOL_CONFIG_POOL_STATE, &state) == 0);
"may be in use from other system\n"), name);
return (1);
}
return (1);
return (1);
}
return (0);
}
/*
* zpool import [-d dir] [-D]
* import [-R root] [-D] [-d dir] [-f] -a
* import [-R root] [-D] [-d dir] [-f] <pool | id> [newpool]
*
* 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.
*
* -f Force import, even if it appears that the pool is active.
*
* -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
{
char **searchdirs = NULL;
int nsearch = 0;
int c;
int err;
int do_destroyed = FALSE;
char *searchname;
int first;
/* check options */
switch (c) {
case 'a':
break;
case 'd':
if (searchdirs == NULL) {
searchdirs = safe_malloc(sizeof (char *));
} else {
sizeof (char *));
sizeof (char *));
searchdirs = tmp;
}
break;
case 'D':
do_destroyed = TRUE;
break;
case 'f':
break;
case 'o':
break;
case 'R':
break;
case ':':
"'%c' option\n"), optopt);
break;
case '?':
optopt);
}
}
if (searchdirs == NULL) {
searchdirs = safe_malloc(sizeof (char *));
searchdirs[0] = "/dev/dsk";
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);
}
}
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
* 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];
else
searchname = NULL;
found_config = NULL;
}
err = 0;
&pool_state) == 0);
continue;
continue;
if (argc == 0) {
if (first)
else
(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_verbose;
int cb_iteration;
int cb_namewidth;
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 used avail read write read write\n",
}
/*
* Display a single statistic.
*/
void
{
char buf[64];
}
/*
* 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
{
vdev_stat_t zerovs = { 0 };
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++) {
}
}
static int
{
/*
* If the pool has disappeared, remove it from the list and continue.
*/
if (zpool_refresh_stats(zhp) != 0)
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
}
/*
* 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);
}
/*
* zpool iostat [-v] [pool] ... [interval [count]]
*
* -v Display statistics for individual vdevs
*
* 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 'v':
break;
case '?':
optopt);
}
}
/*
* 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 integer.
*/
char *end;
errno = 0;
if (interval == 0) {
"cannot be zero\n"));
}
/*
* Ignore the last parameter
*/
argc--;
} else {
interval = 0;
}
}
/*
* 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 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");
if (interval == 0)
break;
break;
}
return (ret);
}
typedef struct list_cbdata {
int cb_scripted;
int cb_first;
int cb_fields[MAX_FIELDS];
int cb_fieldcount;
/*
* Given a list of columns to display, output appropriate headers for each one.
*/
void
{
int i;
const char *fmt;
for (i = 0; i < count; i++) {
if (i != 0)
(void) printf(" ");
fmt = "%-*s";
else
fmt = "%*s";
}
(void) printf("\n");
}
int
{
int i;
char buf[ZPOOL_MAXNAMELEN];
const char *fmt;
if (!cbp->cb_scripted)
}
} else {
}
for (i = 0; i < cbp->cb_fieldcount; i++) {
if (i != 0) {
if (cbp->cb_scripted)
(void) printf("\t");
else
(void) printf(" ");
}
case ZPOOL_FIELD_NAME:
break;
case ZPOOL_FIELD_SIZE:
else
break;
case ZPOOL_FIELD_USED:
else
break;
case ZPOOL_FIELD_AVAILABLE:
else
break;
case ZPOOL_FIELD_CAPACITY:
} else {
capacity);
}
break;
case ZPOOL_FIELD_HEALTH:
} else {
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
&vsc) == 0);
sizeof (buf));
}
break;
case ZPOOL_FIELD_ROOT:
break;
}
if (cbp->cb_scripted)
else {
fmt = "%-*s";
else
fmt = "%*s";
}
}
(void) printf("\n");
return (0);
}
/*
* zpool list [-H] [-o field[,field]*] [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"
*
* 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;
list_cbdata_t cb = { 0 };
static char default_fields[] =
"name,size,used,available,capacity,health,root";
char *fields = default_fields;
char *value;
/* check options */
switch (c) {
case 'H':
break;
case 'o':
break;
case ':':
"'%c' option\n"), optopt);
break;
case '?':
optopt);
}
}
while (*fields != '\0') {
"properties given to -o option\n"));
}
"'%s'\n"), value);
}
cb.cb_fieldcount++;
}
return (0);
}
return (ret);
}
static nvlist_t *
{
char *path;
name += 9;
path += 9;
return (nv);
return (NULL);
}
for (c = 0; c < children; c++)
return (match);
return (NULL);
}
static int
{
int c;
/* 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);
}
}
/*
* 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;
/* 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);
}
/*
* zpool online <pool> <device> ...
*/
/* ARGSUSED */
int
{
int c, i;
char *poolname;
int ret = 0;
/* check options */
switch (c) {
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++)
argv[i]);
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;
/* 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++)
argv[i]);
else
ret = 1;
return (ret);
}
/*
* zpool clear <pool> [device]
*
* Clear all errors associated with a pool or a particular device.
*/
int
{
int ret = 0;
if (argc < 2) {
}
if (argc > 3) {
}
return (1);
ret = 1;
return (ret);
}
typedef struct scrub_cbdata {
int cb_type;
int
{
/*
* Ignore faulted pools.
*/
return (1);
}
}
/*
* 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_verbose;
int cb_explain;
int cb_count;
int cb_first;
/*
* Print out detailed scrub status.
*/
void
{
double fraction_done;
char *scrub_type;
/*
* If there's never been a scrub, there's not much to say.
*/
return;
}
"resilver" : "scrub";
if (end != 0) {
return;
}
if (examined == 0)
examined = 1;
}
/*
* Print out configuration state as requested by status_callback.
*/
void
{
char *vname;
children = 0;
¬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;
default:
break;
}
/*
* Report bytes resilvered/repaired on leaf devices.
*/
"resilvered" : "repaired");
}
(void) printf("\n");
for (c = 0; c < children; c++) {
}
}
static void
{
int i;
(void) printf("errors: List of errors unavailable "
"(insufficient privileges)\n");
return;
}
for (i = 0; i < nelem; i++) {
&dsname) == 0);
&objname) == 0);
if (len > maxobjname)
maxobjname = len;
}
(void) printf("errors: The following persistent errors have been "
"detected:\n\n");
for (i = 0; i < nelem; i++) {
&dsname) == 0);
&objname) == 0);
&range) == 0);
}
}
/*
* 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;
char *health;
/*
* If we were given 'zpool status -x', only report those pools with
* problems.
*/
return (0);
else
(void) printf("\n");
&health) == 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 the label is missing \n\tor invalid. "
"There are insufficient replicas for the pool to "
"continue\n\tfunctioning.\n"));
"from a backup source.\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 adminstrator.\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"));
"from a backup source.\n"));
break;
default:
/*
* The remaining errors can't actually be generated, yet.
*/
}
msgid);
int namewidth;
&nvroot) == 0);
if (namewidth < 10)
namewidth = 10;
"NAME", "STATE", "READ", "WRITE", "CKSUM");
namewidth, 0);
&nerr) == 0) {
/*
* If the approximate error count is small, get a
* precise count by fetching the entire log and
* uniquifying the results.
*/
(void) printf("\n");
if (nerr == 0)
"errors\n"));
else if (!cbp->cb_verbose)
"use '-v' for a list\n"), nerr);
else
}
} else {
"determined.\n"));
}
return (0);
}
/*
* zpool status [-vx] [pool] ...
*
* -v Display complete error logs
* -x Display only pools with potential problems
*
* Describes the health status of all pools or some subset.
*/
int
{
int c;
int ret;
status_cbdata_t cb = { 0 };
/* check options */
switch (c) {
case 'v':
break;
case 'x':
break;
case '?':
optopt);
}
}
if (argc == 0) {
} else {
int i;
for (i = 0; i < argc; i++)
argv[i]);
}
}
return (ret);
}
int
{
int ret;
int i;
char *cmdname;
(void) textdomain(TEXT_DOMAIN);
opterr = 0;
/*
* Make sure the user has specified some command.
*/
if (argc < 2) {
}
/*
* Special case '-?'
*/
/*
* Run the appropriate command.
*/
for (i = 0; i < NCOMMAND; i++) {
continue;
current_command = &command_table[i];
break;
}
}
/*
* 'freeze' is a vile debugging abomination, so we treat it as such.
*/
char buf[16384];
}
if (i == NCOMMAND) {
"command '%s'\n"), cmdname);
}
/*
* 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);
}