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 7906eeb2adSek110237 static int zpool_do_history(int, char **); 8006eeb2adSek110237 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, 10806eeb2adSek110237 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 }, 16206eeb2adSek110237 { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 16306eeb2adSek110237 { 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; 1722a6b87f0Sek110237 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: 185990b4856Slling return (gettext("\tcreate [-fn] [-o property=value] ... \n" 186990b4856Slling "\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")); 19306eeb2adSek110237 case HELP_HISTORY: 194ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 19565cd9f28Seschrock case HELP_IMPORT: 1964c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 1972f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 1982f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n" 1992f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 2002f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] " 2012f8aaab3Seschrock "<pool | id> [newpool]\n")); 20265cd9f28Seschrock case HELP_IOSTAT: 20365cd9f28Seschrock return (gettext("\tiostat [-v] [pool] ... [interval " 20465cd9f28Seschrock "[count]]\n")); 20565cd9f28Seschrock case HELP_LIST: 206990b4856Slling return (gettext("\tlist [-H] [-o property[,...]] " 207990b4856Slling "[pool] ...\n")); 20865cd9f28Seschrock case HELP_OFFLINE: 209441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 21065cd9f28Seschrock case HELP_ONLINE: 211441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 21265cd9f28Seschrock case HELP_REPLACE: 21365cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 214e45ce728Sahrens "[new-device]\n")); 21599653d4eSeschrock case HELP_REMOVE: 216*fa94a07fSbrendan return (gettext("\tremove <pool> <device> ...\n")); 21765cd9f28Seschrock case HELP_SCRUB: 21865cd9f28Seschrock return (gettext("\tscrub [-s] <pool> ...\n")); 21965cd9f28Seschrock case HELP_STATUS: 22065cd9f28Seschrock return (gettext("\tstatus [-vx] [pool] ...\n")); 221eaca9bbdSeschrock case HELP_UPGRADE: 222eaca9bbdSeschrock return (gettext("\tupgrade\n" 223eaca9bbdSeschrock "\tupgrade -v\n" 224990b4856Slling "\tupgrade [-V version] <-a | pool ...>\n")); 225b1b8ab34Slling case HELP_GET: 226e45ce728Sahrens return (gettext("\tget <\"all\" | property[,...]> " 227b1b8ab34Slling "<pool> ...\n")); 228b1b8ab34Slling case HELP_SET: 229b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 23065cd9f28Seschrock } 23165cd9f28Seschrock 23265cd9f28Seschrock abort(); 23365cd9f28Seschrock /* NOTREACHED */ 23465cd9f28Seschrock } 23565cd9f28Seschrock 236fa9e4066Sahrens 237fa9e4066Sahrens /* 238b1b8ab34Slling * Callback routine that will print out a pool property value. 239b1b8ab34Slling */ 240990b4856Slling static int 241990b4856Slling print_prop_cb(int prop, void *cb) 242b1b8ab34Slling { 243b1b8ab34Slling FILE *fp = cb; 244b1b8ab34Slling 245b1b8ab34Slling (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 246b1b8ab34Slling 247990b4856Slling if (zpool_prop_readonly(prop)) 248990b4856Slling (void) fprintf(fp, " NO "); 249990b4856Slling else 250990b4856Slling (void) fprintf(fp, " YES "); 251990b4856Slling 252b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 253b1b8ab34Slling (void) fprintf(fp, "-\n"); 254b1b8ab34Slling else 255b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 256b1b8ab34Slling 257990b4856Slling return (ZPROP_CONT); 258b1b8ab34Slling } 259b1b8ab34Slling 260b1b8ab34Slling /* 261fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 262fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 263fa9e4066Sahrens * a complete usage message. 264fa9e4066Sahrens */ 265fa9e4066Sahrens void 26699653d4eSeschrock usage(boolean_t requested) 267fa9e4066Sahrens { 268fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 269fa9e4066Sahrens 270fa9e4066Sahrens if (current_command == NULL) { 271fa9e4066Sahrens int i; 272fa9e4066Sahrens 273fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 274fa9e4066Sahrens (void) fprintf(fp, 275fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 276fa9e4066Sahrens 277fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 278fa9e4066Sahrens if (command_table[i].name == NULL) 279fa9e4066Sahrens (void) fprintf(fp, "\n"); 280fa9e4066Sahrens else 281fa9e4066Sahrens (void) fprintf(fp, "%s", 28265cd9f28Seschrock get_usage(command_table[i].usage)); 283fa9e4066Sahrens } 284fa9e4066Sahrens } else { 285fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 28665cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 287fa9e4066Sahrens } 288fa9e4066Sahrens 289b1b8ab34Slling if (current_command != NULL && 290b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 291990b4856Slling (strcmp(current_command->name, "get") == 0) || 292990b4856Slling (strcmp(current_command->name, "list") == 0))) { 293b1b8ab34Slling 294b1b8ab34Slling (void) fprintf(fp, 295b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 296b1b8ab34Slling 297990b4856Slling (void) fprintf(fp, "\n\t%-13s %s %s\n\n", 298990b4856Slling "PROPERTY", "EDIT", "VALUES"); 299b1b8ab34Slling 300b1b8ab34Slling /* Iterate over all properties */ 301990b4856Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 302990b4856Slling ZFS_TYPE_POOL); 303b1b8ab34Slling } 304b1b8ab34Slling 305e9dbad6fSeschrock /* 306e9dbad6fSeschrock * See comments at end of main(). 307e9dbad6fSeschrock */ 308e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 309e9dbad6fSeschrock (void) printf("dumping core by request\n"); 310e9dbad6fSeschrock abort(); 311e9dbad6fSeschrock } 312e9dbad6fSeschrock 313fa9e4066Sahrens exit(requested ? 0 : 2); 314fa9e4066Sahrens } 315fa9e4066Sahrens 316fa9e4066Sahrens void 3178654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 3188654d025Sperrin boolean_t print_logs) 319fa9e4066Sahrens { 320fa9e4066Sahrens nvlist_t **child; 321fa9e4066Sahrens uint_t c, children; 322afefbcddSeschrock char *vname; 323fa9e4066Sahrens 324fa9e4066Sahrens if (name != NULL) 325fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 326fa9e4066Sahrens 327fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 328fa9e4066Sahrens &child, &children) != 0) 329fa9e4066Sahrens return; 330fa9e4066Sahrens 331afefbcddSeschrock for (c = 0; c < children; c++) { 3328654d025Sperrin uint64_t is_log = B_FALSE; 3338654d025Sperrin 3348654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3358654d025Sperrin &is_log); 3368654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 3378654d025Sperrin continue; 3388654d025Sperrin 33999653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 3408654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 3418654d025Sperrin B_FALSE); 342afefbcddSeschrock free(vname); 343afefbcddSeschrock } 344fa9e4066Sahrens } 345fa9e4066Sahrens 346fa9e4066Sahrens /* 347990b4856Slling * Add a property pair (name, string-value) into a property nvlist. 348990b4856Slling */ 349990b4856Slling static int 350990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props) 351990b4856Slling { 352990b4856Slling char *strval; 353990b4856Slling nvlist_t *proplist; 354990b4856Slling zpool_prop_t prop; 355990b4856Slling 356990b4856Slling if (*props == NULL && 357990b4856Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 358990b4856Slling (void) fprintf(stderr, 359990b4856Slling gettext("internal error: out of memory\n")); 360990b4856Slling return (1); 361990b4856Slling } 362990b4856Slling 363990b4856Slling proplist = *props; 364990b4856Slling 365990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 366990b4856Slling (void) fprintf(stderr, gettext("property '%s' is " 367990b4856Slling "not a valid pool property\n"), propname); 368990b4856Slling return (2); 369990b4856Slling } 370990b4856Slling 371990b4856Slling /* Use normalized property name for nvlist operations */ 372990b4856Slling if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop), 3732f8aaab3Seschrock &strval) == 0 && prop != ZPOOL_PROP_CACHEFILE) { 374990b4856Slling (void) fprintf(stderr, gettext("property '%s' " 375990b4856Slling "specified multiple times\n"), propname); 376990b4856Slling return (2); 377990b4856Slling } 378990b4856Slling 379990b4856Slling if (nvlist_add_string(proplist, zpool_prop_to_name(prop), 380990b4856Slling propval) != 0) { 381990b4856Slling (void) fprintf(stderr, gettext("internal " 382990b4856Slling "error: out of memory\n")); 383990b4856Slling return (1); 384990b4856Slling } 385990b4856Slling 386990b4856Slling return (0); 387990b4856Slling } 388990b4856Slling 389990b4856Slling /* 390fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 391fa9e4066Sahrens * 392fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 393fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 394fa9e4066Sahrens * they were to be added. 395fa9e4066Sahrens * 396fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 397fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 398fa9e4066Sahrens * libzfs. 399fa9e4066Sahrens */ 400fa9e4066Sahrens int 401fa9e4066Sahrens zpool_do_add(int argc, char **argv) 402fa9e4066Sahrens { 40399653d4eSeschrock boolean_t force = B_FALSE; 40499653d4eSeschrock boolean_t dryrun = B_FALSE; 405fa9e4066Sahrens int c; 406fa9e4066Sahrens nvlist_t *nvroot; 407fa9e4066Sahrens char *poolname; 408fa9e4066Sahrens int ret; 409fa9e4066Sahrens zpool_handle_t *zhp; 410fa9e4066Sahrens nvlist_t *config; 411fa9e4066Sahrens 412fa9e4066Sahrens /* check options */ 413fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 414fa9e4066Sahrens switch (c) { 415fa9e4066Sahrens case 'f': 41699653d4eSeschrock force = B_TRUE; 417fa9e4066Sahrens break; 418fa9e4066Sahrens case 'n': 41999653d4eSeschrock dryrun = B_TRUE; 420fa9e4066Sahrens break; 421fa9e4066Sahrens case '?': 422fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 423fa9e4066Sahrens optopt); 42499653d4eSeschrock usage(B_FALSE); 425fa9e4066Sahrens } 426fa9e4066Sahrens } 427fa9e4066Sahrens 428fa9e4066Sahrens argc -= optind; 429fa9e4066Sahrens argv += optind; 430fa9e4066Sahrens 431fa9e4066Sahrens /* get pool name and check number of arguments */ 432fa9e4066Sahrens if (argc < 1) { 433fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 43499653d4eSeschrock usage(B_FALSE); 435fa9e4066Sahrens } 436fa9e4066Sahrens if (argc < 2) { 437fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 43899653d4eSeschrock usage(B_FALSE); 439fa9e4066Sahrens } 440fa9e4066Sahrens 441fa9e4066Sahrens poolname = argv[0]; 442fa9e4066Sahrens 443fa9e4066Sahrens argc--; 444fa9e4066Sahrens argv++; 445fa9e4066Sahrens 44699653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 447fa9e4066Sahrens return (1); 448fa9e4066Sahrens 449088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 450fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 451fa9e4066Sahrens poolname); 452fa9e4066Sahrens zpool_close(zhp); 453fa9e4066Sahrens return (1); 454fa9e4066Sahrens } 455fa9e4066Sahrens 456fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 4578488aeb5Staylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv); 458fa9e4066Sahrens if (nvroot == NULL) { 459fa9e4066Sahrens zpool_close(zhp); 460fa9e4066Sahrens return (1); 461fa9e4066Sahrens } 462fa9e4066Sahrens 463fa9e4066Sahrens if (dryrun) { 464fa9e4066Sahrens nvlist_t *poolnvroot; 465fa9e4066Sahrens 466fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 467fa9e4066Sahrens &poolnvroot) == 0); 468fa9e4066Sahrens 469fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 470fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 471fa9e4066Sahrens 4728654d025Sperrin /* print original main pool and new tree */ 4738654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 4748654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 4758654d025Sperrin 4768654d025Sperrin /* Do the same for the logs */ 4778654d025Sperrin if (num_logs(poolnvroot) > 0) { 4788654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 4798654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 4808654d025Sperrin } else if (num_logs(nvroot) > 0) { 4818654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 4828654d025Sperrin } 483fa9e4066Sahrens 484fa9e4066Sahrens ret = 0; 485fa9e4066Sahrens } else { 486fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 487fa9e4066Sahrens } 488fa9e4066Sahrens 48999653d4eSeschrock nvlist_free(nvroot); 49099653d4eSeschrock zpool_close(zhp); 49199653d4eSeschrock 49299653d4eSeschrock return (ret); 49399653d4eSeschrock } 49499653d4eSeschrock 49599653d4eSeschrock /* 496*fa94a07fSbrendan * zpool remove <pool> <vdev> ... 49799653d4eSeschrock * 49899653d4eSeschrock * Removes the given vdev from the pool. Currently, this only supports removing 499*fa94a07fSbrendan * spares and cache devices from the pool. Eventually, we'll want to support 500*fa94a07fSbrendan * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs. 50199653d4eSeschrock */ 50299653d4eSeschrock int 50399653d4eSeschrock zpool_do_remove(int argc, char **argv) 50499653d4eSeschrock { 50599653d4eSeschrock char *poolname; 506*fa94a07fSbrendan int i, ret = 0; 50799653d4eSeschrock zpool_handle_t *zhp; 50899653d4eSeschrock 50999653d4eSeschrock argc--; 51099653d4eSeschrock argv++; 51199653d4eSeschrock 51299653d4eSeschrock /* get pool name and check number of arguments */ 51399653d4eSeschrock if (argc < 1) { 51499653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 51599653d4eSeschrock usage(B_FALSE); 51699653d4eSeschrock } 51799653d4eSeschrock if (argc < 2) { 51899653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 51999653d4eSeschrock usage(B_FALSE); 52099653d4eSeschrock } 52199653d4eSeschrock 52299653d4eSeschrock poolname = argv[0]; 52399653d4eSeschrock 52499653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 52599653d4eSeschrock return (1); 52699653d4eSeschrock 527*fa94a07fSbrendan for (i = 1; i < argc; i++) { 528*fa94a07fSbrendan if (zpool_vdev_remove(zhp, argv[i]) != 0) 529*fa94a07fSbrendan ret = 1; 530*fa94a07fSbrendan } 53199653d4eSeschrock 532fa9e4066Sahrens return (ret); 533fa9e4066Sahrens } 534fa9e4066Sahrens 535fa9e4066Sahrens /* 536990b4856Slling * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint] 537990b4856Slling * <pool> <dev> ... 538fa9e4066Sahrens * 539fa9e4066Sahrens * -f Force creation, even if devices appear in use 540fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 541fa9e4066Sahrens * were to be created. 542fa9e4066Sahrens * -R Create a pool under an alternate root 543fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 544fa9e4066Sahrens * '/<pool>' 545990b4856Slling * -o Set property=value. 546fa9e4066Sahrens * 547b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 548fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 549fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 550fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 551fa9e4066Sahrens */ 552fa9e4066Sahrens int 553fa9e4066Sahrens zpool_do_create(int argc, char **argv) 554fa9e4066Sahrens { 55599653d4eSeschrock boolean_t force = B_FALSE; 55699653d4eSeschrock boolean_t dryrun = B_FALSE; 557fa9e4066Sahrens int c; 558990b4856Slling nvlist_t *nvroot = NULL; 559fa9e4066Sahrens char *poolname; 560990b4856Slling int ret = 1; 561fa9e4066Sahrens char *altroot = NULL; 562fa9e4066Sahrens char *mountpoint = NULL; 56399653d4eSeschrock nvlist_t **child; 56499653d4eSeschrock uint_t children; 565990b4856Slling nvlist_t *props = NULL; 5662f8aaab3Seschrock char *propval; 567fa9e4066Sahrens 568fa9e4066Sahrens /* check options */ 569990b4856Slling while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) { 570fa9e4066Sahrens switch (c) { 571fa9e4066Sahrens case 'f': 57299653d4eSeschrock force = B_TRUE; 573fa9e4066Sahrens break; 574fa9e4066Sahrens case 'n': 57599653d4eSeschrock dryrun = B_TRUE; 576fa9e4066Sahrens break; 577fa9e4066Sahrens case 'R': 578fa9e4066Sahrens altroot = optarg; 579990b4856Slling if (add_prop_list(zpool_prop_to_name( 580990b4856Slling ZPOOL_PROP_ALTROOT), optarg, &props)) 581990b4856Slling goto errout; 5822f8aaab3Seschrock if (nvlist_lookup_string(props, 5832f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 5842f8aaab3Seschrock &propval) == 0) 5852f8aaab3Seschrock break; 586990b4856Slling if (add_prop_list(zpool_prop_to_name( 5872f8aaab3Seschrock ZPOOL_PROP_CACHEFILE), "none", &props)) 588990b4856Slling goto errout; 589fa9e4066Sahrens break; 590fa9e4066Sahrens case 'm': 591fa9e4066Sahrens mountpoint = optarg; 592fa9e4066Sahrens break; 593990b4856Slling case 'o': 594990b4856Slling if ((propval = strchr(optarg, '=')) == NULL) { 595990b4856Slling (void) fprintf(stderr, gettext("missing " 596990b4856Slling "'=' for -o option\n")); 597990b4856Slling goto errout; 598990b4856Slling } 599990b4856Slling *propval = '\0'; 600990b4856Slling propval++; 601990b4856Slling 602990b4856Slling if (add_prop_list(optarg, propval, &props)) 603990b4856Slling goto errout; 604990b4856Slling break; 605fa9e4066Sahrens case ':': 606fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 607fa9e4066Sahrens "'%c' option\n"), optopt); 608990b4856Slling goto badusage; 609fa9e4066Sahrens case '?': 610fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 611fa9e4066Sahrens optopt); 612990b4856Slling goto badusage; 613fa9e4066Sahrens } 614fa9e4066Sahrens } 615fa9e4066Sahrens 616fa9e4066Sahrens argc -= optind; 617fa9e4066Sahrens argv += optind; 618fa9e4066Sahrens 619fa9e4066Sahrens /* get pool name and check number of arguments */ 620fa9e4066Sahrens if (argc < 1) { 621fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 622990b4856Slling goto badusage; 623fa9e4066Sahrens } 624fa9e4066Sahrens if (argc < 2) { 625fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 626990b4856Slling goto badusage; 627fa9e4066Sahrens } 628fa9e4066Sahrens 629fa9e4066Sahrens poolname = argv[0]; 630fa9e4066Sahrens 631fa9e4066Sahrens /* 632fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 633fa9e4066Sahrens * user to use 'zfs create' instead. 634fa9e4066Sahrens */ 635fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 636fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 637fa9e4066Sahrens "character '/' in pool name\n"), poolname); 638fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 639fa9e4066Sahrens "create a dataset\n")); 640990b4856Slling goto errout; 641fa9e4066Sahrens } 642fa9e4066Sahrens 643fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 64499653d4eSeschrock nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1, 64599653d4eSeschrock argv + 1); 646fa9e4066Sahrens if (nvroot == NULL) 647fa9e4066Sahrens return (1); 648fa9e4066Sahrens 64999653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 65099653d4eSeschrock verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 65199653d4eSeschrock &child, &children) == 0); 65299653d4eSeschrock if (children == 0) { 65399653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 65499653d4eSeschrock "specification: at least one toplevel vdev must be " 65599653d4eSeschrock "specified\n")); 656990b4856Slling goto errout; 65799653d4eSeschrock } 65899653d4eSeschrock 65999653d4eSeschrock 660fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 661fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 662e9dbad6fSeschrock "must be an absolute path\n"), altroot); 663990b4856Slling goto errout; 664fa9e4066Sahrens } 665fa9e4066Sahrens 666fa9e4066Sahrens /* 667fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 668fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 669fa9e4066Sahrens */ 670fa9e4066Sahrens if (mountpoint == NULL || 671fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 672fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 673fa9e4066Sahrens char buf[MAXPATHLEN]; 674fa9e4066Sahrens struct stat64 statbuf; 675fa9e4066Sahrens 676fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 677fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 678fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 679fa9e4066Sahrens "'none'\n"), mountpoint); 680990b4856Slling goto errout; 681fa9e4066Sahrens } 682fa9e4066Sahrens 683fa9e4066Sahrens if (mountpoint == NULL) { 684fa9e4066Sahrens if (altroot != NULL) 685fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 686fa9e4066Sahrens altroot, poolname); 687fa9e4066Sahrens else 688fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 689fa9e4066Sahrens poolname); 690fa9e4066Sahrens } else { 691fa9e4066Sahrens if (altroot != NULL) 692fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 693fa9e4066Sahrens altroot, mountpoint); 694fa9e4066Sahrens else 695fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 696fa9e4066Sahrens mountpoint); 697fa9e4066Sahrens } 698fa9e4066Sahrens 699fa9e4066Sahrens if (stat64(buf, &statbuf) == 0 && 700fa9e4066Sahrens statbuf.st_nlink != 2) { 701fa9e4066Sahrens if (mountpoint == NULL) 702fa9e4066Sahrens (void) fprintf(stderr, gettext("default " 703fa9e4066Sahrens "mountpoint '%s' exists and is not " 704fa9e4066Sahrens "empty\n"), buf); 705fa9e4066Sahrens else 706fa9e4066Sahrens (void) fprintf(stderr, gettext("mountpoint " 707fa9e4066Sahrens "'%s' exists and is not empty\n"), buf); 708fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 709fa9e4066Sahrens "option to provide a different default\n")); 710990b4856Slling goto errout; 711fa9e4066Sahrens } 712fa9e4066Sahrens } 713fa9e4066Sahrens 714fa9e4066Sahrens if (dryrun) { 715fa9e4066Sahrens /* 716fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 717fa9e4066Sahrens * through all the vdevs in the list and print out in an 718fa9e4066Sahrens * appropriate hierarchy. 719fa9e4066Sahrens */ 720fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 721fa9e4066Sahrens "following layout:\n\n"), poolname); 722fa9e4066Sahrens 7238654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 7248654d025Sperrin if (num_logs(nvroot) > 0) 7258654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 726fa9e4066Sahrens 727fa9e4066Sahrens ret = 0; 728fa9e4066Sahrens } else { 729fa9e4066Sahrens /* 730fa9e4066Sahrens * Hand off to libzfs. 731fa9e4066Sahrens */ 732990b4856Slling if (zpool_create(g_zfs, poolname, nvroot, props) == 0) { 73399653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 734fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 735fa9e4066Sahrens if (pool != NULL) { 736fa9e4066Sahrens if (mountpoint != NULL) 737fa9e4066Sahrens verify(zfs_prop_set(pool, 738e9dbad6fSeschrock zfs_prop_to_name( 739e9dbad6fSeschrock ZFS_PROP_MOUNTPOINT), 740fa9e4066Sahrens mountpoint) == 0); 741fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 742da6c28aaSamw ret = zfs_shareall(pool); 743fa9e4066Sahrens zfs_close(pool); 744fa9e4066Sahrens } 74599653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 74699653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 74799653d4eSeschrock "been omitted\n")); 748fa9e4066Sahrens } 749fa9e4066Sahrens } 750fa9e4066Sahrens 751990b4856Slling errout: 752fa9e4066Sahrens nvlist_free(nvroot); 753990b4856Slling nvlist_free(props); 754fa9e4066Sahrens return (ret); 755990b4856Slling badusage: 756990b4856Slling nvlist_free(props); 757990b4856Slling usage(B_FALSE); 758990b4856Slling return (2); 759fa9e4066Sahrens } 760fa9e4066Sahrens 761fa9e4066Sahrens /* 762fa9e4066Sahrens * zpool destroy <pool> 763fa9e4066Sahrens * 764fa9e4066Sahrens * -f Forcefully unmount any datasets 765fa9e4066Sahrens * 766fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 767fa9e4066Sahrens */ 768fa9e4066Sahrens int 769fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 770fa9e4066Sahrens { 77199653d4eSeschrock boolean_t force = B_FALSE; 772fa9e4066Sahrens int c; 773fa9e4066Sahrens char *pool; 774fa9e4066Sahrens zpool_handle_t *zhp; 775fa9e4066Sahrens int ret; 776fa9e4066Sahrens 777fa9e4066Sahrens /* check options */ 778fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 779fa9e4066Sahrens switch (c) { 780fa9e4066Sahrens case 'f': 78199653d4eSeschrock force = B_TRUE; 782fa9e4066Sahrens break; 783fa9e4066Sahrens case '?': 784fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 785fa9e4066Sahrens optopt); 78699653d4eSeschrock usage(B_FALSE); 787fa9e4066Sahrens } 788fa9e4066Sahrens } 789fa9e4066Sahrens 790fa9e4066Sahrens argc -= optind; 791fa9e4066Sahrens argv += optind; 792fa9e4066Sahrens 793fa9e4066Sahrens /* check arguments */ 794fa9e4066Sahrens if (argc < 1) { 795fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 79699653d4eSeschrock usage(B_FALSE); 797fa9e4066Sahrens } 798fa9e4066Sahrens if (argc > 1) { 799fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 80099653d4eSeschrock usage(B_FALSE); 801fa9e4066Sahrens } 802fa9e4066Sahrens 803fa9e4066Sahrens pool = argv[0]; 804fa9e4066Sahrens 80599653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 806fa9e4066Sahrens /* 807fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 808fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 809fa9e4066Sahrens */ 810fa9e4066Sahrens if (strchr(pool, '/') != NULL) 811fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 812fa9e4066Sahrens "destroy a dataset\n")); 813fa9e4066Sahrens return (1); 814fa9e4066Sahrens } 815fa9e4066Sahrens 816f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 817fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 818fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 819fa9e4066Sahrens return (1); 820fa9e4066Sahrens } 821fa9e4066Sahrens 822fa9e4066Sahrens ret = (zpool_destroy(zhp) != 0); 823fa9e4066Sahrens 824fa9e4066Sahrens zpool_close(zhp); 825fa9e4066Sahrens 826fa9e4066Sahrens return (ret); 827fa9e4066Sahrens } 828fa9e4066Sahrens 829fa9e4066Sahrens /* 830fa9e4066Sahrens * zpool export [-f] <pool> ... 831fa9e4066Sahrens * 832fa9e4066Sahrens * -f Forcefully unmount datasets 833fa9e4066Sahrens * 834b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 835fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 836fa9e4066Sahrens * then the datasets will be forcefully unmounted. 837fa9e4066Sahrens */ 838fa9e4066Sahrens int 839fa9e4066Sahrens zpool_do_export(int argc, char **argv) 840fa9e4066Sahrens { 84199653d4eSeschrock boolean_t force = B_FALSE; 842fa9e4066Sahrens int c; 843fa9e4066Sahrens zpool_handle_t *zhp; 844fa9e4066Sahrens int ret; 845fa9e4066Sahrens int i; 846fa9e4066Sahrens 847fa9e4066Sahrens /* check options */ 848fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 849fa9e4066Sahrens switch (c) { 850fa9e4066Sahrens case 'f': 85199653d4eSeschrock force = B_TRUE; 852fa9e4066Sahrens break; 853fa9e4066Sahrens case '?': 854fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 855fa9e4066Sahrens optopt); 85699653d4eSeschrock usage(B_FALSE); 857fa9e4066Sahrens } 858fa9e4066Sahrens } 859fa9e4066Sahrens 860fa9e4066Sahrens argc -= optind; 861fa9e4066Sahrens argv += optind; 862fa9e4066Sahrens 863fa9e4066Sahrens /* check arguments */ 864fa9e4066Sahrens if (argc < 1) { 865fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 86699653d4eSeschrock usage(B_FALSE); 867fa9e4066Sahrens } 868fa9e4066Sahrens 869fa9e4066Sahrens ret = 0; 870fa9e4066Sahrens for (i = 0; i < argc; i++) { 87199653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 872fa9e4066Sahrens ret = 1; 873fa9e4066Sahrens continue; 874fa9e4066Sahrens } 875fa9e4066Sahrens 876f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 877fa9e4066Sahrens ret = 1; 878fa9e4066Sahrens zpool_close(zhp); 879fa9e4066Sahrens continue; 880fa9e4066Sahrens } 881fa9e4066Sahrens 882fa9e4066Sahrens if (zpool_export(zhp) != 0) 883fa9e4066Sahrens ret = 1; 884fa9e4066Sahrens 885fa9e4066Sahrens zpool_close(zhp); 886fa9e4066Sahrens } 887fa9e4066Sahrens 888fa9e4066Sahrens return (ret); 889fa9e4066Sahrens } 890fa9e4066Sahrens 891fa9e4066Sahrens /* 892fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 893fa9e4066Sahrens * name column. 894fa9e4066Sahrens */ 895fa9e4066Sahrens static int 896c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 897fa9e4066Sahrens { 89899653d4eSeschrock char *name = zpool_vdev_name(g_zfs, zhp, nv); 899fa9e4066Sahrens nvlist_t **child; 900fa9e4066Sahrens uint_t c, children; 901fa9e4066Sahrens int ret; 902fa9e4066Sahrens 903fa9e4066Sahrens if (strlen(name) + depth > max) 904fa9e4066Sahrens max = strlen(name) + depth; 905fa9e4066Sahrens 906afefbcddSeschrock free(name); 907afefbcddSeschrock 90899653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 90999653d4eSeschrock &child, &children) == 0) { 910fa9e4066Sahrens for (c = 0; c < children; c++) 91199653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 91299653d4eSeschrock max)) > max) 913fa9e4066Sahrens max = ret; 91499653d4eSeschrock } 91599653d4eSeschrock 916*fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 917*fa94a07fSbrendan &child, &children) == 0) { 918*fa94a07fSbrendan for (c = 0; c < children; c++) 919*fa94a07fSbrendan if ((ret = max_width(zhp, child[c], depth + 2, 920*fa94a07fSbrendan max)) > max) 921*fa94a07fSbrendan max = ret; 922*fa94a07fSbrendan } 923*fa94a07fSbrendan 92499653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 92599653d4eSeschrock &child, &children) == 0) { 92699653d4eSeschrock for (c = 0; c < children; c++) 92799653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 92899653d4eSeschrock max)) > max) 92999653d4eSeschrock max = ret; 93099653d4eSeschrock } 93199653d4eSeschrock 932fa9e4066Sahrens 933fa9e4066Sahrens return (max); 934fa9e4066Sahrens } 935fa9e4066Sahrens 936fa9e4066Sahrens 937fa9e4066Sahrens /* 938fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 939fa9e4066Sahrens * pool, printing out the name and status for each one. 940fa9e4066Sahrens */ 941fa9e4066Sahrens void 9428654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth, 9438654d025Sperrin boolean_t print_logs) 944fa9e4066Sahrens { 945fa9e4066Sahrens nvlist_t **child; 946fa9e4066Sahrens uint_t c, children; 947fa9e4066Sahrens vdev_stat_t *vs; 948afefbcddSeschrock char *type, *vname; 949fa9e4066Sahrens 950fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 951fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_MISSING) == 0) 952fa9e4066Sahrens return; 953fa9e4066Sahrens 954fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 955fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 956fa9e4066Sahrens 957fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 958990b4856Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 959fa9e4066Sahrens 960fa9e4066Sahrens if (vs->vs_aux != 0) { 9613d7072f8Seschrock (void) printf(" "); 962fa9e4066Sahrens 963fa9e4066Sahrens switch (vs->vs_aux) { 964fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 965fa9e4066Sahrens (void) printf(gettext("cannot open")); 966fa9e4066Sahrens break; 967fa9e4066Sahrens 968fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 969fa9e4066Sahrens (void) printf(gettext("missing device")); 970fa9e4066Sahrens break; 971fa9e4066Sahrens 972fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 973fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 974fa9e4066Sahrens break; 975fa9e4066Sahrens 976eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 977eaca9bbdSeschrock (void) printf(gettext("newer version")); 978eaca9bbdSeschrock break; 979eaca9bbdSeschrock 9803d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 9813d7072f8Seschrock (void) printf(gettext("too many errors")); 9823d7072f8Seschrock break; 9833d7072f8Seschrock 984fa9e4066Sahrens default: 985fa9e4066Sahrens (void) printf(gettext("corrupted data")); 986fa9e4066Sahrens break; 987fa9e4066Sahrens } 988fa9e4066Sahrens } 989fa9e4066Sahrens (void) printf("\n"); 990fa9e4066Sahrens 991fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 992fa9e4066Sahrens &child, &children) != 0) 993fa9e4066Sahrens return; 994fa9e4066Sahrens 995afefbcddSeschrock for (c = 0; c < children; c++) { 9968654d025Sperrin uint64_t is_log = B_FALSE; 9978654d025Sperrin 9988654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 9998654d025Sperrin &is_log); 10008654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 10018654d025Sperrin continue; 10028654d025Sperrin 100399653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1004afefbcddSeschrock print_import_config(vname, child[c], 10058654d025Sperrin namewidth, depth + 2, B_FALSE); 1006afefbcddSeschrock free(vname); 1007afefbcddSeschrock } 100899653d4eSeschrock 1009*fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1010*fa94a07fSbrendan &child, &children) == 0) { 1011*fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 1012*fa94a07fSbrendan for (c = 0; c < children; c++) { 1013*fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1014*fa94a07fSbrendan (void) printf("\t %s\n", vname); 1015*fa94a07fSbrendan free(vname); 1016*fa94a07fSbrendan } 1017*fa94a07fSbrendan } 101899653d4eSeschrock 1019*fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1020*fa94a07fSbrendan &child, &children) == 0) { 102199653d4eSeschrock (void) printf(gettext("\tspares\n")); 102299653d4eSeschrock for (c = 0; c < children; c++) { 102399653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 102499653d4eSeschrock (void) printf("\t %s\n", vname); 102599653d4eSeschrock free(vname); 102699653d4eSeschrock } 1027fa9e4066Sahrens } 1028*fa94a07fSbrendan } 1029fa9e4066Sahrens 1030fa9e4066Sahrens /* 1031fa9e4066Sahrens * Display the status for the given pool. 1032fa9e4066Sahrens */ 1033fa9e4066Sahrens static void 1034fa9e4066Sahrens show_import(nvlist_t *config) 1035fa9e4066Sahrens { 1036fa9e4066Sahrens uint64_t pool_state; 1037fa9e4066Sahrens vdev_stat_t *vs; 1038fa9e4066Sahrens char *name; 1039fa9e4066Sahrens uint64_t guid; 1040fa9e4066Sahrens char *msgid; 1041fa9e4066Sahrens nvlist_t *nvroot; 1042fa9e4066Sahrens int reason; 104346657f8dSmmusante const char *health; 1044fa9e4066Sahrens uint_t vsc; 1045fa9e4066Sahrens int namewidth; 1046fa9e4066Sahrens 1047fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1048fa9e4066Sahrens &name) == 0); 1049fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1050fa9e4066Sahrens &guid) == 0); 1051fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1052fa9e4066Sahrens &pool_state) == 0); 1053fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1054fa9e4066Sahrens &nvroot) == 0); 1055fa9e4066Sahrens 1056fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1057fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 1058990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1059fa9e4066Sahrens 1060fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1061fa9e4066Sahrens 106246657f8dSmmusante (void) printf(gettext(" pool: %s\n"), name); 106346657f8dSmmusante (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 106446657f8dSmmusante (void) printf(gettext(" state: %s"), health); 10654c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 106646657f8dSmmusante (void) printf(gettext(" (DESTROYED)")); 10674c58d714Sdarrenm (void) printf("\n"); 1068fa9e4066Sahrens 1069fa9e4066Sahrens switch (reason) { 1070fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1071fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1072fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 1073fa9e4066Sahrens (void) printf(gettext("status: One or more devices are missing " 1074fa9e4066Sahrens "from the system.\n")); 1075fa9e4066Sahrens break; 1076fa9e4066Sahrens 1077fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1078fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1079fa9e4066Sahrens (void) printf(gettext("status: One or more devices contains " 1080fa9e4066Sahrens "corrupted data.\n")); 1081fa9e4066Sahrens break; 1082fa9e4066Sahrens 1083fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 1084fa9e4066Sahrens (void) printf(gettext("status: The pool data is corrupted.\n")); 1085fa9e4066Sahrens break; 1086fa9e4066Sahrens 1087441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 1088441d80aaSlling (void) printf(gettext("status: One or more devices " 1089441d80aaSlling "are offlined.\n")); 1090441d80aaSlling break; 1091441d80aaSlling 1092ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 1093ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is " 1094ea8dc4b6Seschrock "corrupted.\n")); 1095ea8dc4b6Seschrock break; 1096ea8dc4b6Seschrock 1097eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 1098eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1099eaca9bbdSeschrock "older on-disk version.\n")); 1100eaca9bbdSeschrock break; 1101eaca9bbdSeschrock 1102eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1103eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1104eaca9bbdSeschrock "incompatible version.\n")); 1105eaca9bbdSeschrock break; 110695173954Sek110237 case ZPOOL_STATUS_HOSTID_MISMATCH: 110795173954Sek110237 (void) printf(gettext("status: The pool was last accessed by " 110895173954Sek110237 "another system.\n")); 110995173954Sek110237 break; 11103d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 11113d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 11123d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 11133d7072f8Seschrock "faulted.\n")); 11143d7072f8Seschrock break; 11153d7072f8Seschrock 1116fa9e4066Sahrens default: 1117fa9e4066Sahrens /* 1118fa9e4066Sahrens * No other status can be seen when importing pools. 1119fa9e4066Sahrens */ 1120fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1121fa9e4066Sahrens } 1122fa9e4066Sahrens 1123fa9e4066Sahrens /* 1124fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1125fa9e4066Sahrens */ 112646657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 1127eaca9bbdSeschrock if (reason == ZPOOL_STATUS_VERSION_OLDER) 1128eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1129eaca9bbdSeschrock "imported using its name or numeric identifier, " 1130eaca9bbdSeschrock "though\n\tsome features will not be available " 1131eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 113295173954Sek110237 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 113395173954Sek110237 (void) printf(gettext("action: The pool can be " 113495173954Sek110237 "imported using its name or numeric " 113595173954Sek110237 "identifier and\n\tthe '-f' flag.\n")); 1136fa9e4066Sahrens else 1137eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1138eaca9bbdSeschrock "imported using its name or numeric " 1139eaca9bbdSeschrock "identifier.\n")); 114046657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1141fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported " 1142fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1143eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1144fa9e4066Sahrens } else { 1145eaca9bbdSeschrock switch (reason) { 1146eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1147eaca9bbdSeschrock (void) printf(gettext("action: The pool cannot be " 1148eaca9bbdSeschrock "imported. Access the pool on a system running " 1149eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1150eaca9bbdSeschrock "backup.\n")); 1151eaca9bbdSeschrock break; 1152eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1153eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1154eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 1155fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1156fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1157fa9e4066Sahrens "again.\n")); 1158eaca9bbdSeschrock break; 1159eaca9bbdSeschrock default: 1160fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1161fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1162fa9e4066Sahrens } 1163eaca9bbdSeschrock } 1164eaca9bbdSeschrock 116546657f8dSmmusante /* 116646657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 116746657f8dSmmusante * is "corrupt data": 116846657f8dSmmusante */ 116946657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 117046657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 117146657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1172eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1173eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1174eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1175eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1176eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 1177eaca9bbdSeschrock "on another system, but can be imported using\n\t" 1178eaca9bbdSeschrock "the '-f' flag.\n")); 1179eaca9bbdSeschrock } 1180fa9e4066Sahrens 1181fa9e4066Sahrens if (msgid != NULL) 1182fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1183fa9e4066Sahrens msgid); 1184fa9e4066Sahrens 1185fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 1186fa9e4066Sahrens 1187c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1188fa9e4066Sahrens if (namewidth < 10) 1189fa9e4066Sahrens namewidth = 10; 11908654d025Sperrin 11918654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_FALSE); 11928654d025Sperrin if (num_logs(nvroot) > 0) { 11938654d025Sperrin (void) printf(gettext("\tlogs\n")); 11948654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_TRUE); 11958654d025Sperrin } 1196fa9e4066Sahrens 1197fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 119846657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1199fa9e4066Sahrens "be part of this pool, though their\n\texact " 120046657f8dSmmusante "configuration cannot be determined.\n")); 1201fa9e4066Sahrens } 1202fa9e4066Sahrens } 1203fa9e4066Sahrens 1204fa9e4066Sahrens /* 1205fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1206990b4856Slling * lifting off to zpool_import_props(), and then mounts the datasets contained 1207990b4856Slling * within the pool. 1208fa9e4066Sahrens */ 1209fa9e4066Sahrens static int 1210fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 1211990b4856Slling int force, nvlist_t *props) 1212fa9e4066Sahrens { 1213fa9e4066Sahrens zpool_handle_t *zhp; 1214fa9e4066Sahrens char *name; 1215fa9e4066Sahrens uint64_t state; 1216eaca9bbdSeschrock uint64_t version; 1217ecd6cf80Smarks int error = 0; 1218fa9e4066Sahrens 1219fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1220fa9e4066Sahrens &name) == 0); 1221fa9e4066Sahrens 1222fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1223fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1224eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1225eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1226e7437265Sahrens if (version > SPA_VERSION) { 1227eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1228eaca9bbdSeschrock "is formatted using a newer ZFS version\n"), name); 1229eaca9bbdSeschrock return (1); 1230eaca9bbdSeschrock } else if (state != POOL_STATE_EXPORTED && !force) { 123195173954Sek110237 uint64_t hostid; 123295173954Sek110237 123395173954Sek110237 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 123495173954Sek110237 &hostid) == 0) { 123595173954Sek110237 if ((unsigned long)hostid != gethostid()) { 123695173954Sek110237 char *hostname; 123795173954Sek110237 uint64_t timestamp; 123895173954Sek110237 time_t t; 123995173954Sek110237 124095173954Sek110237 verify(nvlist_lookup_string(config, 124195173954Sek110237 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 124295173954Sek110237 verify(nvlist_lookup_uint64(config, 124395173954Sek110237 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 124495173954Sek110237 t = timestamp; 124595173954Sek110237 (void) fprintf(stderr, gettext("cannot import " 124695173954Sek110237 "'%s': pool may be in use from other " 124795173954Sek110237 "system, it was last accessed by %s " 124895173954Sek110237 "(hostid: 0x%lx) on %s"), name, hostname, 124995173954Sek110237 (unsigned long)hostid, 125095173954Sek110237 asctime(localtime(&t))); 125195173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to " 125295173954Sek110237 "import anyway\n")); 1253fa9e4066Sahrens return (1); 1254fa9e4066Sahrens } 125595173954Sek110237 } else { 125695173954Sek110237 (void) fprintf(stderr, gettext("cannot import '%s': " 125795173954Sek110237 "pool may be in use from other system\n"), name); 125895173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to import " 125995173954Sek110237 "anyway\n")); 126095173954Sek110237 return (1); 126195173954Sek110237 } 126295173954Sek110237 } 1263fa9e4066Sahrens 1264990b4856Slling if (zpool_import_props(g_zfs, config, newname, props) != 0) 1265fa9e4066Sahrens return (1); 1266fa9e4066Sahrens 1267fa9e4066Sahrens if (newname != NULL) 1268fa9e4066Sahrens name = (char *)newname; 1269fa9e4066Sahrens 127099653d4eSeschrock verify((zhp = zpool_open(g_zfs, name)) != NULL); 1271fa9e4066Sahrens 1272f3861e1aSahl if (zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1273fa9e4066Sahrens zpool_close(zhp); 1274fa9e4066Sahrens return (1); 1275fa9e4066Sahrens } 1276fa9e4066Sahrens 1277fa9e4066Sahrens zpool_close(zhp); 1278ecd6cf80Smarks return (error); 1279fa9e4066Sahrens } 1280fa9e4066Sahrens 1281fa9e4066Sahrens /* 12824c58d714Sdarrenm * zpool import [-d dir] [-D] 12832f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 12842f8aaab3Seschrock * [-d dir | -c cachefile] [-f] -a 12852f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 12862f8aaab3Seschrock * [-d dir | -c cachefile] [-f] <pool | id> [newpool] 12872f8aaab3Seschrock * 12882f8aaab3Seschrock * -c Read pool information from a cachefile instead of searching 12892f8aaab3Seschrock * devices. 1290fa9e4066Sahrens * 1291fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1292fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1293fa9e4066Sahrens * 12944c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 12954c58d714Sdarrenm * specified destroyed pools. 12964c58d714Sdarrenm * 1297fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1298fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1299fa9e4066Sahrens * is rebooted. 1300fa9e4066Sahrens * 1301fa9e4066Sahrens * -f Force import, even if it appears that the pool is active. 1302fa9e4066Sahrens * 1303fa9e4066Sahrens * -a Import all pools found. 1304fa9e4066Sahrens * 1305990b4856Slling * -o Set property=value and/or temporary mount options (without '='). 1306ecd6cf80Smarks * 1307fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 1308fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 1309fa9e4066Sahrens */ 1310fa9e4066Sahrens int 1311fa9e4066Sahrens zpool_do_import(int argc, char **argv) 1312fa9e4066Sahrens { 1313fa9e4066Sahrens char **searchdirs = NULL; 1314fa9e4066Sahrens int nsearch = 0; 1315fa9e4066Sahrens int c; 1316fa9e4066Sahrens int err; 13172f8aaab3Seschrock nvlist_t *pools = NULL; 131899653d4eSeschrock boolean_t do_all = B_FALSE; 131999653d4eSeschrock boolean_t do_destroyed = B_FALSE; 1320fa9e4066Sahrens char *mntopts = NULL; 132199653d4eSeschrock boolean_t do_force = B_FALSE; 1322fa9e4066Sahrens nvpair_t *elem; 1323fa9e4066Sahrens nvlist_t *config; 1324fa9e4066Sahrens uint64_t searchguid; 1325fa9e4066Sahrens char *searchname; 1326990b4856Slling char *propval; 1327fa9e4066Sahrens nvlist_t *found_config; 1328ecd6cf80Smarks nvlist_t *props = NULL; 132999653d4eSeschrock boolean_t first; 13304c58d714Sdarrenm uint64_t pool_state; 13312f8aaab3Seschrock char *cachefile = NULL; 1332fa9e4066Sahrens 1333fa9e4066Sahrens /* check options */ 13342f8aaab3Seschrock while ((c = getopt(argc, argv, ":afc:d:Do:p:R:")) != -1) { 1335fa9e4066Sahrens switch (c) { 1336fa9e4066Sahrens case 'a': 133799653d4eSeschrock do_all = B_TRUE; 1338fa9e4066Sahrens break; 13392f8aaab3Seschrock case 'c': 13402f8aaab3Seschrock cachefile = optarg; 13412f8aaab3Seschrock break; 1342fa9e4066Sahrens case 'd': 1343fa9e4066Sahrens if (searchdirs == NULL) { 1344fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1345fa9e4066Sahrens } else { 1346fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 1347fa9e4066Sahrens sizeof (char *)); 1348fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 1349fa9e4066Sahrens sizeof (char *)); 1350fa9e4066Sahrens free(searchdirs); 1351fa9e4066Sahrens searchdirs = tmp; 1352fa9e4066Sahrens } 1353fa9e4066Sahrens searchdirs[nsearch++] = optarg; 1354fa9e4066Sahrens break; 13554c58d714Sdarrenm case 'D': 135699653d4eSeschrock do_destroyed = B_TRUE; 13574c58d714Sdarrenm break; 1358fa9e4066Sahrens case 'f': 135999653d4eSeschrock do_force = B_TRUE; 1360fa9e4066Sahrens break; 1361fa9e4066Sahrens case 'o': 1362990b4856Slling if ((propval = strchr(optarg, '=')) != NULL) { 1363990b4856Slling *propval = '\0'; 1364990b4856Slling propval++; 1365990b4856Slling if (add_prop_list(optarg, propval, &props)) 1366990b4856Slling goto error; 1367990b4856Slling } else { 1368fa9e4066Sahrens mntopts = optarg; 1369990b4856Slling } 1370fa9e4066Sahrens break; 1371fa9e4066Sahrens case 'R': 1372990b4856Slling if (add_prop_list(zpool_prop_to_name( 1373990b4856Slling ZPOOL_PROP_ALTROOT), optarg, &props)) 1374990b4856Slling goto error; 13752f8aaab3Seschrock if (nvlist_lookup_string(props, 13762f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 13772f8aaab3Seschrock &propval) == 0) 13782f8aaab3Seschrock break; 1379990b4856Slling if (add_prop_list(zpool_prop_to_name( 13802f8aaab3Seschrock ZPOOL_PROP_CACHEFILE), "none", &props)) 1381990b4856Slling goto error; 1382fa9e4066Sahrens break; 1383fa9e4066Sahrens case ':': 1384fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 1385fa9e4066Sahrens "'%c' option\n"), optopt); 138699653d4eSeschrock usage(B_FALSE); 1387fa9e4066Sahrens break; 1388fa9e4066Sahrens case '?': 1389fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1390fa9e4066Sahrens optopt); 139199653d4eSeschrock usage(B_FALSE); 1392fa9e4066Sahrens } 1393fa9e4066Sahrens } 1394fa9e4066Sahrens 1395fa9e4066Sahrens argc -= optind; 1396fa9e4066Sahrens argv += optind; 1397fa9e4066Sahrens 13982f8aaab3Seschrock if (cachefile && nsearch != 0) { 13992f8aaab3Seschrock (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 14002f8aaab3Seschrock usage(B_FALSE); 14012f8aaab3Seschrock } 14022f8aaab3Seschrock 1403fa9e4066Sahrens if (searchdirs == NULL) { 1404fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1405fa9e4066Sahrens searchdirs[0] = "/dev/dsk"; 1406fa9e4066Sahrens nsearch = 1; 1407fa9e4066Sahrens } 1408fa9e4066Sahrens 1409fa9e4066Sahrens /* check argument count */ 1410fa9e4066Sahrens if (do_all) { 1411fa9e4066Sahrens if (argc != 0) { 1412fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 141399653d4eSeschrock usage(B_FALSE); 1414fa9e4066Sahrens } 1415fa9e4066Sahrens } else { 1416fa9e4066Sahrens if (argc > 2) { 1417fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 141899653d4eSeschrock usage(B_FALSE); 1419fa9e4066Sahrens } 1420fa9e4066Sahrens 1421fa9e4066Sahrens /* 1422fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 1423fa9e4066Sahrens * here because otherwise any attempt to discover pools will 1424fa9e4066Sahrens * silently fail. 1425fa9e4066Sahrens */ 1426fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1427fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 1428fa9e4066Sahrens "discover pools: permission denied\n")); 142999653d4eSeschrock free(searchdirs); 1430fa9e4066Sahrens return (1); 1431fa9e4066Sahrens } 1432fa9e4066Sahrens } 1433fa9e4066Sahrens 14342f8aaab3Seschrock if (cachefile) 14352f8aaab3Seschrock pools = zpool_find_import_cached(g_zfs, cachefile); 14362f8aaab3Seschrock else 14372f8aaab3Seschrock pools = zpool_find_import(g_zfs, nsearch, searchdirs); 14382f8aaab3Seschrock 14392f8aaab3Seschrock if (pools == NULL) { 144099653d4eSeschrock free(searchdirs); 1441fa9e4066Sahrens return (1); 144299653d4eSeschrock } 1443fa9e4066Sahrens 1444fa9e4066Sahrens /* 1445fa9e4066Sahrens * We now have a list of all available pools in the given directories. 1446fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 1447fa9e4066Sahrens * 1448fa9e4066Sahrens * <none> Iterate through all pools and display information about 1449fa9e4066Sahrens * each one. 1450fa9e4066Sahrens * 1451fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 1452fa9e4066Sahrens * 1453fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 1454fa9e4066Sahrens * name and import that one. 14554c58d714Sdarrenm * 14564c58d714Sdarrenm * -D Above options applies only to destroyed pools. 1457fa9e4066Sahrens */ 1458fa9e4066Sahrens if (argc != 0) { 1459fa9e4066Sahrens char *endptr; 1460fa9e4066Sahrens 1461fa9e4066Sahrens errno = 0; 1462fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 1463fa9e4066Sahrens if (errno != 0 || *endptr != '\0') 1464fa9e4066Sahrens searchname = argv[0]; 1465fa9e4066Sahrens else 1466fa9e4066Sahrens searchname = NULL; 1467fa9e4066Sahrens found_config = NULL; 1468fa9e4066Sahrens } 1469fa9e4066Sahrens 1470fa9e4066Sahrens err = 0; 1471fa9e4066Sahrens elem = NULL; 147299653d4eSeschrock first = B_TRUE; 1473fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1474fa9e4066Sahrens 1475fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 1476fa9e4066Sahrens 14774c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 14784c58d714Sdarrenm &pool_state) == 0); 14794c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 14804c58d714Sdarrenm continue; 14814c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 14824c58d714Sdarrenm continue; 14834c58d714Sdarrenm 1484fa9e4066Sahrens if (argc == 0) { 1485fa9e4066Sahrens if (first) 148699653d4eSeschrock first = B_FALSE; 14873bb79becSeschrock else if (!do_all) 1488fa9e4066Sahrens (void) printf("\n"); 1489fa9e4066Sahrens 1490fa9e4066Sahrens if (do_all) 1491fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 1492990b4856Slling do_force, props); 1493fa9e4066Sahrens else 1494fa9e4066Sahrens show_import(config); 1495fa9e4066Sahrens } else if (searchname != NULL) { 1496fa9e4066Sahrens char *name; 1497fa9e4066Sahrens 1498fa9e4066Sahrens /* 1499fa9e4066Sahrens * We are searching for a pool based on name. 1500fa9e4066Sahrens */ 1501fa9e4066Sahrens verify(nvlist_lookup_string(config, 1502fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1503fa9e4066Sahrens 1504fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 1505fa9e4066Sahrens if (found_config != NULL) { 1506fa9e4066Sahrens (void) fprintf(stderr, gettext( 1507fa9e4066Sahrens "cannot import '%s': more than " 1508fa9e4066Sahrens "one matching pool\n"), searchname); 1509fa9e4066Sahrens (void) fprintf(stderr, gettext( 1510fa9e4066Sahrens "import by numeric ID instead\n")); 151199653d4eSeschrock err = B_TRUE; 1512fa9e4066Sahrens } 1513fa9e4066Sahrens found_config = config; 1514fa9e4066Sahrens } 1515fa9e4066Sahrens } else { 1516fa9e4066Sahrens uint64_t guid; 1517fa9e4066Sahrens 1518fa9e4066Sahrens /* 1519fa9e4066Sahrens * Search for a pool by guid. 1520fa9e4066Sahrens */ 1521fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1522fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1523fa9e4066Sahrens 1524fa9e4066Sahrens if (guid == searchguid) 1525fa9e4066Sahrens found_config = config; 1526fa9e4066Sahrens } 1527fa9e4066Sahrens } 1528fa9e4066Sahrens 1529fa9e4066Sahrens /* 1530fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 1531fa9e4066Sahrens * pool, and then do the import. 1532fa9e4066Sahrens */ 1533fa9e4066Sahrens if (argc != 0 && err == 0) { 1534fa9e4066Sahrens if (found_config == NULL) { 1535fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 1536fa9e4066Sahrens "no such pool available\n"), argv[0]); 153799653d4eSeschrock err = B_TRUE; 1538fa9e4066Sahrens } else { 1539fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 1540990b4856Slling argv[1], mntopts, do_force, props); 1541fa9e4066Sahrens } 1542fa9e4066Sahrens } 1543fa9e4066Sahrens 1544fa9e4066Sahrens /* 1545fa9e4066Sahrens * If we were just looking for pools, report an error if none were 1546fa9e4066Sahrens * found. 1547fa9e4066Sahrens */ 1548fa9e4066Sahrens if (argc == 0 && first) 1549fa9e4066Sahrens (void) fprintf(stderr, 1550fa9e4066Sahrens gettext("no pools available to import\n")); 1551fa9e4066Sahrens 1552ecd6cf80Smarks error: 1553ecd6cf80Smarks nvlist_free(props); 1554fa9e4066Sahrens nvlist_free(pools); 155599653d4eSeschrock free(searchdirs); 1556fa9e4066Sahrens 1557fa9e4066Sahrens return (err ? 1 : 0); 1558fa9e4066Sahrens } 1559fa9e4066Sahrens 1560fa9e4066Sahrens typedef struct iostat_cbdata { 1561fa9e4066Sahrens zpool_list_t *cb_list; 1562fa9e4066Sahrens int cb_verbose; 1563fa9e4066Sahrens int cb_iteration; 1564fa9e4066Sahrens int cb_namewidth; 1565fa9e4066Sahrens } iostat_cbdata_t; 1566fa9e4066Sahrens 1567fa9e4066Sahrens static void 1568fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 1569fa9e4066Sahrens { 1570fa9e4066Sahrens int i = 0; 1571fa9e4066Sahrens 1572fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 1573fa9e4066Sahrens (void) printf("-"); 1574fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1575fa9e4066Sahrens } 1576fa9e4066Sahrens 1577fa9e4066Sahrens static void 1578fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 1579fa9e4066Sahrens { 1580fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 1581fa9e4066Sahrens cb->cb_namewidth, ""); 1582fa9e4066Sahrens (void) printf("%-*s used avail read write read write\n", 1583fa9e4066Sahrens cb->cb_namewidth, "pool"); 1584fa9e4066Sahrens print_iostat_separator(cb); 1585fa9e4066Sahrens } 1586fa9e4066Sahrens 1587fa9e4066Sahrens /* 1588fa9e4066Sahrens * Display a single statistic. 1589fa9e4066Sahrens */ 1590990b4856Slling static void 1591fa9e4066Sahrens print_one_stat(uint64_t value) 1592fa9e4066Sahrens { 1593fa9e4066Sahrens char buf[64]; 1594fa9e4066Sahrens 1595fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 1596fa9e4066Sahrens (void) printf(" %5s", buf); 1597fa9e4066Sahrens } 1598fa9e4066Sahrens 1599fa9e4066Sahrens /* 1600fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 1601fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 1602fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 1603fa9e4066Sahrens */ 1604fa9e4066Sahrens void 1605c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1606c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1607fa9e4066Sahrens { 1608fa9e4066Sahrens nvlist_t **oldchild, **newchild; 1609fa9e4066Sahrens uint_t c, children; 1610fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 1611fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 1612fa9e4066Sahrens uint64_t tdelta; 1613fa9e4066Sahrens double scale; 1614afefbcddSeschrock char *vname; 1615fa9e4066Sahrens 1616fa9e4066Sahrens if (oldnv != NULL) { 1617fa9e4066Sahrens verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1618fa9e4066Sahrens (uint64_t **)&oldvs, &c) == 0); 1619fa9e4066Sahrens } else { 1620fa9e4066Sahrens oldvs = &zerovs; 1621fa9e4066Sahrens } 1622fa9e4066Sahrens 1623fa9e4066Sahrens verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1624fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 1625fa9e4066Sahrens 1626fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 1627fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 1628fa9e4066Sahrens else 1629fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 1630fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1631fa9e4066Sahrens 1632fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1633fa9e4066Sahrens 1634fa9e4066Sahrens if (tdelta == 0) 1635fa9e4066Sahrens scale = 1.0; 1636fa9e4066Sahrens else 1637fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 1638fa9e4066Sahrens 1639fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 1640fa9e4066Sahrens if (newvs->vs_space == 0) { 1641fa9e4066Sahrens (void) printf(" - -"); 1642fa9e4066Sahrens } else { 1643fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 1644fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 1645fa9e4066Sahrens } 1646fa9e4066Sahrens 1647fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1648fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 1649fa9e4066Sahrens 1650fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1651fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1652fa9e4066Sahrens 1653fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1654fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 1655fa9e4066Sahrens 1656fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1657fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1658fa9e4066Sahrens 1659fa9e4066Sahrens (void) printf("\n"); 1660fa9e4066Sahrens 1661fa9e4066Sahrens if (!cb->cb_verbose) 1662fa9e4066Sahrens return; 1663fa9e4066Sahrens 1664fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1665fa9e4066Sahrens &newchild, &children) != 0) 1666fa9e4066Sahrens return; 1667fa9e4066Sahrens 1668fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1669fa9e4066Sahrens &oldchild, &c) != 0) 1670fa9e4066Sahrens return; 1671fa9e4066Sahrens 1672afefbcddSeschrock for (c = 0; c < children; c++) { 167399653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1674c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1675afefbcddSeschrock newchild[c], cb, depth + 2); 1676afefbcddSeschrock free(vname); 1677afefbcddSeschrock } 1678*fa94a07fSbrendan 1679*fa94a07fSbrendan /* 1680*fa94a07fSbrendan * Include level 2 ARC devices in iostat output 1681*fa94a07fSbrendan */ 1682*fa94a07fSbrendan if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 1683*fa94a07fSbrendan &newchild, &children) != 0) 1684*fa94a07fSbrendan return; 1685*fa94a07fSbrendan 1686*fa94a07fSbrendan if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 1687*fa94a07fSbrendan &oldchild, &c) != 0) 1688*fa94a07fSbrendan return; 1689*fa94a07fSbrendan 1690*fa94a07fSbrendan if (children > 0) { 1691*fa94a07fSbrendan (void) printf("%-*s - - - - - " 1692*fa94a07fSbrendan "-\n", cb->cb_namewidth, "cache"); 1693*fa94a07fSbrendan for (c = 0; c < children; c++) { 1694*fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1695*fa94a07fSbrendan print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1696*fa94a07fSbrendan newchild[c], cb, depth + 2); 1697*fa94a07fSbrendan free(vname); 1698*fa94a07fSbrendan } 1699*fa94a07fSbrendan } 1700fa9e4066Sahrens } 1701fa9e4066Sahrens 1702088e9d47Seschrock static int 1703088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 1704088e9d47Seschrock { 1705088e9d47Seschrock iostat_cbdata_t *cb = data; 170694de1d4cSeschrock boolean_t missing; 1707088e9d47Seschrock 1708088e9d47Seschrock /* 1709088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 1710088e9d47Seschrock */ 171194de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 171294de1d4cSeschrock return (-1); 171394de1d4cSeschrock 171494de1d4cSeschrock if (missing) 1715088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 1716088e9d47Seschrock 1717088e9d47Seschrock return (0); 1718088e9d47Seschrock } 1719088e9d47Seschrock 1720fa9e4066Sahrens /* 1721fa9e4066Sahrens * Callback to print out the iostats for the given pool. 1722fa9e4066Sahrens */ 1723fa9e4066Sahrens int 1724fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 1725fa9e4066Sahrens { 1726fa9e4066Sahrens iostat_cbdata_t *cb = data; 1727fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 1728fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 1729fa9e4066Sahrens 1730088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 1731fa9e4066Sahrens 1732088e9d47Seschrock if (cb->cb_iteration == 1) 1733fa9e4066Sahrens oldconfig = NULL; 1734fa9e4066Sahrens 1735fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1736fa9e4066Sahrens &newnvroot) == 0); 1737fa9e4066Sahrens 1738088e9d47Seschrock if (oldconfig == NULL) 1739fa9e4066Sahrens oldnvroot = NULL; 1740088e9d47Seschrock else 1741088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 1742088e9d47Seschrock &oldnvroot) == 0); 1743fa9e4066Sahrens 1744fa9e4066Sahrens /* 1745fa9e4066Sahrens * Print out the statistics for the pool. 1746fa9e4066Sahrens */ 1747c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1748fa9e4066Sahrens 1749fa9e4066Sahrens if (cb->cb_verbose) 1750fa9e4066Sahrens print_iostat_separator(cb); 1751fa9e4066Sahrens 1752fa9e4066Sahrens return (0); 1753fa9e4066Sahrens } 1754fa9e4066Sahrens 1755fa9e4066Sahrens int 1756fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 1757fa9e4066Sahrens { 1758fa9e4066Sahrens iostat_cbdata_t *cb = data; 1759fa9e4066Sahrens nvlist_t *config, *nvroot; 1760fa9e4066Sahrens 1761088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 1762fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1763fa9e4066Sahrens &nvroot) == 0); 1764fa9e4066Sahrens if (!cb->cb_verbose) 1765fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1766fa9e4066Sahrens else 1767c67d9675Seschrock cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 1768fa9e4066Sahrens } 1769fa9e4066Sahrens 1770fa9e4066Sahrens /* 1771fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 1772fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 1773fa9e4066Sahrens */ 1774fa9e4066Sahrens if (cb->cb_namewidth < 10) 1775fa9e4066Sahrens cb->cb_namewidth = 10; 1776fa9e4066Sahrens if (cb->cb_namewidth > 38) 1777fa9e4066Sahrens cb->cb_namewidth = 38; 1778fa9e4066Sahrens 1779fa9e4066Sahrens return (0); 1780fa9e4066Sahrens } 1781fa9e4066Sahrens 1782fa9e4066Sahrens /* 1783fa9e4066Sahrens * zpool iostat [-v] [pool] ... [interval [count]] 1784fa9e4066Sahrens * 1785fa9e4066Sahrens * -v Display statistics for individual vdevs 1786fa9e4066Sahrens * 1787fa9e4066Sahrens * This command can be tricky because we want to be able to deal with pool 1788fa9e4066Sahrens * creation/destruction as well as vdev configuration changes. The bulk of this 1789fa9e4066Sahrens * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1790fa9e4066Sahrens * on pool_list_update() to detect the addition of new pools. Configuration 1791fa9e4066Sahrens * changes are all handled within libzfs. 1792fa9e4066Sahrens */ 1793fa9e4066Sahrens int 1794fa9e4066Sahrens zpool_do_iostat(int argc, char **argv) 1795fa9e4066Sahrens { 1796fa9e4066Sahrens int c; 1797fa9e4066Sahrens int ret; 1798fa9e4066Sahrens int npools; 1799fa9e4066Sahrens unsigned long interval = 0, count = 0; 1800fa9e4066Sahrens zpool_list_t *list; 180199653d4eSeschrock boolean_t verbose = B_FALSE; 1802fa9e4066Sahrens iostat_cbdata_t cb; 1803fa9e4066Sahrens 1804fa9e4066Sahrens /* check options */ 1805fa9e4066Sahrens while ((c = getopt(argc, argv, "v")) != -1) { 1806fa9e4066Sahrens switch (c) { 1807fa9e4066Sahrens case 'v': 180899653d4eSeschrock verbose = B_TRUE; 1809fa9e4066Sahrens break; 1810fa9e4066Sahrens case '?': 1811fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1812fa9e4066Sahrens optopt); 181399653d4eSeschrock usage(B_FALSE); 1814fa9e4066Sahrens } 1815fa9e4066Sahrens } 1816fa9e4066Sahrens 1817fa9e4066Sahrens argc -= optind; 1818fa9e4066Sahrens argv += optind; 1819fa9e4066Sahrens 1820fa9e4066Sahrens /* 1821fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 1822fa9e4066Sahrens */ 1823fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1824fa9e4066Sahrens char *end; 1825fa9e4066Sahrens 1826fa9e4066Sahrens errno = 0; 1827fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1828fa9e4066Sahrens 1829fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1830fa9e4066Sahrens if (interval == 0) { 1831fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1832fa9e4066Sahrens "cannot be zero\n")); 183399653d4eSeschrock usage(B_FALSE); 1834fa9e4066Sahrens } 1835fa9e4066Sahrens 1836fa9e4066Sahrens /* 1837fa9e4066Sahrens * Ignore the last parameter 1838fa9e4066Sahrens */ 1839fa9e4066Sahrens argc--; 1840fa9e4066Sahrens } else { 1841fa9e4066Sahrens /* 1842fa9e4066Sahrens * If this is not a valid number, just plow on. The 1843fa9e4066Sahrens * user will get a more informative error message later 1844fa9e4066Sahrens * on. 1845fa9e4066Sahrens */ 1846fa9e4066Sahrens interval = 0; 1847fa9e4066Sahrens } 1848fa9e4066Sahrens } 1849fa9e4066Sahrens 1850fa9e4066Sahrens /* 1851fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 1852fa9e4066Sahrens * and an integer. 1853fa9e4066Sahrens */ 1854fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1855fa9e4066Sahrens char *end; 1856fa9e4066Sahrens 1857fa9e4066Sahrens errno = 0; 1858fa9e4066Sahrens count = interval; 1859fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1860fa9e4066Sahrens 1861fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1862fa9e4066Sahrens if (interval == 0) { 1863fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1864fa9e4066Sahrens "cannot be zero\n")); 186599653d4eSeschrock usage(B_FALSE); 1866fa9e4066Sahrens } 1867fa9e4066Sahrens 1868fa9e4066Sahrens /* 1869fa9e4066Sahrens * Ignore the last parameter 1870fa9e4066Sahrens */ 1871fa9e4066Sahrens argc--; 1872fa9e4066Sahrens } else { 1873fa9e4066Sahrens interval = 0; 1874fa9e4066Sahrens } 1875fa9e4066Sahrens } 1876fa9e4066Sahrens 1877fa9e4066Sahrens /* 1878fa9e4066Sahrens * Construct the list of all interesting pools. 1879fa9e4066Sahrens */ 1880fa9e4066Sahrens ret = 0; 1881b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 1882fa9e4066Sahrens return (1); 1883fa9e4066Sahrens 188499653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 188599653d4eSeschrock pool_list_free(list); 1886fa9e4066Sahrens return (1); 188799653d4eSeschrock } 1888fa9e4066Sahrens 1889fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 189099653d4eSeschrock pool_list_free(list); 1891fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 1892fa9e4066Sahrens return (1); 1893fa9e4066Sahrens } 1894fa9e4066Sahrens 1895fa9e4066Sahrens /* 1896fa9e4066Sahrens * Enter the main iostat loop. 1897fa9e4066Sahrens */ 1898fa9e4066Sahrens cb.cb_list = list; 1899fa9e4066Sahrens cb.cb_verbose = verbose; 1900fa9e4066Sahrens cb.cb_iteration = 0; 1901fa9e4066Sahrens cb.cb_namewidth = 0; 1902fa9e4066Sahrens 1903fa9e4066Sahrens for (;;) { 1904fa9e4066Sahrens pool_list_update(list); 1905fa9e4066Sahrens 1906fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 1907fa9e4066Sahrens break; 1908fa9e4066Sahrens 1909fa9e4066Sahrens /* 1910088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 1911088e9d47Seschrock * before calculating the maximum name width, so that any 1912088e9d47Seschrock * configuration changes are properly accounted for. 1913088e9d47Seschrock */ 191499653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 1915088e9d47Seschrock 1916088e9d47Seschrock /* 1917fa9e4066Sahrens * Iterate over all pools to determine the maximum width 1918fa9e4066Sahrens * for the pool / device name column across all pools. 1919fa9e4066Sahrens */ 1920fa9e4066Sahrens cb.cb_namewidth = 0; 192199653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 1922fa9e4066Sahrens 1923fa9e4066Sahrens /* 1924fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 1925fa9e4066Sahrens */ 1926fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 1927fa9e4066Sahrens print_iostat_header(&cb); 1928fa9e4066Sahrens 192999653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 1930fa9e4066Sahrens 1931fa9e4066Sahrens /* 1932fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 1933fa9e4066Sahrens * (which prints a separator for us), then print a separator. 1934fa9e4066Sahrens */ 1935fa9e4066Sahrens if (npools > 1 && !verbose) 1936fa9e4066Sahrens print_iostat_separator(&cb); 1937fa9e4066Sahrens 1938fa9e4066Sahrens if (verbose) 1939fa9e4066Sahrens (void) printf("\n"); 1940fa9e4066Sahrens 194139c23413Seschrock /* 194239c23413Seschrock * Flush the output so that redirection to a file isn't buffered 194339c23413Seschrock * indefinitely. 194439c23413Seschrock */ 194539c23413Seschrock (void) fflush(stdout); 194639c23413Seschrock 1947fa9e4066Sahrens if (interval == 0) 1948fa9e4066Sahrens break; 1949fa9e4066Sahrens 1950fa9e4066Sahrens if (count != 0 && --count == 0) 1951fa9e4066Sahrens break; 1952fa9e4066Sahrens 1953fa9e4066Sahrens (void) sleep(interval); 1954fa9e4066Sahrens } 1955fa9e4066Sahrens 1956fa9e4066Sahrens pool_list_free(list); 1957fa9e4066Sahrens 1958fa9e4066Sahrens return (ret); 1959fa9e4066Sahrens } 1960fa9e4066Sahrens 1961fa9e4066Sahrens typedef struct list_cbdata { 196299653d4eSeschrock boolean_t cb_scripted; 196399653d4eSeschrock boolean_t cb_first; 1964990b4856Slling zprop_list_t *cb_proplist; 1965fa9e4066Sahrens } list_cbdata_t; 1966fa9e4066Sahrens 1967fa9e4066Sahrens /* 1968fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 1969fa9e4066Sahrens */ 1970990b4856Slling static void 1971990b4856Slling print_header(zprop_list_t *pl) 1972fa9e4066Sahrens { 1973990b4856Slling const char *header; 1974990b4856Slling boolean_t first = B_TRUE; 1975990b4856Slling boolean_t right_justify; 1976fa9e4066Sahrens 1977990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 1978990b4856Slling if (pl->pl_prop == ZPROP_INVAL) 1979990b4856Slling continue; 1980990b4856Slling 1981990b4856Slling if (!first) 1982fa9e4066Sahrens (void) printf(" "); 1983fa9e4066Sahrens else 1984990b4856Slling first = B_FALSE; 1985fa9e4066Sahrens 1986990b4856Slling header = zpool_prop_column_name(pl->pl_prop); 1987990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 1988990b4856Slling 1989990b4856Slling if (pl->pl_next == NULL && !right_justify) 1990990b4856Slling (void) printf("%s", header); 1991990b4856Slling else if (right_justify) 1992990b4856Slling (void) printf("%*s", pl->pl_width, header); 1993990b4856Slling else 1994990b4856Slling (void) printf("%-*s", pl->pl_width, header); 1995fa9e4066Sahrens } 1996fa9e4066Sahrens 1997fa9e4066Sahrens (void) printf("\n"); 1998fa9e4066Sahrens } 1999fa9e4066Sahrens 2000990b4856Slling /* 2001990b4856Slling * Given a pool and a list of properties, print out all the properties according 2002990b4856Slling * to the described layout. 2003990b4856Slling */ 2004990b4856Slling static void 2005990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 2006990b4856Slling { 2007990b4856Slling boolean_t first = B_TRUE; 2008990b4856Slling char property[ZPOOL_MAXPROPLEN]; 2009990b4856Slling char *propstr; 2010990b4856Slling boolean_t right_justify; 2011990b4856Slling int width; 2012990b4856Slling 2013990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 2014990b4856Slling if (!first) { 2015990b4856Slling if (scripted) 2016990b4856Slling (void) printf("\t"); 2017990b4856Slling else 2018990b4856Slling (void) printf(" "); 2019990b4856Slling } else { 2020990b4856Slling first = B_FALSE; 2021990b4856Slling } 2022990b4856Slling 2023990b4856Slling right_justify = B_FALSE; 2024990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 2025990b4856Slling if (zpool_get_prop(zhp, pl->pl_prop, property, 2026990b4856Slling sizeof (property), NULL) != 0) 2027990b4856Slling propstr = "-"; 2028990b4856Slling else 2029990b4856Slling propstr = property; 2030990b4856Slling 2031990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2032990b4856Slling } else { 2033990b4856Slling propstr = "-"; 2034990b4856Slling } 2035990b4856Slling 2036990b4856Slling width = pl->pl_width; 2037990b4856Slling 2038990b4856Slling /* 2039990b4856Slling * If this is being called in scripted mode, or if this is the 2040990b4856Slling * last column and it is left-justified, don't include a width 2041990b4856Slling * format specifier. 2042990b4856Slling */ 2043990b4856Slling if (scripted || (pl->pl_next == NULL && !right_justify)) 2044990b4856Slling (void) printf("%s", propstr); 2045990b4856Slling else if (right_justify) 2046990b4856Slling (void) printf("%*s", width, propstr); 2047990b4856Slling else 2048990b4856Slling (void) printf("%-*s", width, propstr); 2049990b4856Slling } 2050990b4856Slling 2051990b4856Slling (void) printf("\n"); 2052990b4856Slling } 2053990b4856Slling 2054990b4856Slling /* 2055990b4856Slling * Generic callback function to list a pool. 2056990b4856Slling */ 2057fa9e4066Sahrens int 2058fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data) 2059fa9e4066Sahrens { 2060fa9e4066Sahrens list_cbdata_t *cbp = data; 2061fa9e4066Sahrens 2062fa9e4066Sahrens if (cbp->cb_first) { 2063fa9e4066Sahrens if (!cbp->cb_scripted) 2064990b4856Slling print_header(cbp->cb_proplist); 206599653d4eSeschrock cbp->cb_first = B_FALSE; 2066fa9e4066Sahrens } 2067fa9e4066Sahrens 2068990b4856Slling print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2069fa9e4066Sahrens 2070fa9e4066Sahrens return (0); 2071fa9e4066Sahrens } 2072fa9e4066Sahrens 2073fa9e4066Sahrens /* 2074990b4856Slling * zpool list [-H] [-o prop[,prop]*] [pool] ... 2075fa9e4066Sahrens * 2076990b4856Slling * -H Scripted mode. Don't display headers, and separate properties 2077990b4856Slling * by a single tab. 2078990b4856Slling * -o List of properties to display. Defaults to 2079990b4856Slling * "name,size,used,available,capacity,health,altroot" 2080fa9e4066Sahrens * 2081fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 2082fa9e4066Sahrens * statistics for each one, as well as health status summary. 2083fa9e4066Sahrens */ 2084fa9e4066Sahrens int 2085fa9e4066Sahrens zpool_do_list(int argc, char **argv) 2086fa9e4066Sahrens { 2087fa9e4066Sahrens int c; 2088fa9e4066Sahrens int ret; 2089fa9e4066Sahrens list_cbdata_t cb = { 0 }; 2090990b4856Slling static char default_props[] = 2091990b4856Slling "name,size,used,available,capacity,health,altroot"; 2092990b4856Slling char *props = default_props; 2093fa9e4066Sahrens 2094fa9e4066Sahrens /* check options */ 2095fa9e4066Sahrens while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2096fa9e4066Sahrens switch (c) { 2097fa9e4066Sahrens case 'H': 209899653d4eSeschrock cb.cb_scripted = B_TRUE; 2099fa9e4066Sahrens break; 2100fa9e4066Sahrens case 'o': 2101990b4856Slling props = optarg; 2102fa9e4066Sahrens break; 2103fa9e4066Sahrens case ':': 2104fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2105fa9e4066Sahrens "'%c' option\n"), optopt); 210699653d4eSeschrock usage(B_FALSE); 2107fa9e4066Sahrens break; 2108fa9e4066Sahrens case '?': 2109fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2110fa9e4066Sahrens optopt); 211199653d4eSeschrock usage(B_FALSE); 2112fa9e4066Sahrens } 2113fa9e4066Sahrens } 2114fa9e4066Sahrens 2115fa9e4066Sahrens argc -= optind; 2116fa9e4066Sahrens argv += optind; 2117fa9e4066Sahrens 2118990b4856Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 211999653d4eSeschrock usage(B_FALSE); 2120fa9e4066Sahrens 212199653d4eSeschrock cb.cb_first = B_TRUE; 2122fa9e4066Sahrens 2123990b4856Slling ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2124990b4856Slling list_callback, &cb); 2125990b4856Slling 2126990b4856Slling zprop_free_list(cb.cb_proplist); 2127fa9e4066Sahrens 2128fce7d82bSmmusante if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2129fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 2130fa9e4066Sahrens return (0); 2131fa9e4066Sahrens } 2132fa9e4066Sahrens 2133fa9e4066Sahrens return (ret); 2134fa9e4066Sahrens } 2135fa9e4066Sahrens 2136fa9e4066Sahrens static nvlist_t * 2137fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name) 2138fa9e4066Sahrens { 2139fa9e4066Sahrens nvlist_t **child; 2140fa9e4066Sahrens uint_t c, children; 2141fa9e4066Sahrens nvlist_t *match; 2142fa9e4066Sahrens char *path; 2143fa9e4066Sahrens 2144fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2145fa9e4066Sahrens &child, &children) != 0) { 2146fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2147fa9e4066Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0) 2148fa9e4066Sahrens name += 9; 2149fa9e4066Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0) 2150fa9e4066Sahrens path += 9; 2151fa9e4066Sahrens if (strcmp(name, path) == 0) 2152fa9e4066Sahrens return (nv); 2153fa9e4066Sahrens return (NULL); 2154fa9e4066Sahrens } 2155fa9e4066Sahrens 2156fa9e4066Sahrens for (c = 0; c < children; c++) 2157fa9e4066Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2158fa9e4066Sahrens return (match); 2159fa9e4066Sahrens 2160fa9e4066Sahrens return (NULL); 2161fa9e4066Sahrens } 2162fa9e4066Sahrens 2163fa9e4066Sahrens static int 2164fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 2165fa9e4066Sahrens { 216699653d4eSeschrock boolean_t force = B_FALSE; 2167fa9e4066Sahrens int c; 2168fa9e4066Sahrens nvlist_t *nvroot; 2169fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 2170fa9e4066Sahrens zpool_handle_t *zhp; 217199653d4eSeschrock int ret; 2172fa9e4066Sahrens 2173fa9e4066Sahrens /* check options */ 2174fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2175fa9e4066Sahrens switch (c) { 2176fa9e4066Sahrens case 'f': 217799653d4eSeschrock force = B_TRUE; 2178fa9e4066Sahrens break; 2179fa9e4066Sahrens case '?': 2180fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2181fa9e4066Sahrens optopt); 218299653d4eSeschrock usage(B_FALSE); 2183fa9e4066Sahrens } 2184fa9e4066Sahrens } 2185fa9e4066Sahrens 2186fa9e4066Sahrens argc -= optind; 2187fa9e4066Sahrens argv += optind; 2188fa9e4066Sahrens 2189fa9e4066Sahrens /* get pool name and check number of arguments */ 2190fa9e4066Sahrens if (argc < 1) { 2191fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 219299653d4eSeschrock usage(B_FALSE); 2193fa9e4066Sahrens } 2194fa9e4066Sahrens 2195fa9e4066Sahrens poolname = argv[0]; 2196fa9e4066Sahrens 2197fa9e4066Sahrens if (argc < 2) { 2198fa9e4066Sahrens (void) fprintf(stderr, 2199fa9e4066Sahrens gettext("missing <device> specification\n")); 220099653d4eSeschrock usage(B_FALSE); 2201fa9e4066Sahrens } 2202fa9e4066Sahrens 2203fa9e4066Sahrens old_disk = argv[1]; 2204fa9e4066Sahrens 2205fa9e4066Sahrens if (argc < 3) { 2206fa9e4066Sahrens if (!replacing) { 2207fa9e4066Sahrens (void) fprintf(stderr, 2208fa9e4066Sahrens gettext("missing <new_device> specification\n")); 220999653d4eSeschrock usage(B_FALSE); 2210fa9e4066Sahrens } 2211fa9e4066Sahrens new_disk = old_disk; 2212fa9e4066Sahrens argc -= 1; 2213fa9e4066Sahrens argv += 1; 2214fa9e4066Sahrens } else { 2215fa9e4066Sahrens new_disk = argv[2]; 2216fa9e4066Sahrens argc -= 2; 2217fa9e4066Sahrens argv += 2; 2218fa9e4066Sahrens } 2219fa9e4066Sahrens 2220fa9e4066Sahrens if (argc > 1) { 2221fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 222299653d4eSeschrock usage(B_FALSE); 2223fa9e4066Sahrens } 2224fa9e4066Sahrens 222599653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2226fa9e4066Sahrens return (1); 2227fa9e4066Sahrens 22288488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 2229fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2230fa9e4066Sahrens poolname); 2231fa9e4066Sahrens zpool_close(zhp); 2232fa9e4066Sahrens return (1); 2233fa9e4066Sahrens } 2234fa9e4066Sahrens 22358488aeb5Staylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv); 2236fa9e4066Sahrens if (nvroot == NULL) { 2237fa9e4066Sahrens zpool_close(zhp); 2238fa9e4066Sahrens return (1); 2239fa9e4066Sahrens } 2240fa9e4066Sahrens 224199653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 224299653d4eSeschrock 224399653d4eSeschrock nvlist_free(nvroot); 224499653d4eSeschrock zpool_close(zhp); 224599653d4eSeschrock 224699653d4eSeschrock return (ret); 2247fa9e4066Sahrens } 2248fa9e4066Sahrens 2249fa9e4066Sahrens /* 2250fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 2251fa9e4066Sahrens * 2252fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2253fa9e4066Sahrens * 2254fa9e4066Sahrens * Replace <device> with <new_device>. 2255fa9e4066Sahrens */ 2256fa9e4066Sahrens /* ARGSUSED */ 2257fa9e4066Sahrens int 2258fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 2259fa9e4066Sahrens { 2260fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2261fa9e4066Sahrens } 2262fa9e4066Sahrens 2263fa9e4066Sahrens /* 2264fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 2265fa9e4066Sahrens * 2266fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2267fa9e4066Sahrens * 2268fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 2269fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 2270fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 2271fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 2272fa9e4066Sahrens */ 2273fa9e4066Sahrens int 2274fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 2275fa9e4066Sahrens { 2276fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2277fa9e4066Sahrens } 2278fa9e4066Sahrens 2279fa9e4066Sahrens /* 2280fa9e4066Sahrens * zpool detach [-f] <pool> <device> 2281fa9e4066Sahrens * 2282fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 2283fa9e4066Sahrens * (not supported yet) 2284fa9e4066Sahrens * 2285fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 2286fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 2287fa9e4066Sahrens * has the only valid copy of some data. 2288fa9e4066Sahrens */ 2289fa9e4066Sahrens /* ARGSUSED */ 2290fa9e4066Sahrens int 2291fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 2292fa9e4066Sahrens { 2293fa9e4066Sahrens int c; 2294fa9e4066Sahrens char *poolname, *path; 2295fa9e4066Sahrens zpool_handle_t *zhp; 229699653d4eSeschrock int ret; 2297fa9e4066Sahrens 2298fa9e4066Sahrens /* check options */ 2299fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2300fa9e4066Sahrens switch (c) { 2301fa9e4066Sahrens case 'f': 2302fa9e4066Sahrens case '?': 2303fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2304fa9e4066Sahrens optopt); 230599653d4eSeschrock usage(B_FALSE); 2306fa9e4066Sahrens } 2307fa9e4066Sahrens } 2308fa9e4066Sahrens 2309fa9e4066Sahrens argc -= optind; 2310fa9e4066Sahrens argv += optind; 2311fa9e4066Sahrens 2312fa9e4066Sahrens /* get pool name and check number of arguments */ 2313fa9e4066Sahrens if (argc < 1) { 2314fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 231599653d4eSeschrock usage(B_FALSE); 2316fa9e4066Sahrens } 2317fa9e4066Sahrens 2318fa9e4066Sahrens if (argc < 2) { 2319fa9e4066Sahrens (void) fprintf(stderr, 2320fa9e4066Sahrens gettext("missing <device> specification\n")); 232199653d4eSeschrock usage(B_FALSE); 2322fa9e4066Sahrens } 2323fa9e4066Sahrens 2324fa9e4066Sahrens poolname = argv[0]; 2325fa9e4066Sahrens path = argv[1]; 2326fa9e4066Sahrens 232799653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2328fa9e4066Sahrens return (1); 2329fa9e4066Sahrens 233099653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 233199653d4eSeschrock 233299653d4eSeschrock zpool_close(zhp); 233399653d4eSeschrock 233499653d4eSeschrock return (ret); 2335fa9e4066Sahrens } 2336fa9e4066Sahrens 2337fa9e4066Sahrens /* 2338441d80aaSlling * zpool online <pool> <device> ... 2339fa9e4066Sahrens */ 2340fa9e4066Sahrens int 2341fa9e4066Sahrens zpool_do_online(int argc, char **argv) 2342fa9e4066Sahrens { 2343fa9e4066Sahrens int c, i; 2344fa9e4066Sahrens char *poolname; 2345fa9e4066Sahrens zpool_handle_t *zhp; 2346fa9e4066Sahrens int ret = 0; 23473d7072f8Seschrock vdev_state_t newstate; 2348fa9e4066Sahrens 2349fa9e4066Sahrens /* check options */ 2350fa9e4066Sahrens while ((c = getopt(argc, argv, "t")) != -1) { 2351fa9e4066Sahrens switch (c) { 2352fa9e4066Sahrens case 't': 2353fa9e4066Sahrens case '?': 2354fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2355fa9e4066Sahrens optopt); 235699653d4eSeschrock usage(B_FALSE); 2357fa9e4066Sahrens } 2358fa9e4066Sahrens } 2359fa9e4066Sahrens 2360fa9e4066Sahrens argc -= optind; 2361fa9e4066Sahrens argv += optind; 2362fa9e4066Sahrens 2363fa9e4066Sahrens /* get pool name and check number of arguments */ 2364fa9e4066Sahrens if (argc < 1) { 2365fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 236699653d4eSeschrock usage(B_FALSE); 2367fa9e4066Sahrens } 2368fa9e4066Sahrens if (argc < 2) { 2369fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 237099653d4eSeschrock usage(B_FALSE); 2371fa9e4066Sahrens } 2372fa9e4066Sahrens 2373fa9e4066Sahrens poolname = argv[0]; 2374fa9e4066Sahrens 237599653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2376fa9e4066Sahrens return (1); 2377fa9e4066Sahrens 23783d7072f8Seschrock for (i = 1; i < argc; i++) { 23793d7072f8Seschrock if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) { 23803d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 23813d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 23823d7072f8Seschrock "onlined, but remains in faulted state\n"), 2383fa9e4066Sahrens argv[i]); 23843d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 23853d7072f8Seschrock (void) printf(gettext("use 'zpool " 23863d7072f8Seschrock "clear' to restore a faulted " 23873d7072f8Seschrock "device\n")); 2388fa9e4066Sahrens else 23893d7072f8Seschrock (void) printf(gettext("use 'zpool " 23903d7072f8Seschrock "replace' to replace devices " 23913d7072f8Seschrock "that are no longer present\n")); 23923d7072f8Seschrock } 23933d7072f8Seschrock } else { 2394fa9e4066Sahrens ret = 1; 23953d7072f8Seschrock } 23963d7072f8Seschrock } 2397fa9e4066Sahrens 239899653d4eSeschrock zpool_close(zhp); 239999653d4eSeschrock 2400fa9e4066Sahrens return (ret); 2401fa9e4066Sahrens } 2402fa9e4066Sahrens 2403fa9e4066Sahrens /* 2404441d80aaSlling * zpool offline [-ft] <pool> <device> ... 2405fa9e4066Sahrens * 2406fa9e4066Sahrens * -f Force the device into the offline state, even if doing 2407fa9e4066Sahrens * so would appear to compromise pool availability. 2408fa9e4066Sahrens * (not supported yet) 2409fa9e4066Sahrens * 2410fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 2411fa9e4066Sahrens * state will not be persistent across reboots. 2412fa9e4066Sahrens */ 2413fa9e4066Sahrens /* ARGSUSED */ 2414fa9e4066Sahrens int 2415fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 2416fa9e4066Sahrens { 2417fa9e4066Sahrens int c, i; 2418fa9e4066Sahrens char *poolname; 2419fa9e4066Sahrens zpool_handle_t *zhp; 242099653d4eSeschrock int ret = 0; 242199653d4eSeschrock boolean_t istmp = B_FALSE; 2422fa9e4066Sahrens 2423fa9e4066Sahrens /* check options */ 2424fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 2425fa9e4066Sahrens switch (c) { 2426fa9e4066Sahrens case 't': 242799653d4eSeschrock istmp = B_TRUE; 2428441d80aaSlling break; 2429441d80aaSlling case 'f': 2430fa9e4066Sahrens case '?': 2431fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2432fa9e4066Sahrens optopt); 243399653d4eSeschrock usage(B_FALSE); 2434fa9e4066Sahrens } 2435fa9e4066Sahrens } 2436fa9e4066Sahrens 2437fa9e4066Sahrens argc -= optind; 2438fa9e4066Sahrens argv += optind; 2439fa9e4066Sahrens 2440fa9e4066Sahrens /* get pool name and check number of arguments */ 2441fa9e4066Sahrens if (argc < 1) { 2442fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 244399653d4eSeschrock usage(B_FALSE); 2444fa9e4066Sahrens } 2445fa9e4066Sahrens if (argc < 2) { 2446fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 244799653d4eSeschrock usage(B_FALSE); 2448fa9e4066Sahrens } 2449fa9e4066Sahrens 2450fa9e4066Sahrens poolname = argv[0]; 2451fa9e4066Sahrens 245299653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2453fa9e4066Sahrens return (1); 2454fa9e4066Sahrens 24553d7072f8Seschrock for (i = 1; i < argc; i++) { 24563d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2457fa9e4066Sahrens ret = 1; 24583d7072f8Seschrock } 2459fa9e4066Sahrens 246099653d4eSeschrock zpool_close(zhp); 246199653d4eSeschrock 2462fa9e4066Sahrens return (ret); 2463fa9e4066Sahrens } 2464fa9e4066Sahrens 2465ea8dc4b6Seschrock /* 2466ea8dc4b6Seschrock * zpool clear <pool> [device] 2467ea8dc4b6Seschrock * 2468ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 2469ea8dc4b6Seschrock */ 2470ea8dc4b6Seschrock int 2471ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 2472ea8dc4b6Seschrock { 2473ea8dc4b6Seschrock int ret = 0; 2474ea8dc4b6Seschrock zpool_handle_t *zhp; 2475ea8dc4b6Seschrock char *pool, *device; 2476ea8dc4b6Seschrock 2477ea8dc4b6Seschrock if (argc < 2) { 2478ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 247999653d4eSeschrock usage(B_FALSE); 2480ea8dc4b6Seschrock } 2481ea8dc4b6Seschrock 2482ea8dc4b6Seschrock if (argc > 3) { 2483ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 248499653d4eSeschrock usage(B_FALSE); 2485ea8dc4b6Seschrock } 2486ea8dc4b6Seschrock 2487ea8dc4b6Seschrock pool = argv[1]; 2488ea8dc4b6Seschrock device = argc == 3 ? argv[2] : NULL; 2489ea8dc4b6Seschrock 249099653d4eSeschrock if ((zhp = zpool_open(g_zfs, pool)) == NULL) 2491ea8dc4b6Seschrock return (1); 2492ea8dc4b6Seschrock 2493ea8dc4b6Seschrock if (zpool_clear(zhp, device) != 0) 2494ea8dc4b6Seschrock ret = 1; 2495ea8dc4b6Seschrock 2496ea8dc4b6Seschrock zpool_close(zhp); 2497ea8dc4b6Seschrock 2498ea8dc4b6Seschrock return (ret); 2499ea8dc4b6Seschrock } 2500ea8dc4b6Seschrock 2501fa9e4066Sahrens typedef struct scrub_cbdata { 2502fa9e4066Sahrens int cb_type; 250306eeb2adSek110237 int cb_argc; 250406eeb2adSek110237 char **cb_argv; 2505fa9e4066Sahrens } scrub_cbdata_t; 2506fa9e4066Sahrens 2507fa9e4066Sahrens int 2508fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 2509fa9e4066Sahrens { 2510fa9e4066Sahrens scrub_cbdata_t *cb = data; 251106eeb2adSek110237 int err; 2512fa9e4066Sahrens 2513ea8dc4b6Seschrock /* 2514ea8dc4b6Seschrock * Ignore faulted pools. 2515ea8dc4b6Seschrock */ 2516ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2517ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2518ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 2519ea8dc4b6Seschrock return (1); 2520ea8dc4b6Seschrock } 2521ea8dc4b6Seschrock 252206eeb2adSek110237 err = zpool_scrub(zhp, cb->cb_type); 252306eeb2adSek110237 252406eeb2adSek110237 return (err != 0); 2525fa9e4066Sahrens } 2526fa9e4066Sahrens 2527fa9e4066Sahrens /* 2528fa9e4066Sahrens * zpool scrub [-s] <pool> ... 2529fa9e4066Sahrens * 2530fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 2531fa9e4066Sahrens */ 2532fa9e4066Sahrens int 2533fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 2534fa9e4066Sahrens { 2535fa9e4066Sahrens int c; 2536fa9e4066Sahrens scrub_cbdata_t cb; 2537fa9e4066Sahrens 2538fa9e4066Sahrens cb.cb_type = POOL_SCRUB_EVERYTHING; 2539fa9e4066Sahrens 2540fa9e4066Sahrens /* check options */ 2541fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 2542fa9e4066Sahrens switch (c) { 2543fa9e4066Sahrens case 's': 2544fa9e4066Sahrens cb.cb_type = POOL_SCRUB_NONE; 2545fa9e4066Sahrens break; 2546fa9e4066Sahrens case '?': 2547fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2548fa9e4066Sahrens optopt); 254999653d4eSeschrock usage(B_FALSE); 2550fa9e4066Sahrens } 2551fa9e4066Sahrens } 2552fa9e4066Sahrens 255306eeb2adSek110237 cb.cb_argc = argc; 255406eeb2adSek110237 cb.cb_argv = argv; 2555fa9e4066Sahrens argc -= optind; 2556fa9e4066Sahrens argv += optind; 2557fa9e4066Sahrens 2558fa9e4066Sahrens if (argc < 1) { 2559fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 256099653d4eSeschrock usage(B_FALSE); 2561fa9e4066Sahrens } 2562fa9e4066Sahrens 2563b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2564fa9e4066Sahrens } 2565fa9e4066Sahrens 2566fa9e4066Sahrens typedef struct status_cbdata { 2567fa9e4066Sahrens int cb_count; 2568e9dbad6fSeschrock boolean_t cb_allpools; 256999653d4eSeschrock boolean_t cb_verbose; 257099653d4eSeschrock boolean_t cb_explain; 257199653d4eSeschrock boolean_t cb_first; 2572fa9e4066Sahrens } status_cbdata_t; 2573fa9e4066Sahrens 2574fa9e4066Sahrens /* 2575fa9e4066Sahrens * Print out detailed scrub status. 2576fa9e4066Sahrens */ 2577fa9e4066Sahrens void 2578fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot) 2579fa9e4066Sahrens { 2580fa9e4066Sahrens vdev_stat_t *vs; 2581fa9e4066Sahrens uint_t vsc; 2582fa9e4066Sahrens time_t start, end, now; 2583fa9e4066Sahrens double fraction_done; 2584fa9e4066Sahrens uint64_t examined, total, minutes_left; 2585fa9e4066Sahrens char *scrub_type; 2586fa9e4066Sahrens 2587fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2588fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 2589fa9e4066Sahrens 2590fa9e4066Sahrens /* 2591fa9e4066Sahrens * If there's never been a scrub, there's not much to say. 2592fa9e4066Sahrens */ 2593fa9e4066Sahrens if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2594fa9e4066Sahrens (void) printf(gettext("none requested\n")); 2595fa9e4066Sahrens return; 2596fa9e4066Sahrens } 2597fa9e4066Sahrens 2598fa9e4066Sahrens scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2599fa9e4066Sahrens "resilver" : "scrub"; 2600fa9e4066Sahrens 2601fa9e4066Sahrens start = vs->vs_scrub_start; 2602fa9e4066Sahrens end = vs->vs_scrub_end; 2603fa9e4066Sahrens now = time(NULL); 2604fa9e4066Sahrens examined = vs->vs_scrub_examined; 2605fa9e4066Sahrens total = vs->vs_alloc; 2606fa9e4066Sahrens 2607fa9e4066Sahrens if (end != 0) { 2608fa9e4066Sahrens (void) printf(gettext("%s %s with %llu errors on %s"), 2609fa9e4066Sahrens scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 2610fa9e4066Sahrens (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2611fa9e4066Sahrens return; 2612fa9e4066Sahrens } 2613fa9e4066Sahrens 2614fa9e4066Sahrens if (examined == 0) 2615fa9e4066Sahrens examined = 1; 2616fa9e4066Sahrens if (examined > total) 2617fa9e4066Sahrens total = examined; 2618fa9e4066Sahrens 2619fa9e4066Sahrens fraction_done = (double)examined / total; 2620fa9e4066Sahrens minutes_left = (uint64_t)((now - start) * 2621fa9e4066Sahrens (1 - fraction_done) / fraction_done / 60); 2622fa9e4066Sahrens 2623fa9e4066Sahrens (void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"), 2624fa9e4066Sahrens scrub_type, 100 * fraction_done, 2625fa9e4066Sahrens (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2626fa9e4066Sahrens } 2627fa9e4066Sahrens 262899653d4eSeschrock typedef struct spare_cbdata { 262999653d4eSeschrock uint64_t cb_guid; 263099653d4eSeschrock zpool_handle_t *cb_zhp; 263199653d4eSeschrock } spare_cbdata_t; 263299653d4eSeschrock 263399653d4eSeschrock static boolean_t 263499653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search) 263599653d4eSeschrock { 263699653d4eSeschrock uint64_t guid; 263799653d4eSeschrock nvlist_t **child; 263899653d4eSeschrock uint_t c, children; 263999653d4eSeschrock 264099653d4eSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 264199653d4eSeschrock search == guid) 264299653d4eSeschrock return (B_TRUE); 264399653d4eSeschrock 264499653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 264599653d4eSeschrock &child, &children) == 0) { 264699653d4eSeschrock for (c = 0; c < children; c++) 264799653d4eSeschrock if (find_vdev(child[c], search)) 264899653d4eSeschrock return (B_TRUE); 264999653d4eSeschrock } 265099653d4eSeschrock 265199653d4eSeschrock return (B_FALSE); 265299653d4eSeschrock } 265399653d4eSeschrock 265499653d4eSeschrock static int 265599653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data) 265699653d4eSeschrock { 265799653d4eSeschrock spare_cbdata_t *cbp = data; 265899653d4eSeschrock nvlist_t *config, *nvroot; 265999653d4eSeschrock 266099653d4eSeschrock config = zpool_get_config(zhp, NULL); 266199653d4eSeschrock verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 266299653d4eSeschrock &nvroot) == 0); 266399653d4eSeschrock 266499653d4eSeschrock if (find_vdev(nvroot, cbp->cb_guid)) { 266599653d4eSeschrock cbp->cb_zhp = zhp; 266699653d4eSeschrock return (1); 266799653d4eSeschrock } 266899653d4eSeschrock 266999653d4eSeschrock zpool_close(zhp); 267099653d4eSeschrock return (0); 267199653d4eSeschrock } 267299653d4eSeschrock 2673fa9e4066Sahrens /* 2674fa9e4066Sahrens * Print out configuration state as requested by status_callback. 2675fa9e4066Sahrens */ 2676fa9e4066Sahrens void 2677c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 26788654d025Sperrin int namewidth, int depth, boolean_t isspare, boolean_t print_logs) 2679fa9e4066Sahrens { 2680fa9e4066Sahrens nvlist_t **child; 2681fa9e4066Sahrens uint_t c, children; 2682fa9e4066Sahrens vdev_stat_t *vs; 2683ea8dc4b6Seschrock char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 2684afefbcddSeschrock char *vname; 2685ea8dc4b6Seschrock uint64_t notpresent; 268699653d4eSeschrock spare_cbdata_t cb; 2687990b4856Slling char *state; 2688fa9e4066Sahrens 2689fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2690fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 2691fa9e4066Sahrens 2692fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2693fa9e4066Sahrens &child, &children) != 0) 2694fa9e4066Sahrens children = 0; 2695fa9e4066Sahrens 2696990b4856Slling state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 269799653d4eSeschrock if (isspare) { 269899653d4eSeschrock /* 269999653d4eSeschrock * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 270099653d4eSeschrock * online drives. 270199653d4eSeschrock */ 270299653d4eSeschrock if (vs->vs_aux == VDEV_AUX_SPARED) 270399653d4eSeschrock state = "INUSE"; 270499653d4eSeschrock else if (vs->vs_state == VDEV_STATE_HEALTHY) 270599653d4eSeschrock state = "AVAIL"; 270699653d4eSeschrock } 2707fa9e4066Sahrens 270899653d4eSeschrock (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 270999653d4eSeschrock name, state); 271099653d4eSeschrock 271199653d4eSeschrock if (!isspare) { 2712fa9e4066Sahrens zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 2713fa9e4066Sahrens zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 2714fa9e4066Sahrens zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 2715fa9e4066Sahrens (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 271699653d4eSeschrock } 2717fa9e4066Sahrens 2718ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2719ea8dc4b6Seschrock ¬present) == 0) { 2720ea8dc4b6Seschrock char *path; 2721ea8dc4b6Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 27220917b783Seschrock (void) printf(" was %s", path); 2723ea8dc4b6Seschrock } else if (vs->vs_aux != 0) { 2724fa9e4066Sahrens (void) printf(" "); 2725fa9e4066Sahrens 2726fa9e4066Sahrens switch (vs->vs_aux) { 2727fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 2728fa9e4066Sahrens (void) printf(gettext("cannot open")); 2729fa9e4066Sahrens break; 2730fa9e4066Sahrens 2731fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 2732fa9e4066Sahrens (void) printf(gettext("missing device")); 2733fa9e4066Sahrens break; 2734fa9e4066Sahrens 2735fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 2736fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 2737fa9e4066Sahrens break; 2738fa9e4066Sahrens 2739eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 2740eaca9bbdSeschrock (void) printf(gettext("newer version")); 2741eaca9bbdSeschrock break; 2742eaca9bbdSeschrock 274399653d4eSeschrock case VDEV_AUX_SPARED: 274499653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 274599653d4eSeschrock &cb.cb_guid) == 0); 274699653d4eSeschrock if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 274799653d4eSeschrock if (strcmp(zpool_get_name(cb.cb_zhp), 274899653d4eSeschrock zpool_get_name(zhp)) == 0) 274999653d4eSeschrock (void) printf(gettext("currently in " 275099653d4eSeschrock "use")); 275199653d4eSeschrock else 275299653d4eSeschrock (void) printf(gettext("in use by " 275399653d4eSeschrock "pool '%s'"), 275499653d4eSeschrock zpool_get_name(cb.cb_zhp)); 275599653d4eSeschrock zpool_close(cb.cb_zhp); 275699653d4eSeschrock } else { 275799653d4eSeschrock (void) printf(gettext("currently in use")); 275899653d4eSeschrock } 275999653d4eSeschrock break; 276099653d4eSeschrock 27613d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 27623d7072f8Seschrock (void) printf(gettext("too many errors")); 27633d7072f8Seschrock break; 27643d7072f8Seschrock 2765fa9e4066Sahrens default: 2766fa9e4066Sahrens (void) printf(gettext("corrupted data")); 2767fa9e4066Sahrens break; 2768fa9e4066Sahrens } 2769fa9e4066Sahrens } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2770fa9e4066Sahrens /* 2771fa9e4066Sahrens * Report bytes resilvered/repaired on leaf devices. 2772fa9e4066Sahrens */ 2773fa9e4066Sahrens zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2774fa9e4066Sahrens (void) printf(gettext(" %s %s"), repaired, 2775fa9e4066Sahrens (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2776fa9e4066Sahrens "resilvered" : "repaired"); 2777fa9e4066Sahrens } 2778fa9e4066Sahrens 2779fa9e4066Sahrens (void) printf("\n"); 2780fa9e4066Sahrens 2781afefbcddSeschrock for (c = 0; c < children; c++) { 27828654d025Sperrin uint64_t is_log = B_FALSE; 27838654d025Sperrin 27848654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 27858654d025Sperrin &is_log); 27868654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 27878654d025Sperrin continue; 278899653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 2789c67d9675Seschrock print_status_config(zhp, vname, child[c], 27908654d025Sperrin namewidth, depth + 2, isspare, B_FALSE); 2791afefbcddSeschrock free(vname); 2792afefbcddSeschrock } 2793fa9e4066Sahrens } 2794fa9e4066Sahrens 2795ea8dc4b6Seschrock static void 2796ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 2797ea8dc4b6Seschrock { 279875519f38Sek110237 nvlist_t *nverrlist = NULL; 279955434c77Sek110237 nvpair_t *elem; 280055434c77Sek110237 char *pathname; 280155434c77Sek110237 size_t len = MAXPATHLEN * 2; 2802ea8dc4b6Seschrock 280355434c77Sek110237 if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2804ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 2805ea8dc4b6Seschrock "(insufficient privileges)\n"); 2806ea8dc4b6Seschrock return; 2807ea8dc4b6Seschrock } 2808ea8dc4b6Seschrock 280955434c77Sek110237 (void) printf("errors: Permanent errors have been " 281055434c77Sek110237 "detected in the following files:\n\n"); 2811ea8dc4b6Seschrock 281255434c77Sek110237 pathname = safe_malloc(len); 281355434c77Sek110237 elem = NULL; 281455434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 281555434c77Sek110237 nvlist_t *nv; 281655434c77Sek110237 uint64_t dsobj, obj; 2817ea8dc4b6Seschrock 281855434c77Sek110237 verify(nvpair_value_nvlist(elem, &nv) == 0); 281955434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 282055434c77Sek110237 &dsobj) == 0); 282155434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 282255434c77Sek110237 &obj) == 0); 282355434c77Sek110237 zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 282455434c77Sek110237 (void) printf("%7s %s\n", "", pathname); 2825ea8dc4b6Seschrock } 282655434c77Sek110237 free(pathname); 282755434c77Sek110237 nvlist_free(nverrlist); 2828ea8dc4b6Seschrock } 2829ea8dc4b6Seschrock 283099653d4eSeschrock static void 283199653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 283299653d4eSeschrock int namewidth) 283399653d4eSeschrock { 283499653d4eSeschrock uint_t i; 283599653d4eSeschrock char *name; 283699653d4eSeschrock 283799653d4eSeschrock if (nspares == 0) 283899653d4eSeschrock return; 283999653d4eSeschrock 284099653d4eSeschrock (void) printf(gettext("\tspares\n")); 284199653d4eSeschrock 284299653d4eSeschrock for (i = 0; i < nspares; i++) { 284399653d4eSeschrock name = zpool_vdev_name(g_zfs, zhp, spares[i]); 284499653d4eSeschrock print_status_config(zhp, name, spares[i], 28458654d025Sperrin namewidth, 2, B_TRUE, B_FALSE); 284699653d4eSeschrock free(name); 284799653d4eSeschrock } 284899653d4eSeschrock } 284999653d4eSeschrock 2850*fa94a07fSbrendan static void 2851*fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 2852*fa94a07fSbrendan int namewidth) 2853*fa94a07fSbrendan { 2854*fa94a07fSbrendan uint_t i; 2855*fa94a07fSbrendan char *name; 2856*fa94a07fSbrendan 2857*fa94a07fSbrendan if (nl2cache == 0) 2858*fa94a07fSbrendan return; 2859*fa94a07fSbrendan 2860*fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 2861*fa94a07fSbrendan 2862*fa94a07fSbrendan for (i = 0; i < nl2cache; i++) { 2863*fa94a07fSbrendan name = zpool_vdev_name(g_zfs, zhp, l2cache[i]); 2864*fa94a07fSbrendan print_status_config(zhp, name, l2cache[i], 2865*fa94a07fSbrendan namewidth, 2, B_FALSE, B_FALSE); 2866*fa94a07fSbrendan free(name); 2867*fa94a07fSbrendan } 2868*fa94a07fSbrendan } 2869*fa94a07fSbrendan 2870fa9e4066Sahrens /* 2871fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 2872fa9e4066Sahrens * 2873fa9e4066Sahrens * pool: tank 2874fa9e4066Sahrens * status: DEGRADED 2875fa9e4066Sahrens * reason: One or more devices ... 2876fa9e4066Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01 2877fa9e4066Sahrens * config: 2878fa9e4066Sahrens * mirror DEGRADED 2879fa9e4066Sahrens * c1t0d0 OK 2880ea8dc4b6Seschrock * c2t0d0 UNAVAIL 2881fa9e4066Sahrens * 2882fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 2883fa9e4066Sahrens * option is specified, then we print out error rate information as well. 2884fa9e4066Sahrens */ 2885fa9e4066Sahrens int 2886fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 2887fa9e4066Sahrens { 2888fa9e4066Sahrens status_cbdata_t *cbp = data; 2889fa9e4066Sahrens nvlist_t *config, *nvroot; 2890fa9e4066Sahrens char *msgid; 2891fa9e4066Sahrens int reason; 289246657f8dSmmusante const char *health; 289346657f8dSmmusante uint_t c; 289446657f8dSmmusante vdev_stat_t *vs; 2895fa9e4066Sahrens 2896088e9d47Seschrock config = zpool_get_config(zhp, NULL); 2897fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 2898fa9e4066Sahrens 2899fa9e4066Sahrens cbp->cb_count++; 2900fa9e4066Sahrens 2901fa9e4066Sahrens /* 2902fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 2903fa9e4066Sahrens * problems. 2904fa9e4066Sahrens */ 2905e9dbad6fSeschrock if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 2906e9dbad6fSeschrock if (!cbp->cb_allpools) { 2907e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 2908e9dbad6fSeschrock zpool_get_name(zhp)); 2909e9dbad6fSeschrock if (cbp->cb_first) 2910e9dbad6fSeschrock cbp->cb_first = B_FALSE; 2911e9dbad6fSeschrock } 2912fa9e4066Sahrens return (0); 2913e9dbad6fSeschrock } 2914fa9e4066Sahrens 2915fa9e4066Sahrens if (cbp->cb_first) 291699653d4eSeschrock cbp->cb_first = B_FALSE; 2917fa9e4066Sahrens else 2918fa9e4066Sahrens (void) printf("\n"); 2919fa9e4066Sahrens 292046657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 292146657f8dSmmusante &nvroot) == 0); 292246657f8dSmmusante verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 292346657f8dSmmusante (uint64_t **)&vs, &c) == 0); 2924990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 2925fa9e4066Sahrens 2926fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 2927fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 2928fa9e4066Sahrens 2929fa9e4066Sahrens switch (reason) { 2930fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 2931fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2932fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 2933fa9e4066Sahrens "continue functioning in a degraded state.\n")); 2934fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2935fa9e4066Sahrens "online it using 'zpool online'.\n")); 2936fa9e4066Sahrens break; 2937fa9e4066Sahrens 2938fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 2939fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2940fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 2941fa9e4066Sahrens "pool to continue functioning.\n")); 2942fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2943fa9e4066Sahrens "online it using 'zpool online'.\n")); 2944fa9e4066Sahrens break; 2945fa9e4066Sahrens 2946fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 2947fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2948fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 2949fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 2950fa9e4066Sahrens "functioning in a degraded state.\n")); 2951fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 2952fa9e4066Sahrens "'zpool replace'.\n")); 2953fa9e4066Sahrens break; 2954fa9e4066Sahrens 2955fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 2956fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2957b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 2958fa9e4066Sahrens "There are insufficient replicas for the pool to " 2959fa9e4066Sahrens "continue\n\tfunctioning.\n")); 2960fa9e4066Sahrens (void) printf(gettext("action: Destroy and re-create the pool " 2961fa9e4066Sahrens "from a backup source.\n")); 2962fa9e4066Sahrens break; 2963fa9e4066Sahrens 2964fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 2965fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2966fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 2967fa9e4066Sahrens "made to correct the error. Applications are " 2968fa9e4066Sahrens "unaffected.\n")); 2969fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 2970fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 2971ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 2972fa9e4066Sahrens "replace'.\n")); 2973fa9e4066Sahrens break; 2974fa9e4066Sahrens 2975fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 2976fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2977d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 2978fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 2979fa9e4066Sahrens "a\n\tdegraded state.\n")); 2980fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 2981fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 2982fa9e4066Sahrens "replace'.\n")); 2983fa9e4066Sahrens break; 2984fa9e4066Sahrens 2985fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 2986fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 2987fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 2988fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 2989fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 2990fa9e4066Sahrens "complete.\n")); 2991fa9e4066Sahrens break; 2992fa9e4066Sahrens 2993ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 2994ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 2995ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 2996ea8dc4b6Seschrock "Applications may be affected.\n")); 2997ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 2998ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 2999ea8dc4b6Seschrock "backup.\n")); 3000ea8dc4b6Seschrock break; 3001ea8dc4b6Seschrock 3002ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 3003ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 3004ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 3005ea8dc4b6Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 3006ea8dc4b6Seschrock "from a backup source.\n")); 3007ea8dc4b6Seschrock break; 3008ea8dc4b6Seschrock 3009eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 3010eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 3011eaca9bbdSeschrock "older on-disk format. The pool can\n\tstill be used, but " 3012eaca9bbdSeschrock "some features are unavailable.\n")); 3013eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 3014eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 3015eaca9bbdSeschrock "be accessible on older software versions.\n")); 3016eaca9bbdSeschrock break; 3017eaca9bbdSeschrock 3018eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 3019eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 3020eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 3021eaca9bbdSeschrock "be accessed on this system.\n")); 3022eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 3023eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 3024eaca9bbdSeschrock "backup.\n")); 3025eaca9bbdSeschrock break; 3026eaca9bbdSeschrock 30273d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 30283d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 30293d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 30303d7072f8Seschrock "replicas exist for the pool to continue functioning " 30313d7072f8Seschrock "in a\n\tdegraded state.\n")); 30323d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 30333d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 30343d7072f8Seschrock break; 30353d7072f8Seschrock 30363d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 30373d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 30383d7072f8Seschrock "faulted in response to persistent errors. There are " 30393d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 30403d7072f8Seschrock "functioning.\n")); 30413d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 30423d7072f8Seschrock "from a backup source. Manually marking the device\n" 30433d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 30443d7072f8Seschrock "to be recovered.\n")); 30453d7072f8Seschrock break; 30463d7072f8Seschrock 3047fa9e4066Sahrens default: 3048fa9e4066Sahrens /* 3049fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 3050fa9e4066Sahrens */ 3051fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 3052fa9e4066Sahrens } 3053fa9e4066Sahrens 3054fa9e4066Sahrens if (msgid != NULL) 3055fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3056fa9e4066Sahrens msgid); 3057fa9e4066Sahrens 3058fa9e4066Sahrens if (config != NULL) { 3059fa9e4066Sahrens int namewidth; 3060ea8dc4b6Seschrock uint64_t nerr; 3061*fa94a07fSbrendan nvlist_t **spares, **l2cache; 3062*fa94a07fSbrendan uint_t nspares, nl2cache; 3063fa9e4066Sahrens 3064fa9e4066Sahrens 3065fa9e4066Sahrens (void) printf(gettext(" scrub: ")); 3066fa9e4066Sahrens print_scrub_status(nvroot); 3067fa9e4066Sahrens 3068c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 3069fa9e4066Sahrens if (namewidth < 10) 3070fa9e4066Sahrens namewidth = 10; 3071fa9e4066Sahrens 3072fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 3073fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3074fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3075c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 30768654d025Sperrin namewidth, 0, B_FALSE, B_FALSE); 30778654d025Sperrin if (num_logs(nvroot) > 0) 30788654d025Sperrin print_status_config(zhp, "logs", nvroot, namewidth, 0, 30798654d025Sperrin B_FALSE, B_TRUE); 308099653d4eSeschrock 3081*fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 3082*fa94a07fSbrendan &l2cache, &nl2cache) == 0) 3083*fa94a07fSbrendan print_l2cache(zhp, l2cache, nl2cache, namewidth); 3084*fa94a07fSbrendan 308599653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 308699653d4eSeschrock &spares, &nspares) == 0) 308799653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 3088ea8dc4b6Seschrock 3089ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3090ea8dc4b6Seschrock &nerr) == 0) { 309155434c77Sek110237 nvlist_t *nverrlist = NULL; 309255434c77Sek110237 3093ea8dc4b6Seschrock /* 3094ea8dc4b6Seschrock * If the approximate error count is small, get a 3095ea8dc4b6Seschrock * precise count by fetching the entire log and 3096ea8dc4b6Seschrock * uniquifying the results. 3097ea8dc4b6Seschrock */ 309875519f38Sek110237 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 309955434c77Sek110237 zpool_get_errlog(zhp, &nverrlist) == 0) { 310055434c77Sek110237 nvpair_t *elem; 310155434c77Sek110237 310255434c77Sek110237 elem = NULL; 310355434c77Sek110237 nerr = 0; 310455434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, 310555434c77Sek110237 elem)) != NULL) { 310655434c77Sek110237 nerr++; 310755434c77Sek110237 } 310855434c77Sek110237 } 310955434c77Sek110237 nvlist_free(nverrlist); 3110ea8dc4b6Seschrock 3111ea8dc4b6Seschrock (void) printf("\n"); 311299653d4eSeschrock 3113ea8dc4b6Seschrock if (nerr == 0) 3114ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 3115ea8dc4b6Seschrock "errors\n")); 3116ea8dc4b6Seschrock else if (!cbp->cb_verbose) 3117e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 31185ad82045Snd150628 "errors, use '-v' for a list\n"), 31195ad82045Snd150628 (u_longlong_t)nerr); 3120ea8dc4b6Seschrock else 3121ea8dc4b6Seschrock print_error_log(zhp); 3122ea8dc4b6Seschrock } 3123fa9e4066Sahrens } else { 3124fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 3125fa9e4066Sahrens "determined.\n")); 3126fa9e4066Sahrens } 3127fa9e4066Sahrens 3128fa9e4066Sahrens return (0); 3129fa9e4066Sahrens } 3130fa9e4066Sahrens 3131fa9e4066Sahrens /* 3132fa9e4066Sahrens * zpool status [-vx] [pool] ... 3133fa9e4066Sahrens * 3134fa9e4066Sahrens * -v Display complete error logs 3135fa9e4066Sahrens * -x Display only pools with potential problems 3136fa9e4066Sahrens * 3137fa9e4066Sahrens * Describes the health status of all pools or some subset. 3138fa9e4066Sahrens */ 3139fa9e4066Sahrens int 3140fa9e4066Sahrens zpool_do_status(int argc, char **argv) 3141fa9e4066Sahrens { 3142fa9e4066Sahrens int c; 3143fa9e4066Sahrens int ret; 3144fa9e4066Sahrens status_cbdata_t cb = { 0 }; 3145fa9e4066Sahrens 3146fa9e4066Sahrens /* check options */ 3147fa9e4066Sahrens while ((c = getopt(argc, argv, "vx")) != -1) { 3148fa9e4066Sahrens switch (c) { 3149fa9e4066Sahrens case 'v': 315099653d4eSeschrock cb.cb_verbose = B_TRUE; 3151fa9e4066Sahrens break; 3152fa9e4066Sahrens case 'x': 315399653d4eSeschrock cb.cb_explain = B_TRUE; 3154fa9e4066Sahrens break; 3155fa9e4066Sahrens case '?': 3156fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3157fa9e4066Sahrens optopt); 315899653d4eSeschrock usage(B_FALSE); 3159fa9e4066Sahrens } 3160fa9e4066Sahrens } 3161fa9e4066Sahrens 3162fa9e4066Sahrens argc -= optind; 3163fa9e4066Sahrens argv += optind; 3164fa9e4066Sahrens 316599653d4eSeschrock cb.cb_first = B_TRUE; 3166fa9e4066Sahrens 3167e9dbad6fSeschrock if (argc == 0) 3168e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 3169e9dbad6fSeschrock 3170b1b8ab34Slling ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3171fa9e4066Sahrens 3172fa9e4066Sahrens if (argc == 0 && cb.cb_count == 0) 3173fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 3174e9dbad6fSeschrock else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3175fa9e4066Sahrens (void) printf(gettext("all pools are healthy\n")); 3176fa9e4066Sahrens 3177fa9e4066Sahrens return (ret); 3178fa9e4066Sahrens } 3179fa9e4066Sahrens 3180eaca9bbdSeschrock typedef struct upgrade_cbdata { 3181eaca9bbdSeschrock int cb_all; 3182eaca9bbdSeschrock int cb_first; 3183eaca9bbdSeschrock int cb_newer; 318406eeb2adSek110237 int cb_argc; 3185990b4856Slling uint64_t cb_version; 318606eeb2adSek110237 char **cb_argv; 3187eaca9bbdSeschrock } upgrade_cbdata_t; 3188eaca9bbdSeschrock 3189eaca9bbdSeschrock static int 3190eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 3191eaca9bbdSeschrock { 3192eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 3193eaca9bbdSeschrock nvlist_t *config; 3194eaca9bbdSeschrock uint64_t version; 3195eaca9bbdSeschrock int ret = 0; 3196eaca9bbdSeschrock 3197eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 3198eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3199eaca9bbdSeschrock &version) == 0); 3200eaca9bbdSeschrock 3201e7437265Sahrens if (!cbp->cb_newer && version < SPA_VERSION) { 3202eaca9bbdSeschrock if (!cbp->cb_all) { 3203eaca9bbdSeschrock if (cbp->cb_first) { 3204eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3205eaca9bbdSeschrock "out of date, and can be upgraded. After " 3206eaca9bbdSeschrock "being\nupgraded, these pools will no " 3207eaca9bbdSeschrock "longer be accessible by older software " 3208eaca9bbdSeschrock "versions.\n\n")); 3209eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3210eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 321199653d4eSeschrock cbp->cb_first = B_FALSE; 3212eaca9bbdSeschrock } 3213eaca9bbdSeschrock 32145ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3215eaca9bbdSeschrock zpool_get_name(zhp)); 3216eaca9bbdSeschrock } else { 321799653d4eSeschrock cbp->cb_first = B_FALSE; 3218990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 321906eeb2adSek110237 if (!ret) { 3220eaca9bbdSeschrock (void) printf(gettext("Successfully upgraded " 3221990b4856Slling "'%s'\n\n"), zpool_get_name(zhp)); 3222eaca9bbdSeschrock } 322306eeb2adSek110237 } 3224e7437265Sahrens } else if (cbp->cb_newer && version > SPA_VERSION) { 3225eaca9bbdSeschrock assert(!cbp->cb_all); 3226eaca9bbdSeschrock 3227eaca9bbdSeschrock if (cbp->cb_first) { 3228eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3229eaca9bbdSeschrock "formatted using a newer software version and\n" 3230eaca9bbdSeschrock "cannot be accessed on the current system.\n\n")); 3231eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3232eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 323399653d4eSeschrock cbp->cb_first = B_FALSE; 3234eaca9bbdSeschrock } 3235eaca9bbdSeschrock 32365ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3237eaca9bbdSeschrock zpool_get_name(zhp)); 3238eaca9bbdSeschrock } 3239eaca9bbdSeschrock 3240eaca9bbdSeschrock zpool_close(zhp); 3241eaca9bbdSeschrock return (ret); 3242eaca9bbdSeschrock } 3243eaca9bbdSeschrock 3244eaca9bbdSeschrock /* ARGSUSED */ 3245eaca9bbdSeschrock static int 324606eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data) 3247eaca9bbdSeschrock { 3248990b4856Slling upgrade_cbdata_t *cbp = data; 3249990b4856Slling uint64_t cur_version; 3250eaca9bbdSeschrock int ret; 3251eaca9bbdSeschrock 32528654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 32538654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 32548654d025Sperrin "Pool 'log' must be renamed using export and import" 32558654d025Sperrin " to upgrade.\n")); 32568654d025Sperrin return (1); 32578654d025Sperrin } 3258990b4856Slling 3259990b4856Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 3260990b4856Slling if (cur_version >= cbp->cb_version) { 3261eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 3262990b4856Slling "using more current version '%d'.\n"), zpool_get_name(zhp), 3263990b4856Slling cur_version); 3264eaca9bbdSeschrock return (0); 3265eaca9bbdSeschrock } 3266eaca9bbdSeschrock 3267990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 326806eeb2adSek110237 326906eeb2adSek110237 if (!ret) { 327044cd46caSbillm (void) printf(gettext("Successfully upgraded '%s' " 3271990b4856Slling "from version %llu to version %llu\n\n"), 3272990b4856Slling zpool_get_name(zhp), (u_longlong_t)cur_version, 3273990b4856Slling (u_longlong_t)cbp->cb_version); 327406eeb2adSek110237 } 3275eaca9bbdSeschrock 3276eaca9bbdSeschrock return (ret != 0); 3277eaca9bbdSeschrock } 3278eaca9bbdSeschrock 3279eaca9bbdSeschrock /* 3280eaca9bbdSeschrock * zpool upgrade 3281eaca9bbdSeschrock * zpool upgrade -v 3282990b4856Slling * zpool upgrade [-V version] <-a | pool ...> 3283eaca9bbdSeschrock * 3284eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 3285eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 3286eaca9bbdSeschrock * upgrade all pools. 3287eaca9bbdSeschrock */ 3288eaca9bbdSeschrock int 3289eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 3290eaca9bbdSeschrock { 3291eaca9bbdSeschrock int c; 3292eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 3293eaca9bbdSeschrock int ret = 0; 3294eaca9bbdSeschrock boolean_t showversions = B_FALSE; 3295990b4856Slling char *end; 3296990b4856Slling 3297eaca9bbdSeschrock 3298eaca9bbdSeschrock /* check options */ 3299990b4856Slling while ((c = getopt(argc, argv, "avV:")) != -1) { 3300eaca9bbdSeschrock switch (c) { 3301eaca9bbdSeschrock case 'a': 330299653d4eSeschrock cb.cb_all = B_TRUE; 3303eaca9bbdSeschrock break; 3304eaca9bbdSeschrock case 'v': 3305eaca9bbdSeschrock showversions = B_TRUE; 3306eaca9bbdSeschrock break; 3307990b4856Slling case 'V': 3308990b4856Slling cb.cb_version = strtoll(optarg, &end, 10); 3309351420b3Slling if (*end != '\0' || cb.cb_version > SPA_VERSION || 3310351420b3Slling cb.cb_version < SPA_VERSION_1) { 3311990b4856Slling (void) fprintf(stderr, 3312990b4856Slling gettext("invalid version '%s'\n"), optarg); 3313990b4856Slling usage(B_FALSE); 3314990b4856Slling } 3315990b4856Slling break; 3316eaca9bbdSeschrock case '?': 3317eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3318eaca9bbdSeschrock optopt); 331999653d4eSeschrock usage(B_FALSE); 3320eaca9bbdSeschrock } 3321eaca9bbdSeschrock } 3322eaca9bbdSeschrock 332306eeb2adSek110237 cb.cb_argc = argc; 332406eeb2adSek110237 cb.cb_argv = argv; 3325eaca9bbdSeschrock argc -= optind; 3326eaca9bbdSeschrock argv += optind; 3327eaca9bbdSeschrock 3328351420b3Slling if (cb.cb_version == 0) { 3329351420b3Slling cb.cb_version = SPA_VERSION; 3330351420b3Slling } else if (!cb.cb_all && argc == 0) { 3331351420b3Slling (void) fprintf(stderr, gettext("-V option is " 3332351420b3Slling "incompatible with other arguments\n")); 3333351420b3Slling usage(B_FALSE); 3334351420b3Slling } 3335351420b3Slling 3336eaca9bbdSeschrock if (showversions) { 3337eaca9bbdSeschrock if (cb.cb_all || argc != 0) { 3338eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 3339eaca9bbdSeschrock "incompatible with other arguments\n")); 334099653d4eSeschrock usage(B_FALSE); 3341eaca9bbdSeschrock } 3342eaca9bbdSeschrock } else if (cb.cb_all) { 3343eaca9bbdSeschrock if (argc != 0) { 3344351420b3Slling (void) fprintf(stderr, gettext("-a option should not " 3345351420b3Slling "be used along with a pool name\n")); 334699653d4eSeschrock usage(B_FALSE); 3347eaca9bbdSeschrock } 3348eaca9bbdSeschrock } 3349eaca9bbdSeschrock 3350e7437265Sahrens (void) printf(gettext("This system is currently running " 3351e7437265Sahrens "ZFS pool version %llu.\n\n"), SPA_VERSION); 335299653d4eSeschrock cb.cb_first = B_TRUE; 3353eaca9bbdSeschrock if (showversions) { 3354eaca9bbdSeschrock (void) printf(gettext("The following versions are " 3355d7d4af51Smmusante "supported:\n\n")); 3356eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 3357eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 3358eaca9bbdSeschrock "---------------\n"); 335999653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 336044cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 336144cd46caSbillm "(replicated metadata)\n")); 336299653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 336399653d4eSeschrock "RAID-Z\n")); 3364d7306b64Sek110237 (void) printf(gettext(" 4 zpool history\n")); 3365c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 3366c9431fa1Sahl "algorithm\n")); 3367990b4856Slling (void) printf(gettext(" 6 bootfs pool property\n")); 33688654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 3369ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 3370a9799022Sck153898 (void) printf(gettext(" 9 refquota and refreservation " 3371a9799022Sck153898 "properties\n")); 3372*fa94a07fSbrendan (void) printf(gettext(" 10 Cache devices\n")); 33738654d025Sperrin (void) printf(gettext("For more information on a particular " 3374eaca9bbdSeschrock "version, including supported releases, see:\n\n")); 3375eaca9bbdSeschrock (void) printf("http://www.opensolaris.org/os/community/zfs/" 3376eaca9bbdSeschrock "version/N\n\n"); 3377eaca9bbdSeschrock (void) printf(gettext("Where 'N' is the version number.\n")); 3378eaca9bbdSeschrock } else if (argc == 0) { 3379eaca9bbdSeschrock int notfound; 3380eaca9bbdSeschrock 338199653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3382eaca9bbdSeschrock notfound = cb.cb_first; 3383eaca9bbdSeschrock 3384eaca9bbdSeschrock if (!cb.cb_all && ret == 0) { 3385eaca9bbdSeschrock if (!cb.cb_first) 3386eaca9bbdSeschrock (void) printf("\n"); 3387eaca9bbdSeschrock cb.cb_first = B_TRUE; 3388eaca9bbdSeschrock cb.cb_newer = B_TRUE; 338999653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3390eaca9bbdSeschrock if (!cb.cb_first) { 3391eaca9bbdSeschrock notfound = B_FALSE; 3392eaca9bbdSeschrock (void) printf("\n"); 3393eaca9bbdSeschrock } 3394eaca9bbdSeschrock } 3395eaca9bbdSeschrock 3396eaca9bbdSeschrock if (ret == 0) { 3397eaca9bbdSeschrock if (notfound) 3398eaca9bbdSeschrock (void) printf(gettext("All pools are formatted " 3399eaca9bbdSeschrock "using this version.\n")); 3400eaca9bbdSeschrock else if (!cb.cb_all) 3401eaca9bbdSeschrock (void) printf(gettext("Use 'zpool upgrade -v' " 3402eaca9bbdSeschrock "for a list of available versions and " 3403eaca9bbdSeschrock "their associated\nfeatures.\n")); 3404eaca9bbdSeschrock } 3405eaca9bbdSeschrock } else { 3406b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 3407b1b8ab34Slling upgrade_one, &cb); 340806eeb2adSek110237 } 340906eeb2adSek110237 341006eeb2adSek110237 return (ret); 341106eeb2adSek110237 } 341206eeb2adSek110237 3413ecd6cf80Smarks typedef struct hist_cbdata { 3414ecd6cf80Smarks boolean_t first; 3415ecd6cf80Smarks int longfmt; 3416ecd6cf80Smarks int internal; 3417ecd6cf80Smarks } hist_cbdata_t; 3418ecd6cf80Smarks 3419ecd6cf80Smarks char *hist_event_table[LOG_END] = { 3420ecd6cf80Smarks "invalid event", 3421ecd6cf80Smarks "pool create", 3422ecd6cf80Smarks "vdev add", 3423ecd6cf80Smarks "pool remove", 3424ecd6cf80Smarks "pool destroy", 3425ecd6cf80Smarks "pool export", 3426ecd6cf80Smarks "pool import", 3427ecd6cf80Smarks "vdev attach", 3428ecd6cf80Smarks "vdev replace", 3429ecd6cf80Smarks "vdev detach", 3430ecd6cf80Smarks "vdev online", 3431ecd6cf80Smarks "vdev offline", 3432ecd6cf80Smarks "vdev upgrade", 3433ecd6cf80Smarks "pool clear", 3434ecd6cf80Smarks "pool scrub", 3435ecd6cf80Smarks "pool property set", 3436ecd6cf80Smarks "create", 3437ecd6cf80Smarks "clone", 3438ecd6cf80Smarks "destroy", 3439ecd6cf80Smarks "destroy_begin_sync", 3440ecd6cf80Smarks "inherit", 3441ecd6cf80Smarks "property set", 3442ecd6cf80Smarks "quota set", 3443ecd6cf80Smarks "permission update", 3444ecd6cf80Smarks "permission remove", 3445ecd6cf80Smarks "permission who remove", 3446ecd6cf80Smarks "promote", 3447ecd6cf80Smarks "receive", 3448ecd6cf80Smarks "rename", 3449ecd6cf80Smarks "reservation set", 3450ecd6cf80Smarks "replay_inc_sync", 3451ecd6cf80Smarks "replay_full_sync", 3452ecd6cf80Smarks "rollback", 3453ecd6cf80Smarks "snapshot", 3454e7437265Sahrens "filesystem version upgrade", 3455a9799022Sck153898 "refquota set", 3456a9799022Sck153898 "refreservation set", 3457ecd6cf80Smarks }; 3458ecd6cf80Smarks 345906eeb2adSek110237 /* 346006eeb2adSek110237 * Print out the command history for a specific pool. 346106eeb2adSek110237 */ 346206eeb2adSek110237 static int 346306eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data) 346406eeb2adSek110237 { 346506eeb2adSek110237 nvlist_t *nvhis; 346606eeb2adSek110237 nvlist_t **records; 346706eeb2adSek110237 uint_t numrecords; 346806eeb2adSek110237 char *cmdstr; 3469ecd6cf80Smarks char *pathstr; 347006eeb2adSek110237 uint64_t dst_time; 347106eeb2adSek110237 time_t tsec; 347206eeb2adSek110237 struct tm t; 347306eeb2adSek110237 char tbuf[30]; 347406eeb2adSek110237 int ret, i; 3475ecd6cf80Smarks uint64_t who; 3476ecd6cf80Smarks struct passwd *pwd; 3477ecd6cf80Smarks char *hostname; 3478ecd6cf80Smarks char *zonename; 3479ecd6cf80Smarks char internalstr[MAXPATHLEN]; 3480ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 3481ecd6cf80Smarks uint64_t txg; 3482ecd6cf80Smarks uint64_t ievent; 348306eeb2adSek110237 3484ecd6cf80Smarks cb->first = B_FALSE; 348506eeb2adSek110237 348606eeb2adSek110237 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 348706eeb2adSek110237 348806eeb2adSek110237 if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 348906eeb2adSek110237 return (ret); 349006eeb2adSek110237 349106eeb2adSek110237 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 349206eeb2adSek110237 &records, &numrecords) == 0); 349306eeb2adSek110237 for (i = 0; i < numrecords; i++) { 349406eeb2adSek110237 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3495ecd6cf80Smarks &dst_time) != 0) 3496ecd6cf80Smarks continue; 3497ecd6cf80Smarks 3498ecd6cf80Smarks /* is it an internal event or a standard event? */ 3499ecd6cf80Smarks if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3500ecd6cf80Smarks &cmdstr) != 0) { 3501ecd6cf80Smarks if (cb->internal == 0) 3502ecd6cf80Smarks continue; 3503ecd6cf80Smarks 3504ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3505ecd6cf80Smarks ZPOOL_HIST_INT_EVENT, &ievent) != 0) 3506ecd6cf80Smarks continue; 3507ecd6cf80Smarks verify(nvlist_lookup_uint64(records[i], 3508ecd6cf80Smarks ZPOOL_HIST_TXG, &txg) == 0); 3509ecd6cf80Smarks verify(nvlist_lookup_string(records[i], 3510ecd6cf80Smarks ZPOOL_HIST_INT_STR, &pathstr) == 0); 3511ecd6cf80Smarks if (ievent > LOG_END) 3512ecd6cf80Smarks continue; 3513ecd6cf80Smarks (void) snprintf(internalstr, 3514ecd6cf80Smarks sizeof (internalstr), 3515ecd6cf80Smarks "[internal %s txg:%lld] %s", 3516ecd6cf80Smarks hist_event_table[ievent], txg, 3517ecd6cf80Smarks pathstr); 3518ecd6cf80Smarks cmdstr = internalstr; 3519ecd6cf80Smarks } 352006eeb2adSek110237 tsec = dst_time; 352106eeb2adSek110237 (void) localtime_r(&tsec, &t); 352206eeb2adSek110237 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3523ecd6cf80Smarks (void) printf("%s %s", tbuf, cmdstr); 3524ecd6cf80Smarks 3525ecd6cf80Smarks if (!cb->longfmt) { 3526ecd6cf80Smarks (void) printf("\n"); 3527ecd6cf80Smarks continue; 352806eeb2adSek110237 } 3529ecd6cf80Smarks (void) printf(" ["); 3530ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3531ecd6cf80Smarks ZPOOL_HIST_WHO, &who) == 0) { 3532ecd6cf80Smarks pwd = getpwuid((uid_t)who); 3533ecd6cf80Smarks if (pwd) 3534ecd6cf80Smarks (void) printf("user %s on", 3535ecd6cf80Smarks pwd->pw_name); 3536ecd6cf80Smarks else 3537ecd6cf80Smarks (void) printf("user %d on", 3538ecd6cf80Smarks (int)who); 3539ecd6cf80Smarks } else { 3540ecd6cf80Smarks (void) printf(gettext("no info]\n")); 3541ecd6cf80Smarks continue; 3542ecd6cf80Smarks } 3543ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3544ecd6cf80Smarks ZPOOL_HIST_HOST, &hostname) == 0) { 3545ecd6cf80Smarks (void) printf(" %s", hostname); 3546ecd6cf80Smarks } 3547ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3548ecd6cf80Smarks ZPOOL_HIST_ZONE, &zonename) == 0) { 3549ecd6cf80Smarks (void) printf(":%s", zonename); 3550ecd6cf80Smarks } 3551ecd6cf80Smarks 3552ecd6cf80Smarks (void) printf("]"); 3553ecd6cf80Smarks (void) printf("\n"); 355406eeb2adSek110237 } 355506eeb2adSek110237 (void) printf("\n"); 355606eeb2adSek110237 nvlist_free(nvhis); 355706eeb2adSek110237 355806eeb2adSek110237 return (ret); 355906eeb2adSek110237 } 356006eeb2adSek110237 356106eeb2adSek110237 /* 356206eeb2adSek110237 * zpool history <pool> 356306eeb2adSek110237 * 356406eeb2adSek110237 * Displays the history of commands that modified pools. 356506eeb2adSek110237 */ 3566ecd6cf80Smarks 3567ecd6cf80Smarks 356806eeb2adSek110237 int 356906eeb2adSek110237 zpool_do_history(int argc, char **argv) 357006eeb2adSek110237 { 3571ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 357206eeb2adSek110237 int ret; 3573ecd6cf80Smarks int c; 357406eeb2adSek110237 3575ecd6cf80Smarks cbdata.first = B_TRUE; 3576ecd6cf80Smarks /* check options */ 3577ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 3578ecd6cf80Smarks switch (c) { 3579ecd6cf80Smarks case 'l': 3580ecd6cf80Smarks cbdata.longfmt = 1; 3581ecd6cf80Smarks break; 3582ecd6cf80Smarks case 'i': 3583ecd6cf80Smarks cbdata.internal = 1; 3584ecd6cf80Smarks break; 3585ecd6cf80Smarks case '?': 3586ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3587ecd6cf80Smarks optopt); 3588ecd6cf80Smarks usage(B_FALSE); 3589ecd6cf80Smarks } 3590ecd6cf80Smarks } 359106eeb2adSek110237 argc -= optind; 359206eeb2adSek110237 argv += optind; 359306eeb2adSek110237 3594b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3595ecd6cf80Smarks &cbdata); 359606eeb2adSek110237 3597ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 359806eeb2adSek110237 (void) printf(gettext("no pools available\n")); 359906eeb2adSek110237 return (0); 3600eaca9bbdSeschrock } 3601eaca9bbdSeschrock 3602eaca9bbdSeschrock return (ret); 3603eaca9bbdSeschrock } 3604eaca9bbdSeschrock 3605b1b8ab34Slling static int 3606b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 3607b1b8ab34Slling { 3608990b4856Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 3609b1b8ab34Slling char value[MAXNAMELEN]; 3610990b4856Slling zprop_source_t srctype; 3611990b4856Slling zprop_list_t *pl; 3612b1b8ab34Slling 3613b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3614b1b8ab34Slling 3615b1b8ab34Slling /* 3616990b4856Slling * Skip the special fake placeholder. This will also skip 3617990b4856Slling * over the name property when 'all' is specified. 3618b1b8ab34Slling */ 3619990b4856Slling if (pl->pl_prop == ZPOOL_PROP_NAME && 3620b1b8ab34Slling pl == cbp->cb_proplist) 3621b1b8ab34Slling continue; 3622b1b8ab34Slling 3623b1b8ab34Slling if (zpool_get_prop(zhp, pl->pl_prop, 3624b1b8ab34Slling value, sizeof (value), &srctype) != 0) 3625b1b8ab34Slling continue; 3626b1b8ab34Slling 3627990b4856Slling zprop_print_one_property(zpool_get_name(zhp), cbp, 3628b1b8ab34Slling zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3629b1b8ab34Slling } 3630b1b8ab34Slling return (0); 3631b1b8ab34Slling } 3632b1b8ab34Slling 3633b1b8ab34Slling int 3634b1b8ab34Slling zpool_do_get(int argc, char **argv) 3635b1b8ab34Slling { 3636990b4856Slling zprop_get_cbdata_t cb = { 0 }; 3637990b4856Slling zprop_list_t fake_name = { 0 }; 3638b1b8ab34Slling int ret; 3639b1b8ab34Slling 3640b1b8ab34Slling if (argc < 3) 3641b1b8ab34Slling usage(B_FALSE); 3642b1b8ab34Slling 3643b1b8ab34Slling cb.cb_first = B_TRUE; 3644990b4856Slling cb.cb_sources = ZPROP_SRC_ALL; 3645b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 3646b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 3647b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 3648b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 3649990b4856Slling cb.cb_type = ZFS_TYPE_POOL; 3650b1b8ab34Slling 3651990b4856Slling if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 3652990b4856Slling ZFS_TYPE_POOL) != 0) 3653b1b8ab34Slling usage(B_FALSE); 3654b1b8ab34Slling 3655b1b8ab34Slling if (cb.cb_proplist != NULL) { 3656990b4856Slling fake_name.pl_prop = ZPOOL_PROP_NAME; 3657b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 3658b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 3659b1b8ab34Slling cb.cb_proplist = &fake_name; 3660b1b8ab34Slling } 3661b1b8ab34Slling 3662b1b8ab34Slling ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3663b1b8ab34Slling get_callback, &cb); 3664b1b8ab34Slling 3665b1b8ab34Slling if (cb.cb_proplist == &fake_name) 3666990b4856Slling zprop_free_list(fake_name.pl_next); 3667b1b8ab34Slling else 3668990b4856Slling zprop_free_list(cb.cb_proplist); 3669b1b8ab34Slling 3670b1b8ab34Slling return (ret); 3671b1b8ab34Slling } 3672b1b8ab34Slling 3673b1b8ab34Slling typedef struct set_cbdata { 3674b1b8ab34Slling char *cb_propname; 3675b1b8ab34Slling char *cb_value; 3676b1b8ab34Slling boolean_t cb_any_successful; 3677b1b8ab34Slling } set_cbdata_t; 3678b1b8ab34Slling 3679b1b8ab34Slling int 3680b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 3681b1b8ab34Slling { 3682b1b8ab34Slling int error; 3683b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 3684b1b8ab34Slling 3685b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3686b1b8ab34Slling 3687b1b8ab34Slling if (!error) 3688b1b8ab34Slling cb->cb_any_successful = B_TRUE; 3689b1b8ab34Slling 3690b1b8ab34Slling return (error); 3691b1b8ab34Slling } 3692b1b8ab34Slling 3693b1b8ab34Slling int 3694b1b8ab34Slling zpool_do_set(int argc, char **argv) 3695b1b8ab34Slling { 3696b1b8ab34Slling set_cbdata_t cb = { 0 }; 3697b1b8ab34Slling int error; 3698b1b8ab34Slling 3699b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 3700b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3701b1b8ab34Slling argv[1][1]); 3702b1b8ab34Slling usage(B_FALSE); 3703b1b8ab34Slling } 3704b1b8ab34Slling 3705b1b8ab34Slling if (argc < 2) { 3706b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 3707b1b8ab34Slling "argument\n")); 3708b1b8ab34Slling usage(B_FALSE); 3709b1b8ab34Slling } 3710b1b8ab34Slling 3711b1b8ab34Slling if (argc < 3) { 3712b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 3713b1b8ab34Slling usage(B_FALSE); 3714b1b8ab34Slling } 3715b1b8ab34Slling 3716b1b8ab34Slling if (argc > 3) { 3717b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 3718b1b8ab34Slling usage(B_FALSE); 3719b1b8ab34Slling } 3720b1b8ab34Slling 3721b1b8ab34Slling cb.cb_propname = argv[1]; 3722b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 3723b1b8ab34Slling if (cb.cb_value == NULL) { 3724b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 3725b1b8ab34Slling "property=value argument\n")); 3726b1b8ab34Slling usage(B_FALSE); 3727b1b8ab34Slling } 3728b1b8ab34Slling 3729b1b8ab34Slling *(cb.cb_value) = '\0'; 3730b1b8ab34Slling cb.cb_value++; 3731b1b8ab34Slling 3732b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3733b1b8ab34Slling set_callback, &cb); 3734b1b8ab34Slling 3735b1b8ab34Slling return (error); 3736b1b8ab34Slling } 3737b1b8ab34Slling 3738b1b8ab34Slling static int 3739b1b8ab34Slling find_command_idx(char *command, int *idx) 3740b1b8ab34Slling { 3741b1b8ab34Slling int i; 3742b1b8ab34Slling 3743b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 3744b1b8ab34Slling if (command_table[i].name == NULL) 3745b1b8ab34Slling continue; 3746b1b8ab34Slling 3747b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 3748b1b8ab34Slling *idx = i; 3749b1b8ab34Slling return (0); 3750b1b8ab34Slling } 3751b1b8ab34Slling } 3752b1b8ab34Slling return (1); 3753b1b8ab34Slling } 3754b1b8ab34Slling 3755fa9e4066Sahrens int 3756fa9e4066Sahrens main(int argc, char **argv) 3757fa9e4066Sahrens { 3758fa9e4066Sahrens int ret; 3759fa9e4066Sahrens int i; 3760fa9e4066Sahrens char *cmdname; 3761fa9e4066Sahrens 3762fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 3763fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 3764fa9e4066Sahrens 376599653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 376699653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 3767203a47d8Snd150628 "initialize ZFS library\n")); 376899653d4eSeschrock return (1); 376999653d4eSeschrock } 377099653d4eSeschrock 377199653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 377299653d4eSeschrock 3773fa9e4066Sahrens opterr = 0; 3774fa9e4066Sahrens 3775fa9e4066Sahrens /* 3776fa9e4066Sahrens * Make sure the user has specified some command. 3777fa9e4066Sahrens */ 3778fa9e4066Sahrens if (argc < 2) { 3779fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 378099653d4eSeschrock usage(B_FALSE); 3781fa9e4066Sahrens } 3782fa9e4066Sahrens 3783fa9e4066Sahrens cmdname = argv[1]; 3784fa9e4066Sahrens 3785fa9e4066Sahrens /* 3786fa9e4066Sahrens * Special case '-?' 3787fa9e4066Sahrens */ 3788fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 378999653d4eSeschrock usage(B_TRUE); 3790fa9e4066Sahrens 37912a6b87f0Sek110237 zpool_set_history_str("zpool", argc, argv, history_str); 37922a6b87f0Sek110237 verify(zpool_stage_history(g_zfs, history_str) == 0); 37932a6b87f0Sek110237 3794fa9e4066Sahrens /* 3795fa9e4066Sahrens * Run the appropriate command. 3796fa9e4066Sahrens */ 3797b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 3798fa9e4066Sahrens current_command = &command_table[i]; 3799fa9e4066Sahrens ret = command_table[i].func(argc - 1, argv + 1); 380091ebeef5Sahrens } else if (strchr(cmdname, '=')) { 380191ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 380291ebeef5Sahrens current_command = &command_table[i]; 380391ebeef5Sahrens ret = command_table[i].func(argc, argv); 380491ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 3805fa9e4066Sahrens /* 380691ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 380791ebeef5Sahrens * it as such. 3808fa9e4066Sahrens */ 3809ea8dc4b6Seschrock char buf[16384]; 3810ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 3811fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 3812fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 381391ebeef5Sahrens } else { 3814fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 3815fa9e4066Sahrens "command '%s'\n"), cmdname); 381699653d4eSeschrock usage(B_FALSE); 3817fa9e4066Sahrens } 3818fa9e4066Sahrens 381999653d4eSeschrock libzfs_fini(g_zfs); 382099653d4eSeschrock 3821fa9e4066Sahrens /* 3822fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3823fa9e4066Sahrens * for the purposes of running ::findleaks. 3824fa9e4066Sahrens */ 3825fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 3826fa9e4066Sahrens (void) printf("dumping core by request\n"); 3827fa9e4066Sahrens abort(); 3828fa9e4066Sahrens } 3829fa9e4066Sahrens 3830fa9e4066Sahrens return (ret); 3831fa9e4066Sahrens } 3832