1789Sahrens /*
2789Sahrens * CDDL HEADER START
3789Sahrens *
4789Sahrens * The contents of this file are subject to the terms of the
51485Slling * Common Development and Distribution License (the "License").
61485Slling * You may not use this file except in compliance with the License.
7789Sahrens *
8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens * or http://www.opensolaris.org/os/licensing.
10789Sahrens * See the License for the specific language governing permissions
11789Sahrens * and limitations under the License.
12789Sahrens *
13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens *
19789Sahrens * CDDL HEADER END
20789Sahrens */
212082Seschrock
22789Sahrens /*
2312296SLin.Ling@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24789Sahrens */
25789Sahrens
26789Sahrens #include <assert.h>
27789Sahrens #include <ctype.h>
28789Sahrens #include <dirent.h>
29789Sahrens #include <errno.h>
30789Sahrens #include <fcntl.h>
31789Sahrens #include <libgen.h>
32789Sahrens #include <libintl.h>
33789Sahrens #include <libuutil.h>
34789Sahrens #include <locale.h>
35789Sahrens #include <stdio.h>
36789Sahrens #include <stdlib.h>
37789Sahrens #include <string.h>
38789Sahrens #include <strings.h>
39789Sahrens #include <unistd.h>
40789Sahrens #include <priv.h>
414543Smarks #include <pwd.h>
424543Smarks #include <zone.h>
433912Slling #include <sys/fs/zfs.h>
44789Sahrens #include <sys/stat.h>
45789Sahrens
46789Sahrens #include <libzfs.h>
47789Sahrens
48789Sahrens #include "zpool_util.h"
495913Sperrin #include "zfs_comutil.h"
50789Sahrens
5110265SKrishnendu.Sadhukhan@Sun.COM #include "statcommon.h"
5210265SKrishnendu.Sadhukhan@Sun.COM
53789Sahrens static int zpool_do_create(int, char **);
54789Sahrens static int zpool_do_destroy(int, char **);
55789Sahrens
56789Sahrens static int zpool_do_add(int, char **);
572082Seschrock static int zpool_do_remove(int, char **);
58789Sahrens
59789Sahrens static int zpool_do_list(int, char **);
60789Sahrens static int zpool_do_iostat(int, char **);
61789Sahrens static int zpool_do_status(int, char **);
62789Sahrens
63789Sahrens static int zpool_do_online(int, char **);
64789Sahrens static int zpool_do_offline(int, char **);
651544Seschrock static int zpool_do_clear(int, char **);
66789Sahrens
67789Sahrens static int zpool_do_attach(int, char **);
68789Sahrens static int zpool_do_detach(int, char **);
69789Sahrens static int zpool_do_replace(int, char **);
7011422SMark.Musante@Sun.COM static int zpool_do_split(int, char **);
71789Sahrens
72789Sahrens static int zpool_do_scrub(int, char **);
73789Sahrens
74789Sahrens static int zpool_do_import(int, char **);
75789Sahrens static int zpool_do_export(int, char **);
76789Sahrens
771760Seschrock static int zpool_do_upgrade(int, char **);
781760Seschrock
792926Sek110237 static int zpool_do_history(int, char **);
802926Sek110237
813912Slling static int zpool_do_get(int, char **);
823912Slling static int zpool_do_set(int, char **);
833912Slling
84789Sahrens /*
85789Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's
86789Sahrens * debugging facilities.
87789Sahrens */
886865Srm160521
896865Srm160521 #ifdef DEBUG
90789Sahrens const char *
_umem_debug_init(void)912082Seschrock _umem_debug_init(void)
92789Sahrens {
93789Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */
94789Sahrens }
95789Sahrens
96789Sahrens const char *
_umem_logging_init(void)97789Sahrens _umem_logging_init(void)
98789Sahrens {
99789Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */
100789Sahrens }
1016865Srm160521 #endif
102789Sahrens
1031387Seschrock typedef enum {
1041387Seschrock HELP_ADD,
1051387Seschrock HELP_ATTACH,
1061544Seschrock HELP_CLEAR,
1071387Seschrock HELP_CREATE,
1081387Seschrock HELP_DESTROY,
1091387Seschrock HELP_DETACH,
1101387Seschrock HELP_EXPORT,
1112926Sek110237 HELP_HISTORY,
1121387Seschrock HELP_IMPORT,
1131387Seschrock HELP_IOSTAT,
1141387Seschrock HELP_LIST,
1151387Seschrock HELP_OFFLINE,
1161387Seschrock HELP_ONLINE,
1171387Seschrock HELP_REPLACE,
1182082Seschrock HELP_REMOVE,
1191387Seschrock HELP_SCRUB,
1201760Seschrock HELP_STATUS,
1213912Slling HELP_UPGRADE,
1223912Slling HELP_GET,
12311422SMark.Musante@Sun.COM HELP_SET,
12411422SMark.Musante@Sun.COM HELP_SPLIT
1251387Seschrock } zpool_help_t;
1261387Seschrock
1271387Seschrock
128789Sahrens typedef struct zpool_command {
129789Sahrens const char *name;
130789Sahrens int (*func)(int, char **);
1311387Seschrock zpool_help_t usage;
132789Sahrens } zpool_command_t;
133789Sahrens
134789Sahrens /*
135789Sahrens * Master command table. Each ZFS command has a name, associated function, and
1361544Seschrock * usage message. The usage messages need to be internationalized, so we have
1371544Seschrock * to have a function to return the usage message based on a command index.
1381387Seschrock *
1391387Seschrock * These commands are organized according to how they are displayed in the usage
1401387Seschrock * message. An empty command (one with a NULL name) indicates an empty line in
1411387Seschrock * the generic usage message.
142789Sahrens */
143789Sahrens static zpool_command_t command_table[] = {
1441387Seschrock { "create", zpool_do_create, HELP_CREATE },
1451387Seschrock { "destroy", zpool_do_destroy, HELP_DESTROY },
146789Sahrens { NULL },
1471387Seschrock { "add", zpool_do_add, HELP_ADD },
1482082Seschrock { "remove", zpool_do_remove, HELP_REMOVE },
149789Sahrens { NULL },
1501387Seschrock { "list", zpool_do_list, HELP_LIST },
1511387Seschrock { "iostat", zpool_do_iostat, HELP_IOSTAT },
1521387Seschrock { "status", zpool_do_status, HELP_STATUS },
153789Sahrens { NULL },
1541387Seschrock { "online", zpool_do_online, HELP_ONLINE },
1551387Seschrock { "offline", zpool_do_offline, HELP_OFFLINE },
1561544Seschrock { "clear", zpool_do_clear, HELP_CLEAR },
157789Sahrens { NULL },
1581387Seschrock { "attach", zpool_do_attach, HELP_ATTACH },
1591387Seschrock { "detach", zpool_do_detach, HELP_DETACH },
1601387Seschrock { "replace", zpool_do_replace, HELP_REPLACE },
16111422SMark.Musante@Sun.COM { "split", zpool_do_split, HELP_SPLIT },
162789Sahrens { NULL },
1631387Seschrock { "scrub", zpool_do_scrub, HELP_SCRUB },
1641387Seschrock { NULL },
1651387Seschrock { "import", zpool_do_import, HELP_IMPORT },
1661387Seschrock { "export", zpool_do_export, HELP_EXPORT },
1672926Sek110237 { "upgrade", zpool_do_upgrade, HELP_UPGRADE },
1682926Sek110237 { NULL },
1693912Slling { "history", zpool_do_history, HELP_HISTORY },
1703912Slling { "get", zpool_do_get, HELP_GET },
1713912Slling { "set", zpool_do_set, HELP_SET },
172789Sahrens };
173789Sahrens
174789Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
175789Sahrens
176789Sahrens zpool_command_t *current_command;
1774988Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
178789Sahrens
17910265SKrishnendu.Sadhukhan@Sun.COM static uint_t timestamp_fmt = NODATE;
18010265SKrishnendu.Sadhukhan@Sun.COM
1811387Seschrock static const char *
get_usage(zpool_help_t idx)1821387Seschrock get_usage(zpool_help_t idx) {
1831387Seschrock switch (idx) {
1841387Seschrock case HELP_ADD:
1851387Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
1861387Seschrock case HELP_ATTACH:
1871387Seschrock return (gettext("\tattach [-f] <pool> <device> "
1884849Sahrens "<new-device>\n"));
1891544Seschrock case HELP_CLEAR:
19010921STim.Haley@Sun.COM return (gettext("\tclear [-nF] <pool> [device]\n"));
1911387Seschrock case HELP_CREATE:
1925094Slling return (gettext("\tcreate [-fn] [-o property=value] ... \n"
1937184Stimh "\t [-O file-system-property=value] ... \n"
1945094Slling "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
1951387Seschrock case HELP_DESTROY:
1961387Seschrock return (gettext("\tdestroy [-f] <pool>\n"));
1971387Seschrock case HELP_DETACH:
1981387Seschrock return (gettext("\tdetach <pool> <device>\n"));
1991387Seschrock case HELP_EXPORT:
2001387Seschrock return (gettext("\texport [-f] <pool> ...\n"));
2012926Sek110237 case HELP_HISTORY:
2024543Smarks return (gettext("\thistory [-il] [<pool>] ...\n"));
2031387Seschrock case HELP_IMPORT:
2041631Sdarrenm return (gettext("\timport [-d dir] [-D]\n"
20513049SGeorge.Wilson@Sun.COM "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
2065363Seschrock "\timport [-o mntopts] [-o property=value] ... \n"
20713049SGeorge.Wilson@Sun.COM "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
20813049SGeorge.Wilson@Sun.COM "[-R root] [-F [-n]] -a\n"
2095363Seschrock "\timport [-o mntopts] [-o property=value] ... \n"
21013049SGeorge.Wilson@Sun.COM "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
21113049SGeorge.Wilson@Sun.COM "[-R root] [-F [-n]]\n"
21213049SGeorge.Wilson@Sun.COM "\t <pool | id> [newpool]\n"));
2131387Seschrock case HELP_IOSTAT:
21410265SKrishnendu.Sadhukhan@Sun.COM return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
2151387Seschrock "[count]]\n"));
2161387Seschrock case HELP_LIST:
2175094Slling return (gettext("\tlist [-H] [-o property[,...]] "
21812296SLin.Ling@Sun.COM "[-T d|u] [pool] ... [interval [count]]\n"));
2191387Seschrock case HELP_OFFLINE:
2201485Slling return (gettext("\toffline [-t] <pool> <device> ...\n"));
2211387Seschrock case HELP_ONLINE:
2221485Slling return (gettext("\tonline <pool> <device> ...\n"));
2231387Seschrock case HELP_REPLACE:
2241387Seschrock return (gettext("\treplace [-f] <pool> <device> "
2254849Sahrens "[new-device]\n"));
2262082Seschrock case HELP_REMOVE:
2275450Sbrendan return (gettext("\tremove <pool> <device> ...\n"));
2281387Seschrock case HELP_SCRUB:
2291387Seschrock return (gettext("\tscrub [-s] <pool> ...\n"));
2301387Seschrock case HELP_STATUS:
23112296SLin.Ling@Sun.COM return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
23212296SLin.Ling@Sun.COM "[count]]\n"));
2331760Seschrock case HELP_UPGRADE:
2341760Seschrock return (gettext("\tupgrade\n"
2351760Seschrock "\tupgrade -v\n"
2365094Slling "\tupgrade [-V version] <-a | pool ...>\n"));
2373912Slling case HELP_GET:
2384849Sahrens return (gettext("\tget <\"all\" | property[,...]> "
2393912Slling "<pool> ...\n"));
2403912Slling case HELP_SET:
2413912Slling return (gettext("\tset <property=value> <pool> \n"));
24211422SMark.Musante@Sun.COM case HELP_SPLIT:
24311422SMark.Musante@Sun.COM return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
24411422SMark.Musante@Sun.COM "\t [-o property=value] <pool> <newpool> "
24511422SMark.Musante@Sun.COM "[<device> ...]\n"));
2461387Seschrock }
2471387Seschrock
2481387Seschrock abort();
2491387Seschrock /* NOTREACHED */
2501387Seschrock }
2511387Seschrock
252789Sahrens
253789Sahrens /*
2543912Slling * Callback routine that will print out a pool property value.
2553912Slling */
2565094Slling static int
print_prop_cb(int prop,void * cb)2575094Slling print_prop_cb(int prop, void *cb)
2583912Slling {
2593912Slling FILE *fp = cb;
2603912Slling
26110922SJeff.Bonwick@Sun.COM (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop));
2623912Slling
2635094Slling if (zpool_prop_readonly(prop))
2645094Slling (void) fprintf(fp, " NO ");
2655094Slling else
26610922SJeff.Bonwick@Sun.COM (void) fprintf(fp, " YES ");
2675094Slling
2683912Slling if (zpool_prop_values(prop) == NULL)
2693912Slling (void) fprintf(fp, "-\n");
2703912Slling else
2713912Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop));
2723912Slling
2735094Slling return (ZPROP_CONT);
2743912Slling }
2753912Slling
2763912Slling /*
277789Sahrens * Display usage message. If we're inside a command, display only the usage for
278789Sahrens * that command. Otherwise, iterate over the entire command table and display
279789Sahrens * a complete usage message.
280789Sahrens */
281789Sahrens void
usage(boolean_t requested)2822082Seschrock usage(boolean_t requested)
283789Sahrens {
284789Sahrens FILE *fp = requested ? stdout : stderr;
285789Sahrens
286789Sahrens if (current_command == NULL) {
287789Sahrens int i;
288789Sahrens
289789Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n"));
290789Sahrens (void) fprintf(fp,
291789Sahrens gettext("where 'command' is one of the following:\n\n"));
292789Sahrens
293789Sahrens for (i = 0; i < NCOMMAND; i++) {
294789Sahrens if (command_table[i].name == NULL)
295789Sahrens (void) fprintf(fp, "\n");
296789Sahrens else
297789Sahrens (void) fprintf(fp, "%s",
2981387Seschrock get_usage(command_table[i].usage));
299789Sahrens }
300789Sahrens } else {
301789Sahrens (void) fprintf(fp, gettext("usage:\n"));
3021387Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage));
303789Sahrens }
304789Sahrens
3053912Slling if (current_command != NULL &&
3063912Slling ((strcmp(current_command->name, "set") == 0) ||
3075094Slling (strcmp(current_command->name, "get") == 0) ||
3085094Slling (strcmp(current_command->name, "list") == 0))) {
3093912Slling
3103912Slling (void) fprintf(fp,
3113912Slling gettext("\nthe following properties are supported:\n"));
3123912Slling
31310922SJeff.Bonwick@Sun.COM (void) fprintf(fp, "\n\t%-15s %s %s\n\n",
3145094Slling "PROPERTY", "EDIT", "VALUES");
3153912Slling
3163912Slling /* Iterate over all properties */
3175094Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
3185094Slling ZFS_TYPE_POOL);
3193912Slling }
3203912Slling
3212676Seschrock /*
3222676Seschrock * See comments at end of main().
3232676Seschrock */
3242676Seschrock if (getenv("ZFS_ABORT") != NULL) {
3252676Seschrock (void) printf("dumping core by request\n");
3262676Seschrock abort();
3272676Seschrock }
3282676Seschrock
329789Sahrens exit(requested ? 0 : 2);
330789Sahrens }
331789Sahrens
332789Sahrens void
print_vdev_tree(zpool_handle_t * zhp,const char * name,nvlist_t * nv,int indent,boolean_t print_logs)3334527Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3344527Sperrin boolean_t print_logs)
335789Sahrens {
336789Sahrens nvlist_t **child;
337789Sahrens uint_t c, children;
3381171Seschrock char *vname;
339789Sahrens
340789Sahrens if (name != NULL)
341789Sahrens (void) printf("\t%*s%s\n", indent, "", name);
342789Sahrens
343789Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
344789Sahrens &child, &children) != 0)
345789Sahrens return;
346789Sahrens
3471171Seschrock for (c = 0; c < children; c++) {
3484527Sperrin uint64_t is_log = B_FALSE;
3494527Sperrin
3504527Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3514527Sperrin &is_log);
3524527Sperrin if ((is_log && !print_logs) || (!is_log && print_logs))
3534527Sperrin continue;
3544527Sperrin
35510594SGeorge.Wilson@Sun.COM vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3564527Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2,
3574527Sperrin B_FALSE);
3581171Seschrock free(vname);
3591171Seschrock }
360789Sahrens }
361789Sahrens
362789Sahrens /*
3635094Slling * Add a property pair (name, string-value) into a property nvlist.
3645094Slling */
3655094Slling static int
add_prop_list(const char * propname,char * propval,nvlist_t ** props,boolean_t poolprop)3667184Stimh add_prop_list(const char *propname, char *propval, nvlist_t **props,
3677184Stimh boolean_t poolprop)
3685094Slling {
3697184Stimh zpool_prop_t prop = ZPROP_INVAL;
3707184Stimh zfs_prop_t fprop;
3717184Stimh nvlist_t *proplist;
3727184Stimh const char *normnm;
3735094Slling char *strval;
3745094Slling
3755094Slling if (*props == NULL &&
3765094Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
3775094Slling (void) fprintf(stderr,
3785094Slling gettext("internal error: out of memory\n"));
3795094Slling return (1);
3805094Slling }
3815094Slling
3825094Slling proplist = *props;
3835094Slling
3847184Stimh if (poolprop) {
3857184Stimh if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
3867184Stimh (void) fprintf(stderr, gettext("property '%s' is "
3877184Stimh "not a valid pool property\n"), propname);
3887184Stimh return (2);
3897184Stimh }
3907184Stimh normnm = zpool_prop_to_name(prop);
3917184Stimh } else {
3929396SMatthew.Ahrens@Sun.COM if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
3939396SMatthew.Ahrens@Sun.COM normnm = zfs_prop_to_name(fprop);
3949396SMatthew.Ahrens@Sun.COM } else {
3959396SMatthew.Ahrens@Sun.COM normnm = propname;
3967184Stimh }
3975094Slling }
3985094Slling
3997184Stimh if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
4007184Stimh prop != ZPOOL_PROP_CACHEFILE) {
4015094Slling (void) fprintf(stderr, gettext("property '%s' "
4025094Slling "specified multiple times\n"), propname);
4035094Slling return (2);
4045094Slling }
4055094Slling
4067184Stimh if (nvlist_add_string(proplist, normnm, propval) != 0) {
4075094Slling (void) fprintf(stderr, gettext("internal "
4085094Slling "error: out of memory\n"));
4095094Slling return (1);
4105094Slling }
4115094Slling
4125094Slling return (0);
4135094Slling }
4145094Slling
4155094Slling /*
416789Sahrens * zpool add [-fn] <pool> <vdev> ...
417789Sahrens *
418789Sahrens * -f Force addition of devices, even if they appear in use
419789Sahrens * -n Do not add the devices, but display the resulting layout if
420789Sahrens * they were to be added.
421789Sahrens *
422789Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is
423789Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
424789Sahrens * libzfs.
425789Sahrens */
426789Sahrens int
zpool_do_add(int argc,char ** argv)427789Sahrens zpool_do_add(int argc, char **argv)
428789Sahrens {
4292082Seschrock boolean_t force = B_FALSE;
4302082Seschrock boolean_t dryrun = B_FALSE;
431789Sahrens int c;
432789Sahrens nvlist_t *nvroot;
433789Sahrens char *poolname;
434789Sahrens int ret;
435789Sahrens zpool_handle_t *zhp;
436789Sahrens nvlist_t *config;
437789Sahrens
438789Sahrens /* check options */
439789Sahrens while ((c = getopt(argc, argv, "fn")) != -1) {
440789Sahrens switch (c) {
441789Sahrens case 'f':
4422082Seschrock force = B_TRUE;
443789Sahrens break;
444789Sahrens case 'n':
4452082Seschrock dryrun = B_TRUE;
446789Sahrens break;
447789Sahrens case '?':
448789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
449789Sahrens optopt);
4502082Seschrock usage(B_FALSE);
451789Sahrens }
452789Sahrens }
453789Sahrens
454789Sahrens argc -= optind;
455789Sahrens argv += optind;
456789Sahrens
457789Sahrens /* get pool name and check number of arguments */
458789Sahrens if (argc < 1) {
459789Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n"));
4602082Seschrock usage(B_FALSE);
461789Sahrens }
462789Sahrens if (argc < 2) {
463789Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n"));
4642082Seschrock usage(B_FALSE);
465789Sahrens }
466789Sahrens
467789Sahrens poolname = argv[0];
468789Sahrens
469789Sahrens argc--;
470789Sahrens argv++;
471789Sahrens
4722082Seschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
473789Sahrens return (1);
474789Sahrens
475952Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) {
476789Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
477789Sahrens poolname);
478789Sahrens zpool_close(zhp);
479789Sahrens return (1);
480789Sahrens }
481789Sahrens
482789Sahrens /* pass off to get_vdev_spec for processing */
4837343SEric.Taylor@Sun.COM nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
4847343SEric.Taylor@Sun.COM argc, argv);
485789Sahrens if (nvroot == NULL) {
486789Sahrens zpool_close(zhp);
487789Sahrens return (1);
488789Sahrens }
489789Sahrens
490789Sahrens if (dryrun) {
491789Sahrens nvlist_t *poolnvroot;
492789Sahrens
493789Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
494789Sahrens &poolnvroot) == 0);
495789Sahrens
496789Sahrens (void) printf(gettext("would update '%s' to the following "
497789Sahrens "configuration:\n"), zpool_get_name(zhp));
498789Sahrens
4994527Sperrin /* print original main pool and new tree */
5004527Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
5014527Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
5024527Sperrin
5034527Sperrin /* Do the same for the logs */
5044527Sperrin if (num_logs(poolnvroot) > 0) {
5054527Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
5064527Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
5074527Sperrin } else if (num_logs(nvroot) > 0) {
5084527Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
5094527Sperrin }
510789Sahrens
511789Sahrens ret = 0;
512789Sahrens } else {
513789Sahrens ret = (zpool_add(zhp, nvroot) != 0);
514789Sahrens }
515789Sahrens
5162082Seschrock nvlist_free(nvroot);
5172082Seschrock zpool_close(zhp);
5182082Seschrock
5192082Seschrock return (ret);
5202082Seschrock }
5212082Seschrock
5222082Seschrock /*
52312296SLin.Ling@Sun.COM * zpool remove <pool> <vdev> ...
5242082Seschrock *
52512296SLin.Ling@Sun.COM * Removes the given vdev from the pool. Currently, this supports removing
52612296SLin.Ling@Sun.COM * spares, cache, and log devices from the pool.
5272082Seschrock */
5282082Seschrock int
zpool_do_remove(int argc,char ** argv)5292082Seschrock zpool_do_remove(int argc, char **argv)
5302082Seschrock {
5312082Seschrock char *poolname;
5325450Sbrendan int i, ret = 0;
5332082Seschrock zpool_handle_t *zhp;
5342082Seschrock
5352082Seschrock argc--;
5362082Seschrock argv++;
5372082Seschrock
5382082Seschrock /* get pool name and check number of arguments */
5392082Seschrock if (argc < 1) {
5402082Seschrock (void) fprintf(stderr, gettext("missing pool name argument\n"));
5412082Seschrock usage(B_FALSE);
5422082Seschrock }
5432082Seschrock if (argc < 2) {
5442082Seschrock (void) fprintf(stderr, gettext("missing device\n"));
5452082Seschrock usage(B_FALSE);
5462082Seschrock }
5472082Seschrock
5482082Seschrock poolname = argv[0];
5492082Seschrock
5502082Seschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
5512082Seschrock return (1);
5522082Seschrock
5535450Sbrendan for (i = 1; i < argc; i++) {
5545450Sbrendan if (zpool_vdev_remove(zhp, argv[i]) != 0)
5555450Sbrendan ret = 1;
5565450Sbrendan }
5572082Seschrock
558789Sahrens return (ret);
559789Sahrens }
560789Sahrens
561789Sahrens /*
5627184Stimh * zpool create [-fn] [-o property=value] ...
5637184Stimh * [-O file-system-property=value] ...
5647184Stimh * [-R root] [-m mountpoint] <pool> <dev> ...
565789Sahrens *
566789Sahrens * -f Force creation, even if devices appear in use
567789Sahrens * -n Do not create the pool, but display the resulting layout if it
568789Sahrens * were to be created.
569789Sahrens * -R Create a pool under an alternate root
570789Sahrens * -m Set default mountpoint for the root dataset. By default it's
571789Sahrens * '/<pool>'
5725094Slling * -o Set property=value.
5737184Stimh * -O Set fsproperty=value in the pool's root file system
574789Sahrens *
5753912Slling * Creates the named pool according to the given vdev specification. The
576789Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once
577789Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents
578789Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation.
579789Sahrens */
580789Sahrens int
zpool_do_create(int argc,char ** argv)581789Sahrens zpool_do_create(int argc, char **argv)
582789Sahrens {
5832082Seschrock boolean_t force = B_FALSE;
5842082Seschrock boolean_t dryrun = B_FALSE;
585789Sahrens int c;
5865094Slling nvlist_t *nvroot = NULL;
587789Sahrens char *poolname;
5885094Slling int ret = 1;
589789Sahrens char *altroot = NULL;
590789Sahrens char *mountpoint = NULL;
5917184Stimh nvlist_t *fsprops = NULL;
5925094Slling nvlist_t *props = NULL;
5935363Seschrock char *propval;
594789Sahrens
595789Sahrens /* check options */
5967184Stimh while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
597789Sahrens switch (c) {
598789Sahrens case 'f':
5992082Seschrock force = B_TRUE;
600789Sahrens break;
601789Sahrens case 'n':
6022082Seschrock dryrun = B_TRUE;
603789Sahrens break;
604789Sahrens case 'R':
605789Sahrens altroot = optarg;
6065094Slling if (add_prop_list(zpool_prop_to_name(
6077184Stimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
6085094Slling goto errout;
6095363Seschrock if (nvlist_lookup_string(props,
6105363Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
6115363Seschrock &propval) == 0)
6125363Seschrock break;
6135094Slling if (add_prop_list(zpool_prop_to_name(
6147184Stimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
6155094Slling goto errout;
616789Sahrens break;
617789Sahrens case 'm':
618789Sahrens mountpoint = optarg;
619789Sahrens break;
6205094Slling case 'o':
6215094Slling if ((propval = strchr(optarg, '=')) == NULL) {
6225094Slling (void) fprintf(stderr, gettext("missing "
6235094Slling "'=' for -o option\n"));
6245094Slling goto errout;
6255094Slling }
6265094Slling *propval = '\0';
6275094Slling propval++;
6285094Slling
6297184Stimh if (add_prop_list(optarg, propval, &props, B_TRUE))
6307184Stimh goto errout;
6317184Stimh break;
6327184Stimh case 'O':
6337184Stimh if ((propval = strchr(optarg, '=')) == NULL) {
6347184Stimh (void) fprintf(stderr, gettext("missing "
6357184Stimh "'=' for -O option\n"));
6367184Stimh goto errout;
6377184Stimh }
6387184Stimh *propval = '\0';
6397184Stimh propval++;
6407184Stimh
6417184Stimh if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
6425094Slling goto errout;
6435094Slling break;
644789Sahrens case ':':
645789Sahrens (void) fprintf(stderr, gettext("missing argument for "
646789Sahrens "'%c' option\n"), optopt);
6475094Slling goto badusage;
648789Sahrens case '?':
649789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
650789Sahrens optopt);
6515094Slling goto badusage;
652789Sahrens }
653789Sahrens }
654789Sahrens
655789Sahrens argc -= optind;
656789Sahrens argv += optind;
657789Sahrens
658789Sahrens /* get pool name and check number of arguments */
659789Sahrens if (argc < 1) {
660789Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n"));
6615094Slling goto badusage;
662789Sahrens }
663789Sahrens if (argc < 2) {
664789Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n"));
6655094Slling goto badusage;
666789Sahrens }
667789Sahrens
668789Sahrens poolname = argv[0];
669789Sahrens
670789Sahrens /*
671789Sahrens * As a special case, check for use of '/' in the name, and direct the
672789Sahrens * user to use 'zfs create' instead.
673789Sahrens */
674789Sahrens if (strchr(poolname, '/') != NULL) {
675789Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid "
676789Sahrens "character '/' in pool name\n"), poolname);
677789Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to "
678789Sahrens "create a dataset\n"));
6795094Slling goto errout;
680789Sahrens }
681789Sahrens
682789Sahrens /* pass off to get_vdev_spec for bulk processing */
6837343SEric.Taylor@Sun.COM nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
6847343SEric.Taylor@Sun.COM argc - 1, argv + 1);
685789Sahrens if (nvroot == NULL)
6867184Stimh goto errout;
687789Sahrens
6882082Seschrock /* make_root_vdev() allows 0 toplevel children if there are spares */
6895913Sperrin if (!zfs_allocatable_devs(nvroot)) {
6902082Seschrock (void) fprintf(stderr, gettext("invalid vdev "
6912082Seschrock "specification: at least one toplevel vdev must be "
6922082Seschrock "specified\n"));
6935094Slling goto errout;
6942082Seschrock }
6952082Seschrock
6962082Seschrock
697789Sahrens if (altroot != NULL && altroot[0] != '/') {
698789Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': "
6992676Seschrock "must be an absolute path\n"), altroot);
7005094Slling goto errout;
701789Sahrens }
702789Sahrens
703789Sahrens /*
704789Sahrens * Check the validity of the mountpoint and direct the user to use the
705789Sahrens * '-m' mountpoint option if it looks like its in use.
706789Sahrens */
707789Sahrens if (mountpoint == NULL ||
708789Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
709789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
710789Sahrens char buf[MAXPATHLEN];
7115904Stimh DIR *dirp;
712789Sahrens
713789Sahrens if (mountpoint && mountpoint[0] != '/') {
714789Sahrens (void) fprintf(stderr, gettext("invalid mountpoint "
715789Sahrens "'%s': must be an absolute path, 'legacy', or "
716789Sahrens "'none'\n"), mountpoint);
7175094Slling goto errout;
718789Sahrens }
719789Sahrens
720789Sahrens if (mountpoint == NULL) {
721789Sahrens if (altroot != NULL)
722789Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s",
723789Sahrens altroot, poolname);
724789Sahrens else
725789Sahrens (void) snprintf(buf, sizeof (buf), "/%s",
726789Sahrens poolname);
727789Sahrens } else {
728789Sahrens if (altroot != NULL)
729789Sahrens (void) snprintf(buf, sizeof (buf), "%s%s",
730789Sahrens altroot, mountpoint);
731789Sahrens else
732789Sahrens (void) snprintf(buf, sizeof (buf), "%s",
733789Sahrens mountpoint);
734789Sahrens }
735789Sahrens
7365904Stimh if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
7375904Stimh (void) fprintf(stderr, gettext("mountpoint '%s' : "
7385904Stimh "%s\n"), buf, strerror(errno));
739789Sahrens (void) fprintf(stderr, gettext("use '-m' "
740789Sahrens "option to provide a different default\n"));
7415094Slling goto errout;
7425904Stimh } else if (dirp) {
7435904Stimh int count = 0;
7445904Stimh
7455904Stimh while (count < 3 && readdir(dirp) != NULL)
7465904Stimh count++;
7475904Stimh (void) closedir(dirp);
7485904Stimh
7495904Stimh if (count > 2) {
7505904Stimh (void) fprintf(stderr, gettext("mountpoint "
7515904Stimh "'%s' exists and is not empty\n"), buf);
7525904Stimh (void) fprintf(stderr, gettext("use '-m' "
7535904Stimh "option to provide a "
7545904Stimh "different default\n"));
7555904Stimh goto errout;
7565904Stimh }
757789Sahrens }
758789Sahrens }
759789Sahrens
760789Sahrens if (dryrun) {
761789Sahrens /*
762789Sahrens * For a dry run invocation, print out a basic message and run
763789Sahrens * through all the vdevs in the list and print out in an
764789Sahrens * appropriate hierarchy.
765789Sahrens */
766789Sahrens (void) printf(gettext("would create '%s' with the "
767789Sahrens "following layout:\n\n"), poolname);
768789Sahrens
7694527Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7704527Sperrin if (num_logs(nvroot) > 0)
7714527Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
772789Sahrens
773789Sahrens ret = 0;
774789Sahrens } else {
775789Sahrens /*
776789Sahrens * Hand off to libzfs.
777789Sahrens */
7787184Stimh if (zpool_create(g_zfs, poolname,
7797184Stimh nvroot, props, fsprops) == 0) {
7802082Seschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname,
781789Sahrens ZFS_TYPE_FILESYSTEM);
782789Sahrens if (pool != NULL) {
783789Sahrens if (mountpoint != NULL)
784789Sahrens verify(zfs_prop_set(pool,
7852676Seschrock zfs_prop_to_name(
7862676Seschrock ZFS_PROP_MOUNTPOINT),
787789Sahrens mountpoint) == 0);
788789Sahrens if (zfs_mount(pool, NULL, 0) == 0)
7895331Samw ret = zfs_shareall(pool);
790789Sahrens zfs_close(pool);
791789Sahrens }
7922082Seschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
7932082Seschrock (void) fprintf(stderr, gettext("pool name may have "
7942082Seschrock "been omitted\n"));
795789Sahrens }
796789Sahrens }
797789Sahrens
7985094Slling errout:
7995363Seschrock nvlist_free(nvroot);
8007184Stimh nvlist_free(fsprops);
8015363Seschrock nvlist_free(props);
802789Sahrens return (ret);
8035094Slling badusage:
8047184Stimh nvlist_free(fsprops);
8055094Slling nvlist_free(props);
8065094Slling usage(B_FALSE);
8075094Slling return (2);
808789Sahrens }
809789Sahrens
810789Sahrens /*
811789Sahrens * zpool destroy <pool>
812789Sahrens *
813789Sahrens * -f Forcefully unmount any datasets
814789Sahrens *
815789Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool.
816789Sahrens */
817789Sahrens int
zpool_do_destroy(int argc,char ** argv)818789Sahrens zpool_do_destroy(int argc, char **argv)
819789Sahrens {
8202082Seschrock boolean_t force = B_FALSE;
821789Sahrens int c;
822789Sahrens char *pool;
823789Sahrens zpool_handle_t *zhp;
824789Sahrens int ret;
825789Sahrens
826789Sahrens /* check options */
827789Sahrens while ((c = getopt(argc, argv, "f")) != -1) {
828789Sahrens switch (c) {
829789Sahrens case 'f':
8302082Seschrock force = B_TRUE;
831789Sahrens break;
832789Sahrens case '?':
833789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
834789Sahrens optopt);
8352082Seschrock usage(B_FALSE);
836789Sahrens }
837789Sahrens }
838789Sahrens
839789Sahrens argc -= optind;
840789Sahrens argv += optind;
841789Sahrens
842789Sahrens /* check arguments */
843789Sahrens if (argc < 1) {
844789Sahrens (void) fprintf(stderr, gettext("missing pool argument\n"));
8452082Seschrock usage(B_FALSE);
846789Sahrens }
847789Sahrens if (argc > 1) {
848789Sahrens (void) fprintf(stderr, gettext("too many arguments\n"));
8492082Seschrock usage(B_FALSE);
850789Sahrens }
851789Sahrens
852789Sahrens pool = argv[0];
853789Sahrens
8542082Seschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
855789Sahrens /*
856789Sahrens * As a special case, check for use of '/' in the name, and
857789Sahrens * direct the user to use 'zfs destroy' instead.
858789Sahrens */
859789Sahrens if (strchr(pool, '/') != NULL)
860789Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to "
861789Sahrens "destroy a dataset\n"));
862789Sahrens return (1);
863789Sahrens }
864789Sahrens
8653126Sahl if (zpool_disable_datasets(zhp, force) != 0) {
866789Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': "
867789Sahrens "could not unmount datasets\n"), zpool_get_name(zhp));
868789Sahrens return (1);
869789Sahrens }
870789Sahrens
871789Sahrens ret = (zpool_destroy(zhp) != 0);
872789Sahrens
873789Sahrens zpool_close(zhp);
874789Sahrens
875789Sahrens return (ret);
876789Sahrens }
877789Sahrens
878789Sahrens /*
879789Sahrens * zpool export [-f] <pool> ...
880789Sahrens *
881789Sahrens * -f Forcefully unmount datasets
882789Sahrens *
8833912Slling * Export the given pools. By default, the command will attempt to cleanly
884789Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified,
885789Sahrens * then the datasets will be forcefully unmounted.
886789Sahrens */
887789Sahrens int
zpool_do_export(int argc,char ** argv)888789Sahrens zpool_do_export(int argc, char **argv)
889789Sahrens {
8902082Seschrock boolean_t force = B_FALSE;
8918211SGeorge.Wilson@Sun.COM boolean_t hardforce = B_FALSE;
892789Sahrens int c;
893789Sahrens zpool_handle_t *zhp;
894789Sahrens int ret;
895789Sahrens int i;
896789Sahrens
897789Sahrens /* check options */
8988211SGeorge.Wilson@Sun.COM while ((c = getopt(argc, argv, "fF")) != -1) {
899789Sahrens switch (c) {
900789Sahrens case 'f':
9012082Seschrock force = B_TRUE;
902789Sahrens break;
9038211SGeorge.Wilson@Sun.COM case 'F':
9048211SGeorge.Wilson@Sun.COM hardforce = B_TRUE;
9058211SGeorge.Wilson@Sun.COM break;
906789Sahrens case '?':
907789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
908789Sahrens optopt);
9092082Seschrock usage(B_FALSE);
910789Sahrens }
911789Sahrens }
912789Sahrens
913789Sahrens argc -= optind;
914789Sahrens argv += optind;
915789Sahrens
916789Sahrens /* check arguments */
917789Sahrens if (argc < 1) {
918789Sahrens (void) fprintf(stderr, gettext("missing pool argument\n"));
9192082Seschrock usage(B_FALSE);
920789Sahrens }
921789Sahrens
922789Sahrens ret = 0;
923789Sahrens for (i = 0; i < argc; i++) {
9242082Seschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
925789Sahrens ret = 1;
926789Sahrens continue;
927789Sahrens }
928789Sahrens
9293126Sahl if (zpool_disable_datasets(zhp, force) != 0) {
930789Sahrens ret = 1;
931789Sahrens zpool_close(zhp);
932789Sahrens continue;
933789Sahrens }
934789Sahrens
9358211SGeorge.Wilson@Sun.COM if (hardforce) {
9368211SGeorge.Wilson@Sun.COM if (zpool_export_force(zhp) != 0)
9378211SGeorge.Wilson@Sun.COM ret = 1;
9388211SGeorge.Wilson@Sun.COM } else if (zpool_export(zhp, force) != 0) {
939789Sahrens ret = 1;
9408211SGeorge.Wilson@Sun.COM }
941789Sahrens
942789Sahrens zpool_close(zhp);
943789Sahrens }
944789Sahrens
945789Sahrens return (ret);
946789Sahrens }
947789Sahrens
948789Sahrens /*
949789Sahrens * Given a vdev configuration, determine the maximum width needed for the device
950789Sahrens * name column.
951789Sahrens */
952789Sahrens static int
max_width(zpool_handle_t * zhp,nvlist_t * nv,int depth,int max)9531354Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
954789Sahrens {
95510594SGeorge.Wilson@Sun.COM char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
956789Sahrens nvlist_t **child;
957789Sahrens uint_t c, children;
958789Sahrens int ret;
959789Sahrens
960789Sahrens if (strlen(name) + depth > max)
961789Sahrens max = strlen(name) + depth;
962789Sahrens
9631171Seschrock free(name);
9641171Seschrock
9652082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
9662082Seschrock &child, &children) == 0) {
9672082Seschrock for (c = 0; c < children; c++)
9682082Seschrock if ((ret = max_width(zhp, child[c], depth + 2,
9692082Seschrock max)) > max)
9702082Seschrock max = ret;
9712082Seschrock }
9722082Seschrock
9735450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
9745450Sbrendan &child, &children) == 0) {
9755450Sbrendan for (c = 0; c < children; c++)
9765450Sbrendan if ((ret = max_width(zhp, child[c], depth + 2,
9775450Sbrendan max)) > max)
9785450Sbrendan max = ret;
9795450Sbrendan }
9805450Sbrendan
981789Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
9822082Seschrock &child, &children) == 0) {
9832082Seschrock for (c = 0; c < children; c++)
9842082Seschrock if ((ret = max_width(zhp, child[c], depth + 2,
9852082Seschrock max)) > max)
9862082Seschrock max = ret;
9872082Seschrock }
9882082Seschrock
989789Sahrens
990789Sahrens return (max);
991789Sahrens }
992789Sahrens
9939701SGeorge.Wilson@Sun.COM typedef struct spare_cbdata {
9949701SGeorge.Wilson@Sun.COM uint64_t cb_guid;
9959701SGeorge.Wilson@Sun.COM zpool_handle_t *cb_zhp;
9969701SGeorge.Wilson@Sun.COM } spare_cbdata_t;
9979701SGeorge.Wilson@Sun.COM
9989701SGeorge.Wilson@Sun.COM static boolean_t
find_vdev(nvlist_t * nv,uint64_t search)9999701SGeorge.Wilson@Sun.COM find_vdev(nvlist_t *nv, uint64_t search)
10009701SGeorge.Wilson@Sun.COM {
10019701SGeorge.Wilson@Sun.COM uint64_t guid;
10029701SGeorge.Wilson@Sun.COM nvlist_t **child;
10039701SGeorge.Wilson@Sun.COM uint_t c, children;
10049701SGeorge.Wilson@Sun.COM
10059701SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
10069701SGeorge.Wilson@Sun.COM search == guid)
10079701SGeorge.Wilson@Sun.COM return (B_TRUE);
10089701SGeorge.Wilson@Sun.COM
10099701SGeorge.Wilson@Sun.COM if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
10109701SGeorge.Wilson@Sun.COM &child, &children) == 0) {
10119701SGeorge.Wilson@Sun.COM for (c = 0; c < children; c++)
10129701SGeorge.Wilson@Sun.COM if (find_vdev(child[c], search))
10139701SGeorge.Wilson@Sun.COM return (B_TRUE);
10149701SGeorge.Wilson@Sun.COM }
10159701SGeorge.Wilson@Sun.COM
10169701SGeorge.Wilson@Sun.COM return (B_FALSE);
10179701SGeorge.Wilson@Sun.COM }
10189701SGeorge.Wilson@Sun.COM
10199701SGeorge.Wilson@Sun.COM static int
find_spare(zpool_handle_t * zhp,void * data)10209701SGeorge.Wilson@Sun.COM find_spare(zpool_handle_t *zhp, void *data)
10219701SGeorge.Wilson@Sun.COM {
10229701SGeorge.Wilson@Sun.COM spare_cbdata_t *cbp = data;
10239701SGeorge.Wilson@Sun.COM nvlist_t *config, *nvroot;
10249701SGeorge.Wilson@Sun.COM
10259701SGeorge.Wilson@Sun.COM config = zpool_get_config(zhp, NULL);
10269701SGeorge.Wilson@Sun.COM verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
10279701SGeorge.Wilson@Sun.COM &nvroot) == 0);
10289701SGeorge.Wilson@Sun.COM
10299701SGeorge.Wilson@Sun.COM if (find_vdev(nvroot, cbp->cb_guid)) {
10309701SGeorge.Wilson@Sun.COM cbp->cb_zhp = zhp;
10319701SGeorge.Wilson@Sun.COM return (1);
10329701SGeorge.Wilson@Sun.COM }
10339701SGeorge.Wilson@Sun.COM
10349701SGeorge.Wilson@Sun.COM zpool_close(zhp);
10359701SGeorge.Wilson@Sun.COM return (0);
10369701SGeorge.Wilson@Sun.COM }
10379701SGeorge.Wilson@Sun.COM
10389701SGeorge.Wilson@Sun.COM /*
10399701SGeorge.Wilson@Sun.COM * Print out configuration state as requested by status_callback.
10409701SGeorge.Wilson@Sun.COM */
10419701SGeorge.Wilson@Sun.COM void
print_status_config(zpool_handle_t * zhp,const char * name,nvlist_t * nv,int namewidth,int depth,boolean_t isspare)10429701SGeorge.Wilson@Sun.COM print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
10439701SGeorge.Wilson@Sun.COM int namewidth, int depth, boolean_t isspare)
10449701SGeorge.Wilson@Sun.COM {
10459701SGeorge.Wilson@Sun.COM nvlist_t **child;
10469701SGeorge.Wilson@Sun.COM uint_t c, children;
104712296SLin.Ling@Sun.COM pool_scan_stat_t *ps = NULL;
10489701SGeorge.Wilson@Sun.COM vdev_stat_t *vs;
104912296SLin.Ling@Sun.COM char rbuf[6], wbuf[6], cbuf[6];
10509701SGeorge.Wilson@Sun.COM char *vname;
10519701SGeorge.Wilson@Sun.COM uint64_t notpresent;
10529701SGeorge.Wilson@Sun.COM spare_cbdata_t cb;
10539701SGeorge.Wilson@Sun.COM char *state;
10549701SGeorge.Wilson@Sun.COM
10559701SGeorge.Wilson@Sun.COM if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
10569701SGeorge.Wilson@Sun.COM &child, &children) != 0)
10579701SGeorge.Wilson@Sun.COM children = 0;
10589701SGeorge.Wilson@Sun.COM
105912296SLin.Ling@Sun.COM verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
106012296SLin.Ling@Sun.COM (uint64_t **)&vs, &c) == 0);
106112296SLin.Ling@Sun.COM
10629701SGeorge.Wilson@Sun.COM state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
10639701SGeorge.Wilson@Sun.COM if (isspare) {
10649701SGeorge.Wilson@Sun.COM /*
10659701SGeorge.Wilson@Sun.COM * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
10669701SGeorge.Wilson@Sun.COM * online drives.
10679701SGeorge.Wilson@Sun.COM */
10689701SGeorge.Wilson@Sun.COM if (vs->vs_aux == VDEV_AUX_SPARED)
10699701SGeorge.Wilson@Sun.COM state = "INUSE";
10709701SGeorge.Wilson@Sun.COM else if (vs->vs_state == VDEV_STATE_HEALTHY)
10719701SGeorge.Wilson@Sun.COM state = "AVAIL";
10729701SGeorge.Wilson@Sun.COM }
10739701SGeorge.Wilson@Sun.COM
10749701SGeorge.Wilson@Sun.COM (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth,
10759701SGeorge.Wilson@Sun.COM name, state);
10769701SGeorge.Wilson@Sun.COM
10779701SGeorge.Wilson@Sun.COM if (!isspare) {
10789701SGeorge.Wilson@Sun.COM zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
10799701SGeorge.Wilson@Sun.COM zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
10809701SGeorge.Wilson@Sun.COM zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
10819701SGeorge.Wilson@Sun.COM (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
10829701SGeorge.Wilson@Sun.COM }
10839701SGeorge.Wilson@Sun.COM
10849701SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
10859701SGeorge.Wilson@Sun.COM ¬present) == 0) {
10869701SGeorge.Wilson@Sun.COM char *path;
10879701SGeorge.Wilson@Sun.COM verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
10889701SGeorge.Wilson@Sun.COM (void) printf(" was %s", path);
10899701SGeorge.Wilson@Sun.COM } else if (vs->vs_aux != 0) {
10909701SGeorge.Wilson@Sun.COM (void) printf(" ");
10919701SGeorge.Wilson@Sun.COM
10929701SGeorge.Wilson@Sun.COM switch (vs->vs_aux) {
10939701SGeorge.Wilson@Sun.COM case VDEV_AUX_OPEN_FAILED:
10949701SGeorge.Wilson@Sun.COM (void) printf(gettext("cannot open"));
10959701SGeorge.Wilson@Sun.COM break;
10969701SGeorge.Wilson@Sun.COM
10979701SGeorge.Wilson@Sun.COM case VDEV_AUX_BAD_GUID_SUM:
10989701SGeorge.Wilson@Sun.COM (void) printf(gettext("missing device"));
10999701SGeorge.Wilson@Sun.COM break;
11009701SGeorge.Wilson@Sun.COM
11019701SGeorge.Wilson@Sun.COM case VDEV_AUX_NO_REPLICAS:
11029701SGeorge.Wilson@Sun.COM (void) printf(gettext("insufficient replicas"));
11039701SGeorge.Wilson@Sun.COM break;
11049701SGeorge.Wilson@Sun.COM
11059701SGeorge.Wilson@Sun.COM case VDEV_AUX_VERSION_NEWER:
11069701SGeorge.Wilson@Sun.COM (void) printf(gettext("newer version"));
11079701SGeorge.Wilson@Sun.COM break;
11089701SGeorge.Wilson@Sun.COM
11099701SGeorge.Wilson@Sun.COM case VDEV_AUX_SPARED:
11109701SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
11119701SGeorge.Wilson@Sun.COM &cb.cb_guid) == 0);
11129701SGeorge.Wilson@Sun.COM if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
11139701SGeorge.Wilson@Sun.COM if (strcmp(zpool_get_name(cb.cb_zhp),
11149701SGeorge.Wilson@Sun.COM zpool_get_name(zhp)) == 0)
11159701SGeorge.Wilson@Sun.COM (void) printf(gettext("currently in "
11169701SGeorge.Wilson@Sun.COM "use"));
11179701SGeorge.Wilson@Sun.COM else
11189701SGeorge.Wilson@Sun.COM (void) printf(gettext("in use by "
11199701SGeorge.Wilson@Sun.COM "pool '%s'"),
11209701SGeorge.Wilson@Sun.COM zpool_get_name(cb.cb_zhp));
11219701SGeorge.Wilson@Sun.COM zpool_close(cb.cb_zhp);
11229701SGeorge.Wilson@Sun.COM } else {
11239701SGeorge.Wilson@Sun.COM (void) printf(gettext("currently in use"));
11249701SGeorge.Wilson@Sun.COM }
11259701SGeorge.Wilson@Sun.COM break;
11269701SGeorge.Wilson@Sun.COM
11279701SGeorge.Wilson@Sun.COM case VDEV_AUX_ERR_EXCEEDED:
11289701SGeorge.Wilson@Sun.COM (void) printf(gettext("too many errors"));
11299701SGeorge.Wilson@Sun.COM break;
11309701SGeorge.Wilson@Sun.COM
11319701SGeorge.Wilson@Sun.COM case VDEV_AUX_IO_FAILURE:
11329701SGeorge.Wilson@Sun.COM (void) printf(gettext("experienced I/O failures"));
11339701SGeorge.Wilson@Sun.COM break;
11349701SGeorge.Wilson@Sun.COM
11359701SGeorge.Wilson@Sun.COM case VDEV_AUX_BAD_LOG:
11369701SGeorge.Wilson@Sun.COM (void) printf(gettext("bad intent log"));
11379701SGeorge.Wilson@Sun.COM break;
11389701SGeorge.Wilson@Sun.COM
113910817SEric.Schrock@Sun.COM case VDEV_AUX_EXTERNAL:
114010817SEric.Schrock@Sun.COM (void) printf(gettext("external device fault"));
114110817SEric.Schrock@Sun.COM break;
114210817SEric.Schrock@Sun.COM
114311422SMark.Musante@Sun.COM case VDEV_AUX_SPLIT_POOL:
114411422SMark.Musante@Sun.COM (void) printf(gettext("split into new pool"));
114511422SMark.Musante@Sun.COM break;
114611422SMark.Musante@Sun.COM
11479701SGeorge.Wilson@Sun.COM default:
11489701SGeorge.Wilson@Sun.COM (void) printf(gettext("corrupted data"));
11499701SGeorge.Wilson@Sun.COM break;
11509701SGeorge.Wilson@Sun.COM }
115112296SLin.Ling@Sun.COM }
115212296SLin.Ling@Sun.COM
115312296SLin.Ling@Sun.COM (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
115412296SLin.Ling@Sun.COM (uint64_t **)&ps, &c);
115512296SLin.Ling@Sun.COM
115612296SLin.Ling@Sun.COM if (ps && ps->pss_state == DSS_SCANNING &&
115712296SLin.Ling@Sun.COM vs->vs_scan_processed != 0 && children == 0) {
115812296SLin.Ling@Sun.COM (void) printf(gettext(" (%s)"),
115912296SLin.Ling@Sun.COM (ps->pss_func == POOL_SCAN_RESILVER) ?
116012296SLin.Ling@Sun.COM "resilvering" : "repairing");
11619701SGeorge.Wilson@Sun.COM }
11629701SGeorge.Wilson@Sun.COM
11639701SGeorge.Wilson@Sun.COM (void) printf("\n");
11649701SGeorge.Wilson@Sun.COM
11659701SGeorge.Wilson@Sun.COM for (c = 0; c < children; c++) {
116610594SGeorge.Wilson@Sun.COM uint64_t islog = B_FALSE, ishole = B_FALSE;
116710594SGeorge.Wilson@Sun.COM
116810594SGeorge.Wilson@Sun.COM /* Don't print logs or holes here */
11699701SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
117010594SGeorge.Wilson@Sun.COM &islog);
117110594SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
117210594SGeorge.Wilson@Sun.COM &ishole);
117310594SGeorge.Wilson@Sun.COM if (islog || ishole)
11749701SGeorge.Wilson@Sun.COM continue;
117510594SGeorge.Wilson@Sun.COM vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
11769701SGeorge.Wilson@Sun.COM print_status_config(zhp, vname, child[c],
11779701SGeorge.Wilson@Sun.COM namewidth, depth + 2, isspare);
11789701SGeorge.Wilson@Sun.COM free(vname);
11799701SGeorge.Wilson@Sun.COM }
11809701SGeorge.Wilson@Sun.COM }
11819701SGeorge.Wilson@Sun.COM
1182789Sahrens
1183789Sahrens /*
1184789Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the
1185789Sahrens * pool, printing out the name and status for each one.
1186789Sahrens */
1187789Sahrens void
print_import_config(const char * name,nvlist_t * nv,int namewidth,int depth)11889701SGeorge.Wilson@Sun.COM print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1189789Sahrens {
1190789Sahrens nvlist_t **child;
1191789Sahrens uint_t c, children;
1192789Sahrens vdev_stat_t *vs;
11931171Seschrock char *type, *vname;
1194789Sahrens
1195789Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
119610594SGeorge.Wilson@Sun.COM if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
119710594SGeorge.Wilson@Sun.COM strcmp(type, VDEV_TYPE_HOLE) == 0)
1198789Sahrens return;
1199789Sahrens
120012296SLin.Ling@Sun.COM verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1201789Sahrens (uint64_t **)&vs, &c) == 0);
1202789Sahrens
1203789Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
12045094Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1205789Sahrens
1206789Sahrens if (vs->vs_aux != 0) {
12074451Seschrock (void) printf(" ");
1208789Sahrens
1209789Sahrens switch (vs->vs_aux) {
1210789Sahrens case VDEV_AUX_OPEN_FAILED:
1211789Sahrens (void) printf(gettext("cannot open"));
1212789Sahrens break;
1213789Sahrens
1214789Sahrens case VDEV_AUX_BAD_GUID_SUM:
1215789Sahrens (void) printf(gettext("missing device"));
1216789Sahrens break;
1217789Sahrens
1218789Sahrens case VDEV_AUX_NO_REPLICAS:
1219789Sahrens (void) printf(gettext("insufficient replicas"));
1220789Sahrens break;
1221789Sahrens
12221760Seschrock case VDEV_AUX_VERSION_NEWER:
12231760Seschrock (void) printf(gettext("newer version"));
12241760Seschrock break;
12251760Seschrock
12264451Seschrock case VDEV_AUX_ERR_EXCEEDED:
12274451Seschrock (void) printf(gettext("too many errors"));
12284451Seschrock break;
12294451Seschrock
1230789Sahrens default:
1231789Sahrens (void) printf(gettext("corrupted data"));
1232789Sahrens break;
1233789Sahrens }
1234789Sahrens }
1235789Sahrens (void) printf("\n");
1236789Sahrens
1237789Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1238789Sahrens &child, &children) != 0)
1239789Sahrens return;
1240789Sahrens
12411171Seschrock for (c = 0; c < children; c++) {
12424527Sperrin uint64_t is_log = B_FALSE;
12434527Sperrin
12444527Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
12454527Sperrin &is_log);
12469701SGeorge.Wilson@Sun.COM if (is_log)
12474527Sperrin continue;
12484527Sperrin
124910594SGeorge.Wilson@Sun.COM vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
12509701SGeorge.Wilson@Sun.COM print_import_config(vname, child[c], namewidth, depth + 2);
12511171Seschrock free(vname);
12521171Seschrock }
12532082Seschrock
12545450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
12555450Sbrendan &child, &children) == 0) {
12565450Sbrendan (void) printf(gettext("\tcache\n"));
12575450Sbrendan for (c = 0; c < children; c++) {
125810594SGeorge.Wilson@Sun.COM vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
12595450Sbrendan (void) printf("\t %s\n", vname);
12605450Sbrendan free(vname);
12615450Sbrendan }
12625450Sbrendan }
12635450Sbrendan
12642082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
12655450Sbrendan &child, &children) == 0) {
12665450Sbrendan (void) printf(gettext("\tspares\n"));
12675450Sbrendan for (c = 0; c < children; c++) {
126810594SGeorge.Wilson@Sun.COM vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
12695450Sbrendan (void) printf("\t %s\n", vname);
12705450Sbrendan free(vname);
12715450Sbrendan }
12722082Seschrock }
1273789Sahrens }
1274789Sahrens
1275789Sahrens /*
12769701SGeorge.Wilson@Sun.COM * Print log vdevs.
12779701SGeorge.Wilson@Sun.COM * Logs are recorded as top level vdevs in the main pool child array
12789701SGeorge.Wilson@Sun.COM * but with "is_log" set to 1. We use either print_status_config() or
12799701SGeorge.Wilson@Sun.COM * print_import_config() to print the top level logs then any log
12809701SGeorge.Wilson@Sun.COM * children (eg mirrored slogs) are printed recursively - which
12819701SGeorge.Wilson@Sun.COM * works because only the top level vdev is marked "is_log"
12829701SGeorge.Wilson@Sun.COM */
12839701SGeorge.Wilson@Sun.COM static void
print_logs(zpool_handle_t * zhp,nvlist_t * nv,int namewidth,boolean_t verbose)12849701SGeorge.Wilson@Sun.COM print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
12859701SGeorge.Wilson@Sun.COM {
12869701SGeorge.Wilson@Sun.COM uint_t c, children;
12879701SGeorge.Wilson@Sun.COM nvlist_t **child;
12889701SGeorge.Wilson@Sun.COM
12899701SGeorge.Wilson@Sun.COM if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
12909701SGeorge.Wilson@Sun.COM &children) != 0)
12919701SGeorge.Wilson@Sun.COM return;
12929701SGeorge.Wilson@Sun.COM
12939701SGeorge.Wilson@Sun.COM (void) printf(gettext("\tlogs\n"));
12949701SGeorge.Wilson@Sun.COM
12959701SGeorge.Wilson@Sun.COM for (c = 0; c < children; c++) {
12969701SGeorge.Wilson@Sun.COM uint64_t is_log = B_FALSE;
12979701SGeorge.Wilson@Sun.COM char *name;
12989701SGeorge.Wilson@Sun.COM
12999701SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
13009701SGeorge.Wilson@Sun.COM &is_log);
13019701SGeorge.Wilson@Sun.COM if (!is_log)
13029701SGeorge.Wilson@Sun.COM continue;
130310594SGeorge.Wilson@Sun.COM name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
13049701SGeorge.Wilson@Sun.COM if (verbose)
13059701SGeorge.Wilson@Sun.COM print_status_config(zhp, name, child[c], namewidth,
13069701SGeorge.Wilson@Sun.COM 2, B_FALSE);
13079701SGeorge.Wilson@Sun.COM else
13089701SGeorge.Wilson@Sun.COM print_import_config(name, child[c], namewidth, 2);
13099701SGeorge.Wilson@Sun.COM free(name);
13109701SGeorge.Wilson@Sun.COM }
13119701SGeorge.Wilson@Sun.COM }
131210921STim.Haley@Sun.COM
13139701SGeorge.Wilson@Sun.COM /*
1314789Sahrens * Display the status for the given pool.
1315789Sahrens */
1316789Sahrens static void
show_import(nvlist_t * config)1317789Sahrens show_import(nvlist_t *config)
1318789Sahrens {
1319789Sahrens uint64_t pool_state;
1320789Sahrens vdev_stat_t *vs;
1321789Sahrens char *name;
1322789Sahrens uint64_t guid;
1323789Sahrens char *msgid;
1324789Sahrens nvlist_t *nvroot;
1325789Sahrens int reason;
13263741Smmusante const char *health;
1327789Sahrens uint_t vsc;
1328789Sahrens int namewidth;
1329789Sahrens
1330789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1331789Sahrens &name) == 0);
1332789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1333789Sahrens &guid) == 0);
1334789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1335789Sahrens &pool_state) == 0);
1336789Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1337789Sahrens &nvroot) == 0);
1338789Sahrens
133912296SLin.Ling@Sun.COM verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
1340789Sahrens (uint64_t **)&vs, &vsc) == 0);
13415094Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1342789Sahrens
1343789Sahrens reason = zpool_import_status(config, &msgid);
1344789Sahrens
13453741Smmusante (void) printf(gettext(" pool: %s\n"), name);
13463741Smmusante (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
13473741Smmusante (void) printf(gettext(" state: %s"), health);
13481631Sdarrenm if (pool_state == POOL_STATE_DESTROYED)
13493912Slling (void) printf(gettext(" (DESTROYED)"));
13501631Sdarrenm (void) printf("\n");
1351789Sahrens
1352789Sahrens switch (reason) {
1353789Sahrens case ZPOOL_STATUS_MISSING_DEV_R:
1354789Sahrens case ZPOOL_STATUS_MISSING_DEV_NR:
1355789Sahrens case ZPOOL_STATUS_BAD_GUID_SUM:
1356789Sahrens (void) printf(gettext("status: One or more devices are missing "
1357789Sahrens "from the system.\n"));
1358789Sahrens break;
1359789Sahrens
1360789Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R:
1361789Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1362789Sahrens (void) printf(gettext("status: One or more devices contains "
1363789Sahrens "corrupted data.\n"));
1364789Sahrens break;
1365789Sahrens
1366789Sahrens case ZPOOL_STATUS_CORRUPT_DATA:
1367789Sahrens (void) printf(gettext("status: The pool data is corrupted.\n"));
1368789Sahrens break;
1369789Sahrens
13701485Slling case ZPOOL_STATUS_OFFLINE_DEV:
13711485Slling (void) printf(gettext("status: One or more devices "
13721485Slling "are offlined.\n"));
13731485Slling break;
13741485Slling
13751544Seschrock case ZPOOL_STATUS_CORRUPT_POOL:
13761544Seschrock (void) printf(gettext("status: The pool metadata is "
13771544Seschrock "corrupted.\n"));
13781544Seschrock break;
13791544Seschrock
13801760Seschrock case ZPOOL_STATUS_VERSION_OLDER:
13811760Seschrock (void) printf(gettext("status: The pool is formatted using an "
13821760Seschrock "older on-disk version.\n"));
13831760Seschrock break;
13841760Seschrock
13851760Seschrock case ZPOOL_STATUS_VERSION_NEWER:
13861760Seschrock (void) printf(gettext("status: The pool is formatted using an "
13871760Seschrock "incompatible version.\n"));
13881760Seschrock break;
13897294Sperrin
13903975Sek110237 case ZPOOL_STATUS_HOSTID_MISMATCH:
13913975Sek110237 (void) printf(gettext("status: The pool was last accessed by "
13923975Sek110237 "another system.\n"));
13933975Sek110237 break;
13947294Sperrin
13954451Seschrock case ZPOOL_STATUS_FAULTED_DEV_R:
13964451Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR:
13974451Seschrock (void) printf(gettext("status: One or more devices are "
13984451Seschrock "faulted.\n"));
13994451Seschrock break;
14004451Seschrock
14017294Sperrin case ZPOOL_STATUS_BAD_LOG:
14027294Sperrin (void) printf(gettext("status: An intent log record cannot be "
14037294Sperrin "read.\n"));
14047294Sperrin break;
14057294Sperrin
140612296SLin.Ling@Sun.COM case ZPOOL_STATUS_RESILVERING:
140712296SLin.Ling@Sun.COM (void) printf(gettext("status: One or more devices were being "
140812296SLin.Ling@Sun.COM "resilvered.\n"));
140912296SLin.Ling@Sun.COM break;
141012296SLin.Ling@Sun.COM
1411789Sahrens default:
1412789Sahrens /*
1413789Sahrens * No other status can be seen when importing pools.
1414789Sahrens */
1415789Sahrens assert(reason == ZPOOL_STATUS_OK);
1416789Sahrens }
1417789Sahrens
1418789Sahrens /*
1419789Sahrens * Print out an action according to the overall state of the pool.
1420789Sahrens */
14213741Smmusante if (vs->vs_state == VDEV_STATE_HEALTHY) {
14221760Seschrock if (reason == ZPOOL_STATUS_VERSION_OLDER)
14231760Seschrock (void) printf(gettext("action: The pool can be "
14241760Seschrock "imported using its name or numeric identifier, "
14251760Seschrock "though\n\tsome features will not be available "
14261760Seschrock "without an explicit 'zpool upgrade'.\n"));
14273975Sek110237 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
14283975Sek110237 (void) printf(gettext("action: The pool can be "
14293975Sek110237 "imported using its name or numeric "
14303975Sek110237 "identifier and\n\tthe '-f' flag.\n"));
1431789Sahrens else
14321760Seschrock (void) printf(gettext("action: The pool can be "
14331760Seschrock "imported using its name or numeric "
14341760Seschrock "identifier.\n"));
14353741Smmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1436789Sahrens (void) printf(gettext("action: The pool can be imported "
1437789Sahrens "despite missing or damaged devices. The\n\tfault "
14381760Seschrock "tolerance of the pool may be compromised if imported.\n"));
1439789Sahrens } else {
14401760Seschrock switch (reason) {
14411760Seschrock case ZPOOL_STATUS_VERSION_NEWER:
14421760Seschrock (void) printf(gettext("action: The pool cannot be "
14431760Seschrock "imported. Access the pool on a system running "
14441760Seschrock "newer\n\tsoftware, or recreate the pool from "
14451760Seschrock "backup.\n"));
14461760Seschrock break;
14471760Seschrock case ZPOOL_STATUS_MISSING_DEV_R:
14481760Seschrock case ZPOOL_STATUS_MISSING_DEV_NR:
14491760Seschrock case ZPOOL_STATUS_BAD_GUID_SUM:
1450789Sahrens (void) printf(gettext("action: The pool cannot be "
1451789Sahrens "imported. Attach the missing\n\tdevices and try "
1452789Sahrens "again.\n"));
14531760Seschrock break;
14541760Seschrock default:
1455789Sahrens (void) printf(gettext("action: The pool cannot be "
1456789Sahrens "imported due to damaged devices or data.\n"));
14571760Seschrock }
14581760Seschrock }
14591760Seschrock
14603741Smmusante /*
14613741Smmusante * If the state is "closed" or "can't open", and the aux state
14623741Smmusante * is "corrupt data":
14633741Smmusante */
14643741Smmusante if (((vs->vs_state == VDEV_STATE_CLOSED) ||
14653741Smmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
14663741Smmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
14671760Seschrock if (pool_state == POOL_STATE_DESTROYED)
14681760Seschrock (void) printf(gettext("\tThe pool was destroyed, "
14691760Seschrock "but can be imported using the '-Df' flags.\n"));
14701760Seschrock else if (pool_state != POOL_STATE_EXPORTED)
14711760Seschrock (void) printf(gettext("\tThe pool may be active on "
14725853Sek110237 "another system, but can be imported using\n\t"
14731760Seschrock "the '-f' flag.\n"));
1474789Sahrens }
1475789Sahrens
1476789Sahrens if (msgid != NULL)
1477789Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"),
1478789Sahrens msgid);
1479789Sahrens
1480789Sahrens (void) printf(gettext("config:\n\n"));
1481789Sahrens
14821354Seschrock namewidth = max_width(NULL, nvroot, 0, 0);
1483789Sahrens if (namewidth < 10)
1484789Sahrens namewidth = 10;
14854527Sperrin
14869701SGeorge.Wilson@Sun.COM print_import_config(name, nvroot, namewidth, 0);
14879701SGeorge.Wilson@Sun.COM if (num_logs(nvroot) > 0)
14889701SGeorge.Wilson@Sun.COM print_logs(NULL, nvroot, namewidth, B_FALSE);
1489789Sahrens
1490789Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
14913741Smmusante (void) printf(gettext("\n\tAdditional devices are known to "
1492789Sahrens "be part of this pool, though their\n\texact "
14933741Smmusante "configuration cannot be determined.\n"));
1494789Sahrens }
1495789Sahrens }
1496789Sahrens
1497789Sahrens /*
1498789Sahrens * Perform the import for the given configuration. This passes the heavy
14995094Slling * lifting off to zpool_import_props(), and then mounts the datasets contained
15005094Slling * within the pool.
1501789Sahrens */
1502789Sahrens static int
do_import(nvlist_t * config,const char * newname,const char * mntopts,nvlist_t * props,int flags)1503789Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
150412949SGeorge.Wilson@Sun.COM nvlist_t *props, int flags)
1505789Sahrens {
1506789Sahrens zpool_handle_t *zhp;
1507789Sahrens char *name;
1508789Sahrens uint64_t state;
15091760Seschrock uint64_t version;
1510789Sahrens
1511789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1512789Sahrens &name) == 0);
1513789Sahrens
1514789Sahrens verify(nvlist_lookup_uint64(config,
1515789Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0);
15161760Seschrock verify(nvlist_lookup_uint64(config,
15171760Seschrock ZPOOL_CONFIG_VERSION, &version) == 0);
15184577Sahrens if (version > SPA_VERSION) {
15191760Seschrock (void) fprintf(stderr, gettext("cannot import '%s': pool "
15201760Seschrock "is formatted using a newer ZFS version\n"), name);
15211760Seschrock return (1);
152212949SGeorge.Wilson@Sun.COM } else if (state != POOL_STATE_EXPORTED &&
152312949SGeorge.Wilson@Sun.COM !(flags & ZFS_IMPORT_ANY_HOST)) {
15243975Sek110237 uint64_t hostid;
15253975Sek110237
15263975Sek110237 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
15273975Sek110237 &hostid) == 0) {
15283975Sek110237 if ((unsigned long)hostid != gethostid()) {
15293975Sek110237 char *hostname;
15303975Sek110237 uint64_t timestamp;
15313975Sek110237 time_t t;
15323975Sek110237
15333975Sek110237 verify(nvlist_lookup_string(config,
15343975Sek110237 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
15353975Sek110237 verify(nvlist_lookup_uint64(config,
15363975Sek110237 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0);
15373975Sek110237 t = timestamp;
15383975Sek110237 (void) fprintf(stderr, gettext("cannot import "
15393975Sek110237 "'%s': pool may be in use from other "
15403975Sek110237 "system, it was last accessed by %s "
15413975Sek110237 "(hostid: 0x%lx) on %s"), name, hostname,
15423975Sek110237 (unsigned long)hostid,
15433975Sek110237 asctime(localtime(&t)));
15443975Sek110237 (void) fprintf(stderr, gettext("use '-f' to "
15453975Sek110237 "import anyway\n"));
15463975Sek110237 return (1);
15473975Sek110237 }
15483975Sek110237 } else {
15493975Sek110237 (void) fprintf(stderr, gettext("cannot import '%s': "
15503975Sek110237 "pool may be in use from other system\n"), name);
15513975Sek110237 (void) fprintf(stderr, gettext("use '-f' to import "
15523975Sek110237 "anyway\n"));
15533975Sek110237 return (1);
15543975Sek110237 }
1555789Sahrens }
1556789Sahrens
155712949SGeorge.Wilson@Sun.COM if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
1558789Sahrens return (1);
1559789Sahrens
1560789Sahrens if (newname != NULL)
1561789Sahrens name = (char *)newname;
1562789Sahrens
156310000SVictor.Latushkin@Sun.COM if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
156410000SVictor.Latushkin@Sun.COM return (1);
1565789Sahrens
15668525SEric.Schrock@Sun.COM if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
156713049SGeorge.Wilson@Sun.COM !(flags & ZFS_IMPORT_ONLY) &&
15688525SEric.Schrock@Sun.COM zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1569789Sahrens zpool_close(zhp);
1570789Sahrens return (1);
1571789Sahrens }
1572789Sahrens
1573789Sahrens zpool_close(zhp);
157410921STim.Haley@Sun.COM return (0);
1575789Sahrens }
1576789Sahrens
1577789Sahrens /*
15781631Sdarrenm * zpool import [-d dir] [-D]
15795363Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D]
15805363Seschrock * [-d dir | -c cachefile] [-f] -a
15815363Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D]
158210921STim.Haley@Sun.COM * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
15835363Seschrock *
15845363Seschrock * -c Read pool information from a cachefile instead of searching
15855363Seschrock * devices.
1586789Sahrens *
1587789Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than
1588789Sahrens * one directory can be specified using multiple '-d' options.
1589789Sahrens *
15901631Sdarrenm * -D Scan for previously destroyed pools or import all or only
15911631Sdarrenm * specified destroyed pools.
15921631Sdarrenm *
1593789Sahrens * -R Temporarily import the pool, with all mountpoints relative to
1594789Sahrens * the given root. The pool will remain exported when the machine
1595789Sahrens * is rebooted.
1596789Sahrens *
159710921STim.Haley@Sun.COM * -V Import even in the presence of faulted vdevs. This is an
15986643Seschrock * intentionally undocumented option for testing purposes, and
15996643Seschrock * treats the pool configuration as complete, leaving any bad
160010000SVictor.Latushkin@Sun.COM * vdevs in the FAULTED state. In other words, it does verbatim
160110000SVictor.Latushkin@Sun.COM * import.
16026643Seschrock *
160310921STim.Haley@Sun.COM * -f Force import, even if it appears that the pool is active.
160410921STim.Haley@Sun.COM *
160510921STim.Haley@Sun.COM * -F Attempt rewind if necessary.
160610921STim.Haley@Sun.COM *
160710921STim.Haley@Sun.COM * -n See if rewind would work, but don't actually rewind.
160810921STim.Haley@Sun.COM *
160913049SGeorge.Wilson@Sun.COM * -N Import the pool but don't mount datasets.
161013049SGeorge.Wilson@Sun.COM *
161113049SGeorge.Wilson@Sun.COM * -T Specify a starting txg to use for import. This option is
161213049SGeorge.Wilson@Sun.COM * intentionally undocumented option for testing purposes.
161313049SGeorge.Wilson@Sun.COM *
1614789Sahrens * -a Import all pools found.
1615789Sahrens *
16165094Slling * -o Set property=value and/or temporary mount options (without '=').
16174543Smarks *
1618789Sahrens * The import command scans for pools to import, and import pools based on pool
1619789Sahrens * name and GUID. The pool can also be renamed as part of the import process.
1620789Sahrens */
1621789Sahrens int
zpool_do_import(int argc,char ** argv)1622789Sahrens zpool_do_import(int argc, char **argv)
1623789Sahrens {
1624789Sahrens char **searchdirs = NULL;
1625789Sahrens int nsearch = 0;
1626789Sahrens int c;
162711497SMark.Musante@Sun.COM int err = 0;
16285363Seschrock nvlist_t *pools = NULL;
16292082Seschrock boolean_t do_all = B_FALSE;
16302082Seschrock boolean_t do_destroyed = B_FALSE;
1631789Sahrens char *mntopts = NULL;
1632789Sahrens nvpair_t *elem;
1633789Sahrens nvlist_t *config;
16346807Sck153898 uint64_t searchguid = 0;
16356807Sck153898 char *searchname = NULL;
16365094Slling char *propval;
1637789Sahrens nvlist_t *found_config;
163810921STim.Haley@Sun.COM nvlist_t *policy = NULL;
16394543Smarks nvlist_t *props = NULL;
16402082Seschrock boolean_t first;
164112949SGeorge.Wilson@Sun.COM int flags = ZFS_IMPORT_NORMAL;
164210921STim.Haley@Sun.COM uint32_t rewind_policy = ZPOOL_NO_REWIND;
164310921STim.Haley@Sun.COM boolean_t dryrun = B_FALSE;
164410921STim.Haley@Sun.COM boolean_t do_rewind = B_FALSE;
164510921STim.Haley@Sun.COM boolean_t xtreme_rewind = B_FALSE;
164613049SGeorge.Wilson@Sun.COM uint64_t pool_state, txg = -1ULL;
16475363Seschrock char *cachefile = NULL;
164811497SMark.Musante@Sun.COM importargs_t idata = { 0 };
164913049SGeorge.Wilson@Sun.COM char *endptr;
1650789Sahrens
1651789Sahrens /* check options */
165213049SGeorge.Wilson@Sun.COM while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
1653789Sahrens switch (c) {
1654789Sahrens case 'a':
16552082Seschrock do_all = B_TRUE;
1656789Sahrens break;
16575363Seschrock case 'c':
16585363Seschrock cachefile = optarg;
16595363Seschrock break;
1660789Sahrens case 'd':
1661789Sahrens if (searchdirs == NULL) {
1662789Sahrens searchdirs = safe_malloc(sizeof (char *));
1663789Sahrens } else {
1664789Sahrens char **tmp = safe_malloc((nsearch + 1) *
1665789Sahrens sizeof (char *));
1666789Sahrens bcopy(searchdirs, tmp, nsearch *
1667789Sahrens sizeof (char *));
1668789Sahrens free(searchdirs);
1669789Sahrens searchdirs = tmp;
1670789Sahrens }
1671789Sahrens searchdirs[nsearch++] = optarg;
1672789Sahrens break;
16731631Sdarrenm case 'D':
16742082Seschrock do_destroyed = B_TRUE;
16751631Sdarrenm break;
1676789Sahrens case 'f':
167712949SGeorge.Wilson@Sun.COM flags |= ZFS_IMPORT_ANY_HOST;
1678789Sahrens break;
16796643Seschrock case 'F':
168010921STim.Haley@Sun.COM do_rewind = B_TRUE;
168110921STim.Haley@Sun.COM break;
168212949SGeorge.Wilson@Sun.COM case 'm':
168312949SGeorge.Wilson@Sun.COM flags |= ZFS_IMPORT_MISSING_LOG;
168412949SGeorge.Wilson@Sun.COM break;
168510921STim.Haley@Sun.COM case 'n':
168610921STim.Haley@Sun.COM dryrun = B_TRUE;
16876643Seschrock break;
168813049SGeorge.Wilson@Sun.COM case 'N':
168913049SGeorge.Wilson@Sun.COM flags |= ZFS_IMPORT_ONLY;
169013049SGeorge.Wilson@Sun.COM break;
1691789Sahrens case 'o':
16925094Slling if ((propval = strchr(optarg, '=')) != NULL) {
16935094Slling *propval = '\0';
16945094Slling propval++;
16957184Stimh if (add_prop_list(optarg, propval,
16967184Stimh &props, B_TRUE))
16975094Slling goto error;
16985094Slling } else {
16995094Slling mntopts = optarg;
17005094Slling }
1701789Sahrens break;
1702789Sahrens case 'R':
17035094Slling if (add_prop_list(zpool_prop_to_name(
17047184Stimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
17055094Slling goto error;
17065363Seschrock if (nvlist_lookup_string(props,
17075363Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
17085363Seschrock &propval) == 0)
17095363Seschrock break;
17105094Slling if (add_prop_list(zpool_prop_to_name(
17117184Stimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
17125094Slling goto error;
1713789Sahrens break;
171413049SGeorge.Wilson@Sun.COM case 'T':
171513049SGeorge.Wilson@Sun.COM errno = 0;
171613049SGeorge.Wilson@Sun.COM txg = strtoull(optarg, &endptr, 10);
171713049SGeorge.Wilson@Sun.COM if (errno != 0 || *endptr != '\0') {
171813049SGeorge.Wilson@Sun.COM (void) fprintf(stderr,
171913049SGeorge.Wilson@Sun.COM gettext("invalid txg value\n"));
172013049SGeorge.Wilson@Sun.COM usage(B_FALSE);
172113049SGeorge.Wilson@Sun.COM }
172213049SGeorge.Wilson@Sun.COM rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
172313049SGeorge.Wilson@Sun.COM break;
172410921STim.Haley@Sun.COM case 'V':
172512949SGeorge.Wilson@Sun.COM flags |= ZFS_IMPORT_VERBATIM;
172610921STim.Haley@Sun.COM break;
172710921STim.Haley@Sun.COM case 'X':
172810921STim.Haley@Sun.COM xtreme_rewind = B_TRUE;
172910921STim.Haley@Sun.COM break;
1730789Sahrens case ':':
1731789Sahrens (void) fprintf(stderr, gettext("missing argument for "
1732789Sahrens "'%c' option\n"), optopt);
17332082Seschrock usage(B_FALSE);
1734789Sahrens break;
1735789Sahrens case '?':
1736789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
1737789Sahrens optopt);
17382082Seschrock usage(B_FALSE);
1739789Sahrens }
1740789Sahrens }
1741789Sahrens
1742789Sahrens argc -= optind;
1743789Sahrens argv += optind;
1744789Sahrens
17455363Seschrock if (cachefile && nsearch != 0) {
17465363Seschrock (void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
17475363Seschrock usage(B_FALSE);
17485363Seschrock }
17495363Seschrock
175010921STim.Haley@Sun.COM if ((dryrun || xtreme_rewind) && !do_rewind) {
175110921STim.Haley@Sun.COM (void) fprintf(stderr,
175210921STim.Haley@Sun.COM gettext("-n or -X only meaningful with -F\n"));
175310921STim.Haley@Sun.COM usage(B_FALSE);
175410921STim.Haley@Sun.COM }
175510921STim.Haley@Sun.COM if (dryrun)
175610921STim.Haley@Sun.COM rewind_policy = ZPOOL_TRY_REWIND;
175710921STim.Haley@Sun.COM else if (do_rewind)
175810921STim.Haley@Sun.COM rewind_policy = ZPOOL_DO_REWIND;
175910921STim.Haley@Sun.COM if (xtreme_rewind)
176010921STim.Haley@Sun.COM rewind_policy |= ZPOOL_EXTREME_REWIND;
176110921STim.Haley@Sun.COM
176210921STim.Haley@Sun.COM /* In the future, we can capture further policy and include it here */
176310921STim.Haley@Sun.COM if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
176413049SGeorge.Wilson@Sun.COM nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 ||
176510921STim.Haley@Sun.COM nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
176610921STim.Haley@Sun.COM goto error;
176710921STim.Haley@Sun.COM
1768789Sahrens if (searchdirs == NULL) {
1769789Sahrens searchdirs = safe_malloc(sizeof (char *));
1770789Sahrens searchdirs[0] = "/dev/dsk";
1771789Sahrens nsearch = 1;
1772789Sahrens }
1773789Sahrens
1774789Sahrens /* check argument count */
1775789Sahrens if (do_all) {
1776789Sahrens if (argc != 0) {
1777789Sahrens (void) fprintf(stderr, gettext("too many arguments\n"));
17782082Seschrock usage(B_FALSE);
1779789Sahrens }
1780789Sahrens } else {
1781789Sahrens if (argc > 2) {
1782789Sahrens (void) fprintf(stderr, gettext("too many arguments\n"));
17832082Seschrock usage(B_FALSE);
1784789Sahrens }
1785789Sahrens
1786789Sahrens /*
1787789Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly
1788789Sahrens * here because otherwise any attempt to discover pools will
1789789Sahrens * silently fail.
1790789Sahrens */
1791789Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1792789Sahrens (void) fprintf(stderr, gettext("cannot "
1793789Sahrens "discover pools: permission denied\n"));
17942082Seschrock free(searchdirs);
179510921STim.Haley@Sun.COM nvlist_free(policy);
1796789Sahrens return (1);
1797789Sahrens }
1798789Sahrens }
1799789Sahrens
1800789Sahrens /*
1801789Sahrens * Depending on the arguments given, we do one of the following:
1802789Sahrens *
1803789Sahrens * <none> Iterate through all pools and display information about
1804789Sahrens * each one.
1805789Sahrens *
1806789Sahrens * -a Iterate through all pools and try to import each one.
1807789Sahrens *
1808789Sahrens * <id> Find the pool that corresponds to the given GUID/pool
1809789Sahrens * name and import that one.
18101631Sdarrenm *
18111631Sdarrenm * -D Above options applies only to destroyed pools.
1812789Sahrens */
1813789Sahrens if (argc != 0) {
1814789Sahrens char *endptr;
1815789Sahrens
1816789Sahrens errno = 0;
1817789Sahrens searchguid = strtoull(argv[0], &endptr, 10);
1818789Sahrens if (errno != 0 || *endptr != '\0')
1819789Sahrens searchname = argv[0];
1820789Sahrens found_config = NULL;
182111497SMark.Musante@Sun.COM
182211497SMark.Musante@Sun.COM /*
182311497SMark.Musante@Sun.COM * User specified a name or guid. Ensure it's unique.
182411497SMark.Musante@Sun.COM */
182511497SMark.Musante@Sun.COM idata.unique = B_TRUE;
1826789Sahrens }
1827789Sahrens
182811497SMark.Musante@Sun.COM
182911497SMark.Musante@Sun.COM idata.path = searchdirs;
183011497SMark.Musante@Sun.COM idata.paths = nsearch;
183111497SMark.Musante@Sun.COM idata.poolname = searchname;
183211497SMark.Musante@Sun.COM idata.guid = searchguid;
183311497SMark.Musante@Sun.COM idata.cachefile = cachefile;
183411497SMark.Musante@Sun.COM
183511497SMark.Musante@Sun.COM pools = zpool_search_import(g_zfs, &idata);
183611497SMark.Musante@Sun.COM
183711497SMark.Musante@Sun.COM if (pools != NULL && idata.exists &&
183811497SMark.Musante@Sun.COM (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
183911497SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("cannot import '%s': "
184011497SMark.Musante@Sun.COM "a pool with that name already exists\n"),
184111497SMark.Musante@Sun.COM argv[0]);
184211497SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("use the form '%s "
184311497SMark.Musante@Sun.COM "<pool | id> <newpool>' to give it a new name\n"),
184411497SMark.Musante@Sun.COM "zpool import");
184511497SMark.Musante@Sun.COM err = 1;
184611497SMark.Musante@Sun.COM } else if (pools == NULL && idata.exists) {
184711497SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("cannot import '%s': "
184811497SMark.Musante@Sun.COM "a pool with that name is already created/imported,\n"),
184911497SMark.Musante@Sun.COM argv[0]);
185011497SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("and no additional pools "
185111497SMark.Musante@Sun.COM "with that name were found\n"));
185211497SMark.Musante@Sun.COM err = 1;
185311497SMark.Musante@Sun.COM } else if (pools == NULL) {
18546807Sck153898 if (argc != 0) {
18556807Sck153898 (void) fprintf(stderr, gettext("cannot import '%s': "
18566807Sck153898 "no such pool available\n"), argv[0]);
18576807Sck153898 }
185811497SMark.Musante@Sun.COM err = 1;
185911497SMark.Musante@Sun.COM }
186011497SMark.Musante@Sun.COM
186111497SMark.Musante@Sun.COM if (err == 1) {
18626807Sck153898 free(searchdirs);
186310921STim.Haley@Sun.COM nvlist_free(policy);
18646807Sck153898 return (1);
18656807Sck153898 }
18666807Sck153898
18676807Sck153898 /*
18686807Sck153898 * At this point we have a list of import candidate configs. Even if
18696807Sck153898 * we were searching by pool name or guid, we still need to
18706807Sck153898 * post-process the list to deal with pool state and possible
18716807Sck153898 * duplicate names.
18726807Sck153898 */
1873789Sahrens err = 0;
1874789Sahrens elem = NULL;
18752082Seschrock first = B_TRUE;
1876789Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1877789Sahrens
1878789Sahrens verify(nvpair_value_nvlist(elem, &config) == 0);
1879789Sahrens
18801631Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
18811631Sdarrenm &pool_state) == 0);
18821631Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
18831631Sdarrenm continue;
18841631Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
18851631Sdarrenm continue;
18861631Sdarrenm
188710921STim.Haley@Sun.COM verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY,
188810921STim.Haley@Sun.COM policy) == 0);
188910921STim.Haley@Sun.COM
1890789Sahrens if (argc == 0) {
1891789Sahrens if (first)
18922082Seschrock first = B_FALSE;
18932474Seschrock else if (!do_all)
1894789Sahrens (void) printf("\n");
1895789Sahrens
189610921STim.Haley@Sun.COM if (do_all) {
1897789Sahrens err |= do_import(config, NULL, mntopts,
189812949SGeorge.Wilson@Sun.COM props, flags);
189910921STim.Haley@Sun.COM } else {
1900789Sahrens show_import(config);
190110921STim.Haley@Sun.COM }
1902789Sahrens } else if (searchname != NULL) {
1903789Sahrens char *name;
1904789Sahrens
1905789Sahrens /*
1906789Sahrens * We are searching for a pool based on name.
1907789Sahrens */
1908789Sahrens verify(nvlist_lookup_string(config,
1909789Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1910789Sahrens
1911789Sahrens if (strcmp(name, searchname) == 0) {
1912789Sahrens if (found_config != NULL) {
1913789Sahrens (void) fprintf(stderr, gettext(
1914789Sahrens "cannot import '%s': more than "
1915789Sahrens "one matching pool\n"), searchname);
1916789Sahrens (void) fprintf(stderr, gettext(
1917789Sahrens "import by numeric ID instead\n"));
19182082Seschrock err = B_TRUE;
1919789Sahrens }
1920789Sahrens found_config = config;
1921789Sahrens }
1922789Sahrens } else {
1923789Sahrens uint64_t guid;
1924789Sahrens
1925789Sahrens /*
1926789Sahrens * Search for a pool by guid.
1927789Sahrens */
1928789Sahrens verify(nvlist_lookup_uint64(config,
1929789Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1930789Sahrens
1931789Sahrens if (guid == searchguid)
1932789Sahrens found_config = config;
1933789Sahrens }
1934789Sahrens }
1935789Sahrens
1936789Sahrens /*
1937789Sahrens * If we were searching for a specific pool, verify that we found a
1938789Sahrens * pool, and then do the import.
1939789Sahrens */
1940789Sahrens if (argc != 0 && err == 0) {
1941789Sahrens if (found_config == NULL) {
1942789Sahrens (void) fprintf(stderr, gettext("cannot import '%s': "
1943789Sahrens "no such pool available\n"), argv[0]);
19442082Seschrock err = B_TRUE;
1945789Sahrens } else {
1946789Sahrens err |= do_import(found_config, argc == 1 ? NULL :
194712949SGeorge.Wilson@Sun.COM argv[1], mntopts, props, flags);
1948789Sahrens }
1949789Sahrens }
1950789Sahrens
1951789Sahrens /*
1952789Sahrens * If we were just looking for pools, report an error if none were
1953789Sahrens * found.
1954789Sahrens */
1955789Sahrens if (argc == 0 && first)
1956789Sahrens (void) fprintf(stderr,
1957789Sahrens gettext("no pools available to import\n"));
1958789Sahrens
19594543Smarks error:
19605363Seschrock nvlist_free(props);
1961789Sahrens nvlist_free(pools);
196210921STim.Haley@Sun.COM nvlist_free(policy);
19632082Seschrock free(searchdirs);
1964789Sahrens
1965789Sahrens return (err ? 1 : 0);
1966789Sahrens }
1967789Sahrens
1968789Sahrens typedef struct iostat_cbdata {
1969789Sahrens zpool_list_t *cb_list;
1970789Sahrens int cb_verbose;
1971789Sahrens int cb_iteration;
1972789Sahrens int cb_namewidth;
1973789Sahrens } iostat_cbdata_t;
1974789Sahrens
1975789Sahrens static void
print_iostat_separator(iostat_cbdata_t * cb)1976789Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1977789Sahrens {
1978789Sahrens int i = 0;
1979789Sahrens
1980789Sahrens for (i = 0; i < cb->cb_namewidth; i++)
1981789Sahrens (void) printf("-");
1982789Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n");
1983789Sahrens }
1984789Sahrens
1985789Sahrens static void
print_iostat_header(iostat_cbdata_t * cb)1986789Sahrens print_iostat_header(iostat_cbdata_t *cb)
1987789Sahrens {
1988789Sahrens (void) printf("%*s capacity operations bandwidth\n",
1989789Sahrens cb->cb_namewidth, "");
199010956SGeorge.Wilson@Sun.COM (void) printf("%-*s alloc free read write read write\n",
1991789Sahrens cb->cb_namewidth, "pool");
1992789Sahrens print_iostat_separator(cb);
1993789Sahrens }
1994789Sahrens
1995789Sahrens /*
1996789Sahrens * Display a single statistic.
1997789Sahrens */
19985094Slling static void
print_one_stat(uint64_t value)1999789Sahrens print_one_stat(uint64_t value)
2000789Sahrens {
2001789Sahrens char buf[64];
2002789Sahrens
2003789Sahrens zfs_nicenum(value, buf, sizeof (buf));
2004789Sahrens (void) printf(" %5s", buf);
2005789Sahrens }
2006789Sahrens
2007789Sahrens /*
2008789Sahrens * Print out all the statistics for the given vdev. This can either be the
2009789Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this
2010789Sahrens * is a verbose output, and we don't want to display the toplevel pool stats.
2011789Sahrens */
2012789Sahrens void
print_vdev_stats(zpool_handle_t * zhp,const char * name,nvlist_t * oldnv,nvlist_t * newnv,iostat_cbdata_t * cb,int depth)20131354Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
20141354Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2015789Sahrens {
2016789Sahrens nvlist_t **oldchild, **newchild;
2017789Sahrens uint_t c, children;
2018789Sahrens vdev_stat_t *oldvs, *newvs;
2019789Sahrens vdev_stat_t zerovs = { 0 };
2020789Sahrens uint64_t tdelta;
2021789Sahrens double scale;
20221171Seschrock char *vname;
2023789Sahrens
2024789Sahrens if (oldnv != NULL) {
202512296SLin.Ling@Sun.COM verify(nvlist_lookup_uint64_array(oldnv,
202612296SLin.Ling@Sun.COM ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2027789Sahrens } else {
2028789Sahrens oldvs = &zerovs;
2029789Sahrens }
2030789Sahrens
203112296SLin.Ling@Sun.COM verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2032789Sahrens (uint64_t **)&newvs, &c) == 0);
2033789Sahrens
2034789Sahrens if (strlen(name) + depth > cb->cb_namewidth)
2035789Sahrens (void) printf("%*s%s", depth, "", name);
2036789Sahrens else
2037789Sahrens (void) printf("%*s%s%*s", depth, "", name,
2038789Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), "");
2039789Sahrens
2040789Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
2041789Sahrens
2042789Sahrens if (tdelta == 0)
2043789Sahrens scale = 1.0;
2044789Sahrens else
2045789Sahrens scale = (double)NANOSEC / tdelta;
2046789Sahrens
2047789Sahrens /* only toplevel vdevs have capacity stats */
2048789Sahrens if (newvs->vs_space == 0) {
2049789Sahrens (void) printf(" - -");
2050789Sahrens } else {
2051789Sahrens print_one_stat(newvs->vs_alloc);
2052789Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc);
2053789Sahrens }
2054789Sahrens
2055789Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
2056789Sahrens oldvs->vs_ops[ZIO_TYPE_READ])));
2057789Sahrens
2058789Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2059789Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE])));
2060789Sahrens
2061789Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2062789Sahrens oldvs->vs_bytes[ZIO_TYPE_READ])));
2063789Sahrens
2064789Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2065789Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2066789Sahrens
2067789Sahrens (void) printf("\n");
2068789Sahrens
2069789Sahrens if (!cb->cb_verbose)
2070789Sahrens return;
2071789Sahrens
2072789Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2073789Sahrens &newchild, &children) != 0)
2074789Sahrens return;
2075789Sahrens
2076789Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2077789Sahrens &oldchild, &c) != 0)
2078789Sahrens return;
2079789Sahrens
20801171Seschrock for (c = 0; c < children; c++) {
208112296SLin.Ling@Sun.COM uint64_t ishole = B_FALSE;
208212296SLin.Ling@Sun.COM
208312296SLin.Ling@Sun.COM if (nvlist_lookup_uint64(newchild[c],
208412296SLin.Ling@Sun.COM ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
208512296SLin.Ling@Sun.COM continue;
208612296SLin.Ling@Sun.COM
208710594SGeorge.Wilson@Sun.COM vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
20881354Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
20891171Seschrock newchild[c], cb, depth + 2);
20901171Seschrock free(vname);
20911171Seschrock }
20925450Sbrendan
20935450Sbrendan /*
20945450Sbrendan * Include level 2 ARC devices in iostat output
20955450Sbrendan */
20965450Sbrendan if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
20975450Sbrendan &newchild, &children) != 0)
20985450Sbrendan return;
20995450Sbrendan
21005450Sbrendan if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
21015450Sbrendan &oldchild, &c) != 0)
21025450Sbrendan return;
21035450Sbrendan
21045450Sbrendan if (children > 0) {
21055450Sbrendan (void) printf("%-*s - - - - - "
21065450Sbrendan "-\n", cb->cb_namewidth, "cache");
21075450Sbrendan for (c = 0; c < children; c++) {
210810594SGeorge.Wilson@Sun.COM vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
210910594SGeorge.Wilson@Sun.COM B_FALSE);
21105450Sbrendan print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
21115450Sbrendan newchild[c], cb, depth + 2);
21125450Sbrendan free(vname);
21135450Sbrendan }
21145450Sbrendan }
2115789Sahrens }
2116789Sahrens
2117952Seschrock static int
refresh_iostat(zpool_handle_t * zhp,void * data)2118952Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
2119952Seschrock {
2120952Seschrock iostat_cbdata_t *cb = data;
21212142Seschrock boolean_t missing;
2122952Seschrock
2123952Seschrock /*
2124952Seschrock * If the pool has disappeared, remove it from the list and continue.
2125952Seschrock */
21262142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0)
21272142Seschrock return (-1);
21282142Seschrock
21292142Seschrock if (missing)
2130952Seschrock pool_list_remove(cb->cb_list, zhp);
2131952Seschrock
2132952Seschrock return (0);
2133952Seschrock }
2134952Seschrock
2135789Sahrens /*
2136789Sahrens * Callback to print out the iostats for the given pool.
2137789Sahrens */
2138789Sahrens int
print_iostat(zpool_handle_t * zhp,void * data)2139789Sahrens print_iostat(zpool_handle_t *zhp, void *data)
2140789Sahrens {
2141789Sahrens iostat_cbdata_t *cb = data;
2142789Sahrens nvlist_t *oldconfig, *newconfig;
2143789Sahrens nvlist_t *oldnvroot, *newnvroot;
2144952Seschrock
2145952Seschrock newconfig = zpool_get_config(zhp, &oldconfig);
2146789Sahrens
2147952Seschrock if (cb->cb_iteration == 1)
2148952Seschrock oldconfig = NULL;
2149789Sahrens
2150789Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2151789Sahrens &newnvroot) == 0);
2152789Sahrens
2153952Seschrock if (oldconfig == NULL)
2154789Sahrens oldnvroot = NULL;
2155952Seschrock else
2156952Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2157952Seschrock &oldnvroot) == 0);
2158789Sahrens
2159789Sahrens /*
2160789Sahrens * Print out the statistics for the pool.
2161789Sahrens */
21621354Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2163789Sahrens
2164789Sahrens if (cb->cb_verbose)
2165789Sahrens print_iostat_separator(cb);
2166789Sahrens
2167789Sahrens return (0);
2168789Sahrens }
2169789Sahrens
2170789Sahrens int
get_namewidth(zpool_handle_t * zhp,void * data)2171789Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
2172789Sahrens {
2173789Sahrens iostat_cbdata_t *cb = data;
2174789Sahrens nvlist_t *config, *nvroot;
2175789Sahrens
2176952Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2177789Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2178789Sahrens &nvroot) == 0);
2179789Sahrens if (!cb->cb_verbose)
2180789Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp));
2181789Sahrens else
21821354Seschrock cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
2183789Sahrens }
2184789Sahrens
2185789Sahrens /*
2186789Sahrens * The width must fall into the range [10,38]. The upper limit is the
2187789Sahrens * maximum we can have and still fit in 80 columns.
2188789Sahrens */
2189789Sahrens if (cb->cb_namewidth < 10)
2190789Sahrens cb->cb_namewidth = 10;
2191789Sahrens if (cb->cb_namewidth > 38)
2192789Sahrens cb->cb_namewidth = 38;
2193789Sahrens
2194789Sahrens return (0);
2195789Sahrens }
2196789Sahrens
2197789Sahrens /*
219812296SLin.Ling@Sun.COM * Parse the input string, get the 'interval' and 'count' value if there is one.
2199789Sahrens */
220012296SLin.Ling@Sun.COM static void
get_interval_count(int * argcp,char ** argv,unsigned long * iv,unsigned long * cnt)220112296SLin.Ling@Sun.COM get_interval_count(int *argcp, char **argv, unsigned long *iv,
220212296SLin.Ling@Sun.COM unsigned long *cnt)
2203789Sahrens {
2204789Sahrens unsigned long interval = 0, count = 0;
220512296SLin.Ling@Sun.COM int argc = *argcp, errno;
2206789Sahrens
2207789Sahrens /*
2208789Sahrens * Determine if the last argument is an integer or a pool name
2209789Sahrens */
2210789Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) {
2211789Sahrens char *end;
2212789Sahrens
2213789Sahrens errno = 0;
2214789Sahrens interval = strtoul(argv[argc - 1], &end, 10);
2215789Sahrens
2216789Sahrens if (*end == '\0' && errno == 0) {
2217789Sahrens if (interval == 0) {
2218789Sahrens (void) fprintf(stderr, gettext("interval "
2219789Sahrens "cannot be zero\n"));
22202082Seschrock usage(B_FALSE);
2221789Sahrens }
2222789Sahrens /*
2223789Sahrens * Ignore the last parameter
2224789Sahrens */
2225789Sahrens argc--;
2226789Sahrens } else {
2227789Sahrens /*
2228789Sahrens * If this is not a valid number, just plow on. The
2229789Sahrens * user will get a more informative error message later
2230789Sahrens * on.
2231789Sahrens */
2232789Sahrens interval = 0;
2233789Sahrens }
2234789Sahrens }
2235789Sahrens
2236789Sahrens /*
2237789Sahrens * If the last argument is also an integer, then we have both a count
223812296SLin.Ling@Sun.COM * and an interval.
2239789Sahrens */
2240789Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) {
2241789Sahrens char *end;
2242789Sahrens
2243789Sahrens errno = 0;
2244789Sahrens count = interval;
2245789Sahrens interval = strtoul(argv[argc - 1], &end, 10);
2246789Sahrens
2247789Sahrens if (*end == '\0' && errno == 0) {
2248789Sahrens if (interval == 0) {
2249789Sahrens (void) fprintf(stderr, gettext("interval "
2250789Sahrens "cannot be zero\n"));
22512082Seschrock usage(B_FALSE);
2252789Sahrens }
2253789Sahrens
2254789Sahrens /*
2255789Sahrens * Ignore the last parameter
2256789Sahrens */
2257789Sahrens argc--;
2258789Sahrens } else {
2259789Sahrens interval = 0;
2260789Sahrens }
2261789Sahrens }
2262789Sahrens
226312296SLin.Ling@Sun.COM *iv = interval;
226412296SLin.Ling@Sun.COM *cnt = count;
226512296SLin.Ling@Sun.COM *argcp = argc;
226612296SLin.Ling@Sun.COM }
226712296SLin.Ling@Sun.COM
226812296SLin.Ling@Sun.COM static void
get_timestamp_arg(char c)226912296SLin.Ling@Sun.COM get_timestamp_arg(char c)
227012296SLin.Ling@Sun.COM {
227112296SLin.Ling@Sun.COM if (c == 'u')
227212296SLin.Ling@Sun.COM timestamp_fmt = UDATE;
227312296SLin.Ling@Sun.COM else if (c == 'd')
227412296SLin.Ling@Sun.COM timestamp_fmt = DDATE;
227512296SLin.Ling@Sun.COM else
227612296SLin.Ling@Sun.COM usage(B_FALSE);
227712296SLin.Ling@Sun.COM }
227812296SLin.Ling@Sun.COM
227912296SLin.Ling@Sun.COM /*
228012296SLin.Ling@Sun.COM * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
228112296SLin.Ling@Sun.COM *
228212296SLin.Ling@Sun.COM * -v Display statistics for individual vdevs
228312296SLin.Ling@Sun.COM * -T Display a timestamp in date(1) or Unix format
228412296SLin.Ling@Sun.COM *
228512296SLin.Ling@Sun.COM * This command can be tricky because we want to be able to deal with pool
228612296SLin.Ling@Sun.COM * creation/destruction as well as vdev configuration changes. The bulk of this
228712296SLin.Ling@Sun.COM * processing is handled by the pool_list_* routines in zpool_iter.c. We rely
228812296SLin.Ling@Sun.COM * on pool_list_update() to detect the addition of new pools. Configuration
228912296SLin.Ling@Sun.COM * changes are all handled within libzfs.
229012296SLin.Ling@Sun.COM */
229112296SLin.Ling@Sun.COM int
zpool_do_iostat(int argc,char ** argv)229212296SLin.Ling@Sun.COM zpool_do_iostat(int argc, char **argv)
229312296SLin.Ling@Sun.COM {
229412296SLin.Ling@Sun.COM int c;
229512296SLin.Ling@Sun.COM int ret;
229612296SLin.Ling@Sun.COM int npools;
229712296SLin.Ling@Sun.COM unsigned long interval = 0, count = 0;
229812296SLin.Ling@Sun.COM zpool_list_t *list;
229912296SLin.Ling@Sun.COM boolean_t verbose = B_FALSE;
230012296SLin.Ling@Sun.COM iostat_cbdata_t cb;
230112296SLin.Ling@Sun.COM
230212296SLin.Ling@Sun.COM /* check options */
230312296SLin.Ling@Sun.COM while ((c = getopt(argc, argv, "T:v")) != -1) {
230412296SLin.Ling@Sun.COM switch (c) {
230512296SLin.Ling@Sun.COM case 'T':
230612296SLin.Ling@Sun.COM get_timestamp_arg(*optarg);
230712296SLin.Ling@Sun.COM break;
230812296SLin.Ling@Sun.COM case 'v':
230912296SLin.Ling@Sun.COM verbose = B_TRUE;
231012296SLin.Ling@Sun.COM break;
231112296SLin.Ling@Sun.COM case '?':
231212296SLin.Ling@Sun.COM (void) fprintf(stderr, gettext("invalid option '%c'\n"),
231312296SLin.Ling@Sun.COM optopt);
231412296SLin.Ling@Sun.COM usage(B_FALSE);
231512296SLin.Ling@Sun.COM }
231612296SLin.Ling@Sun.COM }
231712296SLin.Ling@Sun.COM
231812296SLin.Ling@Sun.COM argc -= optind;
231912296SLin.Ling@Sun.COM argv += optind;
232012296SLin.Ling@Sun.COM
232112296SLin.Ling@Sun.COM get_interval_count(&argc, argv, &interval, &count);
232212296SLin.Ling@Sun.COM
2323789Sahrens /*
2324789Sahrens * Construct the list of all interesting pools.
2325789Sahrens */
2326789Sahrens ret = 0;
23273912Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2328789Sahrens return (1);
2329789Sahrens
23302082Seschrock if (pool_list_count(list) == 0 && argc != 0) {
23312082Seschrock pool_list_free(list);
2332789Sahrens return (1);
23332082Seschrock }
2334789Sahrens
2335789Sahrens if (pool_list_count(list) == 0 && interval == 0) {
23362082Seschrock pool_list_free(list);
2337789Sahrens (void) fprintf(stderr, gettext("no pools available\n"));
2338789Sahrens return (1);
2339789Sahrens }
2340789Sahrens
2341789Sahrens /*
2342789Sahrens * Enter the main iostat loop.
2343789Sahrens */
2344789Sahrens cb.cb_list = list;
2345789Sahrens cb.cb_verbose = verbose;
2346789Sahrens cb.cb_iteration = 0;
2347789Sahrens cb.cb_namewidth = 0;
2348789Sahrens
2349789Sahrens for (;;) {
2350789Sahrens pool_list_update(list);
2351789Sahrens
2352789Sahrens if ((npools = pool_list_count(list)) == 0)
2353789Sahrens break;
2354789Sahrens
2355789Sahrens /*
2356952Seschrock * Refresh all statistics. This is done as an explicit step
2357952Seschrock * before calculating the maximum name width, so that any
2358952Seschrock * configuration changes are properly accounted for.
2359952Seschrock */
23602082Seschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2361952Seschrock
2362952Seschrock /*
2363789Sahrens * Iterate over all pools to determine the maximum width
2364789Sahrens * for the pool / device name column across all pools.
2365789Sahrens */
2366789Sahrens cb.cb_namewidth = 0;
23672082Seschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2368789Sahrens
236910265SKrishnendu.Sadhukhan@Sun.COM if (timestamp_fmt != NODATE)
237010265SKrishnendu.Sadhukhan@Sun.COM print_timestamp(timestamp_fmt);
237110265SKrishnendu.Sadhukhan@Sun.COM
2372789Sahrens /*
2373789Sahrens * If it's the first time, or verbose mode, print the header.
2374789Sahrens */
2375789Sahrens if (++cb.cb_iteration == 1 || verbose)
2376789Sahrens print_iostat_header(&cb);
2377789Sahrens
23782082Seschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2379789Sahrens
2380789Sahrens /*
2381789Sahrens * If there's more than one pool, and we're not in verbose mode
2382789Sahrens * (which prints a separator for us), then print a separator.
2383789Sahrens */
2384789Sahrens if (npools > 1 && !verbose)
2385789Sahrens print_iostat_separator(&cb);
2386789Sahrens
2387789Sahrens if (verbose)
2388789Sahrens (void) printf("\n");
2389789Sahrens
23903377Seschrock /*
23913377Seschrock * Flush the output so that redirection to a file isn't buffered
23923377Seschrock * indefinitely.
23933377Seschrock */
23943377Seschrock (void) fflush(stdout);
23953377Seschrock
2396789Sahrens if (interval == 0)
2397789Sahrens break;
2398789Sahrens
2399789Sahrens if (count != 0 && --count == 0)
2400789Sahrens break;
2401789Sahrens
2402789Sahrens (void) sleep(interval);
2403789Sahrens }
2404789Sahrens
2405789Sahrens pool_list_free(list);
2406789Sahrens
2407789Sahrens return (ret);
2408789Sahrens }
2409789Sahrens
2410789Sahrens typedef struct list_cbdata {
24112082Seschrock boolean_t cb_scripted;
24122082Seschrock boolean_t cb_first;
24135094Slling zprop_list_t *cb_proplist;
2414789Sahrens } list_cbdata_t;
2415789Sahrens
2416789Sahrens /*
2417789Sahrens * Given a list of columns to display, output appropriate headers for each one.
2418789Sahrens */
24195094Slling static void
print_header(zprop_list_t * pl)24205094Slling print_header(zprop_list_t *pl)
2421789Sahrens {
24225094Slling const char *header;
24235094Slling boolean_t first = B_TRUE;
24245094Slling boolean_t right_justify;
24255094Slling
24265094Slling for (; pl != NULL; pl = pl->pl_next) {
24275094Slling if (pl->pl_prop == ZPROP_INVAL)
24285094Slling continue;
24295094Slling
24305094Slling if (!first)
2431789Sahrens (void) printf(" ");
2432789Sahrens else
24335094Slling first = B_FALSE;
24345094Slling
24355094Slling header = zpool_prop_column_name(pl->pl_prop);
24365094Slling right_justify = zpool_prop_align_right(pl->pl_prop);
24375094Slling
24385094Slling if (pl->pl_next == NULL && !right_justify)
24395094Slling (void) printf("%s", header);
24405094Slling else if (right_justify)
24415094Slling (void) printf("%*s", pl->pl_width, header);
24425094Slling else
24435094Slling (void) printf("%-*s", pl->pl_width, header);
2444789Sahrens }
2445789Sahrens
2446789Sahrens (void) printf("\n");
2447789Sahrens }
2448789Sahrens
24495094Slling /*
24505094Slling * Given a pool and a list of properties, print out all the properties according
24515094Slling * to the described layout.
24525094Slling */
24535094Slling static void
print_pool(zpool_handle_t * zhp,zprop_list_t * pl,int scripted)24545094Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
24555094Slling {
24565094Slling boolean_t first = B_TRUE;
24575094Slling char property[ZPOOL_MAXPROPLEN];
24585094Slling char *propstr;
24595094Slling boolean_t right_justify;
24605094Slling int width;
24615094Slling
24625094Slling for (; pl != NULL; pl = pl->pl_next) {
24635094Slling if (!first) {
24645094Slling if (scripted)
24655094Slling (void) printf("\t");
24665094Slling else
24675094Slling (void) printf(" ");
24685094Slling } else {
24695094Slling first = B_FALSE;
24705094Slling }
24715094Slling
24725094Slling right_justify = B_FALSE;
24735094Slling if (pl->pl_prop != ZPROP_INVAL) {
24745094Slling if (zpool_get_prop(zhp, pl->pl_prop, property,
24755094Slling sizeof (property), NULL) != 0)
24765094Slling propstr = "-";
24775094Slling else
24785094Slling propstr = property;
24795094Slling
24805094Slling right_justify = zpool_prop_align_right(pl->pl_prop);
24815094Slling } else {
24825094Slling propstr = "-";
24835094Slling }
24845094Slling
24855094Slling width = pl->pl_width;
24865094Slling
24875094Slling /*
24885094Slling * If this is being called in scripted mode, or if this is the
24895094Slling * last column and it is left-justified, don't include a width
24905094Slling * format specifier.
24915094Slling */
24925094Slling if (scripted || (pl->pl_next == NULL && !right_justify))
24935094Slling (void) printf("%s", propstr);
24945094Slling else if (right_justify)
24955094Slling (void) printf("%*s", width, propstr);
24965094Slling else
24975094Slling (void) printf("%-*s", width, propstr);
24985094Slling }
24995094Slling
25005094Slling (void) printf("\n");
25015094Slling }
25025094Slling
25035094Slling /*
25045094Slling * Generic callback function to list a pool.
25055094Slling */
2506789Sahrens int
list_callback(zpool_handle_t * zhp,void * data)2507789Sahrens list_callback(zpool_handle_t *zhp, void *data)
2508789Sahrens {
2509789Sahrens list_cbdata_t *cbp = data;
2510789Sahrens
2511789Sahrens if (cbp->cb_first) {
2512789Sahrens if (!cbp->cb_scripted)
25135094Slling print_header(cbp->cb_proplist);
25142082Seschrock cbp->cb_first = B_FALSE;
2515789Sahrens }
2516789Sahrens
25175094Slling print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2518789Sahrens
2519789Sahrens return (0);
2520789Sahrens }
2521789Sahrens
2522789Sahrens /*
252312296SLin.Ling@Sun.COM * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
2524789Sahrens *
25255094Slling * -H Scripted mode. Don't display headers, and separate properties
25265094Slling * by a single tab.
25275094Slling * -o List of properties to display. Defaults to
252810956SGeorge.Wilson@Sun.COM * "name,size,allocated,free,capacity,health,altroot"
252912296SLin.Ling@Sun.COM * -T Display a timestamp in date(1) or Unix format
2530789Sahrens *
2531789Sahrens * List all pools in the system, whether or not they're healthy. Output space
2532789Sahrens * statistics for each one, as well as health status summary.
2533789Sahrens */
2534789Sahrens int
zpool_do_list(int argc,char ** argv)2535789Sahrens zpool_do_list(int argc, char **argv)
2536789Sahrens {
2537789Sahrens int c;
2538789Sahrens int ret;
2539789Sahrens list_cbdata_t cb = { 0 };
25405094Slling static char default_props[] =
254110956SGeorge.Wilson@Sun.COM "name,size,allocated,free,capacity,dedupratio,health,altroot";
25425094Slling char *props = default_props;
254312296SLin.Ling@Sun.COM unsigned long interval = 0, count = 0;
2544789Sahrens
2545789Sahrens /* check options */
254612296SLin.Ling@Sun.COM while ((c = getopt(argc, argv, ":Ho:T:")) != -1) {
2547789Sahrens switch (c) {
2548789Sahrens case 'H':
25492082Seschrock cb.cb_scripted = B_TRUE;
2550789Sahrens break;
2551789Sahrens case 'o':
25525094Slling props = optarg;
2553789Sahrens break;
255412296SLin.Ling@Sun.COM case 'T':
255512296SLin.Ling@Sun.COM get_timestamp_arg(*optarg);
255612296SLin.Ling@Sun.COM break;
2557789Sahrens case ':':
2558789Sahrens (void) fprintf(stderr, gettext("missing argument for "
2559789Sahrens "'%c' option\n"), optopt);
25602082Seschrock usage(B_FALSE);
2561789Sahrens break;
2562789Sahrens case '?':
2563789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2564789Sahrens optopt);
25652082Seschrock usage(B_FALSE);
2566789Sahrens }
2567789Sahrens }
2568789Sahrens
2569789Sahrens argc -= optind;
2570789Sahrens argv += optind;
2571789Sahrens
257212296SLin.Ling@Sun.COM get_interval_count(&argc, argv, &interval, &count);
257312296SLin.Ling@Sun.COM
25745094Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
25755094Slling usage(B_FALSE);
2576789Sahrens
25772082Seschrock cb.cb_first = B_TRUE;
25782082Seschrock
257912296SLin.Ling@Sun.COM for (;;) {
258012296SLin.Ling@Sun.COM
258112296SLin.Ling@Sun.COM if (timestamp_fmt != NODATE)
258212296SLin.Ling@Sun.COM print_timestamp(timestamp_fmt);
258312296SLin.Ling@Sun.COM
258412296SLin.Ling@Sun.COM ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
258512296SLin.Ling@Sun.COM list_callback, &cb);
258612296SLin.Ling@Sun.COM
258712296SLin.Ling@Sun.COM if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
258812296SLin.Ling@Sun.COM (void) printf(gettext("no pools available\n"));
258912296SLin.Ling@Sun.COM zprop_free_list(cb.cb_proplist);
259012296SLin.Ling@Sun.COM return (0);
259112296SLin.Ling@Sun.COM }
259212296SLin.Ling@Sun.COM
259312296SLin.Ling@Sun.COM if (interval == 0)
259412296SLin.Ling@Sun.COM break;
259512296SLin.Ling@Sun.COM
259612296SLin.Ling@Sun.COM if (count != 0 && --count == 0)
259712296SLin.Ling@Sun.COM break;
259812296SLin.Ling@Sun.COM
259912296SLin.Ling@Sun.COM (void) sleep(interval);
260012296SLin.Ling@Sun.COM }
26015094Slling
26025094Slling zprop_free_list(cb.cb_proplist);
2603789Sahrens return (ret);
2604789Sahrens }
2605789Sahrens
2606789Sahrens static nvlist_t *
zpool_get_vdev_by_name(nvlist_t * nv,char * name)2607789Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2608789Sahrens {
2609789Sahrens nvlist_t **child;
2610789Sahrens uint_t c, children;
2611789Sahrens nvlist_t *match;
2612789Sahrens char *path;
2613789Sahrens
2614789Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2615789Sahrens &child, &children) != 0) {
2616789Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2617789Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0)
2618789Sahrens name += 9;
2619789Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0)
2620789Sahrens path += 9;
2621789Sahrens if (strcmp(name, path) == 0)
2622789Sahrens return (nv);
2623789Sahrens return (NULL);
2624789Sahrens }
2625789Sahrens
2626789Sahrens for (c = 0; c < children; c++)
2627789Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2628789Sahrens return (match);
2629789Sahrens
2630789Sahrens return (NULL);
2631789Sahrens }
2632789Sahrens
2633789Sahrens static int
zpool_do_attach_or_replace(int argc,char ** argv,int replacing)2634789Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2635789Sahrens {
26362082Seschrock boolean_t force = B_FALSE;
2637789Sahrens int c;
2638789Sahrens nvlist_t *nvroot;
2639789Sahrens char *poolname, *old_disk, *new_disk;
2640789Sahrens zpool_handle_t *zhp;
26412082Seschrock int ret;
2642789Sahrens
2643789Sahrens /* check options */
2644789Sahrens while ((c = getopt(argc, argv, "f")) != -1) {
2645789Sahrens switch (c) {
2646789Sahrens case 'f':
26472082Seschrock force = B_TRUE;
2648789Sahrens break;
2649789Sahrens case '?':
2650789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2651789Sahrens optopt);
26522082Seschrock usage(B_FALSE);
2653789Sahrens }
2654789Sahrens }
2655789Sahrens
2656789Sahrens argc -= optind;
2657789Sahrens argv += optind;
2658789Sahrens
2659789Sahrens /* get pool name and check number of arguments */
2660789Sahrens if (argc < 1) {
2661789Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n"));
26622082Seschrock usage(B_FALSE);
2663789Sahrens }
2664789Sahrens
2665789Sahrens poolname = argv[0];
2666789Sahrens
2667789Sahrens if (argc < 2) {
2668789Sahrens (void) fprintf(stderr,
2669789Sahrens gettext("missing <device> specification\n"));
26702082Seschrock usage(B_FALSE);
2671789Sahrens }
2672789Sahrens
2673789Sahrens old_disk = argv[1];
2674789Sahrens
2675789Sahrens if (argc < 3) {
2676789Sahrens if (!replacing) {
2677789Sahrens (void) fprintf(stderr,
2678789Sahrens gettext("missing <new_device> specification\n"));
26792082Seschrock usage(B_FALSE);
2680789Sahrens }
2681789Sahrens new_disk = old_disk;
2682789Sahrens argc -= 1;
2683789Sahrens argv += 1;
2684789Sahrens } else {
2685789Sahrens new_disk = argv[2];
2686789Sahrens argc -= 2;
2687789Sahrens argv += 2;
2688789Sahrens }
2689789Sahrens
2690789Sahrens if (argc > 1) {
2691789Sahrens (void) fprintf(stderr, gettext("too many arguments\n"));
26922082Seschrock usage(B_FALSE);
2693789Sahrens }
2694789Sahrens
26952082Seschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2696789Sahrens return (1);
2697789Sahrens
26984276Staylor if (zpool_get_config(zhp, NULL) == NULL) {
2699789Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2700789Sahrens poolname);
2701789Sahrens zpool_close(zhp);
2702789Sahrens return (1);
2703789Sahrens }
2704789Sahrens
27057343SEric.Taylor@Sun.COM nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
27067343SEric.Taylor@Sun.COM argc, argv);
2707789Sahrens if (nvroot == NULL) {
2708789Sahrens zpool_close(zhp);
2709789Sahrens return (1);
2710789Sahrens }
2711789Sahrens
27122082Seschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
27132082Seschrock
27142082Seschrock nvlist_free(nvroot);
27152082Seschrock zpool_close(zhp);
27162082Seschrock
27172082Seschrock return (ret);
2718789Sahrens }
2719789Sahrens
2720789Sahrens /*
2721789Sahrens * zpool replace [-f] <pool> <device> <new_device>
2722789Sahrens *
2723789Sahrens * -f Force attach, even if <new_device> appears to be in use.
2724789Sahrens *
2725789Sahrens * Replace <device> with <new_device>.
2726789Sahrens */
2727789Sahrens /* ARGSUSED */
2728789Sahrens int
zpool_do_replace(int argc,char ** argv)2729789Sahrens zpool_do_replace(int argc, char **argv)
2730789Sahrens {
2731789Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2732789Sahrens }
2733789Sahrens
2734789Sahrens /*
2735789Sahrens * zpool attach [-f] <pool> <device> <new_device>
2736789Sahrens *
2737789Sahrens * -f Force attach, even if <new_device> appears to be in use.
2738789Sahrens *
2739789Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not
2740789Sahrens * part of a mirror, then <device> will be transformed into a mirror of
2741789Sahrens * <device> and <new_device>. In either case, <new_device> will begin life
2742789Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself.
2743789Sahrens */
2744789Sahrens int
zpool_do_attach(int argc,char ** argv)2745789Sahrens zpool_do_attach(int argc, char **argv)
2746789Sahrens {
2747789Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2748789Sahrens }
2749789Sahrens
2750789Sahrens /*
2751789Sahrens * zpool detach [-f] <pool> <device>
2752789Sahrens *
2753789Sahrens * -f Force detach of <device>, even if DTLs argue against it
2754789Sahrens * (not supported yet)
2755789Sahrens *
2756789Sahrens * Detach a device from a mirror. The operation will be refused if <device>
2757789Sahrens * is the last device in the mirror, or if the DTLs indicate that this device
2758789Sahrens * has the only valid copy of some data.
2759789Sahrens */
2760789Sahrens /* ARGSUSED */
2761789Sahrens int
zpool_do_detach(int argc,char ** argv)2762789Sahrens zpool_do_detach(int argc, char **argv)
2763789Sahrens {
2764789Sahrens int c;
2765789Sahrens char *poolname, *path;
2766789Sahrens zpool_handle_t *zhp;
27672082Seschrock int ret;
2768789Sahrens
2769789Sahrens /* check options */
2770789Sahrens while ((c = getopt(argc, argv, "f")) != -1) {
2771789Sahrens switch (c) {
2772789Sahrens case 'f':
2773789Sahrens case '?':
2774789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2775789Sahrens optopt);
27762082Seschrock usage(B_FALSE);
2777789Sahrens }
2778789Sahrens }
2779789Sahrens
2780789Sahrens argc -= optind;
2781789Sahrens argv += optind;
2782789Sahrens
2783789Sahrens /* get pool name and check number of arguments */
2784789Sahrens if (argc < 1) {
2785789Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n"));
27862082Seschrock usage(B_FALSE);
2787789Sahrens }
2788789Sahrens
2789789Sahrens if (argc < 2) {
2790789Sahrens (void) fprintf(stderr,
2791789Sahrens gettext("missing <device> specification\n"));
27922082Seschrock usage(B_FALSE);
2793789Sahrens }
2794789Sahrens
2795789Sahrens poolname = argv[0];
2796789Sahrens path = argv[1];
2797789Sahrens
27982082Seschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2799789Sahrens return (1);
2800789Sahrens
28012082Seschrock ret = zpool_vdev_detach(zhp, path);
28022082Seschrock
28032082Seschrock zpool_close(zhp);
28042082Seschrock
28052082Seschrock return (ret);
2806789Sahrens }
2807789Sahrens
2808789Sahrens /*
280911422SMark.Musante@Sun.COM * zpool split [-n] [-o prop=val] ...
281011422SMark.Musante@Sun.COM * [-o mntopt] ...
281111422SMark.Musante@Sun.COM * [-R altroot] <pool> <newpool> [<device> ...]
281211422SMark.Musante@Sun.COM *
281311422SMark.Musante@Sun.COM * -n Do not split the pool, but display the resulting layout if
281411422SMark.Musante@Sun.COM * it were to be split.
281511422SMark.Musante@Sun.COM * -o Set property=value, or set mount options.
281611422SMark.Musante@Sun.COM * -R Mount the split-off pool under an alternate root.
281711422SMark.Musante@Sun.COM *
281811422SMark.Musante@Sun.COM * Splits the named pool and gives it the new pool name. Devices to be split
281911422SMark.Musante@Sun.COM * off may be listed, provided that no more than one device is specified
282011422SMark.Musante@Sun.COM * per top-level vdev mirror. The newly split pool is left in an exported
282111422SMark.Musante@Sun.COM * state unless -R is specified.
282211422SMark.Musante@Sun.COM *
282311422SMark.Musante@Sun.COM * Restrictions: the top-level of the pool pool must only be made up of
282411422SMark.Musante@Sun.COM * mirrors; all devices in the pool must be healthy; no device may be
282511422SMark.Musante@Sun.COM * undergoing a resilvering operation.
282611422SMark.Musante@Sun.COM */
282711422SMark.Musante@Sun.COM int
zpool_do_split(int argc,char ** argv)282811422SMark.Musante@Sun.COM zpool_do_split(int argc, char **argv)
282911422SMark.Musante@Sun.COM {
283011422SMark.Musante@Sun.COM char *srcpool, *newpool, *propval;
283111422SMark.Musante@Sun.COM char *mntopts = NULL;
283211422SMark.Musante@Sun.COM splitflags_t flags;
283311422SMark.Musante@Sun.COM int c, ret = 0;
283411422SMark.Musante@Sun.COM zpool_handle_t *zhp;
283511422SMark.Musante@Sun.COM nvlist_t *config, *props = NULL;
283611422SMark.Musante@Sun.COM
283711422SMark.Musante@Sun.COM flags.dryrun = B_FALSE;
283811422SMark.Musante@Sun.COM flags.import = B_FALSE;
283911422SMark.Musante@Sun.COM
284011422SMark.Musante@Sun.COM /* check options */
284111422SMark.Musante@Sun.COM while ((c = getopt(argc, argv, ":R:no:")) != -1) {
284211422SMark.Musante@Sun.COM switch (c) {
284311422SMark.Musante@Sun.COM case 'R':
284411422SMark.Musante@Sun.COM flags.import = B_TRUE;
284511422SMark.Musante@Sun.COM if (add_prop_list(
284611422SMark.Musante@Sun.COM zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
284711422SMark.Musante@Sun.COM &props, B_TRUE) != 0) {
284811422SMark.Musante@Sun.COM if (props)
284911422SMark.Musante@Sun.COM nvlist_free(props);
285011422SMark.Musante@Sun.COM usage(B_FALSE);
285111422SMark.Musante@Sun.COM }
285211422SMark.Musante@Sun.COM break;
285311422SMark.Musante@Sun.COM case 'n':
285411422SMark.Musante@Sun.COM flags.dryrun = B_TRUE;
285511422SMark.Musante@Sun.COM break;
285611422SMark.Musante@Sun.COM case 'o':
285711422SMark.Musante@Sun.COM if ((propval = strchr(optarg, '=')) != NULL) {
285811422SMark.Musante@Sun.COM *propval = '\0';
285911422SMark.Musante@Sun.COM propval++;
286011422SMark.Musante@Sun.COM if (add_prop_list(optarg, propval,
286111422SMark.Musante@Sun.COM &props, B_TRUE) != 0) {
286211422SMark.Musante@Sun.COM if (props)
286311422SMark.Musante@Sun.COM nvlist_free(props);
286411422SMark.Musante@Sun.COM usage(B_FALSE);
286511422SMark.Musante@Sun.COM }
286611422SMark.Musante@Sun.COM } else {
286711422SMark.Musante@Sun.COM mntopts = optarg;
286811422SMark.Musante@Sun.COM }
286911422SMark.Musante@Sun.COM break;
287011422SMark.Musante@Sun.COM case ':':
287111422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("missing argument for "
287211422SMark.Musante@Sun.COM "'%c' option\n"), optopt);
287311422SMark.Musante@Sun.COM usage(B_FALSE);
287411422SMark.Musante@Sun.COM break;
287511422SMark.Musante@Sun.COM case '?':
287611422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("invalid option '%c'\n"),
287711422SMark.Musante@Sun.COM optopt);
287811422SMark.Musante@Sun.COM usage(B_FALSE);
287911422SMark.Musante@Sun.COM break;
288011422SMark.Musante@Sun.COM }
288111422SMark.Musante@Sun.COM }
288211422SMark.Musante@Sun.COM
288311422SMark.Musante@Sun.COM if (!flags.import && mntopts != NULL) {
288411422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("setting mntopts is only "
288511422SMark.Musante@Sun.COM "valid when importing the pool\n"));
288611422SMark.Musante@Sun.COM usage(B_FALSE);
288711422SMark.Musante@Sun.COM }
288811422SMark.Musante@Sun.COM
288911422SMark.Musante@Sun.COM argc -= optind;
289011422SMark.Musante@Sun.COM argv += optind;
289111422SMark.Musante@Sun.COM
289211422SMark.Musante@Sun.COM if (argc < 1) {
289311422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("Missing pool name\n"));
289411422SMark.Musante@Sun.COM usage(B_FALSE);
289511422SMark.Musante@Sun.COM }
289611422SMark.Musante@Sun.COM if (argc < 2) {
289711422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("Missing new pool name\n"));
289811422SMark.Musante@Sun.COM usage(B_FALSE);
289911422SMark.Musante@Sun.COM }
290011422SMark.Musante@Sun.COM
290111422SMark.Musante@Sun.COM srcpool = argv[0];
290211422SMark.Musante@Sun.COM newpool = argv[1];
290311422SMark.Musante@Sun.COM
290411422SMark.Musante@Sun.COM argc -= 2;
290511422SMark.Musante@Sun.COM argv += 2;
290611422SMark.Musante@Sun.COM
290711422SMark.Musante@Sun.COM if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
290811422SMark.Musante@Sun.COM return (1);
290911422SMark.Musante@Sun.COM
291011422SMark.Musante@Sun.COM config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
291111422SMark.Musante@Sun.COM if (config == NULL) {
291211422SMark.Musante@Sun.COM ret = 1;
291311422SMark.Musante@Sun.COM } else {
291411422SMark.Musante@Sun.COM if (flags.dryrun) {
291511422SMark.Musante@Sun.COM (void) printf(gettext("would create '%s' with the "
291611422SMark.Musante@Sun.COM "following layout:\n\n"), newpool);
291711422SMark.Musante@Sun.COM print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
291811422SMark.Musante@Sun.COM }
291911422SMark.Musante@Sun.COM nvlist_free(config);
292011422SMark.Musante@Sun.COM }
292111422SMark.Musante@Sun.COM
292211422SMark.Musante@Sun.COM zpool_close(zhp);
292311422SMark.Musante@Sun.COM
292411422SMark.Musante@Sun.COM if (ret != 0 || flags.dryrun || !flags.import)
292511422SMark.Musante@Sun.COM return (ret);
292611422SMark.Musante@Sun.COM
292711422SMark.Musante@Sun.COM /*
292811422SMark.Musante@Sun.COM * The split was successful. Now we need to open the new
292911422SMark.Musante@Sun.COM * pool and import it.
293011422SMark.Musante@Sun.COM */
293111422SMark.Musante@Sun.COM if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
293211422SMark.Musante@Sun.COM return (1);
293311422SMark.Musante@Sun.COM if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
293411422SMark.Musante@Sun.COM zpool_enable_datasets(zhp, mntopts, 0) != 0) {
293511422SMark.Musante@Sun.COM ret = 1;
293611422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("Split was succssful, but "
293711422SMark.Musante@Sun.COM "the datasets could not all be mounted\n"));
293811422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("Try doing '%s' with a "
293911422SMark.Musante@Sun.COM "different altroot\n"), "zpool import");
294011422SMark.Musante@Sun.COM }
294111422SMark.Musante@Sun.COM zpool_close(zhp);
294211422SMark.Musante@Sun.COM
294311422SMark.Musante@Sun.COM return (ret);
294411422SMark.Musante@Sun.COM }
294511422SMark.Musante@Sun.COM
294611422SMark.Musante@Sun.COM
294711422SMark.Musante@Sun.COM
294811422SMark.Musante@Sun.COM /*
29491485Slling * zpool online <pool> <device> ...
2950789Sahrens */
2951789Sahrens int
zpool_do_online(int argc,char ** argv)2952789Sahrens zpool_do_online(int argc, char **argv)
2953789Sahrens {
2954789Sahrens int c, i;
2955789Sahrens char *poolname;
2956789Sahrens zpool_handle_t *zhp;
2957789Sahrens int ret = 0;
29584451Seschrock vdev_state_t newstate;
29599816SGeorge.Wilson@Sun.COM int flags = 0;
2960789Sahrens
2961789Sahrens /* check options */
29629816SGeorge.Wilson@Sun.COM while ((c = getopt(argc, argv, "et")) != -1) {
2963789Sahrens switch (c) {
29649816SGeorge.Wilson@Sun.COM case 'e':
29659816SGeorge.Wilson@Sun.COM flags |= ZFS_ONLINE_EXPAND;
29669816SGeorge.Wilson@Sun.COM break;
2967789Sahrens case 't':
2968789Sahrens case '?':
2969789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2970789Sahrens optopt);
29712082Seschrock usage(B_FALSE);
2972789Sahrens }
2973789Sahrens }
2974789Sahrens
2975789Sahrens argc -= optind;
2976789Sahrens argv += optind;
2977789Sahrens
2978789Sahrens /* get pool name and check number of arguments */
2979789Sahrens if (argc < 1) {
2980789Sahrens (void) fprintf(stderr, gettext("missing pool name\n"));
29812082Seschrock usage(B_FALSE);
2982789Sahrens }
2983789Sahrens if (argc < 2) {
2984789Sahrens (void) fprintf(stderr, gettext("missing device name\n"));
29852082Seschrock usage(B_FALSE);
2986789Sahrens }
2987789Sahrens
2988789Sahrens poolname = argv[0];
2989789Sahrens
29902082Seschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2991789Sahrens return (1);
2992789Sahrens
29934451Seschrock for (i = 1; i < argc; i++) {
29949816SGeorge.Wilson@Sun.COM if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
29954451Seschrock if (newstate != VDEV_STATE_HEALTHY) {
29964451Seschrock (void) printf(gettext("warning: device '%s' "
29974451Seschrock "onlined, but remains in faulted state\n"),
29984451Seschrock argv[i]);
29994451Seschrock if (newstate == VDEV_STATE_FAULTED)
30004451Seschrock (void) printf(gettext("use 'zpool "
30014451Seschrock "clear' to restore a faulted "
30024451Seschrock "device\n"));
30034451Seschrock else
30044451Seschrock (void) printf(gettext("use 'zpool "
30054451Seschrock "replace' to replace devices "
30064451Seschrock "that are no longer present\n"));
30074451Seschrock }
30084451Seschrock } else {
3009789Sahrens ret = 1;
30104451Seschrock }
30114451Seschrock }
3012789Sahrens
30132082Seschrock zpool_close(zhp);
30142082Seschrock
3015789Sahrens return (ret);
3016789Sahrens }
3017789Sahrens
3018789Sahrens /*
30191485Slling * zpool offline [-ft] <pool> <device> ...
3020789Sahrens *
3021789Sahrens * -f Force the device into the offline state, even if doing
3022789Sahrens * so would appear to compromise pool availability.
3023789Sahrens * (not supported yet)
3024789Sahrens *
3025789Sahrens * -t Only take the device off-line temporarily. The offline
3026789Sahrens * state will not be persistent across reboots.
3027789Sahrens */
3028789Sahrens /* ARGSUSED */
3029789Sahrens int
zpool_do_offline(int argc,char ** argv)3030789Sahrens zpool_do_offline(int argc, char **argv)
3031789Sahrens {
3032789Sahrens int c, i;
3033789Sahrens char *poolname;
3034789Sahrens zpool_handle_t *zhp;
30352082Seschrock int ret = 0;
30362082Seschrock boolean_t istmp = B_FALSE;
3037789Sahrens
3038789Sahrens /* check options */
3039789Sahrens while ((c = getopt(argc, argv, "ft")) != -1) {
3040789Sahrens switch (c) {
30411485Slling case 't':
30422082Seschrock istmp = B_TRUE;
30431485Slling break;
3044789Sahrens case 'f':
3045789Sahrens case '?':
3046789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3047789Sahrens optopt);
30482082Seschrock usage(B_FALSE);
3049789Sahrens }
3050789Sahrens }
3051789Sahrens
3052789Sahrens argc -= optind;
3053789Sahrens argv += optind;
3054789Sahrens
3055789Sahrens /* get pool name and check number of arguments */
3056789Sahrens if (argc < 1) {
3057789Sahrens (void) fprintf(stderr, gettext("missing pool name\n"));
30582082Seschrock usage(B_FALSE);
3059789Sahrens }
3060789Sahrens if (argc < 2) {
3061789Sahrens (void) fprintf(stderr, gettext("missing device name\n"));
30622082Seschrock usage(B_FALSE);
3063789Sahrens }
3064789Sahrens
3065789Sahrens poolname = argv[0];
3066789Sahrens
30672082Seschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3068789Sahrens return (1);
3069789Sahrens
30704451Seschrock for (i = 1; i < argc; i++) {
30714451Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
3072789Sahrens ret = 1;
30734451Seschrock }
3074789Sahrens
30752082Seschrock zpool_close(zhp);
30762082Seschrock
3077789Sahrens return (ret);
3078789Sahrens }
3079789Sahrens
30801544Seschrock /*
30811544Seschrock * zpool clear <pool> [device]
30821544Seschrock *
30831544Seschrock * Clear all errors associated with a pool or a particular device.
30841544Seschrock */
30851544Seschrock int
zpool_do_clear(int argc,char ** argv)30861544Seschrock zpool_do_clear(int argc, char **argv)
30871544Seschrock {
308810921STim.Haley@Sun.COM int c;
30891544Seschrock int ret = 0;
309010921STim.Haley@Sun.COM boolean_t dryrun = B_FALSE;
309110921STim.Haley@Sun.COM boolean_t do_rewind = B_FALSE;
309210921STim.Haley@Sun.COM boolean_t xtreme_rewind = B_FALSE;
309310921STim.Haley@Sun.COM uint32_t rewind_policy = ZPOOL_NO_REWIND;
309410921STim.Haley@Sun.COM nvlist_t *policy = NULL;
30951544Seschrock zpool_handle_t *zhp;
30961544Seschrock char *pool, *device;
30971544Seschrock
309810921STim.Haley@Sun.COM /* check options */
309910921STim.Haley@Sun.COM while ((c = getopt(argc, argv, "FnX")) != -1) {
310010921STim.Haley@Sun.COM switch (c) {
310110921STim.Haley@Sun.COM case 'F':
310210921STim.Haley@Sun.COM do_rewind = B_TRUE;
310310921STim.Haley@Sun.COM break;
310410921STim.Haley@Sun.COM case 'n':
310510921STim.Haley@Sun.COM dryrun = B_TRUE;
310610921STim.Haley@Sun.COM break;
310710921STim.Haley@Sun.COM case 'X':
310810921STim.Haley@Sun.COM xtreme_rewind = B_TRUE;
310910921STim.Haley@Sun.COM break;
311010921STim.Haley@Sun.COM case '?':
311110921STim.Haley@Sun.COM (void) fprintf(stderr, gettext("invalid option '%c'\n"),
311210921STim.Haley@Sun.COM optopt);
311310921STim.Haley@Sun.COM usage(B_FALSE);
311410921STim.Haley@Sun.COM }
311510921STim.Haley@Sun.COM }
311610921STim.Haley@Sun.COM
311710921STim.Haley@Sun.COM argc -= optind;
311810921STim.Haley@Sun.COM argv += optind;
311910921STim.Haley@Sun.COM
312010921STim.Haley@Sun.COM if (argc < 1) {
31211544Seschrock (void) fprintf(stderr, gettext("missing pool name\n"));
31222082Seschrock usage(B_FALSE);
31231544Seschrock }
31241544Seschrock
312510921STim.Haley@Sun.COM if (argc > 2) {
31261544Seschrock (void) fprintf(stderr, gettext("too many arguments\n"));
31272082Seschrock usage(B_FALSE);
31281544Seschrock }
31291544Seschrock
313010921STim.Haley@Sun.COM if ((dryrun || xtreme_rewind) && !do_rewind) {
313110921STim.Haley@Sun.COM (void) fprintf(stderr,
313210921STim.Haley@Sun.COM gettext("-n or -X only meaningful with -F\n"));
313310921STim.Haley@Sun.COM usage(B_FALSE);
313410921STim.Haley@Sun.COM }
313510921STim.Haley@Sun.COM if (dryrun)
313610921STim.Haley@Sun.COM rewind_policy = ZPOOL_TRY_REWIND;
313710921STim.Haley@Sun.COM else if (do_rewind)
313810921STim.Haley@Sun.COM rewind_policy = ZPOOL_DO_REWIND;
313910921STim.Haley@Sun.COM if (xtreme_rewind)
314010921STim.Haley@Sun.COM rewind_policy |= ZPOOL_EXTREME_REWIND;
314110921STim.Haley@Sun.COM
314210921STim.Haley@Sun.COM /* In future, further rewind policy choices can be passed along here */
314310921STim.Haley@Sun.COM if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
314410921STim.Haley@Sun.COM nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
31451544Seschrock return (1);
31461544Seschrock
314710921STim.Haley@Sun.COM pool = argv[0];
314810921STim.Haley@Sun.COM device = argc == 2 ? argv[1] : NULL;
314910921STim.Haley@Sun.COM
315010921STim.Haley@Sun.COM if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
315110921STim.Haley@Sun.COM nvlist_free(policy);
315210921STim.Haley@Sun.COM return (1);
315310921STim.Haley@Sun.COM }
315410921STim.Haley@Sun.COM
315510921STim.Haley@Sun.COM if (zpool_clear(zhp, device, policy) != 0)
31561544Seschrock ret = 1;
31571544Seschrock
31581544Seschrock zpool_close(zhp);
31591544Seschrock
316010921STim.Haley@Sun.COM nvlist_free(policy);
316110921STim.Haley@Sun.COM
31621544Seschrock return (ret);
31631544Seschrock }
31641544Seschrock
3165789Sahrens typedef struct scrub_cbdata {
3166789Sahrens int cb_type;
31672926Sek110237 int cb_argc;
31682926Sek110237 char **cb_argv;
3169789Sahrens } scrub_cbdata_t;
3170789Sahrens
3171789Sahrens int
scrub_callback(zpool_handle_t * zhp,void * data)3172789Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
3173789Sahrens {
3174789Sahrens scrub_cbdata_t *cb = data;
31752926Sek110237 int err;
3176789Sahrens
31771544Seschrock /*
31781544Seschrock * Ignore faulted pools.
31791544Seschrock */
31801544Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
31811544Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
31821544Seschrock "currently unavailable\n"), zpool_get_name(zhp));
31831544Seschrock return (1);
31841544Seschrock }
31851544Seschrock
318612296SLin.Ling@Sun.COM err = zpool_scan(zhp, cb->cb_type);
31872926Sek110237
31882926Sek110237 return (err != 0);
3189789Sahrens }
3190789Sahrens
3191789Sahrens /*
3192789Sahrens * zpool scrub [-s] <pool> ...
3193789Sahrens *
3194789Sahrens * -s Stop. Stops any in-progress scrub.
3195789Sahrens */
3196789Sahrens int
zpool_do_scrub(int argc,char ** argv)3197789Sahrens zpool_do_scrub(int argc, char **argv)
3198789Sahrens {
3199789Sahrens int c;
3200789Sahrens scrub_cbdata_t cb;
3201789Sahrens
320212296SLin.Ling@Sun.COM cb.cb_type = POOL_SCAN_SCRUB;
3203789Sahrens
3204789Sahrens /* check options */
3205789Sahrens while ((c = getopt(argc, argv, "s")) != -1) {
3206789Sahrens switch (c) {
3207789Sahrens case 's':
320812296SLin.Ling@Sun.COM cb.cb_type = POOL_SCAN_NONE;
3209789Sahrens break;
3210789Sahrens case '?':
3211789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3212789Sahrens optopt);
32132082Seschrock usage(B_FALSE);
3214789Sahrens }
3215789Sahrens }
3216789Sahrens
32172926Sek110237 cb.cb_argc = argc;
32182926Sek110237 cb.cb_argv = argv;
3219789Sahrens argc -= optind;
3220789Sahrens argv += optind;
3221789Sahrens
3222789Sahrens if (argc < 1) {
3223789Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n"));
32242082Seschrock usage(B_FALSE);
3225789Sahrens }
3226789Sahrens
32273912Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
3228789Sahrens }
3229789Sahrens
3230789Sahrens typedef struct status_cbdata {
32312082Seschrock int cb_count;
32322676Seschrock boolean_t cb_allpools;
32332082Seschrock boolean_t cb_verbose;
32342082Seschrock boolean_t cb_explain;
32352082Seschrock boolean_t cb_first;
323611149SGeorge.Wilson@Sun.COM boolean_t cb_dedup_stats;
3237789Sahrens } status_cbdata_t;
3238789Sahrens
3239789Sahrens /*
3240789Sahrens * Print out detailed scrub status.
3241789Sahrens */
3242789Sahrens void
print_scan_status(pool_scan_stat_t * ps)324312296SLin.Ling@Sun.COM print_scan_status(pool_scan_stat_t *ps)
3244789Sahrens {
324512296SLin.Ling@Sun.COM time_t start, end;
3246*13099SLin.Ling@Sun.COM uint64_t elapsed, mins_left, hours_left;
324712296SLin.Ling@Sun.COM uint64_t pass_exam, examined, total;
324812296SLin.Ling@Sun.COM uint_t rate;
3249789Sahrens double fraction_done;
325012296SLin.Ling@Sun.COM char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
325112296SLin.Ling@Sun.COM
325212296SLin.Ling@Sun.COM (void) printf(gettext(" scan: "));
325312296SLin.Ling@Sun.COM
325412296SLin.Ling@Sun.COM /* If there's never been a scan, there's not much to say. */
325512296SLin.Ling@Sun.COM if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
325612296SLin.Ling@Sun.COM ps->pss_func >= POOL_SCAN_FUNCS) {
3257789Sahrens (void) printf(gettext("none requested\n"));
3258789Sahrens return;
3259789Sahrens }
3260789Sahrens
326112296SLin.Ling@Sun.COM start = ps->pss_start_time;
326212296SLin.Ling@Sun.COM end = ps->pss_end_time;
326312296SLin.Ling@Sun.COM zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
326412296SLin.Ling@Sun.COM
326512296SLin.Ling@Sun.COM assert(ps->pss_func == POOL_SCAN_SCRUB ||
326612296SLin.Ling@Sun.COM ps->pss_func == POOL_SCAN_RESILVER);
326712296SLin.Ling@Sun.COM /*
326812296SLin.Ling@Sun.COM * Scan is finished or canceled.
326912296SLin.Ling@Sun.COM */
327012296SLin.Ling@Sun.COM if (ps->pss_state == DSS_FINISHED) {
327112296SLin.Ling@Sun.COM uint64_t minutes_taken = (end - start) / 60;
327212296SLin.Ling@Sun.COM char *fmt;
327312296SLin.Ling@Sun.COM
327412296SLin.Ling@Sun.COM if (ps->pss_func == POOL_SCAN_SCRUB) {
327512296SLin.Ling@Sun.COM fmt = gettext("scrub repaired %s in %lluh%um with "
327612296SLin.Ling@Sun.COM "%llu errors on %s");
327712296SLin.Ling@Sun.COM } else if (ps->pss_func == POOL_SCAN_RESILVER) {
327812296SLin.Ling@Sun.COM fmt = gettext("resilvered %s in %lluh%um with "
327912296SLin.Ling@Sun.COM "%llu errors on %s");
328012296SLin.Ling@Sun.COM }
328112296SLin.Ling@Sun.COM /* LINTED */
328212296SLin.Ling@Sun.COM (void) printf(fmt, processed_buf,
32835853Sek110237 (u_longlong_t)(minutes_taken / 60),
32845853Sek110237 (uint_t)(minutes_taken % 60),
328512296SLin.Ling@Sun.COM (u_longlong_t)ps->pss_errors,
328612296SLin.Ling@Sun.COM ctime((time_t *)&end));
328712296SLin.Ling@Sun.COM return;
328812296SLin.Ling@Sun.COM } else if (ps->pss_state == DSS_CANCELED) {
328912296SLin.Ling@Sun.COM if (ps->pss_func == POOL_SCAN_SCRUB) {
329012296SLin.Ling@Sun.COM (void) printf(gettext("scrub canceled on %s"),
329112296SLin.Ling@Sun.COM ctime(&end));
329212296SLin.Ling@Sun.COM } else if (ps->pss_func == POOL_SCAN_RESILVER) {
329312296SLin.Ling@Sun.COM (void) printf(gettext("resilver canceled on %s"),
329412296SLin.Ling@Sun.COM ctime(&end));
329512296SLin.Ling@Sun.COM }
3296789Sahrens return;
3297789Sahrens }
3298789Sahrens
329912296SLin.Ling@Sun.COM assert(ps->pss_state == DSS_SCANNING);
330012296SLin.Ling@Sun.COM
330112296SLin.Ling@Sun.COM /*
330212296SLin.Ling@Sun.COM * Scan is in progress.
330312296SLin.Ling@Sun.COM */
330412296SLin.Ling@Sun.COM if (ps->pss_func == POOL_SCAN_SCRUB) {
330512296SLin.Ling@Sun.COM (void) printf(gettext("scrub in progress since %s"),
330612296SLin.Ling@Sun.COM ctime(&start));
330712296SLin.Ling@Sun.COM } else if (ps->pss_func == POOL_SCAN_RESILVER) {
330812296SLin.Ling@Sun.COM (void) printf(gettext("resilver in progress since %s"),
330912296SLin.Ling@Sun.COM ctime(&start));
331012296SLin.Ling@Sun.COM }
331112296SLin.Ling@Sun.COM
331212296SLin.Ling@Sun.COM examined = ps->pss_examined ? ps->pss_examined : 1;
331312296SLin.Ling@Sun.COM total = ps->pss_to_examine;
3314789Sahrens fraction_done = (double)examined / total;
331512296SLin.Ling@Sun.COM
331612296SLin.Ling@Sun.COM /* elapsed time for this pass */
331712296SLin.Ling@Sun.COM elapsed = time(NULL) - ps->pss_pass_start;
331812296SLin.Ling@Sun.COM elapsed = elapsed ? elapsed : 1;
331912296SLin.Ling@Sun.COM pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
332012296SLin.Ling@Sun.COM rate = pass_exam / elapsed;
332112296SLin.Ling@Sun.COM rate = rate ? rate : 1;
332212296SLin.Ling@Sun.COM mins_left = ((total - examined) / rate) / 60;
3323*13099SLin.Ling@Sun.COM hours_left = mins_left / 60;
332412296SLin.Ling@Sun.COM
332512296SLin.Ling@Sun.COM zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
332612296SLin.Ling@Sun.COM zfs_nicenum(total, total_buf, sizeof (total_buf));
332712296SLin.Ling@Sun.COM zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
332812296SLin.Ling@Sun.COM
3329*13099SLin.Ling@Sun.COM /*
3330*13099SLin.Ling@Sun.COM * do not print estimated time if hours_left is more than 30 days
3331*13099SLin.Ling@Sun.COM */
3332*13099SLin.Ling@Sun.COM (void) printf(gettext(" %s scanned out of %s at %s/s"),
3333*13099SLin.Ling@Sun.COM examined_buf, total_buf, rate_buf);
3334*13099SLin.Ling@Sun.COM if (hours_left < (30 * 24)) {
3335*13099SLin.Ling@Sun.COM (void) printf(gettext(", %lluh%um to go\n"),
3336*13099SLin.Ling@Sun.COM (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
3337*13099SLin.Ling@Sun.COM } else {
3338*13099SLin.Ling@Sun.COM (void) printf(gettext(
3339*13099SLin.Ling@Sun.COM ", (scan is slow, no estimated time)\n"));
3340*13099SLin.Ling@Sun.COM }
334112296SLin.Ling@Sun.COM
334212296SLin.Ling@Sun.COM if (ps->pss_func == POOL_SCAN_RESILVER) {
334312296SLin.Ling@Sun.COM (void) printf(gettext(" %s resilvered, %.2f%% done\n"),
334412296SLin.Ling@Sun.COM processed_buf, 100 * fraction_done);
334512296SLin.Ling@Sun.COM } else if (ps->pss_func == POOL_SCAN_SCRUB) {
334612296SLin.Ling@Sun.COM (void) printf(gettext(" %s repaired, %.2f%% done\n"),
334712296SLin.Ling@Sun.COM processed_buf, 100 * fraction_done);
334812296SLin.Ling@Sun.COM }
3349789Sahrens }
3350789Sahrens
33511544Seschrock static void
print_error_log(zpool_handle_t * zhp)33521544Seschrock print_error_log(zpool_handle_t *zhp)
33531544Seschrock {
33544820Sek110237 nvlist_t *nverrlist = NULL;
33553444Sek110237 nvpair_t *elem;
33563444Sek110237 char *pathname;
33573444Sek110237 size_t len = MAXPATHLEN * 2;
33583444Sek110237
33593444Sek110237 if (zpool_get_errlog(zhp, &nverrlist) != 0) {
33601544Seschrock (void) printf("errors: List of errors unavailable "
33611544Seschrock "(insufficient privileges)\n");
33621544Seschrock return;
33631544Seschrock }
33641544Seschrock
33653444Sek110237 (void) printf("errors: Permanent errors have been "
33663444Sek110237 "detected in the following files:\n\n");
33673444Sek110237
33683444Sek110237 pathname = safe_malloc(len);
33693444Sek110237 elem = NULL;
33703444Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
33713444Sek110237 nvlist_t *nv;
33723444Sek110237 uint64_t dsobj, obj;
33733444Sek110237
33743444Sek110237 verify(nvpair_value_nvlist(elem, &nv) == 0);
33753444Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
33763444Sek110237 &dsobj) == 0);
33773444Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
33783444Sek110237 &obj) == 0);
33793444Sek110237 zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
33803444Sek110237 (void) printf("%7s %s\n", "", pathname);
33811544Seschrock }
33823444Sek110237 free(pathname);
33833444Sek110237 nvlist_free(nverrlist);
33841544Seschrock }
33851544Seschrock
33862082Seschrock static void
print_spares(zpool_handle_t * zhp,nvlist_t ** spares,uint_t nspares,int namewidth)33872082Seschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
33882082Seschrock int namewidth)
33892082Seschrock {
33902082Seschrock uint_t i;
33912082Seschrock char *name;
33922082Seschrock
33932082Seschrock if (nspares == 0)
33942082Seschrock return;
33952082Seschrock
33962082Seschrock (void) printf(gettext("\tspares\n"));
33972082Seschrock
33982082Seschrock for (i = 0; i < nspares; i++) {
339910594SGeorge.Wilson@Sun.COM name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
34002082Seschrock print_status_config(zhp, name, spares[i],
34019391SNeil.Perrin@Sun.COM namewidth, 2, B_TRUE);
34022082Seschrock free(name);
34032082Seschrock }
34042082Seschrock }
34052082Seschrock
34065450Sbrendan static void
print_l2cache(zpool_handle_t * zhp,nvlist_t ** l2cache,uint_t nl2cache,int namewidth)34075450Sbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
34085450Sbrendan int namewidth)
34095450Sbrendan {
34105450Sbrendan uint_t i;
34115450Sbrendan char *name;
34125450Sbrendan
34135450Sbrendan if (nl2cache == 0)
34145450Sbrendan return;
34155450Sbrendan
34165450Sbrendan (void) printf(gettext("\tcache\n"));
34175450Sbrendan
34185450Sbrendan for (i = 0; i < nl2cache; i++) {
341910594SGeorge.Wilson@Sun.COM name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
34205450Sbrendan print_status_config(zhp, name, l2cache[i],
34219391SNeil.Perrin@Sun.COM namewidth, 2, B_FALSE);
34229391SNeil.Perrin@Sun.COM free(name);
34239391SNeil.Perrin@Sun.COM }
34249391SNeil.Perrin@Sun.COM }
34259391SNeil.Perrin@Sun.COM
342611149SGeorge.Wilson@Sun.COM static void
print_dedup_stats(nvlist_t * config)342711149SGeorge.Wilson@Sun.COM print_dedup_stats(nvlist_t *config)
342811149SGeorge.Wilson@Sun.COM {
342911149SGeorge.Wilson@Sun.COM ddt_histogram_t *ddh;
343011149SGeorge.Wilson@Sun.COM ddt_stat_t *dds;
343111149SGeorge.Wilson@Sun.COM ddt_object_t *ddo;
343211149SGeorge.Wilson@Sun.COM uint_t c;
343311149SGeorge.Wilson@Sun.COM
343411149SGeorge.Wilson@Sun.COM /*
343511149SGeorge.Wilson@Sun.COM * If the pool was faulted then we may not have been able to
343611149SGeorge.Wilson@Sun.COM * obtain the config. Otherwise, if have anything in the dedup
343711149SGeorge.Wilson@Sun.COM * table continue processing the stats.
343811149SGeorge.Wilson@Sun.COM */
343911149SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
344011149SGeorge.Wilson@Sun.COM (uint64_t **)&ddo, &c) != 0 || ddo->ddo_count == 0)
344111149SGeorge.Wilson@Sun.COM return;
344211149SGeorge.Wilson@Sun.COM
344311149SGeorge.Wilson@Sun.COM (void) printf("\n");
344411149SGeorge.Wilson@Sun.COM (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
344511149SGeorge.Wilson@Sun.COM (u_longlong_t)ddo->ddo_count,
344611149SGeorge.Wilson@Sun.COM (u_longlong_t)ddo->ddo_dspace,
344711149SGeorge.Wilson@Sun.COM (u_longlong_t)ddo->ddo_mspace);
344811149SGeorge.Wilson@Sun.COM
344911149SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
345011149SGeorge.Wilson@Sun.COM (uint64_t **)&dds, &c) == 0);
345111149SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
345211149SGeorge.Wilson@Sun.COM (uint64_t **)&ddh, &c) == 0);
345311149SGeorge.Wilson@Sun.COM zpool_dump_ddt(dds, ddh);
345411149SGeorge.Wilson@Sun.COM }
345511149SGeorge.Wilson@Sun.COM
34569391SNeil.Perrin@Sun.COM /*
3457789Sahrens * Display a summary of pool status. Displays a summary such as:
3458789Sahrens *
3459789Sahrens * pool: tank
3460789Sahrens * status: DEGRADED
3461789Sahrens * reason: One or more devices ...
3462789Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01
3463789Sahrens * config:
3464789Sahrens * mirror DEGRADED
3465789Sahrens * c1t0d0 OK
34661544Seschrock * c2t0d0 UNAVAIL
3467789Sahrens *
3468789Sahrens * When given the '-v' option, we print out the complete config. If the '-e'
3469789Sahrens * option is specified, then we print out error rate information as well.
3470789Sahrens */
3471789Sahrens int
status_callback(zpool_handle_t * zhp,void * data)3472789Sahrens status_callback(zpool_handle_t *zhp, void *data)
3473789Sahrens {
3474789Sahrens status_cbdata_t *cbp = data;
3475789Sahrens nvlist_t *config, *nvroot;
3476789Sahrens char *msgid;
3477789Sahrens int reason;
34783741Smmusante const char *health;
34793741Smmusante uint_t c;
34803741Smmusante vdev_stat_t *vs;
3481789Sahrens
3482952Seschrock config = zpool_get_config(zhp, NULL);
3483789Sahrens reason = zpool_get_status(zhp, &msgid);
3484789Sahrens
3485789Sahrens cbp->cb_count++;
3486789Sahrens
3487789Sahrens /*
3488789Sahrens * If we were given 'zpool status -x', only report those pools with
3489789Sahrens * problems.
3490789Sahrens */
34912676Seschrock if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
34922676Seschrock if (!cbp->cb_allpools) {
34932676Seschrock (void) printf(gettext("pool '%s' is healthy\n"),
34942676Seschrock zpool_get_name(zhp));
34952676Seschrock if (cbp->cb_first)
34962676Seschrock cbp->cb_first = B_FALSE;
34972676Seschrock }
3498789Sahrens return (0);
34992676Seschrock }
3500789Sahrens
3501789Sahrens if (cbp->cb_first)
35022082Seschrock cbp->cb_first = B_FALSE;
3503789Sahrens else
3504789Sahrens (void) printf("\n");
3505789Sahrens
35063741Smmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
35073741Smmusante &nvroot) == 0);
350812296SLin.Ling@Sun.COM verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
35093741Smmusante (uint64_t **)&vs, &c) == 0);
35105094Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3511789Sahrens
3512789Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp));
3513789Sahrens (void) printf(gettext(" state: %s\n"), health);
3514789Sahrens
3515789Sahrens switch (reason) {
3516789Sahrens case ZPOOL_STATUS_MISSING_DEV_R:
3517789Sahrens (void) printf(gettext("status: One or more devices could not "
3518789Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to "
3519789Sahrens "continue functioning in a degraded state.\n"));
3520789Sahrens (void) printf(gettext("action: Attach the missing device and "
3521789Sahrens "online it using 'zpool online'.\n"));
3522789Sahrens break;
3523789Sahrens
3524789Sahrens case ZPOOL_STATUS_MISSING_DEV_NR:
3525789Sahrens (void) printf(gettext("status: One or more devices could not "
3526789Sahrens "be opened. There are insufficient\n\treplicas for the "
3527789Sahrens "pool to continue functioning.\n"));
3528789Sahrens (void) printf(gettext("action: Attach the missing device and "
3529789Sahrens "online it using 'zpool online'.\n"));
3530789Sahrens break;
3531789Sahrens
3532789Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R:
3533789Sahrens (void) printf(gettext("status: One or more devices could not "
3534789Sahrens "be used because the label is missing or\n\tinvalid. "
3535789Sahrens "Sufficient replicas exist for the pool to continue\n\t"
3536789Sahrens "functioning in a degraded state.\n"));
3537789Sahrens (void) printf(gettext("action: Replace the device using "
3538789Sahrens "'zpool replace'.\n"));
3539789Sahrens break;
3540789Sahrens
3541789Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3542789Sahrens (void) printf(gettext("status: One or more devices could not "
35433912Slling "be used because the label is missing \n\tor invalid. "
3544789Sahrens "There are insufficient replicas for the pool to "
3545789Sahrens "continue\n\tfunctioning.\n"));
354610921STim.Haley@Sun.COM zpool_explain_recover(zpool_get_handle(zhp),
354710921STim.Haley@Sun.COM zpool_get_name(zhp), reason, config);
3548789Sahrens break;
3549789Sahrens
3550789Sahrens case ZPOOL_STATUS_FAILING_DEV:
3551789Sahrens (void) printf(gettext("status: One or more devices has "
3552789Sahrens "experienced an unrecoverable error. An\n\tattempt was "
3553789Sahrens "made to correct the error. Applications are "
3554789Sahrens "unaffected.\n"));
3555789Sahrens (void) printf(gettext("action: Determine if the device needs "
3556789Sahrens "to be replaced, and clear the errors\n\tusing "
35571544Seschrock "'zpool clear' or replace the device with 'zpool "
3558789Sahrens "replace'.\n"));
3559789Sahrens break;
3560789Sahrens
3561789Sahrens case ZPOOL_STATUS_OFFLINE_DEV:
3562789Sahrens (void) printf(gettext("status: One or more devices has "
35633413Smmusante "been taken offline by the administrator.\n\tSufficient "
3564789Sahrens "replicas exist for the pool to continue functioning in "
3565789Sahrens "a\n\tdegraded state.\n"));
3566789Sahrens (void) printf(gettext("action: Online the device using "
3567789Sahrens "'zpool online' or replace the device with\n\t'zpool "
3568789Sahrens "replace'.\n"));
3569789Sahrens break;
3570789Sahrens
357110151SGeorge.Wilson@Sun.COM case ZPOOL_STATUS_REMOVED_DEV:
357210151SGeorge.Wilson@Sun.COM (void) printf(gettext("status: One or more devices has "
357310151SGeorge.Wilson@Sun.COM "been removed by the administrator.\n\tSufficient "
357410151SGeorge.Wilson@Sun.COM "replicas exist for the pool to continue functioning in "
357510151SGeorge.Wilson@Sun.COM "a\n\tdegraded state.\n"));
357610151SGeorge.Wilson@Sun.COM (void) printf(gettext("action: Online the device using "
357710151SGeorge.Wilson@Sun.COM "'zpool online' or replace the device with\n\t'zpool "
357810151SGeorge.Wilson@Sun.COM "replace'.\n"));
357910151SGeorge.Wilson@Sun.COM break;
358010151SGeorge.Wilson@Sun.COM
3581789Sahrens case ZPOOL_STATUS_RESILVERING:
3582789Sahrens (void) printf(gettext("status: One or more devices is "
3583789Sahrens "currently being resilvered. The pool will\n\tcontinue "
3584789Sahrens "to function, possibly in a degraded state.\n"));
3585789Sahrens (void) printf(gettext("action: Wait for the resilver to "
3586789Sahrens "complete.\n"));
3587789Sahrens break;
3588789Sahrens
35891544Seschrock case ZPOOL_STATUS_CORRUPT_DATA:
35901544Seschrock (void) printf(gettext("status: One or more devices has "
35911544Seschrock "experienced an error resulting in data\n\tcorruption. "
35921544Seschrock "Applications may be affected.\n"));
35931544Seschrock (void) printf(gettext("action: Restore the file in question "
35941544Seschrock "if possible. Otherwise restore the\n\tentire pool from "
35951544Seschrock "backup.\n"));
35961544Seschrock break;
35971544Seschrock
35981544Seschrock case ZPOOL_STATUS_CORRUPT_POOL:
35991544Seschrock (void) printf(gettext("status: The pool metadata is corrupted "
36001544Seschrock "and the pool cannot be opened.\n"));
360110921STim.Haley@Sun.COM zpool_explain_recover(zpool_get_handle(zhp),
360210921STim.Haley@Sun.COM zpool_get_name(zhp), reason, config);
36031544Seschrock break;
36041544Seschrock
36051760Seschrock case ZPOOL_STATUS_VERSION_OLDER:
36061760Seschrock (void) printf(gettext("status: The pool is formatted using an "
36071760Seschrock "older on-disk format. The pool can\n\tstill be used, but "
36081760Seschrock "some features are unavailable.\n"));
36091760Seschrock (void) printf(gettext("action: Upgrade the pool using 'zpool "
36101760Seschrock "upgrade'. Once this is done, the\n\tpool will no longer "
36111760Seschrock "be accessible on older software versions.\n"));
36121760Seschrock break;
36131760Seschrock
36141760Seschrock case ZPOOL_STATUS_VERSION_NEWER:
36151760Seschrock (void) printf(gettext("status: The pool has been upgraded to a "
36161760Seschrock "newer, incompatible on-disk version.\n\tThe pool cannot "
36171760Seschrock "be accessed on this system.\n"));
36181760Seschrock (void) printf(gettext("action: Access the pool from a system "
36191760Seschrock "running more recent software, or\n\trestore the pool from "
36201760Seschrock "backup.\n"));
36211760Seschrock break;
36221760Seschrock
36234451Seschrock case ZPOOL_STATUS_FAULTED_DEV_R:
36244451Seschrock (void) printf(gettext("status: One or more devices are "
36254451Seschrock "faulted in response to persistent errors.\n\tSufficient "
36264451Seschrock "replicas exist for the pool to continue functioning "
36274451Seschrock "in a\n\tdegraded state.\n"));
36284451Seschrock (void) printf(gettext("action: Replace the faulted device, "
36294451Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n"));
36304451Seschrock break;
36314451Seschrock
36324451Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR:
36334451Seschrock (void) printf(gettext("status: One or more devices are "
36344451Seschrock "faulted in response to persistent errors. There are "
36354451Seschrock "insufficient replicas for the pool to\n\tcontinue "
36364451Seschrock "functioning.\n"));
36374451Seschrock (void) printf(gettext("action: Destroy and re-create the pool "
36384451Seschrock "from a backup source. Manually marking the device\n"
36394451Seschrock "\trepaired using 'zpool clear' may allow some data "
36404451Seschrock "to be recovered.\n"));
36414451Seschrock break;
36424451Seschrock
36436523Sek110237 case ZPOOL_STATUS_IO_FAILURE_WAIT:
36446523Sek110237 case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
36456523Sek110237 (void) printf(gettext("status: One or more devices are "
36466959Sek110237 "faulted in response to IO failures.\n"));
36476523Sek110237 (void) printf(gettext("action: Make sure the affected devices "
36486523Sek110237 "are connected, then run 'zpool clear'.\n"));
36496523Sek110237 break;
36506523Sek110237
36517294Sperrin case ZPOOL_STATUS_BAD_LOG:
36527294Sperrin (void) printf(gettext("status: An intent log record "
36537294Sperrin "could not be read.\n"
36547294Sperrin "\tWaiting for adminstrator intervention to fix the "
36557294Sperrin "faulted pool.\n"));
36567294Sperrin (void) printf(gettext("action: Either restore the affected "
36577294Sperrin "device(s) and run 'zpool online',\n"
36587294Sperrin "\tor ignore the intent log records by running "
36597294Sperrin "'zpool clear'.\n"));
36607294Sperrin break;
36617294Sperrin
3662789Sahrens default:
3663789Sahrens /*
3664789Sahrens * The remaining errors can't actually be generated, yet.
3665789Sahrens */
3666789Sahrens assert(reason == ZPOOL_STATUS_OK);
3667789Sahrens }
3668789Sahrens
3669789Sahrens if (msgid != NULL)
3670789Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"),
3671789Sahrens msgid);
3672789Sahrens
3673789Sahrens if (config != NULL) {
3674789Sahrens int namewidth;
36751544Seschrock uint64_t nerr;
36765450Sbrendan nvlist_t **spares, **l2cache;
36775450Sbrendan uint_t nspares, nl2cache;
367812296SLin.Ling@Sun.COM pool_scan_stat_t *ps = NULL;
367912296SLin.Ling@Sun.COM
368012296SLin.Ling@Sun.COM (void) nvlist_lookup_uint64_array(nvroot,
368112296SLin.Ling@Sun.COM ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
368212296SLin.Ling@Sun.COM print_scan_status(ps);
3683789Sahrens
36841354Seschrock namewidth = max_width(zhp, nvroot, 0, 0);
3685789Sahrens if (namewidth < 10)
3686789Sahrens namewidth = 10;
3687789Sahrens
3688789Sahrens (void) printf(gettext("config:\n\n"));
3689789Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth,
3690789Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM");
36911354Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot,
36929391SNeil.Perrin@Sun.COM namewidth, 0, B_FALSE);
36939391SNeil.Perrin@Sun.COM
36949466SNeil.Perrin@Sun.COM if (num_logs(nvroot) > 0)
36959701SGeorge.Wilson@Sun.COM print_logs(zhp, nvroot, namewidth, B_TRUE);
36965450Sbrendan if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
36975450Sbrendan &l2cache, &nl2cache) == 0)
36985450Sbrendan print_l2cache(zhp, l2cache, nl2cache, namewidth);
36995450Sbrendan
37002082Seschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
37012082Seschrock &spares, &nspares) == 0)
37022082Seschrock print_spares(zhp, spares, nspares, namewidth);
37031544Seschrock
37041544Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
37051544Seschrock &nerr) == 0) {
37063444Sek110237 nvlist_t *nverrlist = NULL;
37073444Sek110237
37081544Seschrock /*
37091544Seschrock * If the approximate error count is small, get a
37101544Seschrock * precise count by fetching the entire log and
37111544Seschrock * uniquifying the results.
37121544Seschrock */
37134820Sek110237 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
37143444Sek110237 zpool_get_errlog(zhp, &nverrlist) == 0) {
37153444Sek110237 nvpair_t *elem;
37163444Sek110237
37173444Sek110237 elem = NULL;
37183444Sek110237 nerr = 0;
37193444Sek110237 while ((elem = nvlist_next_nvpair(nverrlist,
37203444Sek110237 elem)) != NULL) {
37213444Sek110237 nerr++;
37223444Sek110237 }
37233444Sek110237 }
37243444Sek110237 nvlist_free(nverrlist);
37251544Seschrock
37261544Seschrock (void) printf("\n");
37272082Seschrock
37281544Seschrock if (nerr == 0)
37291544Seschrock (void) printf(gettext("errors: No known data "
37301544Seschrock "errors\n"));
37311544Seschrock else if (!cbp->cb_verbose)
37322676Seschrock (void) printf(gettext("errors: %llu data "
37332856Snd150628 "errors, use '-v' for a list\n"),
37342856Snd150628 (u_longlong_t)nerr);
37351544Seschrock else
37361544Seschrock print_error_log(zhp);
37371544Seschrock }
373811149SGeorge.Wilson@Sun.COM
373911149SGeorge.Wilson@Sun.COM if (cbp->cb_dedup_stats)
374011149SGeorge.Wilson@Sun.COM print_dedup_stats(config);
3741789Sahrens } else {
3742789Sahrens (void) printf(gettext("config: The configuration cannot be "
3743789Sahrens "determined.\n"));
3744789Sahrens }
3745789Sahrens
3746789Sahrens return (0);
3747789Sahrens }
3748789Sahrens
3749789Sahrens /*
375012296SLin.Ling@Sun.COM * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
3751789Sahrens *
3752789Sahrens * -v Display complete error logs
3753789Sahrens * -x Display only pools with potential problems
375411149SGeorge.Wilson@Sun.COM * -D Display dedup status (undocumented)
375512296SLin.Ling@Sun.COM * -T Display a timestamp in date(1) or Unix format
3756789Sahrens *
3757789Sahrens * Describes the health status of all pools or some subset.
3758789Sahrens */
3759789Sahrens int
zpool_do_status(int argc,char ** argv)3760789Sahrens zpool_do_status(int argc, char **argv)
3761789Sahrens {
3762789Sahrens int c;
3763789Sahrens int ret;
376412296SLin.Ling@Sun.COM unsigned long interval = 0, count = 0;
3765789Sahrens status_cbdata_t cb = { 0 };
3766789Sahrens
3767789Sahrens /* check options */
376812296SLin.Ling@Sun.COM while ((c = getopt(argc, argv, "vxDT:")) != -1) {
3769789Sahrens switch (c) {
3770789Sahrens case 'v':
37712082Seschrock cb.cb_verbose = B_TRUE;
3772789Sahrens break;
3773789Sahrens case 'x':
37742082Seschrock cb.cb_explain = B_TRUE;
3775789Sahrens break;
377611149SGeorge.Wilson@Sun.COM case 'D':
377711149SGeorge.Wilson@Sun.COM cb.cb_dedup_stats = B_TRUE;
377811149SGeorge.Wilson@Sun.COM break;
377912296SLin.Ling@Sun.COM case 'T':
378012296SLin.Ling@Sun.COM get_timestamp_arg(*optarg);
378112296SLin.Ling@Sun.COM break;
3782789Sahrens case '?':
3783789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3784789Sahrens optopt);
37852082Seschrock usage(B_FALSE);
3786789Sahrens }
3787789Sahrens }
3788789Sahrens
3789789Sahrens argc -= optind;
3790789Sahrens argv += optind;
3791789Sahrens
379212296SLin.Ling@Sun.COM get_interval_count(&argc, argv, &interval, &count);
37932082Seschrock
37942676Seschrock if (argc == 0)
37952676Seschrock cb.cb_allpools = B_TRUE;
37962676Seschrock
379712296SLin.Ling@Sun.COM cb.cb_first = B_TRUE;
379812296SLin.Ling@Sun.COM
379912296SLin.Ling@Sun.COM for (;;) {
380012296SLin.Ling@Sun.COM if (timestamp_fmt != NODATE)
380112296SLin.Ling@Sun.COM print_timestamp(timestamp_fmt);
380212296SLin.Ling@Sun.COM
380312296SLin.Ling@Sun.COM ret = for_each_pool(argc, argv, B_TRUE, NULL,
380412296SLin.Ling@Sun.COM status_callback, &cb);
380512296SLin.Ling@Sun.COM
380612296SLin.Ling@Sun.COM if (argc == 0 && cb.cb_count == 0)
380712296SLin.Ling@Sun.COM (void) printf(gettext("no pools available\n"));
380812296SLin.Ling@Sun.COM else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
380912296SLin.Ling@Sun.COM (void) printf(gettext("all pools are healthy\n"));
381012296SLin.Ling@Sun.COM
381112296SLin.Ling@Sun.COM if (ret != 0)
381212296SLin.Ling@Sun.COM return (ret);
381312296SLin.Ling@Sun.COM
381412296SLin.Ling@Sun.COM if (interval == 0)
381512296SLin.Ling@Sun.COM break;
381612296SLin.Ling@Sun.COM
381712296SLin.Ling@Sun.COM if (count != 0 && --count == 0)
381812296SLin.Ling@Sun.COM break;
381912296SLin.Ling@Sun.COM
382012296SLin.Ling@Sun.COM (void) sleep(interval);
382112296SLin.Ling@Sun.COM }
382212296SLin.Ling@Sun.COM
382312296SLin.Ling@Sun.COM return (0);
3824789Sahrens }
3825789Sahrens
38261760Seschrock typedef struct upgrade_cbdata {
38271760Seschrock int cb_all;
38281760Seschrock int cb_first;
38291760Seschrock int cb_newer;
38302926Sek110237 int cb_argc;
38315094Slling uint64_t cb_version;
38322926Sek110237 char **cb_argv;
38331760Seschrock } upgrade_cbdata_t;
38341760Seschrock
38351760Seschrock static int
upgrade_cb(zpool_handle_t * zhp,void * arg)38361760Seschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
38371760Seschrock {
38381760Seschrock upgrade_cbdata_t *cbp = arg;
38391760Seschrock nvlist_t *config;
38401760Seschrock uint64_t version;
38411760Seschrock int ret = 0;
38421760Seschrock
38431760Seschrock config = zpool_get_config(zhp, NULL);
38441760Seschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
38451760Seschrock &version) == 0);
38461760Seschrock
38474577Sahrens if (!cbp->cb_newer && version < SPA_VERSION) {
38481760Seschrock if (!cbp->cb_all) {
38491760Seschrock if (cbp->cb_first) {
38501760Seschrock (void) printf(gettext("The following pools are "
38511760Seschrock "out of date, and can be upgraded. After "
38521760Seschrock "being\nupgraded, these pools will no "
38531760Seschrock "longer be accessible by older software "
38541760Seschrock "versions.\n\n"));
38551760Seschrock (void) printf(gettext("VER POOL\n"));
38561760Seschrock (void) printf(gettext("--- ------------\n"));
38572082Seschrock cbp->cb_first = B_FALSE;
38581760Seschrock }
38591760Seschrock
38602856Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version,
38611760Seschrock zpool_get_name(zhp));
38621760Seschrock } else {
38632082Seschrock cbp->cb_first = B_FALSE;
38645094Slling ret = zpool_upgrade(zhp, cbp->cb_version);
38652926Sek110237 if (!ret) {
38661760Seschrock (void) printf(gettext("Successfully upgraded "
38675094Slling "'%s'\n\n"), zpool_get_name(zhp));
38682926Sek110237 }
38691760Seschrock }
38704577Sahrens } else if (cbp->cb_newer && version > SPA_VERSION) {
38711760Seschrock assert(!cbp->cb_all);
38721760Seschrock
38731760Seschrock if (cbp->cb_first) {
38741760Seschrock (void) printf(gettext("The following pools are "
38751760Seschrock "formatted using a newer software version and\n"
38761760Seschrock "cannot be accessed on the current system.\n\n"));
38771760Seschrock (void) printf(gettext("VER POOL\n"));
38781760Seschrock (void) printf(gettext("--- ------------\n"));
38792082Seschrock cbp->cb_first = B_FALSE;
38801760Seschrock }
38811760Seschrock
38822856Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version,
38831760Seschrock zpool_get_name(zhp));
38841760Seschrock }
38851760Seschrock
38861760Seschrock zpool_close(zhp);
38871760Seschrock return (ret);
38881760Seschrock }
38891760Seschrock
38901760Seschrock /* ARGSUSED */
38911760Seschrock static int
upgrade_one(zpool_handle_t * zhp,void * data)38922926Sek110237 upgrade_one(zpool_handle_t *zhp, void *data)
38931760Seschrock {
38945094Slling upgrade_cbdata_t *cbp = data;
38955094Slling uint64_t cur_version;
38961760Seschrock int ret;
38971760Seschrock
38984527Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) {
38994527Sperrin (void) printf(gettext("'log' is now a reserved word\n"
39004527Sperrin "Pool 'log' must be renamed using export and import"
39014527Sperrin " to upgrade.\n"));
39024527Sperrin return (1);
39034527Sperrin }
39045094Slling
39055094Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
39066018Sbrendan if (cur_version > cbp->cb_version) {
39071760Seschrock (void) printf(gettext("Pool '%s' is already formatted "
39086018Sbrendan "using more current version '%llu'.\n"),
39096018Sbrendan zpool_get_name(zhp), cur_version);
39106018Sbrendan return (0);
39116018Sbrendan }
39126018Sbrendan if (cur_version == cbp->cb_version) {
39136018Sbrendan (void) printf(gettext("Pool '%s' is already formatted "
39146018Sbrendan "using the current version.\n"), zpool_get_name(zhp));
39151760Seschrock return (0);
39161760Seschrock }
39171760Seschrock
39185094Slling ret = zpool_upgrade(zhp, cbp->cb_version);
39192926Sek110237
39202926Sek110237 if (!ret) {
39211775Sbillm (void) printf(gettext("Successfully upgraded '%s' "
39225094Slling "from version %llu to version %llu\n\n"),
39235094Slling zpool_get_name(zhp), (u_longlong_t)cur_version,
39245094Slling (u_longlong_t)cbp->cb_version);
39252926Sek110237 }
39261760Seschrock
39271760Seschrock return (ret != 0);
39281760Seschrock }
39291760Seschrock
39301760Seschrock /*
39311760Seschrock * zpool upgrade
39321760Seschrock * zpool upgrade -v
39335094Slling * zpool upgrade [-V version] <-a | pool ...>
39341760Seschrock *
39351760Seschrock * With no arguments, display downrev'd ZFS pool available for upgrade.
39361760Seschrock * Individual pools can be upgraded by specifying the pool, and '-a' will
39371760Seschrock * upgrade all pools.
39381760Seschrock */
39391760Seschrock int
zpool_do_upgrade(int argc,char ** argv)39401760Seschrock zpool_do_upgrade(int argc, char **argv)
39411760Seschrock {
39421760Seschrock int c;
39431760Seschrock upgrade_cbdata_t cb = { 0 };
39441760Seschrock int ret = 0;
39451760Seschrock boolean_t showversions = B_FALSE;
39465094Slling char *end;
39475094Slling
39481760Seschrock
39491760Seschrock /* check options */
39509643SEric.Taylor@Sun.COM while ((c = getopt(argc, argv, ":avV:")) != -1) {
39511760Seschrock switch (c) {
39521760Seschrock case 'a':
39532082Seschrock cb.cb_all = B_TRUE;
39541760Seschrock break;
39551760Seschrock case 'v':
39561760Seschrock showversions = B_TRUE;
39571760Seschrock break;
39585094Slling case 'V':
39595094Slling cb.cb_version = strtoll(optarg, &end, 10);
39605320Slling if (*end != '\0' || cb.cb_version > SPA_VERSION ||
39615320Slling cb.cb_version < SPA_VERSION_1) {
39625094Slling (void) fprintf(stderr,
39635094Slling gettext("invalid version '%s'\n"), optarg);
39645094Slling usage(B_FALSE);
39655094Slling }
39665094Slling break;
39679643SEric.Taylor@Sun.COM case ':':
39689643SEric.Taylor@Sun.COM (void) fprintf(stderr, gettext("missing argument for "
39699643SEric.Taylor@Sun.COM "'%c' option\n"), optopt);
39709643SEric.Taylor@Sun.COM usage(B_FALSE);
39719643SEric.Taylor@Sun.COM break;
39721760Seschrock case '?':
39731760Seschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"),
39741760Seschrock optopt);
39752082Seschrock usage(B_FALSE);
39761760Seschrock }
39771760Seschrock }
39781760Seschrock
39792926Sek110237 cb.cb_argc = argc;
39802926Sek110237 cb.cb_argv = argv;
39811760Seschrock argc -= optind;
39821760Seschrock argv += optind;
39831760Seschrock
39845320Slling if (cb.cb_version == 0) {
39855320Slling cb.cb_version = SPA_VERSION;
39865320Slling } else if (!cb.cb_all && argc == 0) {
39875320Slling (void) fprintf(stderr, gettext("-V option is "
39885320Slling "incompatible with other arguments\n"));
39895320Slling usage(B_FALSE);
39905320Slling }
39915320Slling
39921760Seschrock if (showversions) {
39931760Seschrock if (cb.cb_all || argc != 0) {
39941760Seschrock (void) fprintf(stderr, gettext("-v option is "
39951760Seschrock "incompatible with other arguments\n"));
39962082Seschrock usage(B_FALSE);
39971760Seschrock }
39981760Seschrock } else if (cb.cb_all) {
39991760Seschrock if (argc != 0) {
40005320Slling (void) fprintf(stderr, gettext("-a option should not "
40015320Slling "be used along with a pool name\n"));
40022082Seschrock usage(B_FALSE);
40031760Seschrock }
40041760Seschrock }
40051760Seschrock
40064577Sahrens (void) printf(gettext("This system is currently running "
40074577Sahrens "ZFS pool version %llu.\n\n"), SPA_VERSION);
40082082Seschrock cb.cb_first = B_TRUE;
40091760Seschrock if (showversions) {
40101760Seschrock (void) printf(gettext("The following versions are "
40113413Smmusante "supported:\n\n"));
40121760Seschrock (void) printf(gettext("VER DESCRIPTION\n"));
40131760Seschrock (void) printf("--- -----------------------------------------"
40141760Seschrock "---------------\n");
40152082Seschrock (void) printf(gettext(" 1 Initial ZFS version\n"));
40161775Sbillm (void) printf(gettext(" 2 Ditto blocks "
40171775Sbillm "(replicated metadata)\n"));
40182082Seschrock (void) printf(gettext(" 3 Hot spares and double parity "
40192082Seschrock "RAID-Z\n"));
40203863Sek110237 (void) printf(gettext(" 4 zpool history\n"));
40213886Sahl (void) printf(gettext(" 5 Compression using the gzip "
40223886Sahl "algorithm\n"));
40235094Slling (void) printf(gettext(" 6 bootfs pool property\n"));
40244527Sperrin (void) printf(gettext(" 7 Separate intent log devices\n"));
40254543Smarks (void) printf(gettext(" 8 Delegated administration\n"));
40265390Sck153898 (void) printf(gettext(" 9 refquota and refreservation "
40275378Sck153898 "properties\n"));
40285450Sbrendan (void) printf(gettext(" 10 Cache devices\n"));
40297046Sahrens (void) printf(gettext(" 11 Improved scrub performance\n"));
40307265Sahrens (void) printf(gettext(" 12 Snapshot properties\n"));
40317390SMatthew.Ahrens@Sun.COM (void) printf(gettext(" 13 snapused property\n"));
40329396SMatthew.Ahrens@Sun.COM (void) printf(gettext(" 14 passthrough-x aclinherit\n"));
40339396SMatthew.Ahrens@Sun.COM (void) printf(gettext(" 15 user/group space accounting\n"));
40349643SEric.Taylor@Sun.COM (void) printf(gettext(" 16 stmf property support\n"));
403510117Sadam.leventhal@sun.com (void) printf(gettext(" 17 Triple-parity RAID-Z\n"));
403610922SJeff.Bonwick@Sun.COM (void) printf(gettext(" 18 Snapshot user holds\n"));
403710594SGeorge.Wilson@Sun.COM (void) printf(gettext(" 19 Log device removal\n"));
403810922SJeff.Bonwick@Sun.COM (void) printf(gettext(" 20 Compression using zle "
403910922SJeff.Bonwick@Sun.COM "(zero-length encoding)\n"));
404010922SJeff.Bonwick@Sun.COM (void) printf(gettext(" 21 Deduplication\n"));
404111022STom.Erickson@Sun.COM (void) printf(gettext(" 22 Received properties\n"));
404211670SNeil.Perrin@Sun.COM (void) printf(gettext(" 23 Slim ZIL\n"));
404311935SMark.Shellenbaum@Sun.COM (void) printf(gettext(" 24 System attributes\n"));
404412296SLin.Ling@Sun.COM (void) printf(gettext(" 25 Improved scrub stats\n"));
404512470SMatthew.Ahrens@Sun.COM (void) printf(gettext(" 26 Improved snapshot deletion "
404612470SMatthew.Ahrens@Sun.COM "performance\n"));
404712827SMatthew.Ahrens@Sun.COM (void) printf(gettext(" 27 Improved snapshot creation "
404812827SMatthew.Ahrens@Sun.COM "performance\n"));
404913037SMark.Musante@Sun.COM (void) printf(gettext(" 28 Multiple vdev replacements\n"));
405010922SJeff.Bonwick@Sun.COM (void) printf(gettext("\nFor more information on a particular "
405112321SStephanie.Scheffler@Sun.COM "version, including supported releases,\n"));
405212321SStephanie.Scheffler@Sun.COM (void) printf(gettext("see the ZFS Administration Guide.\n\n"));
40531760Seschrock } else if (argc == 0) {
40541760Seschrock int notfound;
40551760Seschrock
40562082Seschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb);
40571760Seschrock notfound = cb.cb_first;
40581760Seschrock
40591760Seschrock if (!cb.cb_all && ret == 0) {
40601760Seschrock if (!cb.cb_first)
40611760Seschrock (void) printf("\n");
40621760Seschrock cb.cb_first = B_TRUE;
40631760Seschrock cb.cb_newer = B_TRUE;
40642082Seschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb);
40651760Seschrock if (!cb.cb_first) {
40661760Seschrock notfound = B_FALSE;
40671760Seschrock (void) printf("\n");
40681760Seschrock }
40691760Seschrock }
40701760Seschrock
40711760Seschrock if (ret == 0) {
40721760Seschrock if (notfound)
40731760Seschrock (void) printf(gettext("All pools are formatted "
40741760Seschrock "using this version.\n"));
40751760Seschrock else if (!cb.cb_all)
40761760Seschrock (void) printf(gettext("Use 'zpool upgrade -v' "
40771760Seschrock "for a list of available versions and "
40781760Seschrock "their associated\nfeatures.\n"));
40791760Seschrock }
40801760Seschrock } else {
40813912Slling ret = for_each_pool(argc, argv, B_FALSE, NULL,
40823912Slling upgrade_one, &cb);
40832926Sek110237 }
40842926Sek110237
40852926Sek110237 return (ret);
40862926Sek110237 }
40872926Sek110237
40884543Smarks typedef struct hist_cbdata {
40894543Smarks boolean_t first;
40904543Smarks int longfmt;
40914543Smarks int internal;
40924543Smarks } hist_cbdata_t;
40934543Smarks
40942926Sek110237 /*
40952926Sek110237 * Print out the command history for a specific pool.
40962926Sek110237 */
40972926Sek110237 static int
get_history_one(zpool_handle_t * zhp,void * data)40982926Sek110237 get_history_one(zpool_handle_t *zhp, void *data)
40992926Sek110237 {
41002926Sek110237 nvlist_t *nvhis;
41012926Sek110237 nvlist_t **records;
41022926Sek110237 uint_t numrecords;
41032926Sek110237 char *cmdstr;
41044543Smarks char *pathstr;
41052926Sek110237 uint64_t dst_time;
41062926Sek110237 time_t tsec;
41072926Sek110237 struct tm t;
41082926Sek110237 char tbuf[30];
41092926Sek110237 int ret, i;
41104543Smarks uint64_t who;
41114543Smarks struct passwd *pwd;
41124543Smarks char *hostname;
41134543Smarks char *zonename;
41144543Smarks char internalstr[MAXPATHLEN];
41154543Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data;
41164543Smarks uint64_t txg;
41174543Smarks uint64_t ievent;
41184543Smarks
41194543Smarks cb->first = B_FALSE;
41202926Sek110237
41212926Sek110237 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
41222926Sek110237
41232926Sek110237 if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
41242926Sek110237 return (ret);
41252926Sek110237
41262926Sek110237 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
41272926Sek110237 &records, &numrecords) == 0);
41282926Sek110237 for (i = 0; i < numrecords; i++) {
41292926Sek110237 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
41304543Smarks &dst_time) != 0)
41314543Smarks continue;
41324543Smarks
41334543Smarks /* is it an internal event or a standard event? */
41344543Smarks if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
41354543Smarks &cmdstr) != 0) {
41364543Smarks if (cb->internal == 0)
41374543Smarks continue;
41384543Smarks
41394543Smarks if (nvlist_lookup_uint64(records[i],
41404543Smarks ZPOOL_HIST_INT_EVENT, &ievent) != 0)
41414543Smarks continue;
41424543Smarks verify(nvlist_lookup_uint64(records[i],
41434543Smarks ZPOOL_HIST_TXG, &txg) == 0);
41444543Smarks verify(nvlist_lookup_string(records[i],
41454543Smarks ZPOOL_HIST_INT_STR, &pathstr) == 0);
41467046Sahrens if (ievent >= LOG_END)
41474543Smarks continue;
41484543Smarks (void) snprintf(internalstr,
41494543Smarks sizeof (internalstr),
41504543Smarks "[internal %s txg:%lld] %s",
415112296SLin.Ling@Sun.COM zfs_history_event_names[ievent], txg,
41524543Smarks pathstr);
41534543Smarks cmdstr = internalstr;
41542926Sek110237 }
41554543Smarks tsec = dst_time;
41564543Smarks (void) localtime_r(&tsec, &t);
41574543Smarks (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
41584543Smarks (void) printf("%s %s", tbuf, cmdstr);
41594543Smarks
41604543Smarks if (!cb->longfmt) {
41614543Smarks (void) printf("\n");
41624543Smarks continue;
41634543Smarks }
41644543Smarks (void) printf(" [");
41654543Smarks if (nvlist_lookup_uint64(records[i],
41664543Smarks ZPOOL_HIST_WHO, &who) == 0) {
41674543Smarks pwd = getpwuid((uid_t)who);
41684543Smarks if (pwd)
41694543Smarks (void) printf("user %s on",
41704543Smarks pwd->pw_name);
41714543Smarks else
41724543Smarks (void) printf("user %d on",
41734543Smarks (int)who);
41744543Smarks } else {
41754543Smarks (void) printf(gettext("no info]\n"));
41764543Smarks continue;
41774543Smarks }
41784543Smarks if (nvlist_lookup_string(records[i],
41794543Smarks ZPOOL_HIST_HOST, &hostname) == 0) {
41804543Smarks (void) printf(" %s", hostname);
41814543Smarks }
41824543Smarks if (nvlist_lookup_string(records[i],
41834543Smarks ZPOOL_HIST_ZONE, &zonename) == 0) {
41844543Smarks (void) printf(":%s", zonename);
41854543Smarks }
41864543Smarks
41874543Smarks (void) printf("]");
41884543Smarks (void) printf("\n");
41892926Sek110237 }
41902926Sek110237 (void) printf("\n");
41912926Sek110237 nvlist_free(nvhis);
41922926Sek110237
41932926Sek110237 return (ret);
41942926Sek110237 }
41952926Sek110237
41962926Sek110237 /*
41972926Sek110237 * zpool history <pool>
41982926Sek110237 *
41992926Sek110237 * Displays the history of commands that modified pools.
42002926Sek110237 */
42014543Smarks
42024543Smarks
42032926Sek110237 int
zpool_do_history(int argc,char ** argv)42042926Sek110237 zpool_do_history(int argc, char **argv)
42052926Sek110237 {
42064543Smarks hist_cbdata_t cbdata = { 0 };
42072926Sek110237 int ret;
42084543Smarks int c;
42094543Smarks
42104543Smarks cbdata.first = B_TRUE;
42114543Smarks /* check options */
42124543Smarks while ((c = getopt(argc, argv, "li")) != -1) {
42134543Smarks switch (c) {
42144543Smarks case 'l':
42154543Smarks cbdata.longfmt = 1;
42164543Smarks break;
42174543Smarks case 'i':
42184543Smarks cbdata.internal = 1;
42194543Smarks break;
42204543Smarks case '?':
42214543Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"),
42224543Smarks optopt);
42234543Smarks usage(B_FALSE);
42244543Smarks }
42254543Smarks }
42262926Sek110237 argc -= optind;
42272926Sek110237 argv += optind;
42282926Sek110237
42293912Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one,
42304543Smarks &cbdata);
42314543Smarks
42324543Smarks if (argc == 0 && cbdata.first == B_TRUE) {
42332926Sek110237 (void) printf(gettext("no pools available\n"));
42342926Sek110237 return (0);
42351760Seschrock }
42361760Seschrock
42371760Seschrock return (ret);
42381760Seschrock }
42391760Seschrock
42403912Slling static int
get_callback(zpool_handle_t * zhp,void * data)42413912Slling get_callback(zpool_handle_t *zhp, void *data)
42423912Slling {
42435094Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
42443912Slling char value[MAXNAMELEN];
42455094Slling zprop_source_t srctype;
42465094Slling zprop_list_t *pl;
42473912Slling
42483912Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
42493912Slling
42503912Slling /*
42515094Slling * Skip the special fake placeholder. This will also skip
42525094Slling * over the name property when 'all' is specified.
42533912Slling */
42545094Slling if (pl->pl_prop == ZPOOL_PROP_NAME &&
42553912Slling pl == cbp->cb_proplist)
42563912Slling continue;
42573912Slling
42583912Slling if (zpool_get_prop(zhp, pl->pl_prop,
42593912Slling value, sizeof (value), &srctype) != 0)
42603912Slling continue;
42613912Slling
42625094Slling zprop_print_one_property(zpool_get_name(zhp), cbp,
426311022STom.Erickson@Sun.COM zpool_prop_to_name(pl->pl_prop), value, srctype, NULL,
426411022STom.Erickson@Sun.COM NULL);
42653912Slling }
42663912Slling return (0);
42673912Slling }
42683912Slling
42693912Slling int
zpool_do_get(int argc,char ** argv)42703912Slling zpool_do_get(int argc, char **argv)
42713912Slling {
42725094Slling zprop_get_cbdata_t cb = { 0 };
42735094Slling zprop_list_t fake_name = { 0 };
42743912Slling int ret;
42753912Slling
42763912Slling if (argc < 3)
42773912Slling usage(B_FALSE);
42783912Slling
42793912Slling cb.cb_first = B_TRUE;
42805094Slling cb.cb_sources = ZPROP_SRC_ALL;
42813912Slling cb.cb_columns[0] = GET_COL_NAME;
42823912Slling cb.cb_columns[1] = GET_COL_PROPERTY;
42833912Slling cb.cb_columns[2] = GET_COL_VALUE;
42843912Slling cb.cb_columns[3] = GET_COL_SOURCE;
42855094Slling cb.cb_type = ZFS_TYPE_POOL;
42865094Slling
42875094Slling if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
42885094Slling ZFS_TYPE_POOL) != 0)
42893912Slling usage(B_FALSE);
42903912Slling
42913912Slling if (cb.cb_proplist != NULL) {
42925094Slling fake_name.pl_prop = ZPOOL_PROP_NAME;
42933912Slling fake_name.pl_width = strlen(gettext("NAME"));
42943912Slling fake_name.pl_next = cb.cb_proplist;
42953912Slling cb.cb_proplist = &fake_name;
42963912Slling }
42973912Slling
42983912Slling ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
42993912Slling get_callback, &cb);
43003912Slling
43013912Slling if (cb.cb_proplist == &fake_name)
43025094Slling zprop_free_list(fake_name.pl_next);
43033912Slling else
43045094Slling zprop_free_list(cb.cb_proplist);
43053912Slling
43063912Slling return (ret);
43073912Slling }
43083912Slling
43093912Slling typedef struct set_cbdata {
43103912Slling char *cb_propname;
43113912Slling char *cb_value;
43123912Slling boolean_t cb_any_successful;
43133912Slling } set_cbdata_t;
43143912Slling
43153912Slling int
set_callback(zpool_handle_t * zhp,void * data)43163912Slling set_callback(zpool_handle_t *zhp, void *data)
43173912Slling {
43183912Slling int error;
43193912Slling set_cbdata_t *cb = (set_cbdata_t *)data;
43203912Slling
43213912Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
43223912Slling
43233912Slling if (!error)
43243912Slling cb->cb_any_successful = B_TRUE;
43253912Slling
43263912Slling return (error);
43273912Slling }
43283912Slling
43293912Slling int
zpool_do_set(int argc,char ** argv)43303912Slling zpool_do_set(int argc, char **argv)
43313912Slling {
43323912Slling set_cbdata_t cb = { 0 };
43333912Slling int error;
43343912Slling
43353912Slling if (argc > 1 && argv[1][0] == '-') {
43363912Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"),
43373912Slling argv[1][1]);
43383912Slling usage(B_FALSE);
43393912Slling }
43403912Slling
43413912Slling if (argc < 2) {
43423912Slling (void) fprintf(stderr, gettext("missing property=value "
43433912Slling "argument\n"));
43443912Slling usage(B_FALSE);
43453912Slling }
43463912Slling
43473912Slling if (argc < 3) {
43483912Slling (void) fprintf(stderr, gettext("missing pool name\n"));
43493912Slling usage(B_FALSE);
43503912Slling }
43513912Slling
43523912Slling if (argc > 3) {
43533912Slling (void) fprintf(stderr, gettext("too many pool names\n"));
43543912Slling usage(B_FALSE);
43553912Slling }
43563912Slling
43573912Slling cb.cb_propname = argv[1];
43583912Slling cb.cb_value = strchr(cb.cb_propname, '=');
43593912Slling if (cb.cb_value == NULL) {
43603912Slling (void) fprintf(stderr, gettext("missing value in "
43613912Slling "property=value argument\n"));
43623912Slling usage(B_FALSE);
43633912Slling }
43643912Slling
43653912Slling *(cb.cb_value) = '\0';
43663912Slling cb.cb_value++;
43673912Slling
43683912Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
43693912Slling set_callback, &cb);
43703912Slling
43713912Slling return (error);
43723912Slling }
43733912Slling
43743912Slling static int
find_command_idx(char * command,int * idx)43753912Slling find_command_idx(char *command, int *idx)
43763912Slling {
43773912Slling int i;
43783912Slling
43793912Slling for (i = 0; i < NCOMMAND; i++) {
43803912Slling if (command_table[i].name == NULL)
43813912Slling continue;
43823912Slling
43833912Slling if (strcmp(command, command_table[i].name) == 0) {
43843912Slling *idx = i;
43853912Slling return (0);
43863912Slling }
43873912Slling }
43883912Slling return (1);
43893912Slling }
43903912Slling
4391789Sahrens int
main(int argc,char ** argv)4392789Sahrens main(int argc, char **argv)
4393789Sahrens {
4394789Sahrens int ret;
4395789Sahrens int i;
4396789Sahrens char *cmdname;
4397789Sahrens
4398789Sahrens (void) setlocale(LC_ALL, "");
4399789Sahrens (void) textdomain(TEXT_DOMAIN);
4400789Sahrens
44012082Seschrock if ((g_zfs = libzfs_init()) == NULL) {
44022082Seschrock (void) fprintf(stderr, gettext("internal error: failed to "
44032731Snd150628 "initialize ZFS library\n"));
44042082Seschrock return (1);
44052082Seschrock }
44062082Seschrock
44072082Seschrock libzfs_print_on_error(g_zfs, B_TRUE);
44082082Seschrock
4409789Sahrens opterr = 0;
4410789Sahrens
4411789Sahrens /*
4412789Sahrens * Make sure the user has specified some command.
4413789Sahrens */
4414789Sahrens if (argc < 2) {
4415789Sahrens (void) fprintf(stderr, gettext("missing command\n"));
44162082Seschrock usage(B_FALSE);
4417789Sahrens }
4418789Sahrens
4419789Sahrens cmdname = argv[1];
4420789Sahrens
4421789Sahrens /*
4422789Sahrens * Special case '-?'
4423789Sahrens */
4424789Sahrens if (strcmp(cmdname, "-?") == 0)
44252082Seschrock usage(B_TRUE);
4426789Sahrens
44274988Sek110237 zpool_set_history_str("zpool", argc, argv, history_str);
44284988Sek110237 verify(zpool_stage_history(g_zfs, history_str) == 0);
44294988Sek110237
4430789Sahrens /*
4431789Sahrens * Run the appropriate command.
4432789Sahrens */
44333912Slling if (find_command_idx(cmdname, &i) == 0) {
44343912Slling current_command = &command_table[i];
44353912Slling ret = command_table[i].func(argc - 1, argv + 1);
44364787Sahrens } else if (strchr(cmdname, '=')) {
44374787Sahrens verify(find_command_idx("set", &i) == 0);
44384787Sahrens current_command = &command_table[i];
44394787Sahrens ret = command_table[i].func(argc, argv);
44404787Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
44414787Sahrens /*
44424787Sahrens * 'freeze' is a vile debugging abomination, so we treat
44434787Sahrens * it as such.
44444787Sahrens */
44451544Seschrock char buf[16384];
44461544Seschrock int fd = open(ZFS_DEV, O_RDWR);
4447789Sahrens (void) strcpy((void *)buf, argv[2]);
4448789Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
44494787Sahrens } else {
4450789Sahrens (void) fprintf(stderr, gettext("unrecognized "
4451789Sahrens "command '%s'\n"), cmdname);
44522082Seschrock usage(B_FALSE);
4453789Sahrens }
4454789Sahrens
44552082Seschrock libzfs_fini(g_zfs);
44562082Seschrock
4457789Sahrens /*
4458789Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4459789Sahrens * for the purposes of running ::findleaks.
4460789Sahrens */
4461789Sahrens if (getenv("ZFS_ABORT") != NULL) {
4462789Sahrens (void) printf("dumping core by request\n");
4463789Sahrens abort();
4464789Sahrens }
4465789Sahrens
4466789Sahrens return (ret);
4467789Sahrens }
4468