1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 2199653d4eSeschrock 22fa9e4066Sahrens /* 2339c23413Seschrock * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29fa9e4066Sahrens #include <assert.h> 30fa9e4066Sahrens #include <ctype.h> 31fa9e4066Sahrens #include <dirent.h> 32fa9e4066Sahrens #include <errno.h> 33fa9e4066Sahrens #include <fcntl.h> 34fa9e4066Sahrens #include <libgen.h> 35fa9e4066Sahrens #include <libintl.h> 36fa9e4066Sahrens #include <libuutil.h> 37fa9e4066Sahrens #include <locale.h> 38fa9e4066Sahrens #include <stdio.h> 39fa9e4066Sahrens #include <stdlib.h> 40fa9e4066Sahrens #include <string.h> 41fa9e4066Sahrens #include <strings.h> 42fa9e4066Sahrens #include <unistd.h> 43fa9e4066Sahrens #include <priv.h> 44ecd6cf80Smarks #include <pwd.h> 45ecd6cf80Smarks #include <zone.h> 46b1b8ab34Slling #include <sys/fs/zfs.h> 47fa9e4066Sahrens 48fa9e4066Sahrens #include <sys/stat.h> 49fa9e4066Sahrens 50fa9e4066Sahrens #include <libzfs.h> 51fa9e4066Sahrens 52fa9e4066Sahrens #include "zpool_util.h" 53fa9e4066Sahrens 54fa9e4066Sahrens static int zpool_do_create(int, char **); 55fa9e4066Sahrens static int zpool_do_destroy(int, char **); 56fa9e4066Sahrens 57fa9e4066Sahrens static int zpool_do_add(int, char **); 5899653d4eSeschrock static int zpool_do_remove(int, char **); 59fa9e4066Sahrens 60fa9e4066Sahrens static int zpool_do_list(int, char **); 61fa9e4066Sahrens static int zpool_do_iostat(int, char **); 62fa9e4066Sahrens static int zpool_do_status(int, char **); 63fa9e4066Sahrens 64fa9e4066Sahrens static int zpool_do_online(int, char **); 65fa9e4066Sahrens static int zpool_do_offline(int, char **); 66ea8dc4b6Seschrock static int zpool_do_clear(int, char **); 67fa9e4066Sahrens 68fa9e4066Sahrens static int zpool_do_attach(int, char **); 69fa9e4066Sahrens static int zpool_do_detach(int, char **); 70fa9e4066Sahrens static int zpool_do_replace(int, char **); 71fa9e4066Sahrens 72fa9e4066Sahrens static int zpool_do_scrub(int, char **); 73fa9e4066Sahrens 74fa9e4066Sahrens static int zpool_do_import(int, char **); 75fa9e4066Sahrens static int zpool_do_export(int, char **); 76fa9e4066Sahrens 77eaca9bbdSeschrock static int zpool_do_upgrade(int, char **); 78eaca9bbdSeschrock 7906eeb2adSek static int zpool_do_history(int, char **); 8006eeb2adSek 81b1b8ab34Slling static int zpool_do_get(int, char **); 82b1b8ab34Slling static int zpool_do_set(int, char **); 83b1b8ab34Slling 84fa9e4066Sahrens /* 85fa9e4066Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 86fa9e4066Sahrens * debugging facilities. 87fa9e4066Sahrens */ 88fa9e4066Sahrens const char * 8999653d4eSeschrock _umem_debug_init(void) 90fa9e4066Sahrens { 91fa9e4066Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 92fa9e4066Sahrens } 93fa9e4066Sahrens 94fa9e4066Sahrens const char * 95fa9e4066Sahrens _umem_logging_init(void) 96fa9e4066Sahrens { 97fa9e4066Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 98fa9e4066Sahrens } 99fa9e4066Sahrens 10065cd9f28Seschrock typedef enum { 10165cd9f28Seschrock HELP_ADD, 10265cd9f28Seschrock HELP_ATTACH, 103ea8dc4b6Seschrock HELP_CLEAR, 10465cd9f28Seschrock HELP_CREATE, 10565cd9f28Seschrock HELP_DESTROY, 10665cd9f28Seschrock HELP_DETACH, 10765cd9f28Seschrock HELP_EXPORT, 10806eeb2adSek HELP_HISTORY, 10965cd9f28Seschrock HELP_IMPORT, 11065cd9f28Seschrock HELP_IOSTAT, 11165cd9f28Seschrock HELP_LIST, 11265cd9f28Seschrock HELP_OFFLINE, 11365cd9f28Seschrock HELP_ONLINE, 11465cd9f28Seschrock HELP_REPLACE, 11599653d4eSeschrock HELP_REMOVE, 11665cd9f28Seschrock HELP_SCRUB, 117eaca9bbdSeschrock HELP_STATUS, 118b1b8ab34Slling HELP_UPGRADE, 119b1b8ab34Slling HELP_GET, 120b1b8ab34Slling HELP_SET 12165cd9f28Seschrock } zpool_help_t; 12265cd9f28Seschrock 12365cd9f28Seschrock 124fa9e4066Sahrens typedef struct zpool_command { 125fa9e4066Sahrens const char *name; 126fa9e4066Sahrens int (*func)(int, char **); 12765cd9f28Seschrock zpool_help_t usage; 128fa9e4066Sahrens } zpool_command_t; 129fa9e4066Sahrens 130fa9e4066Sahrens /* 131fa9e4066Sahrens * Master command table. Each ZFS command has a name, associated function, and 132ea8dc4b6Seschrock * usage message. The usage messages need to be internationalized, so we have 133ea8dc4b6Seschrock * to have a function to return the usage message based on a command index. 13465cd9f28Seschrock * 13565cd9f28Seschrock * These commands are organized according to how they are displayed in the usage 13665cd9f28Seschrock * message. An empty command (one with a NULL name) indicates an empty line in 13765cd9f28Seschrock * the generic usage message. 138fa9e4066Sahrens */ 139fa9e4066Sahrens static zpool_command_t command_table[] = { 14065cd9f28Seschrock { "create", zpool_do_create, HELP_CREATE }, 14165cd9f28Seschrock { "destroy", zpool_do_destroy, HELP_DESTROY }, 142fa9e4066Sahrens { NULL }, 14365cd9f28Seschrock { "add", zpool_do_add, HELP_ADD }, 14499653d4eSeschrock { "remove", zpool_do_remove, HELP_REMOVE }, 145fa9e4066Sahrens { NULL }, 14665cd9f28Seschrock { "list", zpool_do_list, HELP_LIST }, 14765cd9f28Seschrock { "iostat", zpool_do_iostat, HELP_IOSTAT }, 14865cd9f28Seschrock { "status", zpool_do_status, HELP_STATUS }, 149fa9e4066Sahrens { NULL }, 15065cd9f28Seschrock { "online", zpool_do_online, HELP_ONLINE }, 15165cd9f28Seschrock { "offline", zpool_do_offline, HELP_OFFLINE }, 152ea8dc4b6Seschrock { "clear", zpool_do_clear, HELP_CLEAR }, 153fa9e4066Sahrens { NULL }, 15465cd9f28Seschrock { "attach", zpool_do_attach, HELP_ATTACH }, 15565cd9f28Seschrock { "detach", zpool_do_detach, HELP_DETACH }, 15665cd9f28Seschrock { "replace", zpool_do_replace, HELP_REPLACE }, 157fa9e4066Sahrens { NULL }, 15865cd9f28Seschrock { "scrub", zpool_do_scrub, HELP_SCRUB }, 159fa9e4066Sahrens { NULL }, 16065cd9f28Seschrock { "import", zpool_do_import, HELP_IMPORT }, 16165cd9f28Seschrock { "export", zpool_do_export, HELP_EXPORT }, 16206eeb2adSek { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 16306eeb2adSek { NULL }, 164b1b8ab34Slling { "history", zpool_do_history, HELP_HISTORY }, 165b1b8ab34Slling { "get", zpool_do_get, HELP_GET }, 166b1b8ab34Slling { "set", zpool_do_set, HELP_SET }, 167fa9e4066Sahrens }; 168fa9e4066Sahrens 169fa9e4066Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 170fa9e4066Sahrens 171fa9e4066Sahrens zpool_command_t *current_command; 1722a6b87f0Sek static char history_str[HIS_MAX_RECORD_LEN]; 173fa9e4066Sahrens 17465cd9f28Seschrock static const char * 17565cd9f28Seschrock get_usage(zpool_help_t idx) { 17665cd9f28Seschrock switch (idx) { 17765cd9f28Seschrock case HELP_ADD: 17865cd9f28Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 17965cd9f28Seschrock case HELP_ATTACH: 18065cd9f28Seschrock return (gettext("\tattach [-f] <pool> <device> " 181e45ce728Sahrens "<new-device>\n")); 182ea8dc4b6Seschrock case HELP_CLEAR: 183ea8dc4b6Seschrock return (gettext("\tclear <pool> [device]\n")); 18465cd9f28Seschrock case HELP_CREATE: 185*990b4856Slling return (gettext("\tcreate [-fn] [-o property=value] ... \n" 186*990b4856Slling "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 18765cd9f28Seschrock case HELP_DESTROY: 18865cd9f28Seschrock return (gettext("\tdestroy [-f] <pool>\n")); 18965cd9f28Seschrock case HELP_DETACH: 19065cd9f28Seschrock return (gettext("\tdetach <pool> <device>\n")); 19165cd9f28Seschrock case HELP_EXPORT: 19265cd9f28Seschrock return (gettext("\texport [-f] <pool> ...\n")); 19306eeb2adSek case HELP_HISTORY: 194ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 19565cd9f28Seschrock case HELP_IMPORT: 1964c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 197*990b4856Slling "\timport [-o mntopts] [-o property=value] ... [-d dir]\n" 198*990b4856Slling "\t [-D] [-f] [-R root] -a\n" 199*990b4856Slling "\timport [-o mntopts] [-o property=value] ... [-d dir]\n" 200*990b4856Slling "\t [-D] [-f] [-R root] <pool | id> [newpool]\n")); 20165cd9f28Seschrock case HELP_IOSTAT: 20265cd9f28Seschrock return (gettext("\tiostat [-v] [pool] ... [interval " 20365cd9f28Seschrock "[count]]\n")); 20465cd9f28Seschrock case HELP_LIST: 205*990b4856Slling return (gettext("\tlist [-H] [-o property[,...]] " 206*990b4856Slling "[pool] ...\n")); 20765cd9f28Seschrock case HELP_OFFLINE: 208441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 20965cd9f28Seschrock case HELP_ONLINE: 210441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 21165cd9f28Seschrock case HELP_REPLACE: 21265cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 213e45ce728Sahrens "[new-device]\n")); 21499653d4eSeschrock case HELP_REMOVE: 21599653d4eSeschrock return (gettext("\tremove <pool> <device>\n")); 21665cd9f28Seschrock case HELP_SCRUB: 21765cd9f28Seschrock return (gettext("\tscrub [-s] <pool> ...\n")); 21865cd9f28Seschrock case HELP_STATUS: 21965cd9f28Seschrock return (gettext("\tstatus [-vx] [pool] ...\n")); 220eaca9bbdSeschrock case HELP_UPGRADE: 221eaca9bbdSeschrock return (gettext("\tupgrade\n" 222eaca9bbdSeschrock "\tupgrade -v\n" 223*990b4856Slling "\tupgrade [-V version] <-a | pool ...>\n")); 224b1b8ab34Slling case HELP_GET: 225e45ce728Sahrens return (gettext("\tget <\"all\" | property[,...]> " 226b1b8ab34Slling "<pool> ...\n")); 227b1b8ab34Slling case HELP_SET: 228b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 22965cd9f28Seschrock } 23065cd9f28Seschrock 23165cd9f28Seschrock abort(); 23265cd9f28Seschrock /* NOTREACHED */ 23365cd9f28Seschrock } 23465cd9f28Seschrock 235fa9e4066Sahrens 236b1b8ab34Slling /* 237b1b8ab34Slling * Callback routine that will print out a pool property value. 238b1b8ab34Slling */ 239*990b4856Slling static int 240*990b4856Slling print_prop_cb(int prop, void *cb) 241b1b8ab34Slling { 242b1b8ab34Slling FILE *fp = cb; 243b1b8ab34Slling 244b1b8ab34Slling (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 245b1b8ab34Slling 246*990b4856Slling if (zpool_prop_readonly(prop)) 247*990b4856Slling (void) fprintf(fp, " NO "); 248*990b4856Slling else 249*990b4856Slling (void) fprintf(fp, " YES "); 250*990b4856Slling 251b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 252b1b8ab34Slling (void) fprintf(fp, "-\n"); 253b1b8ab34Slling else 254b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 255b1b8ab34Slling 256*990b4856Slling return (ZPROP_CONT); 257b1b8ab34Slling } 258b1b8ab34Slling 259fa9e4066Sahrens /* 260fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 261fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 262fa9e4066Sahrens * a complete usage message. 263fa9e4066Sahrens */ 264fa9e4066Sahrens void 26599653d4eSeschrock usage(boolean_t requested) 266fa9e4066Sahrens { 267fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 268fa9e4066Sahrens 269fa9e4066Sahrens if (current_command == NULL) { 270fa9e4066Sahrens int i; 271fa9e4066Sahrens 272fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 273fa9e4066Sahrens (void) fprintf(fp, 274fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 275fa9e4066Sahrens 276fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 277fa9e4066Sahrens if (command_table[i].name == NULL) 278fa9e4066Sahrens (void) fprintf(fp, "\n"); 279fa9e4066Sahrens else 280fa9e4066Sahrens (void) fprintf(fp, "%s", 28165cd9f28Seschrock get_usage(command_table[i].usage)); 282fa9e4066Sahrens } 283fa9e4066Sahrens } else { 284fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 28565cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 286fa9e4066Sahrens } 287fa9e4066Sahrens 288b1b8ab34Slling if (current_command != NULL && 289b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 290*990b4856Slling (strcmp(current_command->name, "get") == 0) || 291*990b4856Slling (strcmp(current_command->name, "list") == 0))) { 292b1b8ab34Slling 293b1b8ab34Slling (void) fprintf(fp, 294b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 295b1b8ab34Slling 296*990b4856Slling (void) fprintf(fp, "\n\t%-13s %s %s\n\n", 297*990b4856Slling "PROPERTY", "EDIT", "VALUES"); 298b1b8ab34Slling 299b1b8ab34Slling /* Iterate over all properties */ 300*990b4856Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 301*990b4856Slling ZFS_TYPE_POOL); 302b1b8ab34Slling } 303b1b8ab34Slling 304e9dbad6fSeschrock /* 305e9dbad6fSeschrock * See comments at end of main(). 306e9dbad6fSeschrock */ 307e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 308e9dbad6fSeschrock (void) printf("dumping core by request\n"); 309e9dbad6fSeschrock abort(); 310e9dbad6fSeschrock } 311e9dbad6fSeschrock 312fa9e4066Sahrens exit(requested ? 0 : 2); 313fa9e4066Sahrens } 314fa9e4066Sahrens 315fa9e4066Sahrens void 3168654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 3178654d025Sperrin boolean_t print_logs) 318fa9e4066Sahrens { 319fa9e4066Sahrens nvlist_t **child; 320fa9e4066Sahrens uint_t c, children; 321afefbcddSeschrock char *vname; 322fa9e4066Sahrens 323fa9e4066Sahrens if (name != NULL) 324fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 325fa9e4066Sahrens 326fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 327fa9e4066Sahrens &child, &children) != 0) 328fa9e4066Sahrens return; 329fa9e4066Sahrens 330afefbcddSeschrock for (c = 0; c < children; c++) { 3318654d025Sperrin uint64_t is_log = B_FALSE; 3328654d025Sperrin 3338654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3348654d025Sperrin &is_log); 3358654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 3368654d025Sperrin continue; 3378654d025Sperrin 33899653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 3398654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 3408654d025Sperrin B_FALSE); 341afefbcddSeschrock free(vname); 342afefbcddSeschrock } 343fa9e4066Sahrens } 344fa9e4066Sahrens 345*990b4856Slling /* 346*990b4856Slling * Add a property pair (name, string-value) into a property nvlist. 347*990b4856Slling */ 348*990b4856Slling static int 349*990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props) 350*990b4856Slling { 351*990b4856Slling char *strval; 352*990b4856Slling nvlist_t *proplist; 353*990b4856Slling zpool_prop_t prop; 354*990b4856Slling 355*990b4856Slling if (*props == NULL && 356*990b4856Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 357*990b4856Slling (void) fprintf(stderr, 358*990b4856Slling gettext("internal error: out of memory\n")); 359*990b4856Slling return (1); 360*990b4856Slling } 361*990b4856Slling 362*990b4856Slling proplist = *props; 363*990b4856Slling 364*990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 365*990b4856Slling (void) fprintf(stderr, gettext("property '%s' is " 366*990b4856Slling "not a valid pool property\n"), propname); 367*990b4856Slling return (2); 368*990b4856Slling } 369*990b4856Slling 370*990b4856Slling /* Use normalized property name for nvlist operations */ 371*990b4856Slling if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop), 372*990b4856Slling &strval) == 0) { 373*990b4856Slling (void) fprintf(stderr, gettext("property '%s' " 374*990b4856Slling "specified multiple times\n"), propname); 375*990b4856Slling return (2); 376*990b4856Slling } 377*990b4856Slling 378*990b4856Slling if (nvlist_add_string(proplist, zpool_prop_to_name(prop), 379*990b4856Slling propval) != 0) { 380*990b4856Slling (void) fprintf(stderr, gettext("internal " 381*990b4856Slling "error: out of memory\n")); 382*990b4856Slling return (1); 383*990b4856Slling } 384*990b4856Slling 385*990b4856Slling return (0); 386*990b4856Slling } 387*990b4856Slling 388fa9e4066Sahrens /* 389fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 390fa9e4066Sahrens * 391fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 392fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 393fa9e4066Sahrens * they were to be added. 394fa9e4066Sahrens * 395fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 396fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 397fa9e4066Sahrens * libzfs. 398fa9e4066Sahrens */ 399fa9e4066Sahrens int 400fa9e4066Sahrens zpool_do_add(int argc, char **argv) 401fa9e4066Sahrens { 40299653d4eSeschrock boolean_t force = B_FALSE; 40399653d4eSeschrock boolean_t dryrun = B_FALSE; 404fa9e4066Sahrens int c; 405fa9e4066Sahrens nvlist_t *nvroot; 406fa9e4066Sahrens char *poolname; 407fa9e4066Sahrens int ret; 408fa9e4066Sahrens zpool_handle_t *zhp; 409fa9e4066Sahrens nvlist_t *config; 410fa9e4066Sahrens 411fa9e4066Sahrens /* check options */ 412fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 413fa9e4066Sahrens switch (c) { 414fa9e4066Sahrens case 'f': 41599653d4eSeschrock force = B_TRUE; 416fa9e4066Sahrens break; 417fa9e4066Sahrens case 'n': 41899653d4eSeschrock dryrun = B_TRUE; 419fa9e4066Sahrens break; 420fa9e4066Sahrens case '?': 421fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 422fa9e4066Sahrens optopt); 42399653d4eSeschrock usage(B_FALSE); 424fa9e4066Sahrens } 425fa9e4066Sahrens } 426fa9e4066Sahrens 427fa9e4066Sahrens argc -= optind; 428fa9e4066Sahrens argv += optind; 429fa9e4066Sahrens 430fa9e4066Sahrens /* get pool name and check number of arguments */ 431fa9e4066Sahrens if (argc < 1) { 432fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 43399653d4eSeschrock usage(B_FALSE); 434fa9e4066Sahrens } 435fa9e4066Sahrens if (argc < 2) { 436fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 43799653d4eSeschrock usage(B_FALSE); 438fa9e4066Sahrens } 439fa9e4066Sahrens 440fa9e4066Sahrens poolname = argv[0]; 441fa9e4066Sahrens 442fa9e4066Sahrens argc--; 443fa9e4066Sahrens argv++; 444fa9e4066Sahrens 44599653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 446fa9e4066Sahrens return (1); 447fa9e4066Sahrens 448088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 449fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 450fa9e4066Sahrens poolname); 451fa9e4066Sahrens zpool_close(zhp); 452fa9e4066Sahrens return (1); 453fa9e4066Sahrens } 454fa9e4066Sahrens 455fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 4568488aeb5Staylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv); 457fa9e4066Sahrens if (nvroot == NULL) { 458fa9e4066Sahrens zpool_close(zhp); 459fa9e4066Sahrens return (1); 460fa9e4066Sahrens } 461fa9e4066Sahrens 462fa9e4066Sahrens if (dryrun) { 463fa9e4066Sahrens nvlist_t *poolnvroot; 464fa9e4066Sahrens 465fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 466fa9e4066Sahrens &poolnvroot) == 0); 467fa9e4066Sahrens 468fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 469fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 470fa9e4066Sahrens 4718654d025Sperrin /* print original main pool and new tree */ 4728654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 4738654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 4748654d025Sperrin 4758654d025Sperrin /* Do the same for the logs */ 4768654d025Sperrin if (num_logs(poolnvroot) > 0) { 4778654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 4788654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 4798654d025Sperrin } else if (num_logs(nvroot) > 0) { 4808654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 4818654d025Sperrin } 482fa9e4066Sahrens 483fa9e4066Sahrens ret = 0; 484fa9e4066Sahrens } else { 485fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 486fa9e4066Sahrens } 487fa9e4066Sahrens 48899653d4eSeschrock nvlist_free(nvroot); 48999653d4eSeschrock zpool_close(zhp); 49099653d4eSeschrock 49199653d4eSeschrock return (ret); 49299653d4eSeschrock } 49399653d4eSeschrock 49499653d4eSeschrock /* 49599653d4eSeschrock * zpool remove <pool> <vdev> 49699653d4eSeschrock * 49799653d4eSeschrock * Removes the given vdev from the pool. Currently, this only supports removing 49899653d4eSeschrock * spares from the pool. Eventually, we'll want to support removing leaf vdevs 49999653d4eSeschrock * (as an alias for 'detach') as well as toplevel vdevs. 50099653d4eSeschrock */ 50199653d4eSeschrock int 50299653d4eSeschrock zpool_do_remove(int argc, char **argv) 50399653d4eSeschrock { 50499653d4eSeschrock char *poolname; 50599653d4eSeschrock int ret; 50699653d4eSeschrock zpool_handle_t *zhp; 50799653d4eSeschrock 50899653d4eSeschrock argc--; 50999653d4eSeschrock argv++; 51099653d4eSeschrock 51199653d4eSeschrock /* get pool name and check number of arguments */ 51299653d4eSeschrock if (argc < 1) { 51399653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 51499653d4eSeschrock usage(B_FALSE); 51599653d4eSeschrock } 51699653d4eSeschrock if (argc < 2) { 51799653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 51899653d4eSeschrock usage(B_FALSE); 51999653d4eSeschrock } 52099653d4eSeschrock 52199653d4eSeschrock poolname = argv[0]; 52299653d4eSeschrock 52399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 52499653d4eSeschrock return (1); 52599653d4eSeschrock 52699653d4eSeschrock ret = (zpool_vdev_remove(zhp, argv[1]) != 0); 52799653d4eSeschrock 528fa9e4066Sahrens return (ret); 529fa9e4066Sahrens } 530fa9e4066Sahrens 531fa9e4066Sahrens /* 532*990b4856Slling * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint] 533*990b4856Slling * <pool> <dev> ... 534fa9e4066Sahrens * 535fa9e4066Sahrens * -f Force creation, even if devices appear in use 536fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 537fa9e4066Sahrens * were to be created. 538fa9e4066Sahrens * -R Create a pool under an alternate root 539fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 540fa9e4066Sahrens * '/<pool>' 541*990b4856Slling * -o Set property=value. 542fa9e4066Sahrens * 543b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 544fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 545fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 546fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 547fa9e4066Sahrens */ 548fa9e4066Sahrens int 549fa9e4066Sahrens zpool_do_create(int argc, char **argv) 550fa9e4066Sahrens { 55199653d4eSeschrock boolean_t force = B_FALSE; 55299653d4eSeschrock boolean_t dryrun = B_FALSE; 553fa9e4066Sahrens int c; 554*990b4856Slling nvlist_t *nvroot = NULL; 555fa9e4066Sahrens char *poolname; 556*990b4856Slling int ret = 1; 557fa9e4066Sahrens char *altroot = NULL; 558fa9e4066Sahrens char *mountpoint = NULL; 55999653d4eSeschrock nvlist_t **child; 56099653d4eSeschrock uint_t children; 561*990b4856Slling nvlist_t *props = NULL; 562*990b4856Slling char *propval = NULL; 563fa9e4066Sahrens 564fa9e4066Sahrens /* check options */ 565*990b4856Slling while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) { 566fa9e4066Sahrens switch (c) { 567fa9e4066Sahrens case 'f': 56899653d4eSeschrock force = B_TRUE; 569fa9e4066Sahrens break; 570fa9e4066Sahrens case 'n': 57199653d4eSeschrock dryrun = B_TRUE; 572fa9e4066Sahrens break; 573fa9e4066Sahrens case 'R': 574fa9e4066Sahrens altroot = optarg; 575*990b4856Slling if (add_prop_list(zpool_prop_to_name( 576*990b4856Slling ZPOOL_PROP_ALTROOT), optarg, &props)) 577*990b4856Slling goto errout; 578*990b4856Slling if (add_prop_list(zpool_prop_to_name( 579*990b4856Slling ZPOOL_PROP_TEMPORARY), "on", &props)) 580*990b4856Slling goto errout; 581fa9e4066Sahrens break; 582fa9e4066Sahrens case 'm': 583fa9e4066Sahrens mountpoint = optarg; 584fa9e4066Sahrens break; 585*990b4856Slling case 'o': 586*990b4856Slling if ((propval = strchr(optarg, '=')) == NULL) { 587*990b4856Slling (void) fprintf(stderr, gettext("missing " 588*990b4856Slling "'=' for -o option\n")); 589*990b4856Slling goto errout; 590*990b4856Slling } 591*990b4856Slling *propval = '\0'; 592*990b4856Slling propval++; 593*990b4856Slling 594*990b4856Slling if (add_prop_list(optarg, propval, &props)) 595*990b4856Slling goto errout; 596*990b4856Slling break; 597fa9e4066Sahrens case ':': 598fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 599fa9e4066Sahrens "'%c' option\n"), optopt); 600*990b4856Slling goto badusage; 601fa9e4066Sahrens case '?': 602fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 603fa9e4066Sahrens optopt); 604*990b4856Slling goto badusage; 605fa9e4066Sahrens } 606fa9e4066Sahrens } 607fa9e4066Sahrens 608fa9e4066Sahrens argc -= optind; 609fa9e4066Sahrens argv += optind; 610fa9e4066Sahrens 611fa9e4066Sahrens /* get pool name and check number of arguments */ 612fa9e4066Sahrens if (argc < 1) { 613fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 614*990b4856Slling goto badusage; 615fa9e4066Sahrens } 616fa9e4066Sahrens if (argc < 2) { 617fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 618*990b4856Slling goto badusage; 619fa9e4066Sahrens } 620fa9e4066Sahrens 621fa9e4066Sahrens poolname = argv[0]; 622fa9e4066Sahrens 623fa9e4066Sahrens /* 624fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 625fa9e4066Sahrens * user to use 'zfs create' instead. 626fa9e4066Sahrens */ 627fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 628fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 629fa9e4066Sahrens "character '/' in pool name\n"), poolname); 630fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 631fa9e4066Sahrens "create a dataset\n")); 632*990b4856Slling goto errout; 633fa9e4066Sahrens } 634fa9e4066Sahrens 635fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 63699653d4eSeschrock nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1, 63799653d4eSeschrock argv + 1); 638fa9e4066Sahrens if (nvroot == NULL) 639fa9e4066Sahrens return (1); 640fa9e4066Sahrens 64199653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 64299653d4eSeschrock verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 64399653d4eSeschrock &child, &children) == 0); 64499653d4eSeschrock if (children == 0) { 64599653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 64699653d4eSeschrock "specification: at least one toplevel vdev must be " 64799653d4eSeschrock "specified\n")); 648*990b4856Slling goto errout; 64999653d4eSeschrock } 65099653d4eSeschrock 65199653d4eSeschrock 652fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 653fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 654e9dbad6fSeschrock "must be an absolute path\n"), altroot); 655*990b4856Slling goto errout; 656fa9e4066Sahrens } 657fa9e4066Sahrens 658fa9e4066Sahrens /* 659fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 660fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 661fa9e4066Sahrens */ 662fa9e4066Sahrens if (mountpoint == NULL || 663fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 664fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 665fa9e4066Sahrens char buf[MAXPATHLEN]; 666fa9e4066Sahrens struct stat64 statbuf; 667fa9e4066Sahrens 668fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 669fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 670fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 671fa9e4066Sahrens "'none'\n"), mountpoint); 672*990b4856Slling goto errout; 673fa9e4066Sahrens } 674fa9e4066Sahrens 675fa9e4066Sahrens if (mountpoint == NULL) { 676fa9e4066Sahrens if (altroot != NULL) 677fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 678fa9e4066Sahrens altroot, poolname); 679fa9e4066Sahrens else 680fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 681fa9e4066Sahrens poolname); 682fa9e4066Sahrens } else { 683fa9e4066Sahrens if (altroot != NULL) 684fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 685fa9e4066Sahrens altroot, mountpoint); 686fa9e4066Sahrens else 687fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 688fa9e4066Sahrens mountpoint); 689fa9e4066Sahrens } 690fa9e4066Sahrens 691fa9e4066Sahrens if (stat64(buf, &statbuf) == 0 && 692fa9e4066Sahrens statbuf.st_nlink != 2) { 693fa9e4066Sahrens if (mountpoint == NULL) 694fa9e4066Sahrens (void) fprintf(stderr, gettext("default " 695fa9e4066Sahrens "mountpoint '%s' exists and is not " 696fa9e4066Sahrens "empty\n"), buf); 697fa9e4066Sahrens else 698fa9e4066Sahrens (void) fprintf(stderr, gettext("mountpoint " 699fa9e4066Sahrens "'%s' exists and is not empty\n"), buf); 700fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 701fa9e4066Sahrens "option to provide a different default\n")); 702*990b4856Slling goto errout; 703fa9e4066Sahrens } 704fa9e4066Sahrens } 705fa9e4066Sahrens 706fa9e4066Sahrens if (dryrun) { 707fa9e4066Sahrens /* 708fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 709fa9e4066Sahrens * through all the vdevs in the list and print out in an 710fa9e4066Sahrens * appropriate hierarchy. 711fa9e4066Sahrens */ 712fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 713fa9e4066Sahrens "following layout:\n\n"), poolname); 714fa9e4066Sahrens 7158654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 7168654d025Sperrin if (num_logs(nvroot) > 0) 7178654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 718fa9e4066Sahrens 719fa9e4066Sahrens ret = 0; 720fa9e4066Sahrens } else { 721fa9e4066Sahrens /* 722fa9e4066Sahrens * Hand off to libzfs. 723fa9e4066Sahrens */ 724*990b4856Slling if (zpool_create(g_zfs, poolname, nvroot, props) == 0) { 72599653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 726fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 727fa9e4066Sahrens if (pool != NULL) { 728fa9e4066Sahrens if (mountpoint != NULL) 729fa9e4066Sahrens verify(zfs_prop_set(pool, 730e9dbad6fSeschrock zfs_prop_to_name( 731e9dbad6fSeschrock ZFS_PROP_MOUNTPOINT), 732fa9e4066Sahrens mountpoint) == 0); 733fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 734f3861e1aSahl ret = zfs_share_nfs(pool); 735fa9e4066Sahrens zfs_close(pool); 736fa9e4066Sahrens } 73799653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 73899653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 73999653d4eSeschrock "been omitted\n")); 740fa9e4066Sahrens } 741fa9e4066Sahrens } 742fa9e4066Sahrens 743*990b4856Slling errout: 744*990b4856Slling if (nvroot) 745*990b4856Slling nvlist_free(nvroot); 746*990b4856Slling if (props) 747*990b4856Slling nvlist_free(props); 748fa9e4066Sahrens return (ret); 749*990b4856Slling badusage: 750*990b4856Slling nvlist_free(props); 751*990b4856Slling usage(B_FALSE); 752*990b4856Slling return (2); 753fa9e4066Sahrens } 754fa9e4066Sahrens 755fa9e4066Sahrens /* 756fa9e4066Sahrens * zpool destroy <pool> 757fa9e4066Sahrens * 758fa9e4066Sahrens * -f Forcefully unmount any datasets 759fa9e4066Sahrens * 760fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 761fa9e4066Sahrens */ 762fa9e4066Sahrens int 763fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 764fa9e4066Sahrens { 76599653d4eSeschrock boolean_t force = B_FALSE; 766fa9e4066Sahrens int c; 767fa9e4066Sahrens char *pool; 768fa9e4066Sahrens zpool_handle_t *zhp; 769fa9e4066Sahrens int ret; 770fa9e4066Sahrens 771fa9e4066Sahrens /* check options */ 772fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 773fa9e4066Sahrens switch (c) { 774fa9e4066Sahrens case 'f': 77599653d4eSeschrock force = B_TRUE; 776fa9e4066Sahrens break; 777fa9e4066Sahrens case '?': 778fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 779fa9e4066Sahrens optopt); 78099653d4eSeschrock usage(B_FALSE); 781fa9e4066Sahrens } 782fa9e4066Sahrens } 783fa9e4066Sahrens 784fa9e4066Sahrens argc -= optind; 785fa9e4066Sahrens argv += optind; 786fa9e4066Sahrens 787fa9e4066Sahrens /* check arguments */ 788fa9e4066Sahrens if (argc < 1) { 789fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 79099653d4eSeschrock usage(B_FALSE); 791fa9e4066Sahrens } 792fa9e4066Sahrens if (argc > 1) { 793fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 79499653d4eSeschrock usage(B_FALSE); 795fa9e4066Sahrens } 796fa9e4066Sahrens 797fa9e4066Sahrens pool = argv[0]; 798fa9e4066Sahrens 79999653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 800fa9e4066Sahrens /* 801fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 802fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 803fa9e4066Sahrens */ 804fa9e4066Sahrens if (strchr(pool, '/') != NULL) 805fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 806fa9e4066Sahrens "destroy a dataset\n")); 807fa9e4066Sahrens return (1); 808fa9e4066Sahrens } 809fa9e4066Sahrens 810f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 811fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 812fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 813fa9e4066Sahrens return (1); 814fa9e4066Sahrens } 815fa9e4066Sahrens 816fa9e4066Sahrens ret = (zpool_destroy(zhp) != 0); 817fa9e4066Sahrens 818fa9e4066Sahrens zpool_close(zhp); 819fa9e4066Sahrens 820fa9e4066Sahrens return (ret); 821fa9e4066Sahrens } 822fa9e4066Sahrens 823fa9e4066Sahrens /* 824fa9e4066Sahrens * zpool export [-f] <pool> ... 825fa9e4066Sahrens * 826fa9e4066Sahrens * -f Forcefully unmount datasets 827fa9e4066Sahrens * 828b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 829fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 830fa9e4066Sahrens * then the datasets will be forcefully unmounted. 831fa9e4066Sahrens */ 832fa9e4066Sahrens int 833fa9e4066Sahrens zpool_do_export(int argc, char **argv) 834fa9e4066Sahrens { 83599653d4eSeschrock boolean_t force = B_FALSE; 836fa9e4066Sahrens int c; 837fa9e4066Sahrens zpool_handle_t *zhp; 838fa9e4066Sahrens int ret; 839fa9e4066Sahrens int i; 840fa9e4066Sahrens 841fa9e4066Sahrens /* check options */ 842fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 843fa9e4066Sahrens switch (c) { 844fa9e4066Sahrens case 'f': 84599653d4eSeschrock force = B_TRUE; 846fa9e4066Sahrens break; 847fa9e4066Sahrens case '?': 848fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 849fa9e4066Sahrens optopt); 85099653d4eSeschrock usage(B_FALSE); 851fa9e4066Sahrens } 852fa9e4066Sahrens } 853fa9e4066Sahrens 854fa9e4066Sahrens argc -= optind; 855fa9e4066Sahrens argv += optind; 856fa9e4066Sahrens 857fa9e4066Sahrens /* check arguments */ 858fa9e4066Sahrens if (argc < 1) { 859fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 86099653d4eSeschrock usage(B_FALSE); 861fa9e4066Sahrens } 862fa9e4066Sahrens 863fa9e4066Sahrens ret = 0; 864fa9e4066Sahrens for (i = 0; i < argc; i++) { 86599653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 866fa9e4066Sahrens ret = 1; 867fa9e4066Sahrens continue; 868fa9e4066Sahrens } 869fa9e4066Sahrens 870f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 871fa9e4066Sahrens ret = 1; 872fa9e4066Sahrens zpool_close(zhp); 873fa9e4066Sahrens continue; 874fa9e4066Sahrens } 875fa9e4066Sahrens 876fa9e4066Sahrens if (zpool_export(zhp) != 0) 877fa9e4066Sahrens ret = 1; 878fa9e4066Sahrens 879fa9e4066Sahrens zpool_close(zhp); 880fa9e4066Sahrens } 881fa9e4066Sahrens 882fa9e4066Sahrens return (ret); 883fa9e4066Sahrens } 884fa9e4066Sahrens 885fa9e4066Sahrens /* 886fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 887fa9e4066Sahrens * name column. 888fa9e4066Sahrens */ 889fa9e4066Sahrens static int 890c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 891fa9e4066Sahrens { 89299653d4eSeschrock char *name = zpool_vdev_name(g_zfs, zhp, nv); 893fa9e4066Sahrens nvlist_t **child; 894fa9e4066Sahrens uint_t c, children; 895fa9e4066Sahrens int ret; 896fa9e4066Sahrens 897fa9e4066Sahrens if (strlen(name) + depth > max) 898fa9e4066Sahrens max = strlen(name) + depth; 899fa9e4066Sahrens 900afefbcddSeschrock free(name); 901afefbcddSeschrock 90299653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 90399653d4eSeschrock &child, &children) == 0) { 90499653d4eSeschrock for (c = 0; c < children; c++) 90599653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 90699653d4eSeschrock max)) > max) 90799653d4eSeschrock max = ret; 90899653d4eSeschrock } 90999653d4eSeschrock 910fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 91199653d4eSeschrock &child, &children) == 0) { 91299653d4eSeschrock for (c = 0; c < children; c++) 91399653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 91499653d4eSeschrock max)) > max) 91599653d4eSeschrock max = ret; 91699653d4eSeschrock } 917fa9e4066Sahrens 918fa9e4066Sahrens 919fa9e4066Sahrens return (max); 920fa9e4066Sahrens } 921fa9e4066Sahrens 922fa9e4066Sahrens 923fa9e4066Sahrens /* 924fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 925fa9e4066Sahrens * pool, printing out the name and status for each one. 926fa9e4066Sahrens */ 927fa9e4066Sahrens void 9288654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth, 9298654d025Sperrin boolean_t print_logs) 930fa9e4066Sahrens { 931fa9e4066Sahrens nvlist_t **child; 932fa9e4066Sahrens uint_t c, children; 933fa9e4066Sahrens vdev_stat_t *vs; 934afefbcddSeschrock char *type, *vname; 935fa9e4066Sahrens 936fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 937fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_MISSING) == 0) 938fa9e4066Sahrens return; 939fa9e4066Sahrens 940fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 941fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 942fa9e4066Sahrens 943fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 944*990b4856Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 945fa9e4066Sahrens 946fa9e4066Sahrens if (vs->vs_aux != 0) { 9473d7072f8Seschrock (void) printf(" "); 948fa9e4066Sahrens 949fa9e4066Sahrens switch (vs->vs_aux) { 950fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 951fa9e4066Sahrens (void) printf(gettext("cannot open")); 952fa9e4066Sahrens break; 953fa9e4066Sahrens 954fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 955fa9e4066Sahrens (void) printf(gettext("missing device")); 956fa9e4066Sahrens break; 957fa9e4066Sahrens 958fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 959fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 960fa9e4066Sahrens break; 961fa9e4066Sahrens 962eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 963eaca9bbdSeschrock (void) printf(gettext("newer version")); 964eaca9bbdSeschrock break; 965eaca9bbdSeschrock 9663d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 9673d7072f8Seschrock (void) printf(gettext("too many errors")); 9683d7072f8Seschrock break; 9693d7072f8Seschrock 970fa9e4066Sahrens default: 971fa9e4066Sahrens (void) printf(gettext("corrupted data")); 972fa9e4066Sahrens break; 973fa9e4066Sahrens } 974fa9e4066Sahrens } 975fa9e4066Sahrens (void) printf("\n"); 976fa9e4066Sahrens 977fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 978fa9e4066Sahrens &child, &children) != 0) 979fa9e4066Sahrens return; 980fa9e4066Sahrens 981afefbcddSeschrock for (c = 0; c < children; c++) { 9828654d025Sperrin uint64_t is_log = B_FALSE; 9838654d025Sperrin 9848654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 9858654d025Sperrin &is_log); 9868654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 9878654d025Sperrin continue; 9888654d025Sperrin 98999653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 990afefbcddSeschrock print_import_config(vname, child[c], 9918654d025Sperrin namewidth, depth + 2, B_FALSE); 992afefbcddSeschrock free(vname); 993afefbcddSeschrock } 99499653d4eSeschrock 99599653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 99699653d4eSeschrock &child, &children) != 0) 99799653d4eSeschrock return; 99899653d4eSeschrock 99999653d4eSeschrock (void) printf(gettext("\tspares\n")); 100099653d4eSeschrock for (c = 0; c < children; c++) { 100199653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 100299653d4eSeschrock (void) printf("\t %s\n", vname); 100399653d4eSeschrock free(vname); 100499653d4eSeschrock } 1005fa9e4066Sahrens } 1006fa9e4066Sahrens 1007fa9e4066Sahrens /* 1008fa9e4066Sahrens * Display the status for the given pool. 1009fa9e4066Sahrens */ 1010fa9e4066Sahrens static void 1011fa9e4066Sahrens show_import(nvlist_t *config) 1012fa9e4066Sahrens { 1013fa9e4066Sahrens uint64_t pool_state; 1014fa9e4066Sahrens vdev_stat_t *vs; 1015fa9e4066Sahrens char *name; 1016fa9e4066Sahrens uint64_t guid; 1017fa9e4066Sahrens char *msgid; 1018fa9e4066Sahrens nvlist_t *nvroot; 1019fa9e4066Sahrens int reason; 102046657f8dSmmusante const char *health; 1021fa9e4066Sahrens uint_t vsc; 1022fa9e4066Sahrens int namewidth; 1023fa9e4066Sahrens 1024fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1025fa9e4066Sahrens &name) == 0); 1026fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1027fa9e4066Sahrens &guid) == 0); 1028fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1029fa9e4066Sahrens &pool_state) == 0); 1030fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1031fa9e4066Sahrens &nvroot) == 0); 1032fa9e4066Sahrens 1033fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1034fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 1035*990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1036fa9e4066Sahrens 1037fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1038fa9e4066Sahrens 103946657f8dSmmusante (void) printf(gettext(" pool: %s\n"), name); 104046657f8dSmmusante (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 104146657f8dSmmusante (void) printf(gettext(" state: %s"), health); 10424c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 1043b1b8ab34Slling (void) printf(gettext(" (DESTROYED)")); 10444c58d714Sdarrenm (void) printf("\n"); 1045fa9e4066Sahrens 1046fa9e4066Sahrens switch (reason) { 1047fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1048fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1049fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 1050fa9e4066Sahrens (void) printf(gettext("status: One or more devices are missing " 1051fa9e4066Sahrens "from the system.\n")); 1052fa9e4066Sahrens break; 1053fa9e4066Sahrens 1054fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1055fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1056fa9e4066Sahrens (void) printf(gettext("status: One or more devices contains " 1057fa9e4066Sahrens "corrupted data.\n")); 1058fa9e4066Sahrens break; 1059fa9e4066Sahrens 1060fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 1061fa9e4066Sahrens (void) printf(gettext("status: The pool data is corrupted.\n")); 1062fa9e4066Sahrens break; 1063fa9e4066Sahrens 1064441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 1065441d80aaSlling (void) printf(gettext("status: One or more devices " 1066441d80aaSlling "are offlined.\n")); 1067441d80aaSlling break; 1068441d80aaSlling 1069ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 1070ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is " 1071ea8dc4b6Seschrock "corrupted.\n")); 1072ea8dc4b6Seschrock break; 1073ea8dc4b6Seschrock 1074eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 1075eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1076eaca9bbdSeschrock "older on-disk version.\n")); 1077eaca9bbdSeschrock break; 1078eaca9bbdSeschrock 1079eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1080eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1081eaca9bbdSeschrock "incompatible version.\n")); 1082eaca9bbdSeschrock break; 108395173954Sek case ZPOOL_STATUS_HOSTID_MISMATCH: 108495173954Sek (void) printf(gettext("status: The pool was last accessed by " 108595173954Sek "another system.\n")); 108695173954Sek break; 10873d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 10883d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 10893d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 10903d7072f8Seschrock "faulted.\n")); 10913d7072f8Seschrock break; 10923d7072f8Seschrock 1093fa9e4066Sahrens default: 1094fa9e4066Sahrens /* 1095fa9e4066Sahrens * No other status can be seen when importing pools. 1096fa9e4066Sahrens */ 1097fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1098fa9e4066Sahrens } 1099fa9e4066Sahrens 1100fa9e4066Sahrens /* 1101fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1102fa9e4066Sahrens */ 110346657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 1104eaca9bbdSeschrock if (reason == ZPOOL_STATUS_VERSION_OLDER) 1105eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1106eaca9bbdSeschrock "imported using its name or numeric identifier, " 1107eaca9bbdSeschrock "though\n\tsome features will not be available " 1108eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 110995173954Sek else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 111095173954Sek (void) printf(gettext("action: The pool can be " 111195173954Sek "imported using its name or numeric " 111295173954Sek "identifier and\n\tthe '-f' flag.\n")); 1113fa9e4066Sahrens else 1114eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1115eaca9bbdSeschrock "imported using its name or numeric " 1116eaca9bbdSeschrock "identifier.\n")); 111746657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1118fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported " 1119fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1120eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1121fa9e4066Sahrens } else { 1122eaca9bbdSeschrock switch (reason) { 1123eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1124eaca9bbdSeschrock (void) printf(gettext("action: The pool cannot be " 1125eaca9bbdSeschrock "imported. Access the pool on a system running " 1126eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1127eaca9bbdSeschrock "backup.\n")); 1128eaca9bbdSeschrock break; 1129eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1130eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1131eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 1132fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1133fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1134fa9e4066Sahrens "again.\n")); 1135eaca9bbdSeschrock break; 1136eaca9bbdSeschrock default: 1137fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1138fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1139eaca9bbdSeschrock } 1140eaca9bbdSeschrock } 1141eaca9bbdSeschrock 114246657f8dSmmusante /* 114346657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 114446657f8dSmmusante * is "corrupt data": 114546657f8dSmmusante */ 114646657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 114746657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 114846657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1149eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1150eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1151eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1152eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1153eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 1154eaca9bbdSeschrock "on another system, but can be imported using\n\t" 1155eaca9bbdSeschrock "the '-f' flag.\n")); 1156fa9e4066Sahrens } 1157fa9e4066Sahrens 1158fa9e4066Sahrens if (msgid != NULL) 1159fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1160fa9e4066Sahrens msgid); 1161fa9e4066Sahrens 1162fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 1163fa9e4066Sahrens 1164c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1165fa9e4066Sahrens if (namewidth < 10) 1166fa9e4066Sahrens namewidth = 10; 11678654d025Sperrin 11688654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_FALSE); 11698654d025Sperrin if (num_logs(nvroot) > 0) { 11708654d025Sperrin (void) printf(gettext("\tlogs\n")); 11718654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_TRUE); 11728654d025Sperrin } 1173fa9e4066Sahrens 1174fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 117546657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1176fa9e4066Sahrens "be part of this pool, though their\n\texact " 117746657f8dSmmusante "configuration cannot be determined.\n")); 1178fa9e4066Sahrens } 1179fa9e4066Sahrens } 1180fa9e4066Sahrens 1181fa9e4066Sahrens /* 1182fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1183*990b4856Slling * lifting off to zpool_import_props(), and then mounts the datasets contained 1184*990b4856Slling * within the pool. 1185fa9e4066Sahrens */ 1186fa9e4066Sahrens static int 1187fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 1188*990b4856Slling int force, nvlist_t *props) 1189fa9e4066Sahrens { 1190fa9e4066Sahrens zpool_handle_t *zhp; 1191fa9e4066Sahrens char *name; 1192fa9e4066Sahrens uint64_t state; 1193eaca9bbdSeschrock uint64_t version; 1194ecd6cf80Smarks int error = 0; 1195fa9e4066Sahrens 1196fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1197fa9e4066Sahrens &name) == 0); 1198fa9e4066Sahrens 1199fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1200fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1201eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1202eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1203e7437265Sahrens if (version > SPA_VERSION) { 1204eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1205eaca9bbdSeschrock "is formatted using a newer ZFS version\n"), name); 1206eaca9bbdSeschrock return (1); 1207eaca9bbdSeschrock } else if (state != POOL_STATE_EXPORTED && !force) { 120895173954Sek uint64_t hostid; 120995173954Sek 121095173954Sek if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 121195173954Sek &hostid) == 0) { 121295173954Sek if ((unsigned long)hostid != gethostid()) { 121395173954Sek char *hostname; 121495173954Sek uint64_t timestamp; 121595173954Sek time_t t; 121695173954Sek 121795173954Sek verify(nvlist_lookup_string(config, 121895173954Sek ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 121995173954Sek verify(nvlist_lookup_uint64(config, 122095173954Sek ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 122195173954Sek t = timestamp; 122295173954Sek (void) fprintf(stderr, gettext("cannot import " 122395173954Sek "'%s': pool may be in use from other " 122495173954Sek "system, it was last accessed by %s " 122595173954Sek "(hostid: 0x%lx) on %s"), name, hostname, 122695173954Sek (unsigned long)hostid, 122795173954Sek asctime(localtime(&t))); 122895173954Sek (void) fprintf(stderr, gettext("use '-f' to " 122995173954Sek "import anyway\n")); 123095173954Sek return (1); 123195173954Sek } 123295173954Sek } else { 123395173954Sek (void) fprintf(stderr, gettext("cannot import '%s': " 123495173954Sek "pool may be in use from other system\n"), name); 123595173954Sek (void) fprintf(stderr, gettext("use '-f' to import " 123695173954Sek "anyway\n")); 123795173954Sek return (1); 123895173954Sek } 1239fa9e4066Sahrens } 1240fa9e4066Sahrens 1241*990b4856Slling if (zpool_import_props(g_zfs, config, newname, props) != 0) 1242fa9e4066Sahrens return (1); 1243fa9e4066Sahrens 1244fa9e4066Sahrens if (newname != NULL) 1245fa9e4066Sahrens name = (char *)newname; 1246fa9e4066Sahrens 124799653d4eSeschrock verify((zhp = zpool_open(g_zfs, name)) != NULL); 1248fa9e4066Sahrens 1249f3861e1aSahl if (zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1250fa9e4066Sahrens zpool_close(zhp); 1251fa9e4066Sahrens return (1); 1252fa9e4066Sahrens } 1253fa9e4066Sahrens 1254fa9e4066Sahrens zpool_close(zhp); 1255ecd6cf80Smarks return (error); 1256fa9e4066Sahrens } 1257fa9e4066Sahrens 1258fa9e4066Sahrens /* 12594c58d714Sdarrenm * zpool import [-d dir] [-D] 1260*990b4856Slling * import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-d dir] [-f] -a 1261*990b4856Slling * import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-d dir] [-f] 1262*990b4856Slling * <pool | id> [newpool] 1263fa9e4066Sahrens * 1264fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1265fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1266fa9e4066Sahrens * 12674c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 12684c58d714Sdarrenm * specified destroyed pools. 12694c58d714Sdarrenm * 1270fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1271fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1272fa9e4066Sahrens * is rebooted. 1273fa9e4066Sahrens * 1274fa9e4066Sahrens * -f Force import, even if it appears that the pool is active. 1275fa9e4066Sahrens * 1276fa9e4066Sahrens * -a Import all pools found. 1277fa9e4066Sahrens * 1278*990b4856Slling * -o Set property=value and/or temporary mount options (without '='). 1279ecd6cf80Smarks * 1280fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 1281fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 1282fa9e4066Sahrens */ 1283fa9e4066Sahrens int 1284fa9e4066Sahrens zpool_do_import(int argc, char **argv) 1285fa9e4066Sahrens { 1286fa9e4066Sahrens char **searchdirs = NULL; 1287fa9e4066Sahrens int nsearch = 0; 1288fa9e4066Sahrens int c; 1289fa9e4066Sahrens int err; 1290fa9e4066Sahrens nvlist_t *pools; 129199653d4eSeschrock boolean_t do_all = B_FALSE; 129299653d4eSeschrock boolean_t do_destroyed = B_FALSE; 1293fa9e4066Sahrens char *mntopts = NULL; 129499653d4eSeschrock boolean_t do_force = B_FALSE; 1295fa9e4066Sahrens nvpair_t *elem; 1296fa9e4066Sahrens nvlist_t *config; 1297fa9e4066Sahrens uint64_t searchguid; 1298fa9e4066Sahrens char *searchname; 1299*990b4856Slling char *propval; 1300fa9e4066Sahrens nvlist_t *found_config; 1301ecd6cf80Smarks nvlist_t *props = NULL; 130299653d4eSeschrock boolean_t first; 13034c58d714Sdarrenm uint64_t pool_state; 1304fa9e4066Sahrens 1305fa9e4066Sahrens /* check options */ 1306ecd6cf80Smarks while ((c = getopt(argc, argv, ":Dfd:R:ao:p:")) != -1) { 1307fa9e4066Sahrens switch (c) { 1308fa9e4066Sahrens case 'a': 130999653d4eSeschrock do_all = B_TRUE; 1310fa9e4066Sahrens break; 1311fa9e4066Sahrens case 'd': 1312fa9e4066Sahrens if (searchdirs == NULL) { 1313fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1314fa9e4066Sahrens } else { 1315fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 1316fa9e4066Sahrens sizeof (char *)); 1317fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 1318fa9e4066Sahrens sizeof (char *)); 1319fa9e4066Sahrens free(searchdirs); 1320fa9e4066Sahrens searchdirs = tmp; 1321fa9e4066Sahrens } 1322fa9e4066Sahrens searchdirs[nsearch++] = optarg; 1323fa9e4066Sahrens break; 13244c58d714Sdarrenm case 'D': 132599653d4eSeschrock do_destroyed = B_TRUE; 13264c58d714Sdarrenm break; 1327fa9e4066Sahrens case 'f': 132899653d4eSeschrock do_force = B_TRUE; 1329fa9e4066Sahrens break; 1330fa9e4066Sahrens case 'o': 1331*990b4856Slling if ((propval = strchr(optarg, '=')) != NULL) { 1332*990b4856Slling *propval = '\0'; 1333*990b4856Slling propval++; 1334*990b4856Slling if (add_prop_list(optarg, propval, &props)) 1335*990b4856Slling goto error; 1336*990b4856Slling } else { 1337*990b4856Slling mntopts = optarg; 1338*990b4856Slling } 1339fa9e4066Sahrens break; 1340fa9e4066Sahrens case 'R': 1341*990b4856Slling if (add_prop_list(zpool_prop_to_name( 1342*990b4856Slling ZPOOL_PROP_ALTROOT), optarg, &props)) 1343*990b4856Slling goto error; 1344*990b4856Slling if (add_prop_list(zpool_prop_to_name( 1345*990b4856Slling ZPOOL_PROP_TEMPORARY), "on", &props)) 1346*990b4856Slling goto error; 1347fa9e4066Sahrens break; 1348fa9e4066Sahrens case ':': 1349fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 1350fa9e4066Sahrens "'%c' option\n"), optopt); 135199653d4eSeschrock usage(B_FALSE); 1352fa9e4066Sahrens break; 1353fa9e4066Sahrens case '?': 1354fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1355fa9e4066Sahrens optopt); 135699653d4eSeschrock usage(B_FALSE); 1357fa9e4066Sahrens } 1358fa9e4066Sahrens } 1359fa9e4066Sahrens 1360fa9e4066Sahrens argc -= optind; 1361fa9e4066Sahrens argv += optind; 1362fa9e4066Sahrens 1363fa9e4066Sahrens if (searchdirs == NULL) { 1364fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1365fa9e4066Sahrens searchdirs[0] = "/dev/dsk"; 1366fa9e4066Sahrens nsearch = 1; 1367fa9e4066Sahrens } 1368fa9e4066Sahrens 1369fa9e4066Sahrens /* check argument count */ 1370fa9e4066Sahrens if (do_all) { 1371fa9e4066Sahrens if (argc != 0) { 1372fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 137399653d4eSeschrock usage(B_FALSE); 1374fa9e4066Sahrens } 1375fa9e4066Sahrens } else { 1376fa9e4066Sahrens if (argc > 2) { 1377fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 137899653d4eSeschrock usage(B_FALSE); 1379fa9e4066Sahrens } 1380fa9e4066Sahrens 1381fa9e4066Sahrens /* 1382fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 1383fa9e4066Sahrens * here because otherwise any attempt to discover pools will 1384fa9e4066Sahrens * silently fail. 1385fa9e4066Sahrens */ 1386fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1387fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 1388fa9e4066Sahrens "discover pools: permission denied\n")); 138999653d4eSeschrock free(searchdirs); 1390fa9e4066Sahrens return (1); 1391fa9e4066Sahrens } 1392fa9e4066Sahrens } 1393fa9e4066Sahrens 139499653d4eSeschrock if ((pools = zpool_find_import(g_zfs, nsearch, searchdirs)) == NULL) { 139599653d4eSeschrock free(searchdirs); 1396fa9e4066Sahrens return (1); 139799653d4eSeschrock } 1398fa9e4066Sahrens 1399fa9e4066Sahrens /* 1400fa9e4066Sahrens * We now have a list of all available pools in the given directories. 1401fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 1402fa9e4066Sahrens * 1403fa9e4066Sahrens * <none> Iterate through all pools and display information about 1404fa9e4066Sahrens * each one. 1405fa9e4066Sahrens * 1406fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 1407fa9e4066Sahrens * 1408fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 1409fa9e4066Sahrens * name and import that one. 14104c58d714Sdarrenm * 14114c58d714Sdarrenm * -D Above options applies only to destroyed pools. 1412fa9e4066Sahrens */ 1413fa9e4066Sahrens if (argc != 0) { 1414fa9e4066Sahrens char *endptr; 1415fa9e4066Sahrens 1416fa9e4066Sahrens errno = 0; 1417fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 1418fa9e4066Sahrens if (errno != 0 || *endptr != '\0') 1419fa9e4066Sahrens searchname = argv[0]; 1420fa9e4066Sahrens else 1421fa9e4066Sahrens searchname = NULL; 1422fa9e4066Sahrens found_config = NULL; 1423fa9e4066Sahrens } 1424fa9e4066Sahrens 1425fa9e4066Sahrens err = 0; 1426fa9e4066Sahrens elem = NULL; 142799653d4eSeschrock first = B_TRUE; 1428fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1429fa9e4066Sahrens 1430fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 1431fa9e4066Sahrens 14324c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 14334c58d714Sdarrenm &pool_state) == 0); 14344c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 14354c58d714Sdarrenm continue; 14364c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 14374c58d714Sdarrenm continue; 14384c58d714Sdarrenm 1439fa9e4066Sahrens if (argc == 0) { 1440fa9e4066Sahrens if (first) 144199653d4eSeschrock first = B_FALSE; 14423bb79becSeschrock else if (!do_all) 1443fa9e4066Sahrens (void) printf("\n"); 1444fa9e4066Sahrens 1445fa9e4066Sahrens if (do_all) 1446fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 1447*990b4856Slling do_force, props); 1448fa9e4066Sahrens else 1449fa9e4066Sahrens show_import(config); 1450fa9e4066Sahrens } else if (searchname != NULL) { 1451fa9e4066Sahrens char *name; 1452fa9e4066Sahrens 1453fa9e4066Sahrens /* 1454fa9e4066Sahrens * We are searching for a pool based on name. 1455fa9e4066Sahrens */ 1456fa9e4066Sahrens verify(nvlist_lookup_string(config, 1457fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1458fa9e4066Sahrens 1459fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 1460fa9e4066Sahrens if (found_config != NULL) { 1461fa9e4066Sahrens (void) fprintf(stderr, gettext( 1462fa9e4066Sahrens "cannot import '%s': more than " 1463fa9e4066Sahrens "one matching pool\n"), searchname); 1464fa9e4066Sahrens (void) fprintf(stderr, gettext( 1465fa9e4066Sahrens "import by numeric ID instead\n")); 146699653d4eSeschrock err = B_TRUE; 1467fa9e4066Sahrens } 1468fa9e4066Sahrens found_config = config; 1469fa9e4066Sahrens } 1470fa9e4066Sahrens } else { 1471fa9e4066Sahrens uint64_t guid; 1472fa9e4066Sahrens 1473fa9e4066Sahrens /* 1474fa9e4066Sahrens * Search for a pool by guid. 1475fa9e4066Sahrens */ 1476fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1477fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1478fa9e4066Sahrens 1479fa9e4066Sahrens if (guid == searchguid) 1480fa9e4066Sahrens found_config = config; 1481fa9e4066Sahrens } 1482fa9e4066Sahrens } 1483fa9e4066Sahrens 1484fa9e4066Sahrens /* 1485fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 1486fa9e4066Sahrens * pool, and then do the import. 1487fa9e4066Sahrens */ 1488fa9e4066Sahrens if (argc != 0 && err == 0) { 1489fa9e4066Sahrens if (found_config == NULL) { 1490fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 1491fa9e4066Sahrens "no such pool available\n"), argv[0]); 149299653d4eSeschrock err = B_TRUE; 1493fa9e4066Sahrens } else { 1494fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 1495*990b4856Slling argv[1], mntopts, do_force, props); 1496fa9e4066Sahrens } 1497fa9e4066Sahrens } 1498fa9e4066Sahrens 1499fa9e4066Sahrens /* 1500fa9e4066Sahrens * If we were just looking for pools, report an error if none were 1501fa9e4066Sahrens * found. 1502fa9e4066Sahrens */ 1503fa9e4066Sahrens if (argc == 0 && first) 1504fa9e4066Sahrens (void) fprintf(stderr, 1505fa9e4066Sahrens gettext("no pools available to import\n")); 1506fa9e4066Sahrens 1507ecd6cf80Smarks error: 1508ecd6cf80Smarks if (props) 1509ecd6cf80Smarks nvlist_free(props); 1510fa9e4066Sahrens nvlist_free(pools); 151199653d4eSeschrock free(searchdirs); 1512fa9e4066Sahrens 1513fa9e4066Sahrens return (err ? 1 : 0); 1514fa9e4066Sahrens } 1515fa9e4066Sahrens 1516fa9e4066Sahrens typedef struct iostat_cbdata { 1517fa9e4066Sahrens zpool_list_t *cb_list; 1518fa9e4066Sahrens int cb_verbose; 1519fa9e4066Sahrens int cb_iteration; 1520fa9e4066Sahrens int cb_namewidth; 1521fa9e4066Sahrens } iostat_cbdata_t; 1522fa9e4066Sahrens 1523fa9e4066Sahrens static void 1524fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 1525fa9e4066Sahrens { 1526fa9e4066Sahrens int i = 0; 1527fa9e4066Sahrens 1528fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 1529fa9e4066Sahrens (void) printf("-"); 1530fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1531fa9e4066Sahrens } 1532fa9e4066Sahrens 1533fa9e4066Sahrens static void 1534fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 1535fa9e4066Sahrens { 1536fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 1537fa9e4066Sahrens cb->cb_namewidth, ""); 1538fa9e4066Sahrens (void) printf("%-*s used avail read write read write\n", 1539fa9e4066Sahrens cb->cb_namewidth, "pool"); 1540fa9e4066Sahrens print_iostat_separator(cb); 1541fa9e4066Sahrens } 1542fa9e4066Sahrens 1543fa9e4066Sahrens /* 1544fa9e4066Sahrens * Display a single statistic. 1545fa9e4066Sahrens */ 1546*990b4856Slling static void 1547fa9e4066Sahrens print_one_stat(uint64_t value) 1548fa9e4066Sahrens { 1549fa9e4066Sahrens char buf[64]; 1550fa9e4066Sahrens 1551fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 1552fa9e4066Sahrens (void) printf(" %5s", buf); 1553fa9e4066Sahrens } 1554fa9e4066Sahrens 1555fa9e4066Sahrens /* 1556fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 1557fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 1558fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 1559fa9e4066Sahrens */ 1560fa9e4066Sahrens void 1561c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1562c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1563fa9e4066Sahrens { 1564fa9e4066Sahrens nvlist_t **oldchild, **newchild; 1565fa9e4066Sahrens uint_t c, children; 1566fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 1567fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 1568fa9e4066Sahrens uint64_t tdelta; 1569fa9e4066Sahrens double scale; 1570afefbcddSeschrock char *vname; 1571fa9e4066Sahrens 1572fa9e4066Sahrens if (oldnv != NULL) { 1573fa9e4066Sahrens verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1574fa9e4066Sahrens (uint64_t **)&oldvs, &c) == 0); 1575fa9e4066Sahrens } else { 1576fa9e4066Sahrens oldvs = &zerovs; 1577fa9e4066Sahrens } 1578fa9e4066Sahrens 1579fa9e4066Sahrens verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1580fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 1581fa9e4066Sahrens 1582fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 1583fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 1584fa9e4066Sahrens else 1585fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 1586fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1587fa9e4066Sahrens 1588fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1589fa9e4066Sahrens 1590fa9e4066Sahrens if (tdelta == 0) 1591fa9e4066Sahrens scale = 1.0; 1592fa9e4066Sahrens else 1593fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 1594fa9e4066Sahrens 1595fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 1596fa9e4066Sahrens if (newvs->vs_space == 0) { 1597fa9e4066Sahrens (void) printf(" - -"); 1598fa9e4066Sahrens } else { 1599fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 1600fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 1601fa9e4066Sahrens } 1602fa9e4066Sahrens 1603fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1604fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 1605fa9e4066Sahrens 1606fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1607fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1608fa9e4066Sahrens 1609fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1610fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 1611fa9e4066Sahrens 1612fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1613fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1614fa9e4066Sahrens 1615fa9e4066Sahrens (void) printf("\n"); 1616fa9e4066Sahrens 1617fa9e4066Sahrens if (!cb->cb_verbose) 1618fa9e4066Sahrens return; 1619fa9e4066Sahrens 1620fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1621fa9e4066Sahrens &newchild, &children) != 0) 1622fa9e4066Sahrens return; 1623fa9e4066Sahrens 1624fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1625fa9e4066Sahrens &oldchild, &c) != 0) 1626fa9e4066Sahrens return; 1627fa9e4066Sahrens 1628afefbcddSeschrock for (c = 0; c < children; c++) { 162999653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1630c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1631afefbcddSeschrock newchild[c], cb, depth + 2); 1632afefbcddSeschrock free(vname); 1633afefbcddSeschrock } 1634fa9e4066Sahrens } 1635fa9e4066Sahrens 1636088e9d47Seschrock static int 1637088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 1638088e9d47Seschrock { 1639088e9d47Seschrock iostat_cbdata_t *cb = data; 164094de1d4cSeschrock boolean_t missing; 1641088e9d47Seschrock 1642088e9d47Seschrock /* 1643088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 1644088e9d47Seschrock */ 164594de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 164694de1d4cSeschrock return (-1); 164794de1d4cSeschrock 164894de1d4cSeschrock if (missing) 1649088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 1650088e9d47Seschrock 1651088e9d47Seschrock return (0); 1652088e9d47Seschrock } 1653088e9d47Seschrock 1654fa9e4066Sahrens /* 1655fa9e4066Sahrens * Callback to print out the iostats for the given pool. 1656fa9e4066Sahrens */ 1657fa9e4066Sahrens int 1658fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 1659fa9e4066Sahrens { 1660fa9e4066Sahrens iostat_cbdata_t *cb = data; 1661fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 1662fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 1663fa9e4066Sahrens 1664088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 1665fa9e4066Sahrens 1666088e9d47Seschrock if (cb->cb_iteration == 1) 1667fa9e4066Sahrens oldconfig = NULL; 1668fa9e4066Sahrens 1669fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1670fa9e4066Sahrens &newnvroot) == 0); 1671fa9e4066Sahrens 1672088e9d47Seschrock if (oldconfig == NULL) 1673fa9e4066Sahrens oldnvroot = NULL; 1674088e9d47Seschrock else 1675088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 1676088e9d47Seschrock &oldnvroot) == 0); 1677fa9e4066Sahrens 1678fa9e4066Sahrens /* 1679fa9e4066Sahrens * Print out the statistics for the pool. 1680fa9e4066Sahrens */ 1681c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1682fa9e4066Sahrens 1683fa9e4066Sahrens if (cb->cb_verbose) 1684fa9e4066Sahrens print_iostat_separator(cb); 1685fa9e4066Sahrens 1686fa9e4066Sahrens return (0); 1687fa9e4066Sahrens } 1688fa9e4066Sahrens 1689fa9e4066Sahrens int 1690fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 1691fa9e4066Sahrens { 1692fa9e4066Sahrens iostat_cbdata_t *cb = data; 1693fa9e4066Sahrens nvlist_t *config, *nvroot; 1694fa9e4066Sahrens 1695088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 1696fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1697fa9e4066Sahrens &nvroot) == 0); 1698fa9e4066Sahrens if (!cb->cb_verbose) 1699fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1700fa9e4066Sahrens else 1701c67d9675Seschrock cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 1702fa9e4066Sahrens } 1703fa9e4066Sahrens 1704fa9e4066Sahrens /* 1705fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 1706fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 1707fa9e4066Sahrens */ 1708fa9e4066Sahrens if (cb->cb_namewidth < 10) 1709fa9e4066Sahrens cb->cb_namewidth = 10; 1710fa9e4066Sahrens if (cb->cb_namewidth > 38) 1711fa9e4066Sahrens cb->cb_namewidth = 38; 1712fa9e4066Sahrens 1713fa9e4066Sahrens return (0); 1714fa9e4066Sahrens } 1715fa9e4066Sahrens 1716fa9e4066Sahrens /* 1717fa9e4066Sahrens * zpool iostat [-v] [pool] ... [interval [count]] 1718fa9e4066Sahrens * 1719fa9e4066Sahrens * -v Display statistics for individual vdevs 1720fa9e4066Sahrens * 1721fa9e4066Sahrens * This command can be tricky because we want to be able to deal with pool 1722fa9e4066Sahrens * creation/destruction as well as vdev configuration changes. The bulk of this 1723fa9e4066Sahrens * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1724fa9e4066Sahrens * on pool_list_update() to detect the addition of new pools. Configuration 1725fa9e4066Sahrens * changes are all handled within libzfs. 1726fa9e4066Sahrens */ 1727fa9e4066Sahrens int 1728fa9e4066Sahrens zpool_do_iostat(int argc, char **argv) 1729fa9e4066Sahrens { 1730fa9e4066Sahrens int c; 1731fa9e4066Sahrens int ret; 1732fa9e4066Sahrens int npools; 1733fa9e4066Sahrens unsigned long interval = 0, count = 0; 1734fa9e4066Sahrens zpool_list_t *list; 173599653d4eSeschrock boolean_t verbose = B_FALSE; 1736fa9e4066Sahrens iostat_cbdata_t cb; 1737fa9e4066Sahrens 1738fa9e4066Sahrens /* check options */ 1739fa9e4066Sahrens while ((c = getopt(argc, argv, "v")) != -1) { 1740fa9e4066Sahrens switch (c) { 1741fa9e4066Sahrens case 'v': 174299653d4eSeschrock verbose = B_TRUE; 1743fa9e4066Sahrens break; 1744fa9e4066Sahrens case '?': 1745fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1746fa9e4066Sahrens optopt); 174799653d4eSeschrock usage(B_FALSE); 1748fa9e4066Sahrens } 1749fa9e4066Sahrens } 1750fa9e4066Sahrens 1751fa9e4066Sahrens argc -= optind; 1752fa9e4066Sahrens argv += optind; 1753fa9e4066Sahrens 1754fa9e4066Sahrens /* 1755fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 1756fa9e4066Sahrens */ 1757fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1758fa9e4066Sahrens char *end; 1759fa9e4066Sahrens 1760fa9e4066Sahrens errno = 0; 1761fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1762fa9e4066Sahrens 1763fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1764fa9e4066Sahrens if (interval == 0) { 1765fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1766fa9e4066Sahrens "cannot be zero\n")); 176799653d4eSeschrock usage(B_FALSE); 1768fa9e4066Sahrens } 1769fa9e4066Sahrens 1770fa9e4066Sahrens /* 1771fa9e4066Sahrens * Ignore the last parameter 1772fa9e4066Sahrens */ 1773fa9e4066Sahrens argc--; 1774fa9e4066Sahrens } else { 1775fa9e4066Sahrens /* 1776fa9e4066Sahrens * If this is not a valid number, just plow on. The 1777fa9e4066Sahrens * user will get a more informative error message later 1778fa9e4066Sahrens * on. 1779fa9e4066Sahrens */ 1780fa9e4066Sahrens interval = 0; 1781fa9e4066Sahrens } 1782fa9e4066Sahrens } 1783fa9e4066Sahrens 1784fa9e4066Sahrens /* 1785fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 1786fa9e4066Sahrens * and an integer. 1787fa9e4066Sahrens */ 1788fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1789fa9e4066Sahrens char *end; 1790fa9e4066Sahrens 1791fa9e4066Sahrens errno = 0; 1792fa9e4066Sahrens count = interval; 1793fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1794fa9e4066Sahrens 1795fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1796fa9e4066Sahrens if (interval == 0) { 1797fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1798fa9e4066Sahrens "cannot be zero\n")); 179999653d4eSeschrock usage(B_FALSE); 1800fa9e4066Sahrens } 1801fa9e4066Sahrens 1802fa9e4066Sahrens /* 1803fa9e4066Sahrens * Ignore the last parameter 1804fa9e4066Sahrens */ 1805fa9e4066Sahrens argc--; 1806fa9e4066Sahrens } else { 1807fa9e4066Sahrens interval = 0; 1808fa9e4066Sahrens } 1809fa9e4066Sahrens } 1810fa9e4066Sahrens 1811fa9e4066Sahrens /* 1812fa9e4066Sahrens * Construct the list of all interesting pools. 1813fa9e4066Sahrens */ 1814fa9e4066Sahrens ret = 0; 1815b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 1816fa9e4066Sahrens return (1); 1817fa9e4066Sahrens 181899653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 181999653d4eSeschrock pool_list_free(list); 1820fa9e4066Sahrens return (1); 182199653d4eSeschrock } 1822fa9e4066Sahrens 1823fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 182499653d4eSeschrock pool_list_free(list); 1825fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 1826fa9e4066Sahrens return (1); 1827fa9e4066Sahrens } 1828fa9e4066Sahrens 1829fa9e4066Sahrens /* 1830fa9e4066Sahrens * Enter the main iostat loop. 1831fa9e4066Sahrens */ 1832fa9e4066Sahrens cb.cb_list = list; 1833fa9e4066Sahrens cb.cb_verbose = verbose; 1834fa9e4066Sahrens cb.cb_iteration = 0; 1835fa9e4066Sahrens cb.cb_namewidth = 0; 1836fa9e4066Sahrens 1837fa9e4066Sahrens for (;;) { 1838fa9e4066Sahrens pool_list_update(list); 1839fa9e4066Sahrens 1840fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 1841fa9e4066Sahrens break; 1842fa9e4066Sahrens 1843088e9d47Seschrock /* 1844088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 1845088e9d47Seschrock * before calculating the maximum name width, so that any 1846088e9d47Seschrock * configuration changes are properly accounted for. 1847088e9d47Seschrock */ 184899653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 1849088e9d47Seschrock 1850fa9e4066Sahrens /* 1851fa9e4066Sahrens * Iterate over all pools to determine the maximum width 1852fa9e4066Sahrens * for the pool / device name column across all pools. 1853fa9e4066Sahrens */ 1854fa9e4066Sahrens cb.cb_namewidth = 0; 185599653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 1856fa9e4066Sahrens 1857fa9e4066Sahrens /* 1858fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 1859fa9e4066Sahrens */ 1860fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 1861fa9e4066Sahrens print_iostat_header(&cb); 1862fa9e4066Sahrens 186399653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 1864fa9e4066Sahrens 1865fa9e4066Sahrens /* 1866fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 1867fa9e4066Sahrens * (which prints a separator for us), then print a separator. 1868fa9e4066Sahrens */ 1869fa9e4066Sahrens if (npools > 1 && !verbose) 1870fa9e4066Sahrens print_iostat_separator(&cb); 1871fa9e4066Sahrens 1872fa9e4066Sahrens if (verbose) 1873fa9e4066Sahrens (void) printf("\n"); 1874fa9e4066Sahrens 187539c23413Seschrock /* 187639c23413Seschrock * Flush the output so that redirection to a file isn't buffered 187739c23413Seschrock * indefinitely. 187839c23413Seschrock */ 187939c23413Seschrock (void) fflush(stdout); 188039c23413Seschrock 1881fa9e4066Sahrens if (interval == 0) 1882fa9e4066Sahrens break; 1883fa9e4066Sahrens 1884fa9e4066Sahrens if (count != 0 && --count == 0) 1885fa9e4066Sahrens break; 1886fa9e4066Sahrens 1887fa9e4066Sahrens (void) sleep(interval); 1888fa9e4066Sahrens } 1889fa9e4066Sahrens 1890fa9e4066Sahrens pool_list_free(list); 1891fa9e4066Sahrens 1892fa9e4066Sahrens return (ret); 1893fa9e4066Sahrens } 1894fa9e4066Sahrens 1895fa9e4066Sahrens typedef struct list_cbdata { 189699653d4eSeschrock boolean_t cb_scripted; 189799653d4eSeschrock boolean_t cb_first; 1898*990b4856Slling zprop_list_t *cb_proplist; 1899fa9e4066Sahrens } list_cbdata_t; 1900fa9e4066Sahrens 1901fa9e4066Sahrens /* 1902fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 1903fa9e4066Sahrens */ 1904*990b4856Slling static void 1905*990b4856Slling print_header(zprop_list_t *pl) 1906fa9e4066Sahrens { 1907*990b4856Slling const char *header; 1908*990b4856Slling boolean_t first = B_TRUE; 1909*990b4856Slling boolean_t right_justify; 1910*990b4856Slling 1911*990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 1912*990b4856Slling if (pl->pl_prop == ZPROP_INVAL) 1913*990b4856Slling continue; 1914fa9e4066Sahrens 1915*990b4856Slling if (!first) 1916fa9e4066Sahrens (void) printf(" "); 1917fa9e4066Sahrens else 1918*990b4856Slling first = B_FALSE; 1919*990b4856Slling 1920*990b4856Slling header = zpool_prop_column_name(pl->pl_prop); 1921*990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 1922fa9e4066Sahrens 1923*990b4856Slling if (pl->pl_next == NULL && !right_justify) 1924*990b4856Slling (void) printf("%s", header); 1925*990b4856Slling else if (right_justify) 1926*990b4856Slling (void) printf("%*s", pl->pl_width, header); 1927*990b4856Slling else 1928*990b4856Slling (void) printf("%-*s", pl->pl_width, header); 1929fa9e4066Sahrens } 1930fa9e4066Sahrens 1931fa9e4066Sahrens (void) printf("\n"); 1932fa9e4066Sahrens } 1933fa9e4066Sahrens 1934*990b4856Slling /* 1935*990b4856Slling * Given a pool and a list of properties, print out all the properties according 1936*990b4856Slling * to the described layout. 1937*990b4856Slling */ 1938*990b4856Slling static void 1939*990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 1940fa9e4066Sahrens { 1941*990b4856Slling boolean_t first = B_TRUE; 1942*990b4856Slling char property[ZPOOL_MAXPROPLEN]; 1943*990b4856Slling char *propstr; 1944*990b4856Slling boolean_t right_justify; 1945*990b4856Slling int width; 1946*990b4856Slling 1947*990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 1948*990b4856Slling if (!first) { 1949*990b4856Slling if (scripted) 1950fa9e4066Sahrens (void) printf("\t"); 1951fa9e4066Sahrens else 1952fa9e4066Sahrens (void) printf(" "); 1953*990b4856Slling } else { 1954*990b4856Slling first = B_FALSE; 1955fa9e4066Sahrens } 1956fa9e4066Sahrens 1957*990b4856Slling right_justify = B_FALSE; 1958*990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 1959*990b4856Slling if (zpool_get_prop(zhp, pl->pl_prop, property, 1960*990b4856Slling sizeof (property), NULL) != 0) 1961*990b4856Slling propstr = "-"; 1962fa9e4066Sahrens else 1963*990b4856Slling propstr = property; 1964fa9e4066Sahrens 1965*990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 1966*990b4856Slling } else { 1967*990b4856Slling propstr = "-"; 1968*990b4856Slling } 1969fa9e4066Sahrens 1970*990b4856Slling width = pl->pl_width; 1971fa9e4066Sahrens 1972*990b4856Slling /* 1973*990b4856Slling * If this is being called in scripted mode, or if this is the 1974*990b4856Slling * last column and it is left-justified, don't include a width 1975*990b4856Slling * format specifier. 1976*990b4856Slling */ 1977*990b4856Slling if (scripted || (pl->pl_next == NULL && !right_justify)) 1978*990b4856Slling (void) printf("%s", propstr); 1979*990b4856Slling else if (right_justify) 1980*990b4856Slling (void) printf("%*s", width, propstr); 1981*990b4856Slling else 1982*990b4856Slling (void) printf("%-*s", width, propstr); 1983*990b4856Slling } 1984fa9e4066Sahrens 1985*990b4856Slling (void) printf("\n"); 1986*990b4856Slling } 1987fa9e4066Sahrens 1988*990b4856Slling /* 1989*990b4856Slling * Generic callback function to list a pool. 1990*990b4856Slling */ 1991*990b4856Slling int 1992*990b4856Slling list_callback(zpool_handle_t *zhp, void *data) 1993*990b4856Slling { 1994*990b4856Slling list_cbdata_t *cbp = data; 1995fa9e4066Sahrens 1996*990b4856Slling if (cbp->cb_first) { 1997*990b4856Slling if (!cbp->cb_scripted) 1998*990b4856Slling print_header(cbp->cb_proplist); 1999*990b4856Slling cbp->cb_first = B_FALSE; 2000fa9e4066Sahrens } 2001fa9e4066Sahrens 2002*990b4856Slling print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2003fa9e4066Sahrens 2004fa9e4066Sahrens return (0); 2005fa9e4066Sahrens } 2006fa9e4066Sahrens 2007fa9e4066Sahrens /* 2008*990b4856Slling * zpool list [-H] [-o prop[,prop]*] [pool] ... 2009fa9e4066Sahrens * 2010*990b4856Slling * -H Scripted mode. Don't display headers, and separate properties 2011*990b4856Slling * by a single tab. 2012*990b4856Slling * -o List of properties to display. Defaults to 2013*990b4856Slling * "name,size,used,available,capacity,health,altroot" 2014fa9e4066Sahrens * 2015fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 2016fa9e4066Sahrens * statistics for each one, as well as health status summary. 2017fa9e4066Sahrens */ 2018fa9e4066Sahrens int 2019fa9e4066Sahrens zpool_do_list(int argc, char **argv) 2020fa9e4066Sahrens { 2021fa9e4066Sahrens int c; 2022fa9e4066Sahrens int ret; 2023fa9e4066Sahrens list_cbdata_t cb = { 0 }; 2024*990b4856Slling static char default_props[] = 2025*990b4856Slling "name,size,used,available,capacity,health,altroot"; 2026*990b4856Slling char *props = default_props; 2027fa9e4066Sahrens 2028fa9e4066Sahrens /* check options */ 2029fa9e4066Sahrens while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2030fa9e4066Sahrens switch (c) { 2031fa9e4066Sahrens case 'H': 203299653d4eSeschrock cb.cb_scripted = B_TRUE; 2033fa9e4066Sahrens break; 2034fa9e4066Sahrens case 'o': 2035*990b4856Slling props = optarg; 2036fa9e4066Sahrens break; 2037fa9e4066Sahrens case ':': 2038fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2039fa9e4066Sahrens "'%c' option\n"), optopt); 204099653d4eSeschrock usage(B_FALSE); 2041fa9e4066Sahrens break; 2042fa9e4066Sahrens case '?': 2043fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2044fa9e4066Sahrens optopt); 204599653d4eSeschrock usage(B_FALSE); 2046fa9e4066Sahrens } 2047fa9e4066Sahrens } 2048fa9e4066Sahrens 2049fa9e4066Sahrens argc -= optind; 2050fa9e4066Sahrens argv += optind; 2051fa9e4066Sahrens 2052*990b4856Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 2053*990b4856Slling usage(B_FALSE); 2054fa9e4066Sahrens 205599653d4eSeschrock cb.cb_first = B_TRUE; 2056fa9e4066Sahrens 2057*990b4856Slling ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2058*990b4856Slling list_callback, &cb); 2059*990b4856Slling 2060*990b4856Slling zprop_free_list(cb.cb_proplist); 2061fa9e4066Sahrens 2062fce7d82bSmmusante if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2063fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 2064fa9e4066Sahrens return (0); 2065fa9e4066Sahrens } 2066fa9e4066Sahrens 2067fa9e4066Sahrens return (ret); 2068fa9e4066Sahrens } 2069fa9e4066Sahrens 2070fa9e4066Sahrens static nvlist_t * 2071fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name) 2072fa9e4066Sahrens { 2073fa9e4066Sahrens nvlist_t **child; 2074fa9e4066Sahrens uint_t c, children; 2075fa9e4066Sahrens nvlist_t *match; 2076fa9e4066Sahrens char *path; 2077fa9e4066Sahrens 2078fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2079fa9e4066Sahrens &child, &children) != 0) { 2080fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2081fa9e4066Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0) 2082fa9e4066Sahrens name += 9; 2083fa9e4066Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0) 2084fa9e4066Sahrens path += 9; 2085fa9e4066Sahrens if (strcmp(name, path) == 0) 2086fa9e4066Sahrens return (nv); 2087fa9e4066Sahrens return (NULL); 2088fa9e4066Sahrens } 2089fa9e4066Sahrens 2090fa9e4066Sahrens for (c = 0; c < children; c++) 2091fa9e4066Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2092fa9e4066Sahrens return (match); 2093fa9e4066Sahrens 2094fa9e4066Sahrens return (NULL); 2095fa9e4066Sahrens } 2096fa9e4066Sahrens 2097fa9e4066Sahrens static int 2098fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 2099fa9e4066Sahrens { 210099653d4eSeschrock boolean_t force = B_FALSE; 2101fa9e4066Sahrens int c; 2102fa9e4066Sahrens nvlist_t *nvroot; 2103fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 2104fa9e4066Sahrens zpool_handle_t *zhp; 210599653d4eSeschrock int ret; 2106fa9e4066Sahrens 2107fa9e4066Sahrens /* check options */ 2108fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2109fa9e4066Sahrens switch (c) { 2110fa9e4066Sahrens case 'f': 211199653d4eSeschrock force = B_TRUE; 2112fa9e4066Sahrens break; 2113fa9e4066Sahrens case '?': 2114fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2115fa9e4066Sahrens optopt); 211699653d4eSeschrock usage(B_FALSE); 2117fa9e4066Sahrens } 2118fa9e4066Sahrens } 2119fa9e4066Sahrens 2120fa9e4066Sahrens argc -= optind; 2121fa9e4066Sahrens argv += optind; 2122fa9e4066Sahrens 2123fa9e4066Sahrens /* get pool name and check number of arguments */ 2124fa9e4066Sahrens if (argc < 1) { 2125fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 212699653d4eSeschrock usage(B_FALSE); 2127fa9e4066Sahrens } 2128fa9e4066Sahrens 2129fa9e4066Sahrens poolname = argv[0]; 2130fa9e4066Sahrens 2131fa9e4066Sahrens if (argc < 2) { 2132fa9e4066Sahrens (void) fprintf(stderr, 2133fa9e4066Sahrens gettext("missing <device> specification\n")); 213499653d4eSeschrock usage(B_FALSE); 2135fa9e4066Sahrens } 2136fa9e4066Sahrens 2137fa9e4066Sahrens old_disk = argv[1]; 2138fa9e4066Sahrens 2139fa9e4066Sahrens if (argc < 3) { 2140fa9e4066Sahrens if (!replacing) { 2141fa9e4066Sahrens (void) fprintf(stderr, 2142fa9e4066Sahrens gettext("missing <new_device> specification\n")); 214399653d4eSeschrock usage(B_FALSE); 2144fa9e4066Sahrens } 2145fa9e4066Sahrens new_disk = old_disk; 2146fa9e4066Sahrens argc -= 1; 2147fa9e4066Sahrens argv += 1; 2148fa9e4066Sahrens } else { 2149fa9e4066Sahrens new_disk = argv[2]; 2150fa9e4066Sahrens argc -= 2; 2151fa9e4066Sahrens argv += 2; 2152fa9e4066Sahrens } 2153fa9e4066Sahrens 2154fa9e4066Sahrens if (argc > 1) { 2155fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 215699653d4eSeschrock usage(B_FALSE); 2157fa9e4066Sahrens } 2158fa9e4066Sahrens 215999653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2160fa9e4066Sahrens return (1); 2161fa9e4066Sahrens 21628488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 2163fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2164fa9e4066Sahrens poolname); 2165fa9e4066Sahrens zpool_close(zhp); 2166fa9e4066Sahrens return (1); 2167fa9e4066Sahrens } 2168fa9e4066Sahrens 21698488aeb5Staylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv); 2170fa9e4066Sahrens if (nvroot == NULL) { 2171fa9e4066Sahrens zpool_close(zhp); 2172fa9e4066Sahrens return (1); 2173fa9e4066Sahrens } 2174fa9e4066Sahrens 217599653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 217699653d4eSeschrock 217799653d4eSeschrock nvlist_free(nvroot); 217899653d4eSeschrock zpool_close(zhp); 217999653d4eSeschrock 218099653d4eSeschrock return (ret); 2181fa9e4066Sahrens } 2182fa9e4066Sahrens 2183fa9e4066Sahrens /* 2184fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 2185fa9e4066Sahrens * 2186fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2187fa9e4066Sahrens * 2188fa9e4066Sahrens * Replace <device> with <new_device>. 2189fa9e4066Sahrens */ 2190fa9e4066Sahrens /* ARGSUSED */ 2191fa9e4066Sahrens int 2192fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 2193fa9e4066Sahrens { 2194fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2195fa9e4066Sahrens } 2196fa9e4066Sahrens 2197fa9e4066Sahrens /* 2198fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 2199fa9e4066Sahrens * 2200fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2201fa9e4066Sahrens * 2202fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 2203fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 2204fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 2205fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 2206fa9e4066Sahrens */ 2207fa9e4066Sahrens int 2208fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 2209fa9e4066Sahrens { 2210fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2211fa9e4066Sahrens } 2212fa9e4066Sahrens 2213fa9e4066Sahrens /* 2214fa9e4066Sahrens * zpool detach [-f] <pool> <device> 2215fa9e4066Sahrens * 2216fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 2217fa9e4066Sahrens * (not supported yet) 2218fa9e4066Sahrens * 2219fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 2220fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 2221fa9e4066Sahrens * has the only valid copy of some data. 2222fa9e4066Sahrens */ 2223fa9e4066Sahrens /* ARGSUSED */ 2224fa9e4066Sahrens int 2225fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 2226fa9e4066Sahrens { 2227fa9e4066Sahrens int c; 2228fa9e4066Sahrens char *poolname, *path; 2229fa9e4066Sahrens zpool_handle_t *zhp; 223099653d4eSeschrock int ret; 2231fa9e4066Sahrens 2232fa9e4066Sahrens /* check options */ 2233fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2234fa9e4066Sahrens switch (c) { 2235fa9e4066Sahrens case 'f': 2236fa9e4066Sahrens case '?': 2237fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2238fa9e4066Sahrens optopt); 223999653d4eSeschrock usage(B_FALSE); 2240fa9e4066Sahrens } 2241fa9e4066Sahrens } 2242fa9e4066Sahrens 2243fa9e4066Sahrens argc -= optind; 2244fa9e4066Sahrens argv += optind; 2245fa9e4066Sahrens 2246fa9e4066Sahrens /* get pool name and check number of arguments */ 2247fa9e4066Sahrens if (argc < 1) { 2248fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 224999653d4eSeschrock usage(B_FALSE); 2250fa9e4066Sahrens } 2251fa9e4066Sahrens 2252fa9e4066Sahrens if (argc < 2) { 2253fa9e4066Sahrens (void) fprintf(stderr, 2254fa9e4066Sahrens gettext("missing <device> specification\n")); 225599653d4eSeschrock usage(B_FALSE); 2256fa9e4066Sahrens } 2257fa9e4066Sahrens 2258fa9e4066Sahrens poolname = argv[0]; 2259fa9e4066Sahrens path = argv[1]; 2260fa9e4066Sahrens 226199653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2262fa9e4066Sahrens return (1); 2263fa9e4066Sahrens 226499653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 226599653d4eSeschrock 226699653d4eSeschrock zpool_close(zhp); 226799653d4eSeschrock 226899653d4eSeschrock return (ret); 2269fa9e4066Sahrens } 2270fa9e4066Sahrens 2271fa9e4066Sahrens /* 2272441d80aaSlling * zpool online <pool> <device> ... 2273fa9e4066Sahrens */ 2274fa9e4066Sahrens int 2275fa9e4066Sahrens zpool_do_online(int argc, char **argv) 2276fa9e4066Sahrens { 2277fa9e4066Sahrens int c, i; 2278fa9e4066Sahrens char *poolname; 2279fa9e4066Sahrens zpool_handle_t *zhp; 2280fa9e4066Sahrens int ret = 0; 22813d7072f8Seschrock vdev_state_t newstate; 2282fa9e4066Sahrens 2283fa9e4066Sahrens /* check options */ 2284fa9e4066Sahrens while ((c = getopt(argc, argv, "t")) != -1) { 2285fa9e4066Sahrens switch (c) { 2286fa9e4066Sahrens case 't': 2287fa9e4066Sahrens case '?': 2288fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2289fa9e4066Sahrens optopt); 229099653d4eSeschrock usage(B_FALSE); 2291fa9e4066Sahrens } 2292fa9e4066Sahrens } 2293fa9e4066Sahrens 2294fa9e4066Sahrens argc -= optind; 2295fa9e4066Sahrens argv += optind; 2296fa9e4066Sahrens 2297fa9e4066Sahrens /* get pool name and check number of arguments */ 2298fa9e4066Sahrens if (argc < 1) { 2299fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 230099653d4eSeschrock usage(B_FALSE); 2301fa9e4066Sahrens } 2302fa9e4066Sahrens if (argc < 2) { 2303fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 230499653d4eSeschrock usage(B_FALSE); 2305fa9e4066Sahrens } 2306fa9e4066Sahrens 2307fa9e4066Sahrens poolname = argv[0]; 2308fa9e4066Sahrens 230999653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2310fa9e4066Sahrens return (1); 2311fa9e4066Sahrens 23123d7072f8Seschrock for (i = 1; i < argc; i++) { 23133d7072f8Seschrock if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) { 23143d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 23153d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 23163d7072f8Seschrock "onlined, but remains in faulted state\n"), 23173d7072f8Seschrock argv[i]); 23183d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 23193d7072f8Seschrock (void) printf(gettext("use 'zpool " 23203d7072f8Seschrock "clear' to restore a faulted " 23213d7072f8Seschrock "device\n")); 23223d7072f8Seschrock else 23233d7072f8Seschrock (void) printf(gettext("use 'zpool " 23243d7072f8Seschrock "replace' to replace devices " 23253d7072f8Seschrock "that are no longer present\n")); 23263d7072f8Seschrock } 23273d7072f8Seschrock } else { 2328fa9e4066Sahrens ret = 1; 23293d7072f8Seschrock } 23303d7072f8Seschrock } 2331fa9e4066Sahrens 233299653d4eSeschrock zpool_close(zhp); 233399653d4eSeschrock 2334fa9e4066Sahrens return (ret); 2335fa9e4066Sahrens } 2336fa9e4066Sahrens 2337fa9e4066Sahrens /* 2338441d80aaSlling * zpool offline [-ft] <pool> <device> ... 2339fa9e4066Sahrens * 2340fa9e4066Sahrens * -f Force the device into the offline state, even if doing 2341fa9e4066Sahrens * so would appear to compromise pool availability. 2342fa9e4066Sahrens * (not supported yet) 2343fa9e4066Sahrens * 2344fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 2345fa9e4066Sahrens * state will not be persistent across reboots. 2346fa9e4066Sahrens */ 2347fa9e4066Sahrens /* ARGSUSED */ 2348fa9e4066Sahrens int 2349fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 2350fa9e4066Sahrens { 2351fa9e4066Sahrens int c, i; 2352fa9e4066Sahrens char *poolname; 2353fa9e4066Sahrens zpool_handle_t *zhp; 235499653d4eSeschrock int ret = 0; 235599653d4eSeschrock boolean_t istmp = B_FALSE; 2356fa9e4066Sahrens 2357fa9e4066Sahrens /* check options */ 2358fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 2359fa9e4066Sahrens switch (c) { 2360fa9e4066Sahrens case 't': 236199653d4eSeschrock istmp = B_TRUE; 2362441d80aaSlling break; 2363441d80aaSlling case 'f': 2364fa9e4066Sahrens case '?': 2365fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2366fa9e4066Sahrens optopt); 236799653d4eSeschrock usage(B_FALSE); 2368fa9e4066Sahrens } 2369fa9e4066Sahrens } 2370fa9e4066Sahrens 2371fa9e4066Sahrens argc -= optind; 2372fa9e4066Sahrens argv += optind; 2373fa9e4066Sahrens 2374fa9e4066Sahrens /* get pool name and check number of arguments */ 2375fa9e4066Sahrens if (argc < 1) { 2376fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 237799653d4eSeschrock usage(B_FALSE); 2378fa9e4066Sahrens } 2379fa9e4066Sahrens if (argc < 2) { 2380fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 238199653d4eSeschrock usage(B_FALSE); 2382fa9e4066Sahrens } 2383fa9e4066Sahrens 2384fa9e4066Sahrens poolname = argv[0]; 2385fa9e4066Sahrens 238699653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2387fa9e4066Sahrens return (1); 2388fa9e4066Sahrens 23893d7072f8Seschrock for (i = 1; i < argc; i++) { 23903d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2391fa9e4066Sahrens ret = 1; 23923d7072f8Seschrock } 2393fa9e4066Sahrens 239499653d4eSeschrock zpool_close(zhp); 239599653d4eSeschrock 2396fa9e4066Sahrens return (ret); 2397fa9e4066Sahrens } 2398fa9e4066Sahrens 2399ea8dc4b6Seschrock /* 2400ea8dc4b6Seschrock * zpool clear <pool> [device] 2401ea8dc4b6Seschrock * 2402ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 2403ea8dc4b6Seschrock */ 2404ea8dc4b6Seschrock int 2405ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 2406ea8dc4b6Seschrock { 2407ea8dc4b6Seschrock int ret = 0; 2408ea8dc4b6Seschrock zpool_handle_t *zhp; 2409ea8dc4b6Seschrock char *pool, *device; 2410ea8dc4b6Seschrock 2411ea8dc4b6Seschrock if (argc < 2) { 2412ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 241399653d4eSeschrock usage(B_FALSE); 2414ea8dc4b6Seschrock } 2415ea8dc4b6Seschrock 2416ea8dc4b6Seschrock if (argc > 3) { 2417ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 241899653d4eSeschrock usage(B_FALSE); 2419ea8dc4b6Seschrock } 2420ea8dc4b6Seschrock 2421ea8dc4b6Seschrock pool = argv[1]; 2422ea8dc4b6Seschrock device = argc == 3 ? argv[2] : NULL; 2423ea8dc4b6Seschrock 242499653d4eSeschrock if ((zhp = zpool_open(g_zfs, pool)) == NULL) 2425ea8dc4b6Seschrock return (1); 2426ea8dc4b6Seschrock 2427ea8dc4b6Seschrock if (zpool_clear(zhp, device) != 0) 2428ea8dc4b6Seschrock ret = 1; 2429ea8dc4b6Seschrock 2430ea8dc4b6Seschrock zpool_close(zhp); 2431ea8dc4b6Seschrock 2432ea8dc4b6Seschrock return (ret); 2433ea8dc4b6Seschrock } 2434ea8dc4b6Seschrock 2435fa9e4066Sahrens typedef struct scrub_cbdata { 2436fa9e4066Sahrens int cb_type; 243706eeb2adSek int cb_argc; 243806eeb2adSek char **cb_argv; 2439fa9e4066Sahrens } scrub_cbdata_t; 2440fa9e4066Sahrens 2441fa9e4066Sahrens int 2442fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 2443fa9e4066Sahrens { 2444fa9e4066Sahrens scrub_cbdata_t *cb = data; 244506eeb2adSek int err; 2446fa9e4066Sahrens 2447ea8dc4b6Seschrock /* 2448ea8dc4b6Seschrock * Ignore faulted pools. 2449ea8dc4b6Seschrock */ 2450ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2451ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2452ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 2453ea8dc4b6Seschrock return (1); 2454ea8dc4b6Seschrock } 2455ea8dc4b6Seschrock 245606eeb2adSek err = zpool_scrub(zhp, cb->cb_type); 245706eeb2adSek 245806eeb2adSek return (err != 0); 2459fa9e4066Sahrens } 2460fa9e4066Sahrens 2461fa9e4066Sahrens /* 2462fa9e4066Sahrens * zpool scrub [-s] <pool> ... 2463fa9e4066Sahrens * 2464fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 2465fa9e4066Sahrens */ 2466fa9e4066Sahrens int 2467fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 2468fa9e4066Sahrens { 2469fa9e4066Sahrens int c; 2470fa9e4066Sahrens scrub_cbdata_t cb; 2471fa9e4066Sahrens 2472fa9e4066Sahrens cb.cb_type = POOL_SCRUB_EVERYTHING; 2473fa9e4066Sahrens 2474fa9e4066Sahrens /* check options */ 2475fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 2476fa9e4066Sahrens switch (c) { 2477fa9e4066Sahrens case 's': 2478fa9e4066Sahrens cb.cb_type = POOL_SCRUB_NONE; 2479fa9e4066Sahrens break; 2480fa9e4066Sahrens case '?': 2481fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2482fa9e4066Sahrens optopt); 248399653d4eSeschrock usage(B_FALSE); 2484fa9e4066Sahrens } 2485fa9e4066Sahrens } 2486fa9e4066Sahrens 248706eeb2adSek cb.cb_argc = argc; 248806eeb2adSek cb.cb_argv = argv; 2489fa9e4066Sahrens argc -= optind; 2490fa9e4066Sahrens argv += optind; 2491fa9e4066Sahrens 2492fa9e4066Sahrens if (argc < 1) { 2493fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 249499653d4eSeschrock usage(B_FALSE); 2495fa9e4066Sahrens } 2496fa9e4066Sahrens 2497b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2498fa9e4066Sahrens } 2499fa9e4066Sahrens 2500fa9e4066Sahrens typedef struct status_cbdata { 250199653d4eSeschrock int cb_count; 2502e9dbad6fSeschrock boolean_t cb_allpools; 250399653d4eSeschrock boolean_t cb_verbose; 250499653d4eSeschrock boolean_t cb_explain; 250599653d4eSeschrock boolean_t cb_first; 2506fa9e4066Sahrens } status_cbdata_t; 2507fa9e4066Sahrens 2508fa9e4066Sahrens /* 2509fa9e4066Sahrens * Print out detailed scrub status. 2510fa9e4066Sahrens */ 2511fa9e4066Sahrens void 2512fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot) 2513fa9e4066Sahrens { 2514fa9e4066Sahrens vdev_stat_t *vs; 2515fa9e4066Sahrens uint_t vsc; 2516fa9e4066Sahrens time_t start, end, now; 2517fa9e4066Sahrens double fraction_done; 2518fa9e4066Sahrens uint64_t examined, total, minutes_left; 2519fa9e4066Sahrens char *scrub_type; 2520fa9e4066Sahrens 2521fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2522fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 2523fa9e4066Sahrens 2524fa9e4066Sahrens /* 2525fa9e4066Sahrens * If there's never been a scrub, there's not much to say. 2526fa9e4066Sahrens */ 2527fa9e4066Sahrens if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2528fa9e4066Sahrens (void) printf(gettext("none requested\n")); 2529fa9e4066Sahrens return; 2530fa9e4066Sahrens } 2531fa9e4066Sahrens 2532fa9e4066Sahrens scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2533fa9e4066Sahrens "resilver" : "scrub"; 2534fa9e4066Sahrens 2535fa9e4066Sahrens start = vs->vs_scrub_start; 2536fa9e4066Sahrens end = vs->vs_scrub_end; 2537fa9e4066Sahrens now = time(NULL); 2538fa9e4066Sahrens examined = vs->vs_scrub_examined; 2539fa9e4066Sahrens total = vs->vs_alloc; 2540fa9e4066Sahrens 2541fa9e4066Sahrens if (end != 0) { 2542fa9e4066Sahrens (void) printf(gettext("%s %s with %llu errors on %s"), 2543fa9e4066Sahrens scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 2544fa9e4066Sahrens (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2545fa9e4066Sahrens return; 2546fa9e4066Sahrens } 2547fa9e4066Sahrens 2548fa9e4066Sahrens if (examined == 0) 2549fa9e4066Sahrens examined = 1; 2550fa9e4066Sahrens if (examined > total) 2551fa9e4066Sahrens total = examined; 2552fa9e4066Sahrens 2553fa9e4066Sahrens fraction_done = (double)examined / total; 2554fa9e4066Sahrens minutes_left = (uint64_t)((now - start) * 2555fa9e4066Sahrens (1 - fraction_done) / fraction_done / 60); 2556fa9e4066Sahrens 2557fa9e4066Sahrens (void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"), 2558fa9e4066Sahrens scrub_type, 100 * fraction_done, 2559fa9e4066Sahrens (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2560fa9e4066Sahrens } 2561fa9e4066Sahrens 256299653d4eSeschrock typedef struct spare_cbdata { 256399653d4eSeschrock uint64_t cb_guid; 256499653d4eSeschrock zpool_handle_t *cb_zhp; 256599653d4eSeschrock } spare_cbdata_t; 256699653d4eSeschrock 256799653d4eSeschrock static boolean_t 256899653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search) 256999653d4eSeschrock { 257099653d4eSeschrock uint64_t guid; 257199653d4eSeschrock nvlist_t **child; 257299653d4eSeschrock uint_t c, children; 257399653d4eSeschrock 257499653d4eSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 257599653d4eSeschrock search == guid) 257699653d4eSeschrock return (B_TRUE); 257799653d4eSeschrock 257899653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 257999653d4eSeschrock &child, &children) == 0) { 258099653d4eSeschrock for (c = 0; c < children; c++) 258199653d4eSeschrock if (find_vdev(child[c], search)) 258299653d4eSeschrock return (B_TRUE); 258399653d4eSeschrock } 258499653d4eSeschrock 258599653d4eSeschrock return (B_FALSE); 258699653d4eSeschrock } 258799653d4eSeschrock 258899653d4eSeschrock static int 258999653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data) 259099653d4eSeschrock { 259199653d4eSeschrock spare_cbdata_t *cbp = data; 259299653d4eSeschrock nvlist_t *config, *nvroot; 259399653d4eSeschrock 259499653d4eSeschrock config = zpool_get_config(zhp, NULL); 259599653d4eSeschrock verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 259699653d4eSeschrock &nvroot) == 0); 259799653d4eSeschrock 259899653d4eSeschrock if (find_vdev(nvroot, cbp->cb_guid)) { 259999653d4eSeschrock cbp->cb_zhp = zhp; 260099653d4eSeschrock return (1); 260199653d4eSeschrock } 260299653d4eSeschrock 260399653d4eSeschrock zpool_close(zhp); 260499653d4eSeschrock return (0); 260599653d4eSeschrock } 260699653d4eSeschrock 2607fa9e4066Sahrens /* 2608fa9e4066Sahrens * Print out configuration state as requested by status_callback. 2609fa9e4066Sahrens */ 2610fa9e4066Sahrens void 2611c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 26128654d025Sperrin int namewidth, int depth, boolean_t isspare, boolean_t print_logs) 2613fa9e4066Sahrens { 2614fa9e4066Sahrens nvlist_t **child; 2615fa9e4066Sahrens uint_t c, children; 2616fa9e4066Sahrens vdev_stat_t *vs; 2617ea8dc4b6Seschrock char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 2618afefbcddSeschrock char *vname; 2619ea8dc4b6Seschrock uint64_t notpresent; 262099653d4eSeschrock spare_cbdata_t cb; 2621*990b4856Slling char *state; 2622fa9e4066Sahrens 2623fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2624fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 2625fa9e4066Sahrens 2626fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2627fa9e4066Sahrens &child, &children) != 0) 2628fa9e4066Sahrens children = 0; 2629fa9e4066Sahrens 2630*990b4856Slling state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 263199653d4eSeschrock if (isspare) { 263299653d4eSeschrock /* 263399653d4eSeschrock * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 263499653d4eSeschrock * online drives. 263599653d4eSeschrock */ 263699653d4eSeschrock if (vs->vs_aux == VDEV_AUX_SPARED) 263799653d4eSeschrock state = "INUSE"; 263899653d4eSeschrock else if (vs->vs_state == VDEV_STATE_HEALTHY) 263999653d4eSeschrock state = "AVAIL"; 264099653d4eSeschrock } 264199653d4eSeschrock 2642fa9e4066Sahrens (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 264399653d4eSeschrock name, state); 2644fa9e4066Sahrens 264599653d4eSeschrock if (!isspare) { 264699653d4eSeschrock zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 264799653d4eSeschrock zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 264899653d4eSeschrock zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 264999653d4eSeschrock (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 265099653d4eSeschrock } 2651fa9e4066Sahrens 2652ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2653ea8dc4b6Seschrock ¬present) == 0) { 2654ea8dc4b6Seschrock char *path; 2655ea8dc4b6Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 26560917b783Seschrock (void) printf(" was %s", path); 2657ea8dc4b6Seschrock } else if (vs->vs_aux != 0) { 2658fa9e4066Sahrens (void) printf(" "); 2659fa9e4066Sahrens 2660fa9e4066Sahrens switch (vs->vs_aux) { 2661fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 2662fa9e4066Sahrens (void) printf(gettext("cannot open")); 2663fa9e4066Sahrens break; 2664fa9e4066Sahrens 2665fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 2666fa9e4066Sahrens (void) printf(gettext("missing device")); 2667fa9e4066Sahrens break; 2668fa9e4066Sahrens 2669fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 2670fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 2671fa9e4066Sahrens break; 2672fa9e4066Sahrens 2673eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 2674eaca9bbdSeschrock (void) printf(gettext("newer version")); 2675eaca9bbdSeschrock break; 2676eaca9bbdSeschrock 267799653d4eSeschrock case VDEV_AUX_SPARED: 267899653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 267999653d4eSeschrock &cb.cb_guid) == 0); 268099653d4eSeschrock if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 268199653d4eSeschrock if (strcmp(zpool_get_name(cb.cb_zhp), 268299653d4eSeschrock zpool_get_name(zhp)) == 0) 268399653d4eSeschrock (void) printf(gettext("currently in " 268499653d4eSeschrock "use")); 268599653d4eSeschrock else 268699653d4eSeschrock (void) printf(gettext("in use by " 268799653d4eSeschrock "pool '%s'"), 268899653d4eSeschrock zpool_get_name(cb.cb_zhp)); 268999653d4eSeschrock zpool_close(cb.cb_zhp); 269099653d4eSeschrock } else { 269199653d4eSeschrock (void) printf(gettext("currently in use")); 269299653d4eSeschrock } 269399653d4eSeschrock break; 269499653d4eSeschrock 26953d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 26963d7072f8Seschrock (void) printf(gettext("too many errors")); 26973d7072f8Seschrock break; 26983d7072f8Seschrock 2699fa9e4066Sahrens default: 2700fa9e4066Sahrens (void) printf(gettext("corrupted data")); 2701fa9e4066Sahrens break; 2702fa9e4066Sahrens } 2703fa9e4066Sahrens } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2704fa9e4066Sahrens /* 2705fa9e4066Sahrens * Report bytes resilvered/repaired on leaf devices. 2706fa9e4066Sahrens */ 2707fa9e4066Sahrens zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2708fa9e4066Sahrens (void) printf(gettext(" %s %s"), repaired, 2709fa9e4066Sahrens (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2710fa9e4066Sahrens "resilvered" : "repaired"); 2711fa9e4066Sahrens } 2712fa9e4066Sahrens 2713fa9e4066Sahrens (void) printf("\n"); 2714fa9e4066Sahrens 2715afefbcddSeschrock for (c = 0; c < children; c++) { 27168654d025Sperrin uint64_t is_log = B_FALSE; 27178654d025Sperrin 27188654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 27198654d025Sperrin &is_log); 27208654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 27218654d025Sperrin continue; 272299653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 2723c67d9675Seschrock print_status_config(zhp, vname, child[c], 27248654d025Sperrin namewidth, depth + 2, isspare, B_FALSE); 2725afefbcddSeschrock free(vname); 2726afefbcddSeschrock } 2727fa9e4066Sahrens } 2728fa9e4066Sahrens 2729ea8dc4b6Seschrock static void 2730ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 2731ea8dc4b6Seschrock { 273275519f38Sek nvlist_t *nverrlist = NULL; 273355434c77Sek nvpair_t *elem; 273455434c77Sek char *pathname; 273555434c77Sek size_t len = MAXPATHLEN * 2; 2736ea8dc4b6Seschrock 273755434c77Sek if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2738ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 2739ea8dc4b6Seschrock "(insufficient privileges)\n"); 2740ea8dc4b6Seschrock return; 2741ea8dc4b6Seschrock } 2742ea8dc4b6Seschrock 274355434c77Sek (void) printf("errors: Permanent errors have been " 274455434c77Sek "detected in the following files:\n\n"); 2745ea8dc4b6Seschrock 274655434c77Sek pathname = safe_malloc(len); 274755434c77Sek elem = NULL; 274855434c77Sek while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 274955434c77Sek nvlist_t *nv; 275055434c77Sek uint64_t dsobj, obj; 275155434c77Sek 275255434c77Sek verify(nvpair_value_nvlist(elem, &nv) == 0); 275355434c77Sek verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 275455434c77Sek &dsobj) == 0); 275555434c77Sek verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 275655434c77Sek &obj) == 0); 275755434c77Sek zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 275855434c77Sek (void) printf("%7s %s\n", "", pathname); 275955434c77Sek } 276055434c77Sek free(pathname); 276155434c77Sek nvlist_free(nverrlist); 2762ea8dc4b6Seschrock } 2763ea8dc4b6Seschrock 276499653d4eSeschrock static void 276599653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 276699653d4eSeschrock int namewidth) 276799653d4eSeschrock { 276899653d4eSeschrock uint_t i; 276999653d4eSeschrock char *name; 277099653d4eSeschrock 277199653d4eSeschrock if (nspares == 0) 277299653d4eSeschrock return; 277399653d4eSeschrock 277499653d4eSeschrock (void) printf(gettext("\tspares\n")); 277599653d4eSeschrock 277699653d4eSeschrock for (i = 0; i < nspares; i++) { 277799653d4eSeschrock name = zpool_vdev_name(g_zfs, zhp, spares[i]); 277899653d4eSeschrock print_status_config(zhp, name, spares[i], 27798654d025Sperrin namewidth, 2, B_TRUE, B_FALSE); 278099653d4eSeschrock free(name); 278199653d4eSeschrock } 278299653d4eSeschrock } 278399653d4eSeschrock 2784fa9e4066Sahrens /* 2785fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 2786fa9e4066Sahrens * 2787fa9e4066Sahrens * pool: tank 2788fa9e4066Sahrens * status: DEGRADED 2789fa9e4066Sahrens * reason: One or more devices ... 2790fa9e4066Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01 2791fa9e4066Sahrens * config: 2792fa9e4066Sahrens * mirror DEGRADED 2793fa9e4066Sahrens * c1t0d0 OK 2794ea8dc4b6Seschrock * c2t0d0 UNAVAIL 2795fa9e4066Sahrens * 2796fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 2797fa9e4066Sahrens * option is specified, then we print out error rate information as well. 2798fa9e4066Sahrens */ 2799fa9e4066Sahrens int 2800fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 2801fa9e4066Sahrens { 2802fa9e4066Sahrens status_cbdata_t *cbp = data; 2803fa9e4066Sahrens nvlist_t *config, *nvroot; 2804fa9e4066Sahrens char *msgid; 2805fa9e4066Sahrens int reason; 280646657f8dSmmusante const char *health; 280746657f8dSmmusante uint_t c; 280846657f8dSmmusante vdev_stat_t *vs; 2809fa9e4066Sahrens 2810088e9d47Seschrock config = zpool_get_config(zhp, NULL); 2811fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 2812fa9e4066Sahrens 2813fa9e4066Sahrens cbp->cb_count++; 2814fa9e4066Sahrens 2815fa9e4066Sahrens /* 2816fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 2817fa9e4066Sahrens * problems. 2818fa9e4066Sahrens */ 2819e9dbad6fSeschrock if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 2820e9dbad6fSeschrock if (!cbp->cb_allpools) { 2821e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 2822e9dbad6fSeschrock zpool_get_name(zhp)); 2823e9dbad6fSeschrock if (cbp->cb_first) 2824e9dbad6fSeschrock cbp->cb_first = B_FALSE; 2825e9dbad6fSeschrock } 2826fa9e4066Sahrens return (0); 2827e9dbad6fSeschrock } 2828fa9e4066Sahrens 2829fa9e4066Sahrens if (cbp->cb_first) 283099653d4eSeschrock cbp->cb_first = B_FALSE; 2831fa9e4066Sahrens else 2832fa9e4066Sahrens (void) printf("\n"); 2833fa9e4066Sahrens 283446657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 283546657f8dSmmusante &nvroot) == 0); 283646657f8dSmmusante verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 283746657f8dSmmusante (uint64_t **)&vs, &c) == 0); 2838*990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 2839fa9e4066Sahrens 2840fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 2841fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 2842fa9e4066Sahrens 2843fa9e4066Sahrens switch (reason) { 2844fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 2845fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2846fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 2847fa9e4066Sahrens "continue functioning in a degraded state.\n")); 2848fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2849fa9e4066Sahrens "online it using 'zpool online'.\n")); 2850fa9e4066Sahrens break; 2851fa9e4066Sahrens 2852fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 2853fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2854fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 2855fa9e4066Sahrens "pool to continue functioning.\n")); 2856fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2857fa9e4066Sahrens "online it using 'zpool online'.\n")); 2858fa9e4066Sahrens break; 2859fa9e4066Sahrens 2860fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 2861fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2862fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 2863fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 2864fa9e4066Sahrens "functioning in a degraded state.\n")); 2865fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 2866fa9e4066Sahrens "'zpool replace'.\n")); 2867fa9e4066Sahrens break; 2868fa9e4066Sahrens 2869fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 2870fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2871b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 2872fa9e4066Sahrens "There are insufficient replicas for the pool to " 2873fa9e4066Sahrens "continue\n\tfunctioning.\n")); 2874fa9e4066Sahrens (void) printf(gettext("action: Destroy and re-create the pool " 2875fa9e4066Sahrens "from a backup source.\n")); 2876fa9e4066Sahrens break; 2877fa9e4066Sahrens 2878fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 2879fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2880fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 2881fa9e4066Sahrens "made to correct the error. Applications are " 2882fa9e4066Sahrens "unaffected.\n")); 2883fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 2884fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 2885ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 2886fa9e4066Sahrens "replace'.\n")); 2887fa9e4066Sahrens break; 2888fa9e4066Sahrens 2889fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 2890fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2891d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 2892fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 2893fa9e4066Sahrens "a\n\tdegraded state.\n")); 2894fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 2895fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 2896fa9e4066Sahrens "replace'.\n")); 2897fa9e4066Sahrens break; 2898fa9e4066Sahrens 2899fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 2900fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 2901fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 2902fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 2903fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 2904fa9e4066Sahrens "complete.\n")); 2905fa9e4066Sahrens break; 2906fa9e4066Sahrens 2907ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 2908ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 2909ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 2910ea8dc4b6Seschrock "Applications may be affected.\n")); 2911ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 2912ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 2913ea8dc4b6Seschrock "backup.\n")); 2914ea8dc4b6Seschrock break; 2915ea8dc4b6Seschrock 2916ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 2917ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 2918ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 2919ea8dc4b6Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 2920ea8dc4b6Seschrock "from a backup source.\n")); 2921ea8dc4b6Seschrock break; 2922ea8dc4b6Seschrock 2923eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 2924eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 2925eaca9bbdSeschrock "older on-disk format. The pool can\n\tstill be used, but " 2926eaca9bbdSeschrock "some features are unavailable.\n")); 2927eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 2928eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 2929eaca9bbdSeschrock "be accessible on older software versions.\n")); 2930eaca9bbdSeschrock break; 2931eaca9bbdSeschrock 2932eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 2933eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 2934eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 2935eaca9bbdSeschrock "be accessed on this system.\n")); 2936eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 2937eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 2938eaca9bbdSeschrock "backup.\n")); 2939eaca9bbdSeschrock break; 2940eaca9bbdSeschrock 29413d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 29423d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 29433d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 29443d7072f8Seschrock "replicas exist for the pool to continue functioning " 29453d7072f8Seschrock "in a\n\tdegraded state.\n")); 29463d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 29473d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 29483d7072f8Seschrock break; 29493d7072f8Seschrock 29503d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 29513d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 29523d7072f8Seschrock "faulted in response to persistent errors. There are " 29533d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 29543d7072f8Seschrock "functioning.\n")); 29553d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 29563d7072f8Seschrock "from a backup source. Manually marking the device\n" 29573d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 29583d7072f8Seschrock "to be recovered.\n")); 29593d7072f8Seschrock break; 29603d7072f8Seschrock 2961fa9e4066Sahrens default: 2962fa9e4066Sahrens /* 2963fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 2964fa9e4066Sahrens */ 2965fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 2966fa9e4066Sahrens } 2967fa9e4066Sahrens 2968fa9e4066Sahrens if (msgid != NULL) 2969fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 2970fa9e4066Sahrens msgid); 2971fa9e4066Sahrens 2972fa9e4066Sahrens if (config != NULL) { 2973fa9e4066Sahrens int namewidth; 2974ea8dc4b6Seschrock uint64_t nerr; 297599653d4eSeschrock nvlist_t **spares; 297699653d4eSeschrock uint_t nspares; 2977fa9e4066Sahrens 2978fa9e4066Sahrens 2979fa9e4066Sahrens (void) printf(gettext(" scrub: ")); 2980fa9e4066Sahrens print_scrub_status(nvroot); 2981fa9e4066Sahrens 2982c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 2983fa9e4066Sahrens if (namewidth < 10) 2984fa9e4066Sahrens namewidth = 10; 2985fa9e4066Sahrens 2986fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 2987fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 2988fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 2989c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 29908654d025Sperrin namewidth, 0, B_FALSE, B_FALSE); 29918654d025Sperrin if (num_logs(nvroot) > 0) 29928654d025Sperrin print_status_config(zhp, "logs", nvroot, namewidth, 0, 29938654d025Sperrin B_FALSE, B_TRUE); 299499653d4eSeschrock 299599653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 299699653d4eSeschrock &spares, &nspares) == 0) 299799653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 2998ea8dc4b6Seschrock 2999ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3000ea8dc4b6Seschrock &nerr) == 0) { 300155434c77Sek nvlist_t *nverrlist = NULL; 300255434c77Sek 3003ea8dc4b6Seschrock /* 3004ea8dc4b6Seschrock * If the approximate error count is small, get a 3005ea8dc4b6Seschrock * precise count by fetching the entire log and 3006ea8dc4b6Seschrock * uniquifying the results. 3007ea8dc4b6Seschrock */ 300875519f38Sek if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 300955434c77Sek zpool_get_errlog(zhp, &nverrlist) == 0) { 301055434c77Sek nvpair_t *elem; 301155434c77Sek 301255434c77Sek elem = NULL; 301355434c77Sek nerr = 0; 301455434c77Sek while ((elem = nvlist_next_nvpair(nverrlist, 301555434c77Sek elem)) != NULL) { 301655434c77Sek nerr++; 301755434c77Sek } 301855434c77Sek } 301955434c77Sek nvlist_free(nverrlist); 3020ea8dc4b6Seschrock 3021ea8dc4b6Seschrock (void) printf("\n"); 302299653d4eSeschrock 3023ea8dc4b6Seschrock if (nerr == 0) 3024ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 3025ea8dc4b6Seschrock "errors\n")); 3026ea8dc4b6Seschrock else if (!cbp->cb_verbose) 3027e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 30285ad82045Snd "errors, use '-v' for a list\n"), 30295ad82045Snd (u_longlong_t)nerr); 3030ea8dc4b6Seschrock else 3031ea8dc4b6Seschrock print_error_log(zhp); 3032ea8dc4b6Seschrock } 3033fa9e4066Sahrens } else { 3034fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 3035fa9e4066Sahrens "determined.\n")); 3036fa9e4066Sahrens } 3037fa9e4066Sahrens 3038fa9e4066Sahrens return (0); 3039fa9e4066Sahrens } 3040fa9e4066Sahrens 3041fa9e4066Sahrens /* 3042fa9e4066Sahrens * zpool status [-vx] [pool] ... 3043fa9e4066Sahrens * 3044fa9e4066Sahrens * -v Display complete error logs 3045fa9e4066Sahrens * -x Display only pools with potential problems 3046fa9e4066Sahrens * 3047fa9e4066Sahrens * Describes the health status of all pools or some subset. 3048fa9e4066Sahrens */ 3049fa9e4066Sahrens int 3050fa9e4066Sahrens zpool_do_status(int argc, char **argv) 3051fa9e4066Sahrens { 3052fa9e4066Sahrens int c; 3053fa9e4066Sahrens int ret; 3054fa9e4066Sahrens status_cbdata_t cb = { 0 }; 3055fa9e4066Sahrens 3056fa9e4066Sahrens /* check options */ 3057fa9e4066Sahrens while ((c = getopt(argc, argv, "vx")) != -1) { 3058fa9e4066Sahrens switch (c) { 3059fa9e4066Sahrens case 'v': 306099653d4eSeschrock cb.cb_verbose = B_TRUE; 3061fa9e4066Sahrens break; 3062fa9e4066Sahrens case 'x': 306399653d4eSeschrock cb.cb_explain = B_TRUE; 3064fa9e4066Sahrens break; 3065fa9e4066Sahrens case '?': 3066fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3067fa9e4066Sahrens optopt); 306899653d4eSeschrock usage(B_FALSE); 3069fa9e4066Sahrens } 3070fa9e4066Sahrens } 3071fa9e4066Sahrens 3072fa9e4066Sahrens argc -= optind; 3073fa9e4066Sahrens argv += optind; 3074fa9e4066Sahrens 307599653d4eSeschrock cb.cb_first = B_TRUE; 3076fa9e4066Sahrens 3077e9dbad6fSeschrock if (argc == 0) 3078e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 3079e9dbad6fSeschrock 3080b1b8ab34Slling ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3081fa9e4066Sahrens 3082fa9e4066Sahrens if (argc == 0 && cb.cb_count == 0) 3083fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 3084e9dbad6fSeschrock else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3085e9dbad6fSeschrock (void) printf(gettext("all pools are healthy\n")); 3086fa9e4066Sahrens 3087fa9e4066Sahrens return (ret); 3088fa9e4066Sahrens } 3089fa9e4066Sahrens 3090eaca9bbdSeschrock typedef struct upgrade_cbdata { 3091eaca9bbdSeschrock int cb_all; 3092eaca9bbdSeschrock int cb_first; 3093eaca9bbdSeschrock int cb_newer; 309406eeb2adSek int cb_argc; 3095*990b4856Slling uint64_t cb_version; 309606eeb2adSek char **cb_argv; 3097eaca9bbdSeschrock } upgrade_cbdata_t; 3098eaca9bbdSeschrock 3099eaca9bbdSeschrock static int 3100eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 3101eaca9bbdSeschrock { 3102eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 3103eaca9bbdSeschrock nvlist_t *config; 3104eaca9bbdSeschrock uint64_t version; 3105eaca9bbdSeschrock int ret = 0; 3106eaca9bbdSeschrock 3107eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 3108eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3109eaca9bbdSeschrock &version) == 0); 3110eaca9bbdSeschrock 3111e7437265Sahrens if (!cbp->cb_newer && version < SPA_VERSION) { 3112eaca9bbdSeschrock if (!cbp->cb_all) { 3113eaca9bbdSeschrock if (cbp->cb_first) { 3114eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3115eaca9bbdSeschrock "out of date, and can be upgraded. After " 3116eaca9bbdSeschrock "being\nupgraded, these pools will no " 3117eaca9bbdSeschrock "longer be accessible by older software " 3118eaca9bbdSeschrock "versions.\n\n")); 3119eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3120eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 312199653d4eSeschrock cbp->cb_first = B_FALSE; 3122eaca9bbdSeschrock } 3123eaca9bbdSeschrock 31245ad82045Snd (void) printf("%2llu %s\n", (u_longlong_t)version, 3125eaca9bbdSeschrock zpool_get_name(zhp)); 3126eaca9bbdSeschrock } else { 312799653d4eSeschrock cbp->cb_first = B_FALSE; 3128*990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 312906eeb2adSek if (!ret) { 3130eaca9bbdSeschrock (void) printf(gettext("Successfully upgraded " 3131*990b4856Slling "'%s'\n\n"), zpool_get_name(zhp)); 313206eeb2adSek } 3133eaca9bbdSeschrock } 3134e7437265Sahrens } else if (cbp->cb_newer && version > SPA_VERSION) { 3135eaca9bbdSeschrock assert(!cbp->cb_all); 3136eaca9bbdSeschrock 3137eaca9bbdSeschrock if (cbp->cb_first) { 3138eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3139eaca9bbdSeschrock "formatted using a newer software version and\n" 3140eaca9bbdSeschrock "cannot be accessed on the current system.\n\n")); 3141eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3142eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 314399653d4eSeschrock cbp->cb_first = B_FALSE; 3144eaca9bbdSeschrock } 3145eaca9bbdSeschrock 31465ad82045Snd (void) printf("%2llu %s\n", (u_longlong_t)version, 3147eaca9bbdSeschrock zpool_get_name(zhp)); 3148eaca9bbdSeschrock } 3149eaca9bbdSeschrock 3150eaca9bbdSeschrock zpool_close(zhp); 3151eaca9bbdSeschrock return (ret); 3152eaca9bbdSeschrock } 3153eaca9bbdSeschrock 3154eaca9bbdSeschrock /* ARGSUSED */ 3155eaca9bbdSeschrock static int 315606eeb2adSek upgrade_one(zpool_handle_t *zhp, void *data) 3157eaca9bbdSeschrock { 3158*990b4856Slling upgrade_cbdata_t *cbp = data; 3159*990b4856Slling uint64_t cur_version; 3160eaca9bbdSeschrock int ret; 3161eaca9bbdSeschrock 31628654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 31638654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 31648654d025Sperrin "Pool 'log' must be renamed using export and import" 31658654d025Sperrin " to upgrade.\n")); 31668654d025Sperrin return (1); 31678654d025Sperrin } 3168*990b4856Slling 3169*990b4856Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 3170*990b4856Slling if (cur_version >= cbp->cb_version) { 3171eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 3172*990b4856Slling "using more current version '%d'.\n"), zpool_get_name(zhp), 3173*990b4856Slling cur_version); 3174eaca9bbdSeschrock return (0); 3175eaca9bbdSeschrock } 3176eaca9bbdSeschrock 3177*990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 317806eeb2adSek 317906eeb2adSek if (!ret) { 318044cd46caSbillm (void) printf(gettext("Successfully upgraded '%s' " 3181*990b4856Slling "from version %llu to version %llu\n\n"), 3182*990b4856Slling zpool_get_name(zhp), (u_longlong_t)cur_version, 3183*990b4856Slling (u_longlong_t)cbp->cb_version); 318406eeb2adSek } 3185eaca9bbdSeschrock 3186eaca9bbdSeschrock return (ret != 0); 3187eaca9bbdSeschrock } 3188eaca9bbdSeschrock 3189eaca9bbdSeschrock /* 3190eaca9bbdSeschrock * zpool upgrade 3191eaca9bbdSeschrock * zpool upgrade -v 3192*990b4856Slling * zpool upgrade [-V version] <-a | pool ...> 3193eaca9bbdSeschrock * 3194eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 3195eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 3196eaca9bbdSeschrock * upgrade all pools. 3197eaca9bbdSeschrock */ 3198eaca9bbdSeschrock int 3199eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 3200eaca9bbdSeschrock { 3201eaca9bbdSeschrock int c; 3202eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 3203eaca9bbdSeschrock int ret = 0; 3204eaca9bbdSeschrock boolean_t showversions = B_FALSE; 3205*990b4856Slling char *end; 3206*990b4856Slling 3207*990b4856Slling cb.cb_version = SPA_VERSION; 3208eaca9bbdSeschrock 3209eaca9bbdSeschrock /* check options */ 3210*990b4856Slling while ((c = getopt(argc, argv, "avV:")) != -1) { 3211eaca9bbdSeschrock switch (c) { 3212eaca9bbdSeschrock case 'a': 321399653d4eSeschrock cb.cb_all = B_TRUE; 3214eaca9bbdSeschrock break; 3215eaca9bbdSeschrock case 'v': 3216eaca9bbdSeschrock showversions = B_TRUE; 3217eaca9bbdSeschrock break; 3218*990b4856Slling case 'V': 3219*990b4856Slling cb.cb_version = strtoll(optarg, &end, 10); 3220*990b4856Slling if (*end != '\0') { 3221*990b4856Slling (void) fprintf(stderr, 3222*990b4856Slling gettext("invalid version '%s'\n"), optarg); 3223*990b4856Slling usage(B_FALSE); 3224*990b4856Slling } 3225*990b4856Slling break; 3226eaca9bbdSeschrock case '?': 3227eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3228eaca9bbdSeschrock optopt); 322999653d4eSeschrock usage(B_FALSE); 3230eaca9bbdSeschrock } 3231eaca9bbdSeschrock } 3232eaca9bbdSeschrock 323306eeb2adSek cb.cb_argc = argc; 323406eeb2adSek cb.cb_argv = argv; 3235eaca9bbdSeschrock argc -= optind; 3236eaca9bbdSeschrock argv += optind; 3237eaca9bbdSeschrock 3238eaca9bbdSeschrock if (showversions) { 3239eaca9bbdSeschrock if (cb.cb_all || argc != 0) { 3240eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 3241eaca9bbdSeschrock "incompatible with other arguments\n")); 324299653d4eSeschrock usage(B_FALSE); 3243eaca9bbdSeschrock } 3244eaca9bbdSeschrock } else if (cb.cb_all) { 3245eaca9bbdSeschrock if (argc != 0) { 3246eaca9bbdSeschrock (void) fprintf(stderr, gettext("-a option is " 3247eaca9bbdSeschrock "incompatible with other arguments\n")); 324899653d4eSeschrock usage(B_FALSE); 3249eaca9bbdSeschrock } 3250eaca9bbdSeschrock } 3251eaca9bbdSeschrock 3252e7437265Sahrens (void) printf(gettext("This system is currently running " 3253e7437265Sahrens "ZFS pool version %llu.\n\n"), SPA_VERSION); 325499653d4eSeschrock cb.cb_first = B_TRUE; 3255eaca9bbdSeschrock if (showversions) { 3256eaca9bbdSeschrock (void) printf(gettext("The following versions are " 3257d7d4af51Smmusante "supported:\n\n")); 3258eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 3259eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 3260eaca9bbdSeschrock "---------------\n"); 326199653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 326244cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 326344cd46caSbillm "(replicated metadata)\n")); 326499653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 326599653d4eSeschrock "RAID-Z\n")); 3266d7306b64Sek (void) printf(gettext(" 4 zpool history\n")); 3267c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 3268c9431fa1Sahl "algorithm\n")); 3269*990b4856Slling (void) printf(gettext(" 6 bootfs pool property\n")); 32708654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 3271ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 32728654d025Sperrin (void) printf(gettext("For more information on a particular " 3273eaca9bbdSeschrock "version, including supported releases, see:\n\n")); 3274eaca9bbdSeschrock (void) printf("http://www.opensolaris.org/os/community/zfs/" 3275eaca9bbdSeschrock "version/N\n\n"); 3276eaca9bbdSeschrock (void) printf(gettext("Where 'N' is the version number.\n")); 3277eaca9bbdSeschrock } else if (argc == 0) { 3278eaca9bbdSeschrock int notfound; 3279eaca9bbdSeschrock 328099653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3281eaca9bbdSeschrock notfound = cb.cb_first; 3282eaca9bbdSeschrock 3283eaca9bbdSeschrock if (!cb.cb_all && ret == 0) { 3284eaca9bbdSeschrock if (!cb.cb_first) 3285eaca9bbdSeschrock (void) printf("\n"); 3286eaca9bbdSeschrock cb.cb_first = B_TRUE; 3287eaca9bbdSeschrock cb.cb_newer = B_TRUE; 328899653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3289eaca9bbdSeschrock if (!cb.cb_first) { 3290eaca9bbdSeschrock notfound = B_FALSE; 3291eaca9bbdSeschrock (void) printf("\n"); 3292eaca9bbdSeschrock } 3293eaca9bbdSeschrock } 3294eaca9bbdSeschrock 3295eaca9bbdSeschrock if (ret == 0) { 3296eaca9bbdSeschrock if (notfound) 3297eaca9bbdSeschrock (void) printf(gettext("All pools are formatted " 3298eaca9bbdSeschrock "using this version.\n")); 3299eaca9bbdSeschrock else if (!cb.cb_all) 3300eaca9bbdSeschrock (void) printf(gettext("Use 'zpool upgrade -v' " 3301eaca9bbdSeschrock "for a list of available versions and " 3302eaca9bbdSeschrock "their associated\nfeatures.\n")); 3303eaca9bbdSeschrock } 3304eaca9bbdSeschrock } else { 3305b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 3306b1b8ab34Slling upgrade_one, &cb); 330706eeb2adSek } 330806eeb2adSek 330906eeb2adSek return (ret); 331006eeb2adSek } 331106eeb2adSek 3312ecd6cf80Smarks typedef struct hist_cbdata { 3313ecd6cf80Smarks boolean_t first; 3314ecd6cf80Smarks int longfmt; 3315ecd6cf80Smarks int internal; 3316ecd6cf80Smarks } hist_cbdata_t; 3317ecd6cf80Smarks 3318ecd6cf80Smarks char *hist_event_table[LOG_END] = { 3319ecd6cf80Smarks "invalid event", 3320ecd6cf80Smarks "pool create", 3321ecd6cf80Smarks "vdev add", 3322ecd6cf80Smarks "pool remove", 3323ecd6cf80Smarks "pool destroy", 3324ecd6cf80Smarks "pool export", 3325ecd6cf80Smarks "pool import", 3326ecd6cf80Smarks "vdev attach", 3327ecd6cf80Smarks "vdev replace", 3328ecd6cf80Smarks "vdev detach", 3329ecd6cf80Smarks "vdev online", 3330ecd6cf80Smarks "vdev offline", 3331ecd6cf80Smarks "vdev upgrade", 3332ecd6cf80Smarks "pool clear", 3333ecd6cf80Smarks "pool scrub", 3334ecd6cf80Smarks "pool property set", 3335ecd6cf80Smarks "create", 3336ecd6cf80Smarks "clone", 3337ecd6cf80Smarks "destroy", 3338ecd6cf80Smarks "destroy_begin_sync", 3339ecd6cf80Smarks "inherit", 3340ecd6cf80Smarks "property set", 3341ecd6cf80Smarks "quota set", 3342ecd6cf80Smarks "permission update", 3343ecd6cf80Smarks "permission remove", 3344ecd6cf80Smarks "permission who remove", 3345ecd6cf80Smarks "promote", 3346ecd6cf80Smarks "receive", 3347ecd6cf80Smarks "rename", 3348ecd6cf80Smarks "reservation set", 3349ecd6cf80Smarks "replay_inc_sync", 3350ecd6cf80Smarks "replay_full_sync", 3351ecd6cf80Smarks "rollback", 3352ecd6cf80Smarks "snapshot", 3353e7437265Sahrens "filesystem version upgrade", 3354ecd6cf80Smarks }; 3355ecd6cf80Smarks 335606eeb2adSek /* 335706eeb2adSek * Print out the command history for a specific pool. 335806eeb2adSek */ 335906eeb2adSek static int 336006eeb2adSek get_history_one(zpool_handle_t *zhp, void *data) 336106eeb2adSek { 336206eeb2adSek nvlist_t *nvhis; 336306eeb2adSek nvlist_t **records; 336406eeb2adSek uint_t numrecords; 336506eeb2adSek char *cmdstr; 3366ecd6cf80Smarks char *pathstr; 336706eeb2adSek uint64_t dst_time; 336806eeb2adSek time_t tsec; 336906eeb2adSek struct tm t; 337006eeb2adSek char tbuf[30]; 337106eeb2adSek int ret, i; 3372ecd6cf80Smarks uint64_t who; 3373ecd6cf80Smarks struct passwd *pwd; 3374ecd6cf80Smarks char *hostname; 3375ecd6cf80Smarks char *zonename; 3376ecd6cf80Smarks char internalstr[MAXPATHLEN]; 3377ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 3378ecd6cf80Smarks uint64_t txg; 3379ecd6cf80Smarks uint64_t ievent; 338006eeb2adSek 3381ecd6cf80Smarks cb->first = B_FALSE; 338206eeb2adSek 338306eeb2adSek (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 338406eeb2adSek 338506eeb2adSek if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 338606eeb2adSek return (ret); 338706eeb2adSek 338806eeb2adSek verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 338906eeb2adSek &records, &numrecords) == 0); 339006eeb2adSek for (i = 0; i < numrecords; i++) { 339106eeb2adSek if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3392ecd6cf80Smarks &dst_time) != 0) 3393ecd6cf80Smarks continue; 3394ecd6cf80Smarks 3395ecd6cf80Smarks /* is it an internal event or a standard event? */ 3396ecd6cf80Smarks if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3397ecd6cf80Smarks &cmdstr) != 0) { 3398ecd6cf80Smarks if (cb->internal == 0) 3399ecd6cf80Smarks continue; 3400ecd6cf80Smarks 3401ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3402ecd6cf80Smarks ZPOOL_HIST_INT_EVENT, &ievent) != 0) 3403ecd6cf80Smarks continue; 3404ecd6cf80Smarks verify(nvlist_lookup_uint64(records[i], 3405ecd6cf80Smarks ZPOOL_HIST_TXG, &txg) == 0); 3406ecd6cf80Smarks verify(nvlist_lookup_string(records[i], 3407ecd6cf80Smarks ZPOOL_HIST_INT_STR, &pathstr) == 0); 3408ecd6cf80Smarks if (ievent > LOG_END) 3409ecd6cf80Smarks continue; 3410ecd6cf80Smarks (void) snprintf(internalstr, 3411ecd6cf80Smarks sizeof (internalstr), 3412ecd6cf80Smarks "[internal %s txg:%lld] %s", 3413ecd6cf80Smarks hist_event_table[ievent], txg, 3414ecd6cf80Smarks pathstr); 3415ecd6cf80Smarks cmdstr = internalstr; 341606eeb2adSek } 3417ecd6cf80Smarks tsec = dst_time; 3418ecd6cf80Smarks (void) localtime_r(&tsec, &t); 3419ecd6cf80Smarks (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3420ecd6cf80Smarks (void) printf("%s %s", tbuf, cmdstr); 3421ecd6cf80Smarks 3422ecd6cf80Smarks if (!cb->longfmt) { 3423ecd6cf80Smarks (void) printf("\n"); 3424ecd6cf80Smarks continue; 3425ecd6cf80Smarks } 3426ecd6cf80Smarks (void) printf(" ["); 3427ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3428ecd6cf80Smarks ZPOOL_HIST_WHO, &who) == 0) { 3429ecd6cf80Smarks pwd = getpwuid((uid_t)who); 3430ecd6cf80Smarks if (pwd) 3431ecd6cf80Smarks (void) printf("user %s on", 3432ecd6cf80Smarks pwd->pw_name); 3433ecd6cf80Smarks else 3434ecd6cf80Smarks (void) printf("user %d on", 3435ecd6cf80Smarks (int)who); 3436ecd6cf80Smarks } else { 3437ecd6cf80Smarks (void) printf(gettext("no info]\n")); 3438ecd6cf80Smarks continue; 3439ecd6cf80Smarks } 3440ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3441ecd6cf80Smarks ZPOOL_HIST_HOST, &hostname) == 0) { 3442ecd6cf80Smarks (void) printf(" %s", hostname); 3443ecd6cf80Smarks } 3444ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3445ecd6cf80Smarks ZPOOL_HIST_ZONE, &zonename) == 0) { 3446ecd6cf80Smarks (void) printf(":%s", zonename); 3447ecd6cf80Smarks } 3448ecd6cf80Smarks 3449ecd6cf80Smarks (void) printf("]"); 3450ecd6cf80Smarks (void) printf("\n"); 345106eeb2adSek } 345206eeb2adSek (void) printf("\n"); 345306eeb2adSek nvlist_free(nvhis); 345406eeb2adSek 345506eeb2adSek return (ret); 345606eeb2adSek } 345706eeb2adSek 345806eeb2adSek /* 345906eeb2adSek * zpool history <pool> 346006eeb2adSek * 346106eeb2adSek * Displays the history of commands that modified pools. 346206eeb2adSek */ 3463ecd6cf80Smarks 3464ecd6cf80Smarks 346506eeb2adSek int 346606eeb2adSek zpool_do_history(int argc, char **argv) 346706eeb2adSek { 3468ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 346906eeb2adSek int ret; 3470ecd6cf80Smarks int c; 347106eeb2adSek 3472ecd6cf80Smarks cbdata.first = B_TRUE; 3473ecd6cf80Smarks /* check options */ 3474ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 3475ecd6cf80Smarks switch (c) { 3476ecd6cf80Smarks case 'l': 3477ecd6cf80Smarks cbdata.longfmt = 1; 3478ecd6cf80Smarks break; 3479ecd6cf80Smarks case 'i': 3480ecd6cf80Smarks cbdata.internal = 1; 3481ecd6cf80Smarks break; 3482ecd6cf80Smarks case '?': 3483ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3484ecd6cf80Smarks optopt); 3485ecd6cf80Smarks usage(B_FALSE); 3486ecd6cf80Smarks } 3487ecd6cf80Smarks } 348806eeb2adSek argc -= optind; 348906eeb2adSek argv += optind; 349006eeb2adSek 3491b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3492ecd6cf80Smarks &cbdata); 349306eeb2adSek 3494ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 349506eeb2adSek (void) printf(gettext("no pools available\n")); 349606eeb2adSek return (0); 3497eaca9bbdSeschrock } 3498eaca9bbdSeschrock 3499eaca9bbdSeschrock return (ret); 3500eaca9bbdSeschrock } 3501eaca9bbdSeschrock 3502b1b8ab34Slling static int 3503b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 3504b1b8ab34Slling { 3505*990b4856Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 3506b1b8ab34Slling char value[MAXNAMELEN]; 3507*990b4856Slling zprop_source_t srctype; 3508*990b4856Slling zprop_list_t *pl; 3509b1b8ab34Slling 3510b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3511b1b8ab34Slling 3512b1b8ab34Slling /* 3513*990b4856Slling * Skip the special fake placeholder. This will also skip 3514*990b4856Slling * over the name property when 'all' is specified. 3515b1b8ab34Slling */ 3516*990b4856Slling if (pl->pl_prop == ZPOOL_PROP_NAME && 3517b1b8ab34Slling pl == cbp->cb_proplist) 3518b1b8ab34Slling continue; 3519b1b8ab34Slling 3520b1b8ab34Slling if (zpool_get_prop(zhp, pl->pl_prop, 3521b1b8ab34Slling value, sizeof (value), &srctype) != 0) 3522b1b8ab34Slling continue; 3523b1b8ab34Slling 3524*990b4856Slling zprop_print_one_property(zpool_get_name(zhp), cbp, 3525b1b8ab34Slling zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3526b1b8ab34Slling } 3527b1b8ab34Slling return (0); 3528b1b8ab34Slling } 3529b1b8ab34Slling 3530b1b8ab34Slling int 3531b1b8ab34Slling zpool_do_get(int argc, char **argv) 3532b1b8ab34Slling { 3533*990b4856Slling zprop_get_cbdata_t cb = { 0 }; 3534*990b4856Slling zprop_list_t fake_name = { 0 }; 3535b1b8ab34Slling int ret; 3536b1b8ab34Slling 3537b1b8ab34Slling if (argc < 3) 3538b1b8ab34Slling usage(B_FALSE); 3539b1b8ab34Slling 3540b1b8ab34Slling cb.cb_first = B_TRUE; 3541*990b4856Slling cb.cb_sources = ZPROP_SRC_ALL; 3542b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 3543b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 3544b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 3545b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 3546*990b4856Slling cb.cb_type = ZFS_TYPE_POOL; 3547b1b8ab34Slling 3548*990b4856Slling if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 3549*990b4856Slling ZFS_TYPE_POOL) != 0) 3550b1b8ab34Slling usage(B_FALSE); 3551b1b8ab34Slling 3552b1b8ab34Slling if (cb.cb_proplist != NULL) { 3553*990b4856Slling fake_name.pl_prop = ZPOOL_PROP_NAME; 3554b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 3555b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 3556b1b8ab34Slling cb.cb_proplist = &fake_name; 3557b1b8ab34Slling } 3558b1b8ab34Slling 3559b1b8ab34Slling ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3560b1b8ab34Slling get_callback, &cb); 3561b1b8ab34Slling 3562b1b8ab34Slling if (cb.cb_proplist == &fake_name) 3563*990b4856Slling zprop_free_list(fake_name.pl_next); 3564b1b8ab34Slling else 3565*990b4856Slling zprop_free_list(cb.cb_proplist); 3566b1b8ab34Slling 3567b1b8ab34Slling return (ret); 3568b1b8ab34Slling } 3569b1b8ab34Slling 3570b1b8ab34Slling typedef struct set_cbdata { 3571b1b8ab34Slling char *cb_propname; 3572b1b8ab34Slling char *cb_value; 3573b1b8ab34Slling boolean_t cb_any_successful; 3574b1b8ab34Slling } set_cbdata_t; 3575b1b8ab34Slling 3576b1b8ab34Slling int 3577b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 3578b1b8ab34Slling { 3579b1b8ab34Slling int error; 3580b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 3581b1b8ab34Slling 3582b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3583b1b8ab34Slling 3584b1b8ab34Slling if (!error) 3585b1b8ab34Slling cb->cb_any_successful = B_TRUE; 3586b1b8ab34Slling 3587b1b8ab34Slling return (error); 3588b1b8ab34Slling } 3589b1b8ab34Slling 3590b1b8ab34Slling int 3591b1b8ab34Slling zpool_do_set(int argc, char **argv) 3592b1b8ab34Slling { 3593b1b8ab34Slling set_cbdata_t cb = { 0 }; 3594b1b8ab34Slling int error; 3595b1b8ab34Slling 3596b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 3597b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3598b1b8ab34Slling argv[1][1]); 3599b1b8ab34Slling usage(B_FALSE); 3600b1b8ab34Slling } 3601b1b8ab34Slling 3602b1b8ab34Slling if (argc < 2) { 3603b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 3604b1b8ab34Slling "argument\n")); 3605b1b8ab34Slling usage(B_FALSE); 3606b1b8ab34Slling } 3607b1b8ab34Slling 3608b1b8ab34Slling if (argc < 3) { 3609b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 3610b1b8ab34Slling usage(B_FALSE); 3611b1b8ab34Slling } 3612b1b8ab34Slling 3613b1b8ab34Slling if (argc > 3) { 3614b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 3615b1b8ab34Slling usage(B_FALSE); 3616b1b8ab34Slling } 3617b1b8ab34Slling 3618b1b8ab34Slling cb.cb_propname = argv[1]; 3619b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 3620b1b8ab34Slling if (cb.cb_value == NULL) { 3621b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 3622b1b8ab34Slling "property=value argument\n")); 3623b1b8ab34Slling usage(B_FALSE); 3624b1b8ab34Slling } 3625b1b8ab34Slling 3626b1b8ab34Slling *(cb.cb_value) = '\0'; 3627b1b8ab34Slling cb.cb_value++; 3628b1b8ab34Slling 3629b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3630b1b8ab34Slling set_callback, &cb); 3631b1b8ab34Slling 3632b1b8ab34Slling return (error); 3633b1b8ab34Slling } 3634b1b8ab34Slling 3635b1b8ab34Slling static int 3636b1b8ab34Slling find_command_idx(char *command, int *idx) 3637b1b8ab34Slling { 3638b1b8ab34Slling int i; 3639b1b8ab34Slling 3640b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 3641b1b8ab34Slling if (command_table[i].name == NULL) 3642b1b8ab34Slling continue; 3643b1b8ab34Slling 3644b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 3645b1b8ab34Slling *idx = i; 3646b1b8ab34Slling return (0); 3647b1b8ab34Slling } 3648b1b8ab34Slling } 3649b1b8ab34Slling return (1); 3650b1b8ab34Slling } 3651b1b8ab34Slling 3652fa9e4066Sahrens int 3653fa9e4066Sahrens main(int argc, char **argv) 3654fa9e4066Sahrens { 3655fa9e4066Sahrens int ret; 3656fa9e4066Sahrens int i; 3657fa9e4066Sahrens char *cmdname; 3658fa9e4066Sahrens 3659fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 3660fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 3661fa9e4066Sahrens 366299653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 366399653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 3664203a47d8Snd "initialize ZFS library\n")); 366599653d4eSeschrock return (1); 366699653d4eSeschrock } 366799653d4eSeschrock 366899653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 366999653d4eSeschrock 3670fa9e4066Sahrens opterr = 0; 3671fa9e4066Sahrens 3672fa9e4066Sahrens /* 3673fa9e4066Sahrens * Make sure the user has specified some command. 3674fa9e4066Sahrens */ 3675fa9e4066Sahrens if (argc < 2) { 3676fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 367799653d4eSeschrock usage(B_FALSE); 3678fa9e4066Sahrens } 3679fa9e4066Sahrens 3680fa9e4066Sahrens cmdname = argv[1]; 3681fa9e4066Sahrens 3682fa9e4066Sahrens /* 3683fa9e4066Sahrens * Special case '-?' 3684fa9e4066Sahrens */ 3685fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 368699653d4eSeschrock usage(B_TRUE); 3687fa9e4066Sahrens 36882a6b87f0Sek zpool_set_history_str("zpool", argc, argv, history_str); 36892a6b87f0Sek verify(zpool_stage_history(g_zfs, history_str) == 0); 36902a6b87f0Sek 3691fa9e4066Sahrens /* 3692fa9e4066Sahrens * Run the appropriate command. 3693fa9e4066Sahrens */ 3694b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 3695b1b8ab34Slling current_command = &command_table[i]; 3696b1b8ab34Slling ret = command_table[i].func(argc - 1, argv + 1); 369791ebeef5Sahrens } else if (strchr(cmdname, '=')) { 369891ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 369991ebeef5Sahrens current_command = &command_table[i]; 370091ebeef5Sahrens ret = command_table[i].func(argc, argv); 370191ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 370291ebeef5Sahrens /* 370391ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 370491ebeef5Sahrens * it as such. 370591ebeef5Sahrens */ 3706ea8dc4b6Seschrock char buf[16384]; 3707ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 3708fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 3709fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 371091ebeef5Sahrens } else { 3711fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 3712fa9e4066Sahrens "command '%s'\n"), cmdname); 371399653d4eSeschrock usage(B_FALSE); 3714fa9e4066Sahrens } 3715fa9e4066Sahrens 371699653d4eSeschrock libzfs_fini(g_zfs); 371799653d4eSeschrock 3718fa9e4066Sahrens /* 3719fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3720fa9e4066Sahrens * for the purposes of running ::findleaks. 3721fa9e4066Sahrens */ 3722fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 3723fa9e4066Sahrens (void) printf("dumping core by request\n"); 3724fa9e4066Sahrens abort(); 3725fa9e4066Sahrens } 3726fa9e4066Sahrens 3727fa9e4066Sahrens return (ret); 3728fa9e4066Sahrens } 3729