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 /* 2318ce54dfSek110237 * Copyright 2008 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" 53b7b97454Sperrin #include "zfs_comutil.h" 54fa9e4066Sahrens 55fa9e4066Sahrens static int zpool_do_create(int, char **); 56fa9e4066Sahrens static int zpool_do_destroy(int, char **); 57fa9e4066Sahrens 58fa9e4066Sahrens static int zpool_do_add(int, char **); 5999653d4eSeschrock static int zpool_do_remove(int, char **); 60fa9e4066Sahrens 61fa9e4066Sahrens static int zpool_do_list(int, char **); 62fa9e4066Sahrens static int zpool_do_iostat(int, char **); 63fa9e4066Sahrens static int zpool_do_status(int, char **); 64fa9e4066Sahrens 65fa9e4066Sahrens static int zpool_do_online(int, char **); 66fa9e4066Sahrens static int zpool_do_offline(int, char **); 67ea8dc4b6Seschrock static int zpool_do_clear(int, char **); 68fa9e4066Sahrens 69fa9e4066Sahrens static int zpool_do_attach(int, char **); 70fa9e4066Sahrens static int zpool_do_detach(int, char **); 71fa9e4066Sahrens static int zpool_do_replace(int, char **); 72fa9e4066Sahrens 73fa9e4066Sahrens static int zpool_do_scrub(int, char **); 74fa9e4066Sahrens 75fa9e4066Sahrens static int zpool_do_import(int, char **); 76fa9e4066Sahrens static int zpool_do_export(int, char **); 77fa9e4066Sahrens 78eaca9bbdSeschrock static int zpool_do_upgrade(int, char **); 79eaca9bbdSeschrock 8006eeb2adSek110237 static int zpool_do_history(int, char **); 8106eeb2adSek110237 82b1b8ab34Slling static int zpool_do_get(int, char **); 83b1b8ab34Slling static int zpool_do_set(int, char **); 84b1b8ab34Slling 85fa9e4066Sahrens /* 86fa9e4066Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 87fa9e4066Sahrens * debugging facilities. 88fa9e4066Sahrens */ 89fa9e4066Sahrens const char * 9099653d4eSeschrock _umem_debug_init(void) 91fa9e4066Sahrens { 92fa9e4066Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 93fa9e4066Sahrens } 94fa9e4066Sahrens 95fa9e4066Sahrens const char * 96fa9e4066Sahrens _umem_logging_init(void) 97fa9e4066Sahrens { 98fa9e4066Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 99fa9e4066Sahrens } 100fa9e4066Sahrens 10165cd9f28Seschrock typedef enum { 10265cd9f28Seschrock HELP_ADD, 10365cd9f28Seschrock HELP_ATTACH, 104ea8dc4b6Seschrock HELP_CLEAR, 10565cd9f28Seschrock HELP_CREATE, 10665cd9f28Seschrock HELP_DESTROY, 10765cd9f28Seschrock HELP_DETACH, 10865cd9f28Seschrock HELP_EXPORT, 10906eeb2adSek110237 HELP_HISTORY, 11065cd9f28Seschrock HELP_IMPORT, 11165cd9f28Seschrock HELP_IOSTAT, 11265cd9f28Seschrock HELP_LIST, 11365cd9f28Seschrock HELP_OFFLINE, 11465cd9f28Seschrock HELP_ONLINE, 11565cd9f28Seschrock HELP_REPLACE, 11699653d4eSeschrock HELP_REMOVE, 11765cd9f28Seschrock HELP_SCRUB, 118eaca9bbdSeschrock HELP_STATUS, 119b1b8ab34Slling HELP_UPGRADE, 120b1b8ab34Slling HELP_GET, 121b1b8ab34Slling HELP_SET 12265cd9f28Seschrock } zpool_help_t; 12365cd9f28Seschrock 12465cd9f28Seschrock 125fa9e4066Sahrens typedef struct zpool_command { 126fa9e4066Sahrens const char *name; 127fa9e4066Sahrens int (*func)(int, char **); 12865cd9f28Seschrock zpool_help_t usage; 129fa9e4066Sahrens } zpool_command_t; 130fa9e4066Sahrens 131fa9e4066Sahrens /* 132fa9e4066Sahrens * Master command table. Each ZFS command has a name, associated function, and 133ea8dc4b6Seschrock * usage message. The usage messages need to be internationalized, so we have 134ea8dc4b6Seschrock * to have a function to return the usage message based on a command index. 13565cd9f28Seschrock * 13665cd9f28Seschrock * These commands are organized according to how they are displayed in the usage 13765cd9f28Seschrock * message. An empty command (one with a NULL name) indicates an empty line in 13865cd9f28Seschrock * the generic usage message. 139fa9e4066Sahrens */ 140fa9e4066Sahrens static zpool_command_t command_table[] = { 14165cd9f28Seschrock { "create", zpool_do_create, HELP_CREATE }, 14265cd9f28Seschrock { "destroy", zpool_do_destroy, HELP_DESTROY }, 143fa9e4066Sahrens { NULL }, 14465cd9f28Seschrock { "add", zpool_do_add, HELP_ADD }, 14599653d4eSeschrock { "remove", zpool_do_remove, HELP_REMOVE }, 146fa9e4066Sahrens { NULL }, 14765cd9f28Seschrock { "list", zpool_do_list, HELP_LIST }, 14865cd9f28Seschrock { "iostat", zpool_do_iostat, HELP_IOSTAT }, 14965cd9f28Seschrock { "status", zpool_do_status, HELP_STATUS }, 150fa9e4066Sahrens { NULL }, 15165cd9f28Seschrock { "online", zpool_do_online, HELP_ONLINE }, 15265cd9f28Seschrock { "offline", zpool_do_offline, HELP_OFFLINE }, 153ea8dc4b6Seschrock { "clear", zpool_do_clear, HELP_CLEAR }, 154fa9e4066Sahrens { NULL }, 15565cd9f28Seschrock { "attach", zpool_do_attach, HELP_ATTACH }, 15665cd9f28Seschrock { "detach", zpool_do_detach, HELP_DETACH }, 15765cd9f28Seschrock { "replace", zpool_do_replace, HELP_REPLACE }, 158fa9e4066Sahrens { NULL }, 15965cd9f28Seschrock { "scrub", zpool_do_scrub, HELP_SCRUB }, 160fa9e4066Sahrens { NULL }, 16165cd9f28Seschrock { "import", zpool_do_import, HELP_IMPORT }, 16265cd9f28Seschrock { "export", zpool_do_export, HELP_EXPORT }, 16306eeb2adSek110237 { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 16406eeb2adSek110237 { NULL }, 165b1b8ab34Slling { "history", zpool_do_history, HELP_HISTORY }, 166b1b8ab34Slling { "get", zpool_do_get, HELP_GET }, 167b1b8ab34Slling { "set", zpool_do_set, HELP_SET }, 168fa9e4066Sahrens }; 169fa9e4066Sahrens 170fa9e4066Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 171fa9e4066Sahrens 172fa9e4066Sahrens zpool_command_t *current_command; 1732a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN]; 174fa9e4066Sahrens 17565cd9f28Seschrock static const char * 17665cd9f28Seschrock get_usage(zpool_help_t idx) { 17765cd9f28Seschrock switch (idx) { 17865cd9f28Seschrock case HELP_ADD: 17965cd9f28Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 18065cd9f28Seschrock case HELP_ATTACH: 18165cd9f28Seschrock return (gettext("\tattach [-f] <pool> <device> " 182e45ce728Sahrens "<new-device>\n")); 183ea8dc4b6Seschrock case HELP_CLEAR: 184ea8dc4b6Seschrock return (gettext("\tclear <pool> [device]\n")); 18565cd9f28Seschrock case HELP_CREATE: 186990b4856Slling return (gettext("\tcreate [-fn] [-o property=value] ... \n" 187990b4856Slling "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 18865cd9f28Seschrock case HELP_DESTROY: 18965cd9f28Seschrock return (gettext("\tdestroy [-f] <pool>\n")); 19065cd9f28Seschrock case HELP_DETACH: 19165cd9f28Seschrock return (gettext("\tdetach <pool> <device>\n")); 19265cd9f28Seschrock case HELP_EXPORT: 19365cd9f28Seschrock return (gettext("\texport [-f] <pool> ...\n")); 19406eeb2adSek110237 case HELP_HISTORY: 195ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 19665cd9f28Seschrock case HELP_IMPORT: 1974c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 1982f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 1992f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n" 2002f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 2012f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] " 2022f8aaab3Seschrock "<pool | id> [newpool]\n")); 20365cd9f28Seschrock case HELP_IOSTAT: 20465cd9f28Seschrock return (gettext("\tiostat [-v] [pool] ... [interval " 20565cd9f28Seschrock "[count]]\n")); 20665cd9f28Seschrock case HELP_LIST: 207990b4856Slling return (gettext("\tlist [-H] [-o property[,...]] " 208990b4856Slling "[pool] ...\n")); 20965cd9f28Seschrock case HELP_OFFLINE: 210441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 21165cd9f28Seschrock case HELP_ONLINE: 212441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 21365cd9f28Seschrock case HELP_REPLACE: 21465cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 215e45ce728Sahrens "[new-device]\n")); 21699653d4eSeschrock case HELP_REMOVE: 217fa94a07fSbrendan return (gettext("\tremove <pool> <device> ...\n")); 21865cd9f28Seschrock case HELP_SCRUB: 21965cd9f28Seschrock return (gettext("\tscrub [-s] <pool> ...\n")); 22065cd9f28Seschrock case HELP_STATUS: 22165cd9f28Seschrock return (gettext("\tstatus [-vx] [pool] ...\n")); 222eaca9bbdSeschrock case HELP_UPGRADE: 223eaca9bbdSeschrock return (gettext("\tupgrade\n" 224eaca9bbdSeschrock "\tupgrade -v\n" 225990b4856Slling "\tupgrade [-V version] <-a | pool ...>\n")); 226b1b8ab34Slling case HELP_GET: 227e45ce728Sahrens return (gettext("\tget <\"all\" | property[,...]> " 228b1b8ab34Slling "<pool> ...\n")); 229b1b8ab34Slling case HELP_SET: 230b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 23165cd9f28Seschrock } 23265cd9f28Seschrock 23365cd9f28Seschrock abort(); 23465cd9f28Seschrock /* NOTREACHED */ 23565cd9f28Seschrock } 23665cd9f28Seschrock 237fa9e4066Sahrens 238fa9e4066Sahrens /* 239b1b8ab34Slling * Callback routine that will print out a pool property value. 240b1b8ab34Slling */ 241990b4856Slling static int 242990b4856Slling print_prop_cb(int prop, void *cb) 243b1b8ab34Slling { 244b1b8ab34Slling FILE *fp = cb; 245b1b8ab34Slling 246b1b8ab34Slling (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 247b1b8ab34Slling 248990b4856Slling if (zpool_prop_readonly(prop)) 249990b4856Slling (void) fprintf(fp, " NO "); 250990b4856Slling else 251990b4856Slling (void) fprintf(fp, " YES "); 252990b4856Slling 253b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 254b1b8ab34Slling (void) fprintf(fp, "-\n"); 255b1b8ab34Slling else 256b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 257b1b8ab34Slling 258990b4856Slling return (ZPROP_CONT); 259b1b8ab34Slling } 260b1b8ab34Slling 261b1b8ab34Slling /* 262fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 263fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 264fa9e4066Sahrens * a complete usage message. 265fa9e4066Sahrens */ 266fa9e4066Sahrens void 26799653d4eSeschrock usage(boolean_t requested) 268fa9e4066Sahrens { 269fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 270fa9e4066Sahrens 271fa9e4066Sahrens if (current_command == NULL) { 272fa9e4066Sahrens int i; 273fa9e4066Sahrens 274fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 275fa9e4066Sahrens (void) fprintf(fp, 276fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 277fa9e4066Sahrens 278fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 279fa9e4066Sahrens if (command_table[i].name == NULL) 280fa9e4066Sahrens (void) fprintf(fp, "\n"); 281fa9e4066Sahrens else 282fa9e4066Sahrens (void) fprintf(fp, "%s", 28365cd9f28Seschrock get_usage(command_table[i].usage)); 284fa9e4066Sahrens } 285fa9e4066Sahrens } else { 286fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 28765cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 288fa9e4066Sahrens } 289fa9e4066Sahrens 290b1b8ab34Slling if (current_command != NULL && 291b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 292990b4856Slling (strcmp(current_command->name, "get") == 0) || 293990b4856Slling (strcmp(current_command->name, "list") == 0))) { 294b1b8ab34Slling 295b1b8ab34Slling (void) fprintf(fp, 296b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 297b1b8ab34Slling 298990b4856Slling (void) fprintf(fp, "\n\t%-13s %s %s\n\n", 299990b4856Slling "PROPERTY", "EDIT", "VALUES"); 300b1b8ab34Slling 301b1b8ab34Slling /* Iterate over all properties */ 302990b4856Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 303990b4856Slling ZFS_TYPE_POOL); 304b1b8ab34Slling } 305b1b8ab34Slling 306e9dbad6fSeschrock /* 307e9dbad6fSeschrock * See comments at end of main(). 308e9dbad6fSeschrock */ 309e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 310e9dbad6fSeschrock (void) printf("dumping core by request\n"); 311e9dbad6fSeschrock abort(); 312e9dbad6fSeschrock } 313e9dbad6fSeschrock 314fa9e4066Sahrens exit(requested ? 0 : 2); 315fa9e4066Sahrens } 316fa9e4066Sahrens 317fa9e4066Sahrens void 3188654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 3198654d025Sperrin boolean_t print_logs) 320fa9e4066Sahrens { 321fa9e4066Sahrens nvlist_t **child; 322fa9e4066Sahrens uint_t c, children; 323afefbcddSeschrock char *vname; 324fa9e4066Sahrens 325fa9e4066Sahrens if (name != NULL) 326fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 327fa9e4066Sahrens 328fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 329fa9e4066Sahrens &child, &children) != 0) 330fa9e4066Sahrens return; 331fa9e4066Sahrens 332afefbcddSeschrock for (c = 0; c < children; c++) { 3338654d025Sperrin uint64_t is_log = B_FALSE; 3348654d025Sperrin 3358654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3368654d025Sperrin &is_log); 3378654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 3388654d025Sperrin continue; 3398654d025Sperrin 34099653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 3418654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 3428654d025Sperrin B_FALSE); 343afefbcddSeschrock free(vname); 344afefbcddSeschrock } 345fa9e4066Sahrens } 346fa9e4066Sahrens 347fa9e4066Sahrens /* 348990b4856Slling * Add a property pair (name, string-value) into a property nvlist. 349990b4856Slling */ 350990b4856Slling static int 351990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props) 352990b4856Slling { 353990b4856Slling char *strval; 354990b4856Slling nvlist_t *proplist; 355990b4856Slling zpool_prop_t prop; 356990b4856Slling 357990b4856Slling if (*props == NULL && 358990b4856Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 359990b4856Slling (void) fprintf(stderr, 360990b4856Slling gettext("internal error: out of memory\n")); 361990b4856Slling return (1); 362990b4856Slling } 363990b4856Slling 364990b4856Slling proplist = *props; 365990b4856Slling 366990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 367990b4856Slling (void) fprintf(stderr, gettext("property '%s' is " 368990b4856Slling "not a valid pool property\n"), propname); 369990b4856Slling return (2); 370990b4856Slling } 371990b4856Slling 372990b4856Slling /* Use normalized property name for nvlist operations */ 373990b4856Slling if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop), 3742f8aaab3Seschrock &strval) == 0 && prop != ZPOOL_PROP_CACHEFILE) { 375990b4856Slling (void) fprintf(stderr, gettext("property '%s' " 376990b4856Slling "specified multiple times\n"), propname); 377990b4856Slling return (2); 378990b4856Slling } 379990b4856Slling 380990b4856Slling if (nvlist_add_string(proplist, zpool_prop_to_name(prop), 381990b4856Slling propval) != 0) { 382990b4856Slling (void) fprintf(stderr, gettext("internal " 383990b4856Slling "error: out of memory\n")); 384990b4856Slling return (1); 385990b4856Slling } 386990b4856Slling 387990b4856Slling return (0); 388990b4856Slling } 389990b4856Slling 390990b4856Slling /* 391fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 392fa9e4066Sahrens * 393fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 394fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 395fa9e4066Sahrens * they were to be added. 396fa9e4066Sahrens * 397fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 398fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 399fa9e4066Sahrens * libzfs. 400fa9e4066Sahrens */ 401fa9e4066Sahrens int 402fa9e4066Sahrens zpool_do_add(int argc, char **argv) 403fa9e4066Sahrens { 40499653d4eSeschrock boolean_t force = B_FALSE; 40599653d4eSeschrock boolean_t dryrun = B_FALSE; 406fa9e4066Sahrens int c; 407fa9e4066Sahrens nvlist_t *nvroot; 408fa9e4066Sahrens char *poolname; 409fa9e4066Sahrens int ret; 410fa9e4066Sahrens zpool_handle_t *zhp; 411fa9e4066Sahrens nvlist_t *config; 412fa9e4066Sahrens 413fa9e4066Sahrens /* check options */ 414fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 415fa9e4066Sahrens switch (c) { 416fa9e4066Sahrens case 'f': 41799653d4eSeschrock force = B_TRUE; 418fa9e4066Sahrens break; 419fa9e4066Sahrens case 'n': 42099653d4eSeschrock dryrun = B_TRUE; 421fa9e4066Sahrens break; 422fa9e4066Sahrens case '?': 423fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 424fa9e4066Sahrens optopt); 42599653d4eSeschrock usage(B_FALSE); 426fa9e4066Sahrens } 427fa9e4066Sahrens } 428fa9e4066Sahrens 429fa9e4066Sahrens argc -= optind; 430fa9e4066Sahrens argv += optind; 431fa9e4066Sahrens 432fa9e4066Sahrens /* get pool name and check number of arguments */ 433fa9e4066Sahrens if (argc < 1) { 434fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 43599653d4eSeschrock usage(B_FALSE); 436fa9e4066Sahrens } 437fa9e4066Sahrens if (argc < 2) { 438fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 43999653d4eSeschrock usage(B_FALSE); 440fa9e4066Sahrens } 441fa9e4066Sahrens 442fa9e4066Sahrens poolname = argv[0]; 443fa9e4066Sahrens 444fa9e4066Sahrens argc--; 445fa9e4066Sahrens argv++; 446fa9e4066Sahrens 44799653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 448fa9e4066Sahrens return (1); 449fa9e4066Sahrens 450088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 451fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 452fa9e4066Sahrens poolname); 453fa9e4066Sahrens zpool_close(zhp); 454fa9e4066Sahrens return (1); 455fa9e4066Sahrens } 456fa9e4066Sahrens 457fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 4588488aeb5Staylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv); 459fa9e4066Sahrens if (nvroot == NULL) { 460fa9e4066Sahrens zpool_close(zhp); 461fa9e4066Sahrens return (1); 462fa9e4066Sahrens } 463fa9e4066Sahrens 464fa9e4066Sahrens if (dryrun) { 465fa9e4066Sahrens nvlist_t *poolnvroot; 466fa9e4066Sahrens 467fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 468fa9e4066Sahrens &poolnvroot) == 0); 469fa9e4066Sahrens 470fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 471fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 472fa9e4066Sahrens 4738654d025Sperrin /* print original main pool and new tree */ 4748654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 4758654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 4768654d025Sperrin 4778654d025Sperrin /* Do the same for the logs */ 4788654d025Sperrin if (num_logs(poolnvroot) > 0) { 4798654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 4808654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 4818654d025Sperrin } else if (num_logs(nvroot) > 0) { 4828654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 4838654d025Sperrin } 484fa9e4066Sahrens 485fa9e4066Sahrens ret = 0; 486fa9e4066Sahrens } else { 487fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 488fa9e4066Sahrens } 489fa9e4066Sahrens 49099653d4eSeschrock nvlist_free(nvroot); 49199653d4eSeschrock zpool_close(zhp); 49299653d4eSeschrock 49399653d4eSeschrock return (ret); 49499653d4eSeschrock } 49599653d4eSeschrock 49699653d4eSeschrock /* 497fa94a07fSbrendan * zpool remove <pool> <vdev> ... 49899653d4eSeschrock * 49999653d4eSeschrock * Removes the given vdev from the pool. Currently, this only supports removing 500fa94a07fSbrendan * spares and cache devices from the pool. Eventually, we'll want to support 501fa94a07fSbrendan * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs. 50299653d4eSeschrock */ 50399653d4eSeschrock int 50499653d4eSeschrock zpool_do_remove(int argc, char **argv) 50599653d4eSeschrock { 50699653d4eSeschrock char *poolname; 507fa94a07fSbrendan int i, ret = 0; 50899653d4eSeschrock zpool_handle_t *zhp; 50999653d4eSeschrock 51099653d4eSeschrock argc--; 51199653d4eSeschrock argv++; 51299653d4eSeschrock 51399653d4eSeschrock /* get pool name and check number of arguments */ 51499653d4eSeschrock if (argc < 1) { 51599653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 51699653d4eSeschrock usage(B_FALSE); 51799653d4eSeschrock } 51899653d4eSeschrock if (argc < 2) { 51999653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 52099653d4eSeschrock usage(B_FALSE); 52199653d4eSeschrock } 52299653d4eSeschrock 52399653d4eSeschrock poolname = argv[0]; 52499653d4eSeschrock 52599653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 52699653d4eSeschrock return (1); 52799653d4eSeschrock 528fa94a07fSbrendan for (i = 1; i < argc; i++) { 529fa94a07fSbrendan if (zpool_vdev_remove(zhp, argv[i]) != 0) 530fa94a07fSbrendan ret = 1; 531fa94a07fSbrendan } 53299653d4eSeschrock 533fa9e4066Sahrens return (ret); 534fa9e4066Sahrens } 535fa9e4066Sahrens 536fa9e4066Sahrens /* 537990b4856Slling * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint] 538990b4856Slling * <pool> <dev> ... 539fa9e4066Sahrens * 540fa9e4066Sahrens * -f Force creation, even if devices appear in use 541fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 542fa9e4066Sahrens * were to be created. 543fa9e4066Sahrens * -R Create a pool under an alternate root 544fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 545fa9e4066Sahrens * '/<pool>' 546990b4856Slling * -o Set property=value. 547fa9e4066Sahrens * 548b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 549fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 550fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 551fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 552fa9e4066Sahrens */ 553fa9e4066Sahrens int 554fa9e4066Sahrens zpool_do_create(int argc, char **argv) 555fa9e4066Sahrens { 55699653d4eSeschrock boolean_t force = B_FALSE; 55799653d4eSeschrock boolean_t dryrun = B_FALSE; 558fa9e4066Sahrens int c; 559990b4856Slling nvlist_t *nvroot = NULL; 560fa9e4066Sahrens char *poolname; 561990b4856Slling int ret = 1; 562fa9e4066Sahrens char *altroot = NULL; 563fa9e4066Sahrens char *mountpoint = NULL; 564990b4856Slling nvlist_t *props = NULL; 5652f8aaab3Seschrock char *propval; 566fa9e4066Sahrens 567fa9e4066Sahrens /* check options */ 568990b4856Slling while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) { 569fa9e4066Sahrens switch (c) { 570fa9e4066Sahrens case 'f': 57199653d4eSeschrock force = B_TRUE; 572fa9e4066Sahrens break; 573fa9e4066Sahrens case 'n': 57499653d4eSeschrock dryrun = B_TRUE; 575fa9e4066Sahrens break; 576fa9e4066Sahrens case 'R': 577fa9e4066Sahrens altroot = optarg; 578990b4856Slling if (add_prop_list(zpool_prop_to_name( 579990b4856Slling ZPOOL_PROP_ALTROOT), optarg, &props)) 580990b4856Slling goto errout; 5812f8aaab3Seschrock if (nvlist_lookup_string(props, 5822f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 5832f8aaab3Seschrock &propval) == 0) 5842f8aaab3Seschrock break; 585990b4856Slling if (add_prop_list(zpool_prop_to_name( 5862f8aaab3Seschrock ZPOOL_PROP_CACHEFILE), "none", &props)) 587990b4856Slling goto errout; 588fa9e4066Sahrens break; 589fa9e4066Sahrens case 'm': 590fa9e4066Sahrens mountpoint = optarg; 591fa9e4066Sahrens break; 592990b4856Slling case 'o': 593990b4856Slling if ((propval = strchr(optarg, '=')) == NULL) { 594990b4856Slling (void) fprintf(stderr, gettext("missing " 595990b4856Slling "'=' for -o option\n")); 596990b4856Slling goto errout; 597990b4856Slling } 598990b4856Slling *propval = '\0'; 599990b4856Slling propval++; 600990b4856Slling 601990b4856Slling if (add_prop_list(optarg, propval, &props)) 602990b4856Slling goto errout; 603990b4856Slling break; 604fa9e4066Sahrens case ':': 605fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 606fa9e4066Sahrens "'%c' option\n"), optopt); 607990b4856Slling goto badusage; 608fa9e4066Sahrens case '?': 609fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 610fa9e4066Sahrens optopt); 611990b4856Slling goto badusage; 612fa9e4066Sahrens } 613fa9e4066Sahrens } 614fa9e4066Sahrens 615fa9e4066Sahrens argc -= optind; 616fa9e4066Sahrens argv += optind; 617fa9e4066Sahrens 618fa9e4066Sahrens /* get pool name and check number of arguments */ 619fa9e4066Sahrens if (argc < 1) { 620fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 621990b4856Slling goto badusage; 622fa9e4066Sahrens } 623fa9e4066Sahrens if (argc < 2) { 624fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 625990b4856Slling goto badusage; 626fa9e4066Sahrens } 627fa9e4066Sahrens 628fa9e4066Sahrens poolname = argv[0]; 629fa9e4066Sahrens 630fa9e4066Sahrens /* 631fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 632fa9e4066Sahrens * user to use 'zfs create' instead. 633fa9e4066Sahrens */ 634fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 635fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 636fa9e4066Sahrens "character '/' in pool name\n"), poolname); 637fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 638fa9e4066Sahrens "create a dataset\n")); 639990b4856Slling goto errout; 640fa9e4066Sahrens } 641fa9e4066Sahrens 642fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 64399653d4eSeschrock nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1, 64499653d4eSeschrock argv + 1); 645fa9e4066Sahrens if (nvroot == NULL) 646fa9e4066Sahrens return (1); 647fa9e4066Sahrens 64899653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 649b7b97454Sperrin if (!zfs_allocatable_devs(nvroot)) { 65099653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 65199653d4eSeschrock "specification: at least one toplevel vdev must be " 65299653d4eSeschrock "specified\n")); 653990b4856Slling goto errout; 65499653d4eSeschrock } 65599653d4eSeschrock 65699653d4eSeschrock 657fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 658fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 659e9dbad6fSeschrock "must be an absolute path\n"), altroot); 660990b4856Slling goto errout; 661fa9e4066Sahrens } 662fa9e4066Sahrens 663fa9e4066Sahrens /* 664fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 665fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 666fa9e4066Sahrens */ 667fa9e4066Sahrens if (mountpoint == NULL || 668fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 669fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 670fa9e4066Sahrens char buf[MAXPATHLEN]; 67111022c7cStimh DIR *dirp; 672fa9e4066Sahrens 673fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 674fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 675fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 676fa9e4066Sahrens "'none'\n"), mountpoint); 677990b4856Slling goto errout; 678fa9e4066Sahrens } 679fa9e4066Sahrens 680fa9e4066Sahrens if (mountpoint == NULL) { 681fa9e4066Sahrens if (altroot != NULL) 682fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 683fa9e4066Sahrens altroot, poolname); 684fa9e4066Sahrens else 685fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 686fa9e4066Sahrens poolname); 687fa9e4066Sahrens } else { 688fa9e4066Sahrens if (altroot != NULL) 689fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 690fa9e4066Sahrens altroot, mountpoint); 691fa9e4066Sahrens else 692fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 693fa9e4066Sahrens mountpoint); 694fa9e4066Sahrens } 695fa9e4066Sahrens 69611022c7cStimh if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 69711022c7cStimh (void) fprintf(stderr, gettext("mountpoint '%s' : " 69811022c7cStimh "%s\n"), buf, strerror(errno)); 699fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 700fa9e4066Sahrens "option to provide a different default\n")); 701990b4856Slling goto errout; 70211022c7cStimh } else if (dirp) { 70311022c7cStimh int count = 0; 70411022c7cStimh 70511022c7cStimh while (count < 3 && readdir(dirp) != NULL) 70611022c7cStimh count++; 70711022c7cStimh (void) closedir(dirp); 70811022c7cStimh 70911022c7cStimh if (count > 2) { 71011022c7cStimh (void) fprintf(stderr, gettext("mountpoint " 71111022c7cStimh "'%s' exists and is not empty\n"), buf); 71211022c7cStimh (void) fprintf(stderr, gettext("use '-m' " 71311022c7cStimh "option to provide a " 71411022c7cStimh "different default\n")); 71511022c7cStimh goto errout; 71611022c7cStimh } 717fa9e4066Sahrens } 718fa9e4066Sahrens } 719fa9e4066Sahrens 720fa9e4066Sahrens if (dryrun) { 721fa9e4066Sahrens /* 722fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 723fa9e4066Sahrens * through all the vdevs in the list and print out in an 724fa9e4066Sahrens * appropriate hierarchy. 725fa9e4066Sahrens */ 726fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 727fa9e4066Sahrens "following layout:\n\n"), poolname); 728fa9e4066Sahrens 7298654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 7308654d025Sperrin if (num_logs(nvroot) > 0) 7318654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 732fa9e4066Sahrens 733fa9e4066Sahrens ret = 0; 734fa9e4066Sahrens } else { 735fa9e4066Sahrens /* 736fa9e4066Sahrens * Hand off to libzfs. 737fa9e4066Sahrens */ 738990b4856Slling if (zpool_create(g_zfs, poolname, nvroot, props) == 0) { 73999653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 740fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 741fa9e4066Sahrens if (pool != NULL) { 742fa9e4066Sahrens if (mountpoint != NULL) 743fa9e4066Sahrens verify(zfs_prop_set(pool, 744e9dbad6fSeschrock zfs_prop_to_name( 745e9dbad6fSeschrock ZFS_PROP_MOUNTPOINT), 746fa9e4066Sahrens mountpoint) == 0); 747fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 748da6c28aaSamw ret = zfs_shareall(pool); 749fa9e4066Sahrens zfs_close(pool); 750fa9e4066Sahrens } 75199653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 75299653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 75399653d4eSeschrock "been omitted\n")); 754fa9e4066Sahrens } 755fa9e4066Sahrens } 756fa9e4066Sahrens 757990b4856Slling errout: 758fa9e4066Sahrens nvlist_free(nvroot); 759990b4856Slling nvlist_free(props); 760fa9e4066Sahrens return (ret); 761990b4856Slling badusage: 762990b4856Slling nvlist_free(props); 763990b4856Slling usage(B_FALSE); 764990b4856Slling return (2); 765fa9e4066Sahrens } 766fa9e4066Sahrens 767fa9e4066Sahrens /* 768fa9e4066Sahrens * zpool destroy <pool> 769fa9e4066Sahrens * 770fa9e4066Sahrens * -f Forcefully unmount any datasets 771fa9e4066Sahrens * 772fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 773fa9e4066Sahrens */ 774fa9e4066Sahrens int 775fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 776fa9e4066Sahrens { 77799653d4eSeschrock boolean_t force = B_FALSE; 778fa9e4066Sahrens int c; 779fa9e4066Sahrens char *pool; 780fa9e4066Sahrens zpool_handle_t *zhp; 781fa9e4066Sahrens int ret; 782fa9e4066Sahrens 783fa9e4066Sahrens /* check options */ 784fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 785fa9e4066Sahrens switch (c) { 786fa9e4066Sahrens case 'f': 78799653d4eSeschrock force = B_TRUE; 788fa9e4066Sahrens break; 789fa9e4066Sahrens case '?': 790fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 791fa9e4066Sahrens optopt); 79299653d4eSeschrock usage(B_FALSE); 793fa9e4066Sahrens } 794fa9e4066Sahrens } 795fa9e4066Sahrens 796fa9e4066Sahrens argc -= optind; 797fa9e4066Sahrens argv += optind; 798fa9e4066Sahrens 799fa9e4066Sahrens /* check arguments */ 800fa9e4066Sahrens if (argc < 1) { 801fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 80299653d4eSeschrock usage(B_FALSE); 803fa9e4066Sahrens } 804fa9e4066Sahrens if (argc > 1) { 805fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 80699653d4eSeschrock usage(B_FALSE); 807fa9e4066Sahrens } 808fa9e4066Sahrens 809fa9e4066Sahrens pool = argv[0]; 810fa9e4066Sahrens 81199653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 812fa9e4066Sahrens /* 813fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 814fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 815fa9e4066Sahrens */ 816fa9e4066Sahrens if (strchr(pool, '/') != NULL) 817fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 818fa9e4066Sahrens "destroy a dataset\n")); 819fa9e4066Sahrens return (1); 820fa9e4066Sahrens } 821fa9e4066Sahrens 822f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 823fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 824fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 825fa9e4066Sahrens return (1); 826fa9e4066Sahrens } 827fa9e4066Sahrens 828fa9e4066Sahrens ret = (zpool_destroy(zhp) != 0); 829fa9e4066Sahrens 830fa9e4066Sahrens zpool_close(zhp); 831fa9e4066Sahrens 832fa9e4066Sahrens return (ret); 833fa9e4066Sahrens } 834fa9e4066Sahrens 835fa9e4066Sahrens /* 836fa9e4066Sahrens * zpool export [-f] <pool> ... 837fa9e4066Sahrens * 838fa9e4066Sahrens * -f Forcefully unmount datasets 839fa9e4066Sahrens * 840b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 841fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 842fa9e4066Sahrens * then the datasets will be forcefully unmounted. 843fa9e4066Sahrens */ 844fa9e4066Sahrens int 845fa9e4066Sahrens zpool_do_export(int argc, char **argv) 846fa9e4066Sahrens { 84799653d4eSeschrock boolean_t force = B_FALSE; 848fa9e4066Sahrens int c; 849fa9e4066Sahrens zpool_handle_t *zhp; 850fa9e4066Sahrens int ret; 851fa9e4066Sahrens int i; 852fa9e4066Sahrens 853fa9e4066Sahrens /* check options */ 854fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 855fa9e4066Sahrens switch (c) { 856fa9e4066Sahrens case 'f': 85799653d4eSeschrock force = B_TRUE; 858fa9e4066Sahrens break; 859fa9e4066Sahrens case '?': 860fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 861fa9e4066Sahrens optopt); 86299653d4eSeschrock usage(B_FALSE); 863fa9e4066Sahrens } 864fa9e4066Sahrens } 865fa9e4066Sahrens 866fa9e4066Sahrens argc -= optind; 867fa9e4066Sahrens argv += optind; 868fa9e4066Sahrens 869fa9e4066Sahrens /* check arguments */ 870fa9e4066Sahrens if (argc < 1) { 871fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 87299653d4eSeschrock usage(B_FALSE); 873fa9e4066Sahrens } 874fa9e4066Sahrens 875fa9e4066Sahrens ret = 0; 876fa9e4066Sahrens for (i = 0; i < argc; i++) { 87799653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 878fa9e4066Sahrens ret = 1; 879fa9e4066Sahrens continue; 880fa9e4066Sahrens } 881fa9e4066Sahrens 882f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 883fa9e4066Sahrens ret = 1; 884fa9e4066Sahrens zpool_close(zhp); 885fa9e4066Sahrens continue; 886fa9e4066Sahrens } 887fa9e4066Sahrens 888fa9e4066Sahrens if (zpool_export(zhp) != 0) 889fa9e4066Sahrens ret = 1; 890fa9e4066Sahrens 891fa9e4066Sahrens zpool_close(zhp); 892fa9e4066Sahrens } 893fa9e4066Sahrens 894fa9e4066Sahrens return (ret); 895fa9e4066Sahrens } 896fa9e4066Sahrens 897fa9e4066Sahrens /* 898fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 899fa9e4066Sahrens * name column. 900fa9e4066Sahrens */ 901fa9e4066Sahrens static int 902c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 903fa9e4066Sahrens { 90499653d4eSeschrock char *name = zpool_vdev_name(g_zfs, zhp, nv); 905fa9e4066Sahrens nvlist_t **child; 906fa9e4066Sahrens uint_t c, children; 907fa9e4066Sahrens int ret; 908fa9e4066Sahrens 909fa9e4066Sahrens if (strlen(name) + depth > max) 910fa9e4066Sahrens max = strlen(name) + depth; 911fa9e4066Sahrens 912afefbcddSeschrock free(name); 913afefbcddSeschrock 91499653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 91599653d4eSeschrock &child, &children) == 0) { 916fa9e4066Sahrens for (c = 0; c < children; c++) 91799653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 91899653d4eSeschrock max)) > max) 919fa9e4066Sahrens max = ret; 92099653d4eSeschrock } 92199653d4eSeschrock 922fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 923fa94a07fSbrendan &child, &children) == 0) { 924fa94a07fSbrendan for (c = 0; c < children; c++) 925fa94a07fSbrendan if ((ret = max_width(zhp, child[c], depth + 2, 926fa94a07fSbrendan max)) > max) 927fa94a07fSbrendan max = ret; 928fa94a07fSbrendan } 929fa94a07fSbrendan 93099653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 93199653d4eSeschrock &child, &children) == 0) { 93299653d4eSeschrock for (c = 0; c < children; c++) 93399653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 93499653d4eSeschrock max)) > max) 93599653d4eSeschrock max = ret; 93699653d4eSeschrock } 93799653d4eSeschrock 938fa9e4066Sahrens 939fa9e4066Sahrens return (max); 940fa9e4066Sahrens } 941fa9e4066Sahrens 942fa9e4066Sahrens 943fa9e4066Sahrens /* 944fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 945fa9e4066Sahrens * pool, printing out the name and status for each one. 946fa9e4066Sahrens */ 947fa9e4066Sahrens void 9488654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth, 9498654d025Sperrin boolean_t print_logs) 950fa9e4066Sahrens { 951fa9e4066Sahrens nvlist_t **child; 952fa9e4066Sahrens uint_t c, children; 953fa9e4066Sahrens vdev_stat_t *vs; 954afefbcddSeschrock char *type, *vname; 955fa9e4066Sahrens 956fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 957fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_MISSING) == 0) 958fa9e4066Sahrens return; 959fa9e4066Sahrens 960fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 961fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 962fa9e4066Sahrens 963fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 964990b4856Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 965fa9e4066Sahrens 966fa9e4066Sahrens if (vs->vs_aux != 0) { 9673d7072f8Seschrock (void) printf(" "); 968fa9e4066Sahrens 969fa9e4066Sahrens switch (vs->vs_aux) { 970fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 971fa9e4066Sahrens (void) printf(gettext("cannot open")); 972fa9e4066Sahrens break; 973fa9e4066Sahrens 974fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 975fa9e4066Sahrens (void) printf(gettext("missing device")); 976fa9e4066Sahrens break; 977fa9e4066Sahrens 978fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 979fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 980fa9e4066Sahrens break; 981fa9e4066Sahrens 982eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 983eaca9bbdSeschrock (void) printf(gettext("newer version")); 984eaca9bbdSeschrock break; 985eaca9bbdSeschrock 9863d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 9873d7072f8Seschrock (void) printf(gettext("too many errors")); 9883d7072f8Seschrock break; 9893d7072f8Seschrock 990fa9e4066Sahrens default: 991fa9e4066Sahrens (void) printf(gettext("corrupted data")); 992fa9e4066Sahrens break; 993fa9e4066Sahrens } 994fa9e4066Sahrens } 995fa9e4066Sahrens (void) printf("\n"); 996fa9e4066Sahrens 997fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 998fa9e4066Sahrens &child, &children) != 0) 999fa9e4066Sahrens return; 1000fa9e4066Sahrens 1001afefbcddSeschrock for (c = 0; c < children; c++) { 10028654d025Sperrin uint64_t is_log = B_FALSE; 10038654d025Sperrin 10048654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 10058654d025Sperrin &is_log); 10068654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 10078654d025Sperrin continue; 10088654d025Sperrin 100999653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1010afefbcddSeschrock print_import_config(vname, child[c], 10118654d025Sperrin namewidth, depth + 2, B_FALSE); 1012afefbcddSeschrock free(vname); 1013afefbcddSeschrock } 101499653d4eSeschrock 1015fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1016fa94a07fSbrendan &child, &children) == 0) { 1017fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 1018fa94a07fSbrendan for (c = 0; c < children; c++) { 1019fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1020fa94a07fSbrendan (void) printf("\t %s\n", vname); 1021fa94a07fSbrendan free(vname); 1022fa94a07fSbrendan } 1023fa94a07fSbrendan } 102499653d4eSeschrock 1025fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1026fa94a07fSbrendan &child, &children) == 0) { 102799653d4eSeschrock (void) printf(gettext("\tspares\n")); 102899653d4eSeschrock for (c = 0; c < children; c++) { 102999653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 103099653d4eSeschrock (void) printf("\t %s\n", vname); 103199653d4eSeschrock free(vname); 103299653d4eSeschrock } 1033fa9e4066Sahrens } 1034fa94a07fSbrendan } 1035fa9e4066Sahrens 1036fa9e4066Sahrens /* 1037fa9e4066Sahrens * Display the status for the given pool. 1038fa9e4066Sahrens */ 1039fa9e4066Sahrens static void 1040fa9e4066Sahrens show_import(nvlist_t *config) 1041fa9e4066Sahrens { 1042fa9e4066Sahrens uint64_t pool_state; 1043fa9e4066Sahrens vdev_stat_t *vs; 1044fa9e4066Sahrens char *name; 1045fa9e4066Sahrens uint64_t guid; 1046fa9e4066Sahrens char *msgid; 1047fa9e4066Sahrens nvlist_t *nvroot; 1048fa9e4066Sahrens int reason; 104946657f8dSmmusante const char *health; 1050fa9e4066Sahrens uint_t vsc; 1051fa9e4066Sahrens int namewidth; 1052fa9e4066Sahrens 1053fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1054fa9e4066Sahrens &name) == 0); 1055fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1056fa9e4066Sahrens &guid) == 0); 1057fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1058fa9e4066Sahrens &pool_state) == 0); 1059fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1060fa9e4066Sahrens &nvroot) == 0); 1061fa9e4066Sahrens 1062fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1063fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 1064990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1065fa9e4066Sahrens 1066fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1067fa9e4066Sahrens 106846657f8dSmmusante (void) printf(gettext(" pool: %s\n"), name); 106946657f8dSmmusante (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 107046657f8dSmmusante (void) printf(gettext(" state: %s"), health); 10714c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 107246657f8dSmmusante (void) printf(gettext(" (DESTROYED)")); 10734c58d714Sdarrenm (void) printf("\n"); 1074fa9e4066Sahrens 1075fa9e4066Sahrens switch (reason) { 1076fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1077fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1078fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 1079fa9e4066Sahrens (void) printf(gettext("status: One or more devices are missing " 1080fa9e4066Sahrens "from the system.\n")); 1081fa9e4066Sahrens break; 1082fa9e4066Sahrens 1083fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1084fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1085fa9e4066Sahrens (void) printf(gettext("status: One or more devices contains " 1086fa9e4066Sahrens "corrupted data.\n")); 1087fa9e4066Sahrens break; 1088fa9e4066Sahrens 1089fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 1090fa9e4066Sahrens (void) printf(gettext("status: The pool data is corrupted.\n")); 1091fa9e4066Sahrens break; 1092fa9e4066Sahrens 1093441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 1094441d80aaSlling (void) printf(gettext("status: One or more devices " 1095441d80aaSlling "are offlined.\n")); 1096441d80aaSlling break; 1097441d80aaSlling 1098ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 1099ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is " 1100ea8dc4b6Seschrock "corrupted.\n")); 1101ea8dc4b6Seschrock break; 1102ea8dc4b6Seschrock 1103eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 1104eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1105eaca9bbdSeschrock "older on-disk version.\n")); 1106eaca9bbdSeschrock break; 1107eaca9bbdSeschrock 1108eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1109eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1110eaca9bbdSeschrock "incompatible version.\n")); 1111eaca9bbdSeschrock break; 111295173954Sek110237 case ZPOOL_STATUS_HOSTID_MISMATCH: 111395173954Sek110237 (void) printf(gettext("status: The pool was last accessed by " 111495173954Sek110237 "another system.\n")); 111595173954Sek110237 break; 11163d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 11173d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 11183d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 11193d7072f8Seschrock "faulted.\n")); 11203d7072f8Seschrock break; 11213d7072f8Seschrock 1122fa9e4066Sahrens default: 1123fa9e4066Sahrens /* 1124fa9e4066Sahrens * No other status can be seen when importing pools. 1125fa9e4066Sahrens */ 1126fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1127fa9e4066Sahrens } 1128fa9e4066Sahrens 1129fa9e4066Sahrens /* 1130fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1131fa9e4066Sahrens */ 113246657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 1133eaca9bbdSeschrock if (reason == ZPOOL_STATUS_VERSION_OLDER) 1134eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1135eaca9bbdSeschrock "imported using its name or numeric identifier, " 1136eaca9bbdSeschrock "though\n\tsome features will not be available " 1137eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 113895173954Sek110237 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 113995173954Sek110237 (void) printf(gettext("action: The pool can be " 114095173954Sek110237 "imported using its name or numeric " 114195173954Sek110237 "identifier and\n\tthe '-f' flag.\n")); 1142fa9e4066Sahrens else 1143eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1144eaca9bbdSeschrock "imported using its name or numeric " 1145eaca9bbdSeschrock "identifier.\n")); 114646657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1147fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported " 1148fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1149eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1150fa9e4066Sahrens } else { 1151eaca9bbdSeschrock switch (reason) { 1152eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1153eaca9bbdSeschrock (void) printf(gettext("action: The pool cannot be " 1154eaca9bbdSeschrock "imported. Access the pool on a system running " 1155eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1156eaca9bbdSeschrock "backup.\n")); 1157eaca9bbdSeschrock break; 1158eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1159eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1160eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 1161fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1162fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1163fa9e4066Sahrens "again.\n")); 1164eaca9bbdSeschrock break; 1165eaca9bbdSeschrock default: 1166fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1167fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1168fa9e4066Sahrens } 1169eaca9bbdSeschrock } 1170eaca9bbdSeschrock 117146657f8dSmmusante /* 117246657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 117346657f8dSmmusante * is "corrupt data": 117446657f8dSmmusante */ 117546657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 117646657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 117746657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1178eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1179eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1180eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1181eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1182eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 118318ce54dfSek110237 "another system, but can be imported using\n\t" 1184eaca9bbdSeschrock "the '-f' flag.\n")); 1185eaca9bbdSeschrock } 1186fa9e4066Sahrens 1187fa9e4066Sahrens if (msgid != NULL) 1188fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1189fa9e4066Sahrens msgid); 1190fa9e4066Sahrens 1191fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 1192fa9e4066Sahrens 1193c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1194fa9e4066Sahrens if (namewidth < 10) 1195fa9e4066Sahrens namewidth = 10; 11968654d025Sperrin 11978654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_FALSE); 11988654d025Sperrin if (num_logs(nvroot) > 0) { 11998654d025Sperrin (void) printf(gettext("\tlogs\n")); 12008654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_TRUE); 12018654d025Sperrin } 1202fa9e4066Sahrens 1203fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 120446657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1205fa9e4066Sahrens "be part of this pool, though their\n\texact " 120646657f8dSmmusante "configuration cannot be determined.\n")); 1207fa9e4066Sahrens } 1208fa9e4066Sahrens } 1209fa9e4066Sahrens 1210fa9e4066Sahrens /* 1211fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1212990b4856Slling * lifting off to zpool_import_props(), and then mounts the datasets contained 1213990b4856Slling * within the pool. 1214fa9e4066Sahrens */ 1215fa9e4066Sahrens static int 1216fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 1217990b4856Slling int force, nvlist_t *props) 1218fa9e4066Sahrens { 1219fa9e4066Sahrens zpool_handle_t *zhp; 1220fa9e4066Sahrens char *name; 1221fa9e4066Sahrens uint64_t state; 1222eaca9bbdSeschrock uint64_t version; 1223ecd6cf80Smarks int error = 0; 1224fa9e4066Sahrens 1225fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1226fa9e4066Sahrens &name) == 0); 1227fa9e4066Sahrens 1228fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1229fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1230eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1231eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1232e7437265Sahrens if (version > SPA_VERSION) { 1233eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1234eaca9bbdSeschrock "is formatted using a newer ZFS version\n"), name); 1235eaca9bbdSeschrock return (1); 1236eaca9bbdSeschrock } else if (state != POOL_STATE_EXPORTED && !force) { 123795173954Sek110237 uint64_t hostid; 123895173954Sek110237 123995173954Sek110237 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 124095173954Sek110237 &hostid) == 0) { 124195173954Sek110237 if ((unsigned long)hostid != gethostid()) { 124295173954Sek110237 char *hostname; 124395173954Sek110237 uint64_t timestamp; 124495173954Sek110237 time_t t; 124595173954Sek110237 124695173954Sek110237 verify(nvlist_lookup_string(config, 124795173954Sek110237 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 124895173954Sek110237 verify(nvlist_lookup_uint64(config, 124995173954Sek110237 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 125095173954Sek110237 t = timestamp; 125195173954Sek110237 (void) fprintf(stderr, gettext("cannot import " 125295173954Sek110237 "'%s': pool may be in use from other " 125395173954Sek110237 "system, it was last accessed by %s " 125495173954Sek110237 "(hostid: 0x%lx) on %s"), name, hostname, 125595173954Sek110237 (unsigned long)hostid, 125695173954Sek110237 asctime(localtime(&t))); 125795173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to " 125895173954Sek110237 "import anyway\n")); 1259fa9e4066Sahrens return (1); 1260fa9e4066Sahrens } 126195173954Sek110237 } else { 126295173954Sek110237 (void) fprintf(stderr, gettext("cannot import '%s': " 126395173954Sek110237 "pool may be in use from other system\n"), name); 126495173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to import " 126595173954Sek110237 "anyway\n")); 126695173954Sek110237 return (1); 126795173954Sek110237 } 126895173954Sek110237 } 1269fa9e4066Sahrens 1270990b4856Slling if (zpool_import_props(g_zfs, config, newname, props) != 0) 1271fa9e4066Sahrens return (1); 1272fa9e4066Sahrens 1273fa9e4066Sahrens if (newname != NULL) 1274fa9e4066Sahrens name = (char *)newname; 1275fa9e4066Sahrens 127699653d4eSeschrock verify((zhp = zpool_open(g_zfs, name)) != NULL); 1277fa9e4066Sahrens 1278f3861e1aSahl if (zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1279fa9e4066Sahrens zpool_close(zhp); 1280fa9e4066Sahrens return (1); 1281fa9e4066Sahrens } 1282fa9e4066Sahrens 1283fa9e4066Sahrens zpool_close(zhp); 1284ecd6cf80Smarks return (error); 1285fa9e4066Sahrens } 1286fa9e4066Sahrens 1287fa9e4066Sahrens /* 12884c58d714Sdarrenm * zpool import [-d dir] [-D] 12892f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 12902f8aaab3Seschrock * [-d dir | -c cachefile] [-f] -a 12912f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 12922f8aaab3Seschrock * [-d dir | -c cachefile] [-f] <pool | id> [newpool] 12932f8aaab3Seschrock * 12942f8aaab3Seschrock * -c Read pool information from a cachefile instead of searching 12952f8aaab3Seschrock * devices. 1296fa9e4066Sahrens * 1297fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1298fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1299fa9e4066Sahrens * 13004c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 13014c58d714Sdarrenm * specified destroyed pools. 13024c58d714Sdarrenm * 1303fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1304fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1305fa9e4066Sahrens * is rebooted. 1306fa9e4066Sahrens * 1307fa9e4066Sahrens * -f Force import, even if it appears that the pool is active. 1308fa9e4066Sahrens * 1309fa9e4066Sahrens * -a Import all pools found. 1310fa9e4066Sahrens * 1311990b4856Slling * -o Set property=value and/or temporary mount options (without '='). 1312ecd6cf80Smarks * 1313fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 1314fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 1315fa9e4066Sahrens */ 1316fa9e4066Sahrens int 1317fa9e4066Sahrens zpool_do_import(int argc, char **argv) 1318fa9e4066Sahrens { 1319fa9e4066Sahrens char **searchdirs = NULL; 1320fa9e4066Sahrens int nsearch = 0; 1321fa9e4066Sahrens int c; 1322fa9e4066Sahrens int err; 13232f8aaab3Seschrock nvlist_t *pools = NULL; 132499653d4eSeschrock boolean_t do_all = B_FALSE; 132599653d4eSeschrock boolean_t do_destroyed = B_FALSE; 1326fa9e4066Sahrens char *mntopts = NULL; 132799653d4eSeschrock boolean_t do_force = B_FALSE; 1328fa9e4066Sahrens nvpair_t *elem; 1329fa9e4066Sahrens nvlist_t *config; 1330fa9e4066Sahrens uint64_t searchguid; 1331fa9e4066Sahrens char *searchname; 1332990b4856Slling char *propval; 1333fa9e4066Sahrens nvlist_t *found_config; 1334ecd6cf80Smarks nvlist_t *props = NULL; 133599653d4eSeschrock boolean_t first; 13364c58d714Sdarrenm uint64_t pool_state; 13372f8aaab3Seschrock char *cachefile = NULL; 1338fa9e4066Sahrens 1339fa9e4066Sahrens /* check options */ 13402f8aaab3Seschrock while ((c = getopt(argc, argv, ":afc:d:Do:p:R:")) != -1) { 1341fa9e4066Sahrens switch (c) { 1342fa9e4066Sahrens case 'a': 134399653d4eSeschrock do_all = B_TRUE; 1344fa9e4066Sahrens break; 13452f8aaab3Seschrock case 'c': 13462f8aaab3Seschrock cachefile = optarg; 13472f8aaab3Seschrock break; 1348fa9e4066Sahrens case 'd': 1349fa9e4066Sahrens if (searchdirs == NULL) { 1350fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1351fa9e4066Sahrens } else { 1352fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 1353fa9e4066Sahrens sizeof (char *)); 1354fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 1355fa9e4066Sahrens sizeof (char *)); 1356fa9e4066Sahrens free(searchdirs); 1357fa9e4066Sahrens searchdirs = tmp; 1358fa9e4066Sahrens } 1359fa9e4066Sahrens searchdirs[nsearch++] = optarg; 1360fa9e4066Sahrens break; 13614c58d714Sdarrenm case 'D': 136299653d4eSeschrock do_destroyed = B_TRUE; 13634c58d714Sdarrenm break; 1364fa9e4066Sahrens case 'f': 136599653d4eSeschrock do_force = B_TRUE; 1366fa9e4066Sahrens break; 1367fa9e4066Sahrens case 'o': 1368990b4856Slling if ((propval = strchr(optarg, '=')) != NULL) { 1369990b4856Slling *propval = '\0'; 1370990b4856Slling propval++; 1371990b4856Slling if (add_prop_list(optarg, propval, &props)) 1372990b4856Slling goto error; 1373990b4856Slling } else { 1374fa9e4066Sahrens mntopts = optarg; 1375990b4856Slling } 1376fa9e4066Sahrens break; 1377fa9e4066Sahrens case 'R': 1378990b4856Slling if (add_prop_list(zpool_prop_to_name( 1379990b4856Slling ZPOOL_PROP_ALTROOT), optarg, &props)) 1380990b4856Slling goto error; 13812f8aaab3Seschrock if (nvlist_lookup_string(props, 13822f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 13832f8aaab3Seschrock &propval) == 0) 13842f8aaab3Seschrock break; 1385990b4856Slling if (add_prop_list(zpool_prop_to_name( 13862f8aaab3Seschrock ZPOOL_PROP_CACHEFILE), "none", &props)) 1387990b4856Slling goto error; 1388fa9e4066Sahrens break; 1389fa9e4066Sahrens case ':': 1390fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 1391fa9e4066Sahrens "'%c' option\n"), optopt); 139299653d4eSeschrock usage(B_FALSE); 1393fa9e4066Sahrens break; 1394fa9e4066Sahrens case '?': 1395fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1396fa9e4066Sahrens optopt); 139799653d4eSeschrock usage(B_FALSE); 1398fa9e4066Sahrens } 1399fa9e4066Sahrens } 1400fa9e4066Sahrens 1401fa9e4066Sahrens argc -= optind; 1402fa9e4066Sahrens argv += optind; 1403fa9e4066Sahrens 14042f8aaab3Seschrock if (cachefile && nsearch != 0) { 14052f8aaab3Seschrock (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 14062f8aaab3Seschrock usage(B_FALSE); 14072f8aaab3Seschrock } 14082f8aaab3Seschrock 1409fa9e4066Sahrens if (searchdirs == NULL) { 1410fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1411fa9e4066Sahrens searchdirs[0] = "/dev/dsk"; 1412fa9e4066Sahrens nsearch = 1; 1413fa9e4066Sahrens } 1414fa9e4066Sahrens 1415fa9e4066Sahrens /* check argument count */ 1416fa9e4066Sahrens if (do_all) { 1417fa9e4066Sahrens if (argc != 0) { 1418fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 141999653d4eSeschrock usage(B_FALSE); 1420fa9e4066Sahrens } 1421fa9e4066Sahrens } else { 1422fa9e4066Sahrens if (argc > 2) { 1423fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 142499653d4eSeschrock usage(B_FALSE); 1425fa9e4066Sahrens } 1426fa9e4066Sahrens 1427fa9e4066Sahrens /* 1428fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 1429fa9e4066Sahrens * here because otherwise any attempt to discover pools will 1430fa9e4066Sahrens * silently fail. 1431fa9e4066Sahrens */ 1432fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1433fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 1434fa9e4066Sahrens "discover pools: permission denied\n")); 143599653d4eSeschrock free(searchdirs); 1436fa9e4066Sahrens return (1); 1437fa9e4066Sahrens } 1438fa9e4066Sahrens } 1439fa9e4066Sahrens 14402f8aaab3Seschrock if (cachefile) 14413a57275aSck153898 pools = zpool_find_import_cached(g_zfs, cachefile, B_FALSE); 14422f8aaab3Seschrock else 14433a57275aSck153898 pools = zpool_find_import(g_zfs, nsearch, searchdirs, B_FALSE); 14442f8aaab3Seschrock 14452f8aaab3Seschrock if (pools == NULL) { 144699653d4eSeschrock free(searchdirs); 1447fa9e4066Sahrens return (1); 144899653d4eSeschrock } 1449fa9e4066Sahrens 1450fa9e4066Sahrens /* 1451fa9e4066Sahrens * We now have a list of all available pools in the given directories. 1452fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 1453fa9e4066Sahrens * 1454fa9e4066Sahrens * <none> Iterate through all pools and display information about 1455fa9e4066Sahrens * each one. 1456fa9e4066Sahrens * 1457fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 1458fa9e4066Sahrens * 1459fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 1460fa9e4066Sahrens * name and import that one. 14614c58d714Sdarrenm * 14624c58d714Sdarrenm * -D Above options applies only to destroyed pools. 1463fa9e4066Sahrens */ 1464fa9e4066Sahrens if (argc != 0) { 1465fa9e4066Sahrens char *endptr; 1466fa9e4066Sahrens 1467fa9e4066Sahrens errno = 0; 1468fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 1469fa9e4066Sahrens if (errno != 0 || *endptr != '\0') 1470fa9e4066Sahrens searchname = argv[0]; 1471fa9e4066Sahrens else 1472fa9e4066Sahrens searchname = NULL; 1473fa9e4066Sahrens found_config = NULL; 1474fa9e4066Sahrens } 1475fa9e4066Sahrens 1476fa9e4066Sahrens err = 0; 1477fa9e4066Sahrens elem = NULL; 147899653d4eSeschrock first = B_TRUE; 1479fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1480fa9e4066Sahrens 1481fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 1482fa9e4066Sahrens 14834c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 14844c58d714Sdarrenm &pool_state) == 0); 14854c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 14864c58d714Sdarrenm continue; 14874c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 14884c58d714Sdarrenm continue; 14894c58d714Sdarrenm 1490fa9e4066Sahrens if (argc == 0) { 1491fa9e4066Sahrens if (first) 149299653d4eSeschrock first = B_FALSE; 14933bb79becSeschrock else if (!do_all) 1494fa9e4066Sahrens (void) printf("\n"); 1495fa9e4066Sahrens 1496fa9e4066Sahrens if (do_all) 1497fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 1498990b4856Slling do_force, props); 1499fa9e4066Sahrens else 1500fa9e4066Sahrens show_import(config); 1501fa9e4066Sahrens } else if (searchname != NULL) { 1502fa9e4066Sahrens char *name; 1503fa9e4066Sahrens 1504fa9e4066Sahrens /* 1505fa9e4066Sahrens * We are searching for a pool based on name. 1506fa9e4066Sahrens */ 1507fa9e4066Sahrens verify(nvlist_lookup_string(config, 1508fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1509fa9e4066Sahrens 1510fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 1511fa9e4066Sahrens if (found_config != NULL) { 1512fa9e4066Sahrens (void) fprintf(stderr, gettext( 1513fa9e4066Sahrens "cannot import '%s': more than " 1514fa9e4066Sahrens "one matching pool\n"), searchname); 1515fa9e4066Sahrens (void) fprintf(stderr, gettext( 1516fa9e4066Sahrens "import by numeric ID instead\n")); 151799653d4eSeschrock err = B_TRUE; 1518fa9e4066Sahrens } 1519fa9e4066Sahrens found_config = config; 1520fa9e4066Sahrens } 1521fa9e4066Sahrens } else { 1522fa9e4066Sahrens uint64_t guid; 1523fa9e4066Sahrens 1524fa9e4066Sahrens /* 1525fa9e4066Sahrens * Search for a pool by guid. 1526fa9e4066Sahrens */ 1527fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1528fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1529fa9e4066Sahrens 1530fa9e4066Sahrens if (guid == searchguid) 1531fa9e4066Sahrens found_config = config; 1532fa9e4066Sahrens } 1533fa9e4066Sahrens } 1534fa9e4066Sahrens 1535fa9e4066Sahrens /* 1536fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 1537fa9e4066Sahrens * pool, and then do the import. 1538fa9e4066Sahrens */ 1539fa9e4066Sahrens if (argc != 0 && err == 0) { 1540fa9e4066Sahrens if (found_config == NULL) { 1541fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 1542fa9e4066Sahrens "no such pool available\n"), argv[0]); 154399653d4eSeschrock err = B_TRUE; 1544fa9e4066Sahrens } else { 1545fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 1546990b4856Slling argv[1], mntopts, do_force, props); 1547fa9e4066Sahrens } 1548fa9e4066Sahrens } 1549fa9e4066Sahrens 1550fa9e4066Sahrens /* 1551fa9e4066Sahrens * If we were just looking for pools, report an error if none were 1552fa9e4066Sahrens * found. 1553fa9e4066Sahrens */ 1554fa9e4066Sahrens if (argc == 0 && first) 1555fa9e4066Sahrens (void) fprintf(stderr, 1556fa9e4066Sahrens gettext("no pools available to import\n")); 1557fa9e4066Sahrens 1558ecd6cf80Smarks error: 1559ecd6cf80Smarks nvlist_free(props); 1560fa9e4066Sahrens nvlist_free(pools); 156199653d4eSeschrock free(searchdirs); 1562fa9e4066Sahrens 1563fa9e4066Sahrens return (err ? 1 : 0); 1564fa9e4066Sahrens } 1565fa9e4066Sahrens 1566fa9e4066Sahrens typedef struct iostat_cbdata { 1567fa9e4066Sahrens zpool_list_t *cb_list; 1568fa9e4066Sahrens int cb_verbose; 1569fa9e4066Sahrens int cb_iteration; 1570fa9e4066Sahrens int cb_namewidth; 1571fa9e4066Sahrens } iostat_cbdata_t; 1572fa9e4066Sahrens 1573fa9e4066Sahrens static void 1574fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 1575fa9e4066Sahrens { 1576fa9e4066Sahrens int i = 0; 1577fa9e4066Sahrens 1578fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 1579fa9e4066Sahrens (void) printf("-"); 1580fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1581fa9e4066Sahrens } 1582fa9e4066Sahrens 1583fa9e4066Sahrens static void 1584fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 1585fa9e4066Sahrens { 1586fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 1587fa9e4066Sahrens cb->cb_namewidth, ""); 1588fa9e4066Sahrens (void) printf("%-*s used avail read write read write\n", 1589fa9e4066Sahrens cb->cb_namewidth, "pool"); 1590fa9e4066Sahrens print_iostat_separator(cb); 1591fa9e4066Sahrens } 1592fa9e4066Sahrens 1593fa9e4066Sahrens /* 1594fa9e4066Sahrens * Display a single statistic. 1595fa9e4066Sahrens */ 1596990b4856Slling static void 1597fa9e4066Sahrens print_one_stat(uint64_t value) 1598fa9e4066Sahrens { 1599fa9e4066Sahrens char buf[64]; 1600fa9e4066Sahrens 1601fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 1602fa9e4066Sahrens (void) printf(" %5s", buf); 1603fa9e4066Sahrens } 1604fa9e4066Sahrens 1605fa9e4066Sahrens /* 1606fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 1607fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 1608fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 1609fa9e4066Sahrens */ 1610fa9e4066Sahrens void 1611c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1612c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1613fa9e4066Sahrens { 1614fa9e4066Sahrens nvlist_t **oldchild, **newchild; 1615fa9e4066Sahrens uint_t c, children; 1616fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 1617fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 1618fa9e4066Sahrens uint64_t tdelta; 1619fa9e4066Sahrens double scale; 1620afefbcddSeschrock char *vname; 1621fa9e4066Sahrens 1622fa9e4066Sahrens if (oldnv != NULL) { 1623fa9e4066Sahrens verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1624fa9e4066Sahrens (uint64_t **)&oldvs, &c) == 0); 1625fa9e4066Sahrens } else { 1626fa9e4066Sahrens oldvs = &zerovs; 1627fa9e4066Sahrens } 1628fa9e4066Sahrens 1629fa9e4066Sahrens verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1630fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 1631fa9e4066Sahrens 1632fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 1633fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 1634fa9e4066Sahrens else 1635fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 1636fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1637fa9e4066Sahrens 1638fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1639fa9e4066Sahrens 1640fa9e4066Sahrens if (tdelta == 0) 1641fa9e4066Sahrens scale = 1.0; 1642fa9e4066Sahrens else 1643fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 1644fa9e4066Sahrens 1645fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 1646fa9e4066Sahrens if (newvs->vs_space == 0) { 1647fa9e4066Sahrens (void) printf(" - -"); 1648fa9e4066Sahrens } else { 1649fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 1650fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 1651fa9e4066Sahrens } 1652fa9e4066Sahrens 1653fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1654fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 1655fa9e4066Sahrens 1656fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1657fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1658fa9e4066Sahrens 1659fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1660fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 1661fa9e4066Sahrens 1662fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1663fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1664fa9e4066Sahrens 1665fa9e4066Sahrens (void) printf("\n"); 1666fa9e4066Sahrens 1667fa9e4066Sahrens if (!cb->cb_verbose) 1668fa9e4066Sahrens return; 1669fa9e4066Sahrens 1670fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1671fa9e4066Sahrens &newchild, &children) != 0) 1672fa9e4066Sahrens return; 1673fa9e4066Sahrens 1674fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1675fa9e4066Sahrens &oldchild, &c) != 0) 1676fa9e4066Sahrens return; 1677fa9e4066Sahrens 1678afefbcddSeschrock for (c = 0; c < children; c++) { 167999653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1680c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1681afefbcddSeschrock newchild[c], cb, depth + 2); 1682afefbcddSeschrock free(vname); 1683afefbcddSeschrock } 1684fa94a07fSbrendan 1685fa94a07fSbrendan /* 1686fa94a07fSbrendan * Include level 2 ARC devices in iostat output 1687fa94a07fSbrendan */ 1688fa94a07fSbrendan if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 1689fa94a07fSbrendan &newchild, &children) != 0) 1690fa94a07fSbrendan return; 1691fa94a07fSbrendan 1692fa94a07fSbrendan if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 1693fa94a07fSbrendan &oldchild, &c) != 0) 1694fa94a07fSbrendan return; 1695fa94a07fSbrendan 1696fa94a07fSbrendan if (children > 0) { 1697fa94a07fSbrendan (void) printf("%-*s - - - - - " 1698fa94a07fSbrendan "-\n", cb->cb_namewidth, "cache"); 1699fa94a07fSbrendan for (c = 0; c < children; c++) { 1700fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1701fa94a07fSbrendan print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1702fa94a07fSbrendan newchild[c], cb, depth + 2); 1703fa94a07fSbrendan free(vname); 1704fa94a07fSbrendan } 1705fa94a07fSbrendan } 1706fa9e4066Sahrens } 1707fa9e4066Sahrens 1708088e9d47Seschrock static int 1709088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 1710088e9d47Seschrock { 1711088e9d47Seschrock iostat_cbdata_t *cb = data; 171294de1d4cSeschrock boolean_t missing; 1713088e9d47Seschrock 1714088e9d47Seschrock /* 1715088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 1716088e9d47Seschrock */ 171794de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 171894de1d4cSeschrock return (-1); 171994de1d4cSeschrock 172094de1d4cSeschrock if (missing) 1721088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 1722088e9d47Seschrock 1723088e9d47Seschrock return (0); 1724088e9d47Seschrock } 1725088e9d47Seschrock 1726fa9e4066Sahrens /* 1727fa9e4066Sahrens * Callback to print out the iostats for the given pool. 1728fa9e4066Sahrens */ 1729fa9e4066Sahrens int 1730fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 1731fa9e4066Sahrens { 1732fa9e4066Sahrens iostat_cbdata_t *cb = data; 1733fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 1734fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 1735fa9e4066Sahrens 1736088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 1737fa9e4066Sahrens 1738088e9d47Seschrock if (cb->cb_iteration == 1) 1739fa9e4066Sahrens oldconfig = NULL; 1740fa9e4066Sahrens 1741fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1742fa9e4066Sahrens &newnvroot) == 0); 1743fa9e4066Sahrens 1744088e9d47Seschrock if (oldconfig == NULL) 1745fa9e4066Sahrens oldnvroot = NULL; 1746088e9d47Seschrock else 1747088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 1748088e9d47Seschrock &oldnvroot) == 0); 1749fa9e4066Sahrens 1750fa9e4066Sahrens /* 1751fa9e4066Sahrens * Print out the statistics for the pool. 1752fa9e4066Sahrens */ 1753c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1754fa9e4066Sahrens 1755fa9e4066Sahrens if (cb->cb_verbose) 1756fa9e4066Sahrens print_iostat_separator(cb); 1757fa9e4066Sahrens 1758fa9e4066Sahrens return (0); 1759fa9e4066Sahrens } 1760fa9e4066Sahrens 1761fa9e4066Sahrens int 1762fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 1763fa9e4066Sahrens { 1764fa9e4066Sahrens iostat_cbdata_t *cb = data; 1765fa9e4066Sahrens nvlist_t *config, *nvroot; 1766fa9e4066Sahrens 1767088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 1768fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1769fa9e4066Sahrens &nvroot) == 0); 1770fa9e4066Sahrens if (!cb->cb_verbose) 1771fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1772fa9e4066Sahrens else 1773c67d9675Seschrock cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 1774fa9e4066Sahrens } 1775fa9e4066Sahrens 1776fa9e4066Sahrens /* 1777fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 1778fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 1779fa9e4066Sahrens */ 1780fa9e4066Sahrens if (cb->cb_namewidth < 10) 1781fa9e4066Sahrens cb->cb_namewidth = 10; 1782fa9e4066Sahrens if (cb->cb_namewidth > 38) 1783fa9e4066Sahrens cb->cb_namewidth = 38; 1784fa9e4066Sahrens 1785fa9e4066Sahrens return (0); 1786fa9e4066Sahrens } 1787fa9e4066Sahrens 1788fa9e4066Sahrens /* 1789fa9e4066Sahrens * zpool iostat [-v] [pool] ... [interval [count]] 1790fa9e4066Sahrens * 1791fa9e4066Sahrens * -v Display statistics for individual vdevs 1792fa9e4066Sahrens * 1793fa9e4066Sahrens * This command can be tricky because we want to be able to deal with pool 1794fa9e4066Sahrens * creation/destruction as well as vdev configuration changes. The bulk of this 1795fa9e4066Sahrens * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1796fa9e4066Sahrens * on pool_list_update() to detect the addition of new pools. Configuration 1797fa9e4066Sahrens * changes are all handled within libzfs. 1798fa9e4066Sahrens */ 1799fa9e4066Sahrens int 1800fa9e4066Sahrens zpool_do_iostat(int argc, char **argv) 1801fa9e4066Sahrens { 1802fa9e4066Sahrens int c; 1803fa9e4066Sahrens int ret; 1804fa9e4066Sahrens int npools; 1805fa9e4066Sahrens unsigned long interval = 0, count = 0; 1806fa9e4066Sahrens zpool_list_t *list; 180799653d4eSeschrock boolean_t verbose = B_FALSE; 1808fa9e4066Sahrens iostat_cbdata_t cb; 1809fa9e4066Sahrens 1810fa9e4066Sahrens /* check options */ 1811fa9e4066Sahrens while ((c = getopt(argc, argv, "v")) != -1) { 1812fa9e4066Sahrens switch (c) { 1813fa9e4066Sahrens case 'v': 181499653d4eSeschrock verbose = B_TRUE; 1815fa9e4066Sahrens break; 1816fa9e4066Sahrens case '?': 1817fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1818fa9e4066Sahrens optopt); 181999653d4eSeschrock usage(B_FALSE); 1820fa9e4066Sahrens } 1821fa9e4066Sahrens } 1822fa9e4066Sahrens 1823fa9e4066Sahrens argc -= optind; 1824fa9e4066Sahrens argv += optind; 1825fa9e4066Sahrens 1826fa9e4066Sahrens /* 1827fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 1828fa9e4066Sahrens */ 1829fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1830fa9e4066Sahrens char *end; 1831fa9e4066Sahrens 1832fa9e4066Sahrens errno = 0; 1833fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1834fa9e4066Sahrens 1835fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1836fa9e4066Sahrens if (interval == 0) { 1837fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1838fa9e4066Sahrens "cannot be zero\n")); 183999653d4eSeschrock usage(B_FALSE); 1840fa9e4066Sahrens } 1841fa9e4066Sahrens 1842fa9e4066Sahrens /* 1843fa9e4066Sahrens * Ignore the last parameter 1844fa9e4066Sahrens */ 1845fa9e4066Sahrens argc--; 1846fa9e4066Sahrens } else { 1847fa9e4066Sahrens /* 1848fa9e4066Sahrens * If this is not a valid number, just plow on. The 1849fa9e4066Sahrens * user will get a more informative error message later 1850fa9e4066Sahrens * on. 1851fa9e4066Sahrens */ 1852fa9e4066Sahrens interval = 0; 1853fa9e4066Sahrens } 1854fa9e4066Sahrens } 1855fa9e4066Sahrens 1856fa9e4066Sahrens /* 1857fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 1858fa9e4066Sahrens * and an integer. 1859fa9e4066Sahrens */ 1860fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1861fa9e4066Sahrens char *end; 1862fa9e4066Sahrens 1863fa9e4066Sahrens errno = 0; 1864fa9e4066Sahrens count = interval; 1865fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1866fa9e4066Sahrens 1867fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1868fa9e4066Sahrens if (interval == 0) { 1869fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1870fa9e4066Sahrens "cannot be zero\n")); 187199653d4eSeschrock usage(B_FALSE); 1872fa9e4066Sahrens } 1873fa9e4066Sahrens 1874fa9e4066Sahrens /* 1875fa9e4066Sahrens * Ignore the last parameter 1876fa9e4066Sahrens */ 1877fa9e4066Sahrens argc--; 1878fa9e4066Sahrens } else { 1879fa9e4066Sahrens interval = 0; 1880fa9e4066Sahrens } 1881fa9e4066Sahrens } 1882fa9e4066Sahrens 1883fa9e4066Sahrens /* 1884fa9e4066Sahrens * Construct the list of all interesting pools. 1885fa9e4066Sahrens */ 1886fa9e4066Sahrens ret = 0; 1887b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 1888fa9e4066Sahrens return (1); 1889fa9e4066Sahrens 189099653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 189199653d4eSeschrock pool_list_free(list); 1892fa9e4066Sahrens return (1); 189399653d4eSeschrock } 1894fa9e4066Sahrens 1895fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 189699653d4eSeschrock pool_list_free(list); 1897fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 1898fa9e4066Sahrens return (1); 1899fa9e4066Sahrens } 1900fa9e4066Sahrens 1901fa9e4066Sahrens /* 1902fa9e4066Sahrens * Enter the main iostat loop. 1903fa9e4066Sahrens */ 1904fa9e4066Sahrens cb.cb_list = list; 1905fa9e4066Sahrens cb.cb_verbose = verbose; 1906fa9e4066Sahrens cb.cb_iteration = 0; 1907fa9e4066Sahrens cb.cb_namewidth = 0; 1908fa9e4066Sahrens 1909fa9e4066Sahrens for (;;) { 1910fa9e4066Sahrens pool_list_update(list); 1911fa9e4066Sahrens 1912fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 1913fa9e4066Sahrens break; 1914fa9e4066Sahrens 1915fa9e4066Sahrens /* 1916088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 1917088e9d47Seschrock * before calculating the maximum name width, so that any 1918088e9d47Seschrock * configuration changes are properly accounted for. 1919088e9d47Seschrock */ 192099653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 1921088e9d47Seschrock 1922088e9d47Seschrock /* 1923fa9e4066Sahrens * Iterate over all pools to determine the maximum width 1924fa9e4066Sahrens * for the pool / device name column across all pools. 1925fa9e4066Sahrens */ 1926fa9e4066Sahrens cb.cb_namewidth = 0; 192799653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 1928fa9e4066Sahrens 1929fa9e4066Sahrens /* 1930fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 1931fa9e4066Sahrens */ 1932fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 1933fa9e4066Sahrens print_iostat_header(&cb); 1934fa9e4066Sahrens 193599653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 1936fa9e4066Sahrens 1937fa9e4066Sahrens /* 1938fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 1939fa9e4066Sahrens * (which prints a separator for us), then print a separator. 1940fa9e4066Sahrens */ 1941fa9e4066Sahrens if (npools > 1 && !verbose) 1942fa9e4066Sahrens print_iostat_separator(&cb); 1943fa9e4066Sahrens 1944fa9e4066Sahrens if (verbose) 1945fa9e4066Sahrens (void) printf("\n"); 1946fa9e4066Sahrens 194739c23413Seschrock /* 194839c23413Seschrock * Flush the output so that redirection to a file isn't buffered 194939c23413Seschrock * indefinitely. 195039c23413Seschrock */ 195139c23413Seschrock (void) fflush(stdout); 195239c23413Seschrock 1953fa9e4066Sahrens if (interval == 0) 1954fa9e4066Sahrens break; 1955fa9e4066Sahrens 1956fa9e4066Sahrens if (count != 0 && --count == 0) 1957fa9e4066Sahrens break; 1958fa9e4066Sahrens 1959fa9e4066Sahrens (void) sleep(interval); 1960fa9e4066Sahrens } 1961fa9e4066Sahrens 1962fa9e4066Sahrens pool_list_free(list); 1963fa9e4066Sahrens 1964fa9e4066Sahrens return (ret); 1965fa9e4066Sahrens } 1966fa9e4066Sahrens 1967fa9e4066Sahrens typedef struct list_cbdata { 196899653d4eSeschrock boolean_t cb_scripted; 196999653d4eSeschrock boolean_t cb_first; 1970990b4856Slling zprop_list_t *cb_proplist; 1971fa9e4066Sahrens } list_cbdata_t; 1972fa9e4066Sahrens 1973fa9e4066Sahrens /* 1974fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 1975fa9e4066Sahrens */ 1976990b4856Slling static void 1977990b4856Slling print_header(zprop_list_t *pl) 1978fa9e4066Sahrens { 1979990b4856Slling const char *header; 1980990b4856Slling boolean_t first = B_TRUE; 1981990b4856Slling boolean_t right_justify; 1982fa9e4066Sahrens 1983990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 1984990b4856Slling if (pl->pl_prop == ZPROP_INVAL) 1985990b4856Slling continue; 1986990b4856Slling 1987990b4856Slling if (!first) 1988fa9e4066Sahrens (void) printf(" "); 1989fa9e4066Sahrens else 1990990b4856Slling first = B_FALSE; 1991fa9e4066Sahrens 1992990b4856Slling header = zpool_prop_column_name(pl->pl_prop); 1993990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 1994990b4856Slling 1995990b4856Slling if (pl->pl_next == NULL && !right_justify) 1996990b4856Slling (void) printf("%s", header); 1997990b4856Slling else if (right_justify) 1998990b4856Slling (void) printf("%*s", pl->pl_width, header); 1999990b4856Slling else 2000990b4856Slling (void) printf("%-*s", pl->pl_width, header); 2001fa9e4066Sahrens } 2002fa9e4066Sahrens 2003fa9e4066Sahrens (void) printf("\n"); 2004fa9e4066Sahrens } 2005fa9e4066Sahrens 2006990b4856Slling /* 2007990b4856Slling * Given a pool and a list of properties, print out all the properties according 2008990b4856Slling * to the described layout. 2009990b4856Slling */ 2010990b4856Slling static void 2011990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 2012990b4856Slling { 2013990b4856Slling boolean_t first = B_TRUE; 2014990b4856Slling char property[ZPOOL_MAXPROPLEN]; 2015990b4856Slling char *propstr; 2016990b4856Slling boolean_t right_justify; 2017990b4856Slling int width; 2018990b4856Slling 2019990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 2020990b4856Slling if (!first) { 2021990b4856Slling if (scripted) 2022990b4856Slling (void) printf("\t"); 2023990b4856Slling else 2024990b4856Slling (void) printf(" "); 2025990b4856Slling } else { 2026990b4856Slling first = B_FALSE; 2027990b4856Slling } 2028990b4856Slling 2029990b4856Slling right_justify = B_FALSE; 2030990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 2031990b4856Slling if (zpool_get_prop(zhp, pl->pl_prop, property, 2032990b4856Slling sizeof (property), NULL) != 0) 2033990b4856Slling propstr = "-"; 2034990b4856Slling else 2035990b4856Slling propstr = property; 2036990b4856Slling 2037990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2038990b4856Slling } else { 2039990b4856Slling propstr = "-"; 2040990b4856Slling } 2041990b4856Slling 2042990b4856Slling width = pl->pl_width; 2043990b4856Slling 2044990b4856Slling /* 2045990b4856Slling * If this is being called in scripted mode, or if this is the 2046990b4856Slling * last column and it is left-justified, don't include a width 2047990b4856Slling * format specifier. 2048990b4856Slling */ 2049990b4856Slling if (scripted || (pl->pl_next == NULL && !right_justify)) 2050990b4856Slling (void) printf("%s", propstr); 2051990b4856Slling else if (right_justify) 2052990b4856Slling (void) printf("%*s", width, propstr); 2053990b4856Slling else 2054990b4856Slling (void) printf("%-*s", width, propstr); 2055990b4856Slling } 2056990b4856Slling 2057990b4856Slling (void) printf("\n"); 2058990b4856Slling } 2059990b4856Slling 2060990b4856Slling /* 2061990b4856Slling * Generic callback function to list a pool. 2062990b4856Slling */ 2063fa9e4066Sahrens int 2064fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data) 2065fa9e4066Sahrens { 2066fa9e4066Sahrens list_cbdata_t *cbp = data; 2067fa9e4066Sahrens 2068fa9e4066Sahrens if (cbp->cb_first) { 2069fa9e4066Sahrens if (!cbp->cb_scripted) 2070990b4856Slling print_header(cbp->cb_proplist); 207199653d4eSeschrock cbp->cb_first = B_FALSE; 2072fa9e4066Sahrens } 2073fa9e4066Sahrens 2074990b4856Slling print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2075fa9e4066Sahrens 2076fa9e4066Sahrens return (0); 2077fa9e4066Sahrens } 2078fa9e4066Sahrens 2079fa9e4066Sahrens /* 2080990b4856Slling * zpool list [-H] [-o prop[,prop]*] [pool] ... 2081fa9e4066Sahrens * 2082990b4856Slling * -H Scripted mode. Don't display headers, and separate properties 2083990b4856Slling * by a single tab. 2084990b4856Slling * -o List of properties to display. Defaults to 2085990b4856Slling * "name,size,used,available,capacity,health,altroot" 2086fa9e4066Sahrens * 2087fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 2088fa9e4066Sahrens * statistics for each one, as well as health status summary. 2089fa9e4066Sahrens */ 2090fa9e4066Sahrens int 2091fa9e4066Sahrens zpool_do_list(int argc, char **argv) 2092fa9e4066Sahrens { 2093fa9e4066Sahrens int c; 2094fa9e4066Sahrens int ret; 2095fa9e4066Sahrens list_cbdata_t cb = { 0 }; 2096990b4856Slling static char default_props[] = 2097990b4856Slling "name,size,used,available,capacity,health,altroot"; 2098990b4856Slling char *props = default_props; 2099fa9e4066Sahrens 2100fa9e4066Sahrens /* check options */ 2101fa9e4066Sahrens while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2102fa9e4066Sahrens switch (c) { 2103fa9e4066Sahrens case 'H': 210499653d4eSeschrock cb.cb_scripted = B_TRUE; 2105fa9e4066Sahrens break; 2106fa9e4066Sahrens case 'o': 2107990b4856Slling props = optarg; 2108fa9e4066Sahrens break; 2109fa9e4066Sahrens case ':': 2110fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2111fa9e4066Sahrens "'%c' option\n"), optopt); 211299653d4eSeschrock usage(B_FALSE); 2113fa9e4066Sahrens break; 2114fa9e4066Sahrens case '?': 2115fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2116fa9e4066Sahrens optopt); 211799653d4eSeschrock usage(B_FALSE); 2118fa9e4066Sahrens } 2119fa9e4066Sahrens } 2120fa9e4066Sahrens 2121fa9e4066Sahrens argc -= optind; 2122fa9e4066Sahrens argv += optind; 2123fa9e4066Sahrens 2124990b4856Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 212599653d4eSeschrock usage(B_FALSE); 2126fa9e4066Sahrens 212799653d4eSeschrock cb.cb_first = B_TRUE; 2128fa9e4066Sahrens 2129990b4856Slling ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2130990b4856Slling list_callback, &cb); 2131990b4856Slling 2132990b4856Slling zprop_free_list(cb.cb_proplist); 2133fa9e4066Sahrens 2134fce7d82bSmmusante if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2135fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 2136fa9e4066Sahrens return (0); 2137fa9e4066Sahrens } 2138fa9e4066Sahrens 2139fa9e4066Sahrens return (ret); 2140fa9e4066Sahrens } 2141fa9e4066Sahrens 2142fa9e4066Sahrens static nvlist_t * 2143fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name) 2144fa9e4066Sahrens { 2145fa9e4066Sahrens nvlist_t **child; 2146fa9e4066Sahrens uint_t c, children; 2147fa9e4066Sahrens nvlist_t *match; 2148fa9e4066Sahrens char *path; 2149fa9e4066Sahrens 2150fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2151fa9e4066Sahrens &child, &children) != 0) { 2152fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2153fa9e4066Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0) 2154fa9e4066Sahrens name += 9; 2155fa9e4066Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0) 2156fa9e4066Sahrens path += 9; 2157fa9e4066Sahrens if (strcmp(name, path) == 0) 2158fa9e4066Sahrens return (nv); 2159fa9e4066Sahrens return (NULL); 2160fa9e4066Sahrens } 2161fa9e4066Sahrens 2162fa9e4066Sahrens for (c = 0; c < children; c++) 2163fa9e4066Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2164fa9e4066Sahrens return (match); 2165fa9e4066Sahrens 2166fa9e4066Sahrens return (NULL); 2167fa9e4066Sahrens } 2168fa9e4066Sahrens 2169fa9e4066Sahrens static int 2170fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 2171fa9e4066Sahrens { 217299653d4eSeschrock boolean_t force = B_FALSE; 2173fa9e4066Sahrens int c; 2174fa9e4066Sahrens nvlist_t *nvroot; 2175fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 2176fa9e4066Sahrens zpool_handle_t *zhp; 217799653d4eSeschrock int ret; 2178fa9e4066Sahrens 2179fa9e4066Sahrens /* check options */ 2180fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2181fa9e4066Sahrens switch (c) { 2182fa9e4066Sahrens case 'f': 218399653d4eSeschrock force = B_TRUE; 2184fa9e4066Sahrens break; 2185fa9e4066Sahrens case '?': 2186fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2187fa9e4066Sahrens optopt); 218899653d4eSeschrock usage(B_FALSE); 2189fa9e4066Sahrens } 2190fa9e4066Sahrens } 2191fa9e4066Sahrens 2192fa9e4066Sahrens argc -= optind; 2193fa9e4066Sahrens argv += optind; 2194fa9e4066Sahrens 2195fa9e4066Sahrens /* get pool name and check number of arguments */ 2196fa9e4066Sahrens if (argc < 1) { 2197fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 219899653d4eSeschrock usage(B_FALSE); 2199fa9e4066Sahrens } 2200fa9e4066Sahrens 2201fa9e4066Sahrens poolname = argv[0]; 2202fa9e4066Sahrens 2203fa9e4066Sahrens if (argc < 2) { 2204fa9e4066Sahrens (void) fprintf(stderr, 2205fa9e4066Sahrens gettext("missing <device> specification\n")); 220699653d4eSeschrock usage(B_FALSE); 2207fa9e4066Sahrens } 2208fa9e4066Sahrens 2209fa9e4066Sahrens old_disk = argv[1]; 2210fa9e4066Sahrens 2211fa9e4066Sahrens if (argc < 3) { 2212fa9e4066Sahrens if (!replacing) { 2213fa9e4066Sahrens (void) fprintf(stderr, 2214fa9e4066Sahrens gettext("missing <new_device> specification\n")); 221599653d4eSeschrock usage(B_FALSE); 2216fa9e4066Sahrens } 2217fa9e4066Sahrens new_disk = old_disk; 2218fa9e4066Sahrens argc -= 1; 2219fa9e4066Sahrens argv += 1; 2220fa9e4066Sahrens } else { 2221fa9e4066Sahrens new_disk = argv[2]; 2222fa9e4066Sahrens argc -= 2; 2223fa9e4066Sahrens argv += 2; 2224fa9e4066Sahrens } 2225fa9e4066Sahrens 2226fa9e4066Sahrens if (argc > 1) { 2227fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 222899653d4eSeschrock usage(B_FALSE); 2229fa9e4066Sahrens } 2230fa9e4066Sahrens 223199653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2232fa9e4066Sahrens return (1); 2233fa9e4066Sahrens 22348488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 2235fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2236fa9e4066Sahrens poolname); 2237fa9e4066Sahrens zpool_close(zhp); 2238fa9e4066Sahrens return (1); 2239fa9e4066Sahrens } 2240fa9e4066Sahrens 22418488aeb5Staylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv); 2242fa9e4066Sahrens if (nvroot == NULL) { 2243fa9e4066Sahrens zpool_close(zhp); 2244fa9e4066Sahrens return (1); 2245fa9e4066Sahrens } 2246fa9e4066Sahrens 224799653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 224899653d4eSeschrock 224999653d4eSeschrock nvlist_free(nvroot); 225099653d4eSeschrock zpool_close(zhp); 225199653d4eSeschrock 225299653d4eSeschrock return (ret); 2253fa9e4066Sahrens } 2254fa9e4066Sahrens 2255fa9e4066Sahrens /* 2256fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 2257fa9e4066Sahrens * 2258fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2259fa9e4066Sahrens * 2260fa9e4066Sahrens * Replace <device> with <new_device>. 2261fa9e4066Sahrens */ 2262fa9e4066Sahrens /* ARGSUSED */ 2263fa9e4066Sahrens int 2264fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 2265fa9e4066Sahrens { 2266fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2267fa9e4066Sahrens } 2268fa9e4066Sahrens 2269fa9e4066Sahrens /* 2270fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 2271fa9e4066Sahrens * 2272fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2273fa9e4066Sahrens * 2274fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 2275fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 2276fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 2277fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 2278fa9e4066Sahrens */ 2279fa9e4066Sahrens int 2280fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 2281fa9e4066Sahrens { 2282fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2283fa9e4066Sahrens } 2284fa9e4066Sahrens 2285fa9e4066Sahrens /* 2286fa9e4066Sahrens * zpool detach [-f] <pool> <device> 2287fa9e4066Sahrens * 2288fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 2289fa9e4066Sahrens * (not supported yet) 2290fa9e4066Sahrens * 2291fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 2292fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 2293fa9e4066Sahrens * has the only valid copy of some data. 2294fa9e4066Sahrens */ 2295fa9e4066Sahrens /* ARGSUSED */ 2296fa9e4066Sahrens int 2297fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 2298fa9e4066Sahrens { 2299fa9e4066Sahrens int c; 2300fa9e4066Sahrens char *poolname, *path; 2301fa9e4066Sahrens zpool_handle_t *zhp; 230299653d4eSeschrock int ret; 2303fa9e4066Sahrens 2304fa9e4066Sahrens /* check options */ 2305fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2306fa9e4066Sahrens switch (c) { 2307fa9e4066Sahrens case 'f': 2308fa9e4066Sahrens case '?': 2309fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2310fa9e4066Sahrens optopt); 231199653d4eSeschrock usage(B_FALSE); 2312fa9e4066Sahrens } 2313fa9e4066Sahrens } 2314fa9e4066Sahrens 2315fa9e4066Sahrens argc -= optind; 2316fa9e4066Sahrens argv += optind; 2317fa9e4066Sahrens 2318fa9e4066Sahrens /* get pool name and check number of arguments */ 2319fa9e4066Sahrens if (argc < 1) { 2320fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 232199653d4eSeschrock usage(B_FALSE); 2322fa9e4066Sahrens } 2323fa9e4066Sahrens 2324fa9e4066Sahrens if (argc < 2) { 2325fa9e4066Sahrens (void) fprintf(stderr, 2326fa9e4066Sahrens gettext("missing <device> specification\n")); 232799653d4eSeschrock usage(B_FALSE); 2328fa9e4066Sahrens } 2329fa9e4066Sahrens 2330fa9e4066Sahrens poolname = argv[0]; 2331fa9e4066Sahrens path = argv[1]; 2332fa9e4066Sahrens 233399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2334fa9e4066Sahrens return (1); 2335fa9e4066Sahrens 233699653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 233799653d4eSeschrock 233899653d4eSeschrock zpool_close(zhp); 233999653d4eSeschrock 234099653d4eSeschrock return (ret); 2341fa9e4066Sahrens } 2342fa9e4066Sahrens 2343fa9e4066Sahrens /* 2344441d80aaSlling * zpool online <pool> <device> ... 2345fa9e4066Sahrens */ 2346fa9e4066Sahrens int 2347fa9e4066Sahrens zpool_do_online(int argc, char **argv) 2348fa9e4066Sahrens { 2349fa9e4066Sahrens int c, i; 2350fa9e4066Sahrens char *poolname; 2351fa9e4066Sahrens zpool_handle_t *zhp; 2352fa9e4066Sahrens int ret = 0; 23533d7072f8Seschrock vdev_state_t newstate; 2354fa9e4066Sahrens 2355fa9e4066Sahrens /* check options */ 2356fa9e4066Sahrens while ((c = getopt(argc, argv, "t")) != -1) { 2357fa9e4066Sahrens switch (c) { 2358fa9e4066Sahrens case 't': 2359fa9e4066Sahrens case '?': 2360fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2361fa9e4066Sahrens optopt); 236299653d4eSeschrock usage(B_FALSE); 2363fa9e4066Sahrens } 2364fa9e4066Sahrens } 2365fa9e4066Sahrens 2366fa9e4066Sahrens argc -= optind; 2367fa9e4066Sahrens argv += optind; 2368fa9e4066Sahrens 2369fa9e4066Sahrens /* get pool name and check number of arguments */ 2370fa9e4066Sahrens if (argc < 1) { 2371fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 237299653d4eSeschrock usage(B_FALSE); 2373fa9e4066Sahrens } 2374fa9e4066Sahrens if (argc < 2) { 2375fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 237699653d4eSeschrock usage(B_FALSE); 2377fa9e4066Sahrens } 2378fa9e4066Sahrens 2379fa9e4066Sahrens poolname = argv[0]; 2380fa9e4066Sahrens 238199653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2382fa9e4066Sahrens return (1); 2383fa9e4066Sahrens 23843d7072f8Seschrock for (i = 1; i < argc; i++) { 23853d7072f8Seschrock if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) { 23863d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 23873d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 23883d7072f8Seschrock "onlined, but remains in faulted state\n"), 2389fa9e4066Sahrens argv[i]); 23903d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 23913d7072f8Seschrock (void) printf(gettext("use 'zpool " 23923d7072f8Seschrock "clear' to restore a faulted " 23933d7072f8Seschrock "device\n")); 2394fa9e4066Sahrens else 23953d7072f8Seschrock (void) printf(gettext("use 'zpool " 23963d7072f8Seschrock "replace' to replace devices " 23973d7072f8Seschrock "that are no longer present\n")); 23983d7072f8Seschrock } 23993d7072f8Seschrock } else { 2400fa9e4066Sahrens ret = 1; 24013d7072f8Seschrock } 24023d7072f8Seschrock } 2403fa9e4066Sahrens 240499653d4eSeschrock zpool_close(zhp); 240599653d4eSeschrock 2406fa9e4066Sahrens return (ret); 2407fa9e4066Sahrens } 2408fa9e4066Sahrens 2409fa9e4066Sahrens /* 2410441d80aaSlling * zpool offline [-ft] <pool> <device> ... 2411fa9e4066Sahrens * 2412fa9e4066Sahrens * -f Force the device into the offline state, even if doing 2413fa9e4066Sahrens * so would appear to compromise pool availability. 2414fa9e4066Sahrens * (not supported yet) 2415fa9e4066Sahrens * 2416fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 2417fa9e4066Sahrens * state will not be persistent across reboots. 2418fa9e4066Sahrens */ 2419fa9e4066Sahrens /* ARGSUSED */ 2420fa9e4066Sahrens int 2421fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 2422fa9e4066Sahrens { 2423fa9e4066Sahrens int c, i; 2424fa9e4066Sahrens char *poolname; 2425fa9e4066Sahrens zpool_handle_t *zhp; 242699653d4eSeschrock int ret = 0; 242799653d4eSeschrock boolean_t istmp = B_FALSE; 2428fa9e4066Sahrens 2429fa9e4066Sahrens /* check options */ 2430fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 2431fa9e4066Sahrens switch (c) { 2432fa9e4066Sahrens case 't': 243399653d4eSeschrock istmp = B_TRUE; 2434441d80aaSlling break; 2435441d80aaSlling case 'f': 2436fa9e4066Sahrens case '?': 2437fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2438fa9e4066Sahrens optopt); 243999653d4eSeschrock usage(B_FALSE); 2440fa9e4066Sahrens } 2441fa9e4066Sahrens } 2442fa9e4066Sahrens 2443fa9e4066Sahrens argc -= optind; 2444fa9e4066Sahrens argv += optind; 2445fa9e4066Sahrens 2446fa9e4066Sahrens /* get pool name and check number of arguments */ 2447fa9e4066Sahrens if (argc < 1) { 2448fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 244999653d4eSeschrock usage(B_FALSE); 2450fa9e4066Sahrens } 2451fa9e4066Sahrens if (argc < 2) { 2452fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 245399653d4eSeschrock usage(B_FALSE); 2454fa9e4066Sahrens } 2455fa9e4066Sahrens 2456fa9e4066Sahrens poolname = argv[0]; 2457fa9e4066Sahrens 245899653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2459fa9e4066Sahrens return (1); 2460fa9e4066Sahrens 24613d7072f8Seschrock for (i = 1; i < argc; i++) { 24623d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2463fa9e4066Sahrens ret = 1; 24643d7072f8Seschrock } 2465fa9e4066Sahrens 246699653d4eSeschrock zpool_close(zhp); 246799653d4eSeschrock 2468fa9e4066Sahrens return (ret); 2469fa9e4066Sahrens } 2470fa9e4066Sahrens 2471ea8dc4b6Seschrock /* 2472ea8dc4b6Seschrock * zpool clear <pool> [device] 2473ea8dc4b6Seschrock * 2474ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 2475ea8dc4b6Seschrock */ 2476ea8dc4b6Seschrock int 2477ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 2478ea8dc4b6Seschrock { 2479ea8dc4b6Seschrock int ret = 0; 2480ea8dc4b6Seschrock zpool_handle_t *zhp; 2481ea8dc4b6Seschrock char *pool, *device; 2482ea8dc4b6Seschrock 2483ea8dc4b6Seschrock if (argc < 2) { 2484ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 248599653d4eSeschrock usage(B_FALSE); 2486ea8dc4b6Seschrock } 2487ea8dc4b6Seschrock 2488ea8dc4b6Seschrock if (argc > 3) { 2489ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 249099653d4eSeschrock usage(B_FALSE); 2491ea8dc4b6Seschrock } 2492ea8dc4b6Seschrock 2493ea8dc4b6Seschrock pool = argv[1]; 2494ea8dc4b6Seschrock device = argc == 3 ? argv[2] : NULL; 2495ea8dc4b6Seschrock 249699653d4eSeschrock if ((zhp = zpool_open(g_zfs, pool)) == NULL) 2497ea8dc4b6Seschrock return (1); 2498ea8dc4b6Seschrock 2499ea8dc4b6Seschrock if (zpool_clear(zhp, device) != 0) 2500ea8dc4b6Seschrock ret = 1; 2501ea8dc4b6Seschrock 2502ea8dc4b6Seschrock zpool_close(zhp); 2503ea8dc4b6Seschrock 2504ea8dc4b6Seschrock return (ret); 2505ea8dc4b6Seschrock } 2506ea8dc4b6Seschrock 2507fa9e4066Sahrens typedef struct scrub_cbdata { 2508fa9e4066Sahrens int cb_type; 250906eeb2adSek110237 int cb_argc; 251006eeb2adSek110237 char **cb_argv; 2511fa9e4066Sahrens } scrub_cbdata_t; 2512fa9e4066Sahrens 2513fa9e4066Sahrens int 2514fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 2515fa9e4066Sahrens { 2516fa9e4066Sahrens scrub_cbdata_t *cb = data; 251706eeb2adSek110237 int err; 2518fa9e4066Sahrens 2519ea8dc4b6Seschrock /* 2520ea8dc4b6Seschrock * Ignore faulted pools. 2521ea8dc4b6Seschrock */ 2522ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2523ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2524ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 2525ea8dc4b6Seschrock return (1); 2526ea8dc4b6Seschrock } 2527ea8dc4b6Seschrock 252806eeb2adSek110237 err = zpool_scrub(zhp, cb->cb_type); 252906eeb2adSek110237 253006eeb2adSek110237 return (err != 0); 2531fa9e4066Sahrens } 2532fa9e4066Sahrens 2533fa9e4066Sahrens /* 2534fa9e4066Sahrens * zpool scrub [-s] <pool> ... 2535fa9e4066Sahrens * 2536fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 2537fa9e4066Sahrens */ 2538fa9e4066Sahrens int 2539fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 2540fa9e4066Sahrens { 2541fa9e4066Sahrens int c; 2542fa9e4066Sahrens scrub_cbdata_t cb; 2543fa9e4066Sahrens 2544fa9e4066Sahrens cb.cb_type = POOL_SCRUB_EVERYTHING; 2545fa9e4066Sahrens 2546fa9e4066Sahrens /* check options */ 2547fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 2548fa9e4066Sahrens switch (c) { 2549fa9e4066Sahrens case 's': 2550fa9e4066Sahrens cb.cb_type = POOL_SCRUB_NONE; 2551fa9e4066Sahrens break; 2552fa9e4066Sahrens case '?': 2553fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2554fa9e4066Sahrens optopt); 255599653d4eSeschrock usage(B_FALSE); 2556fa9e4066Sahrens } 2557fa9e4066Sahrens } 2558fa9e4066Sahrens 255906eeb2adSek110237 cb.cb_argc = argc; 256006eeb2adSek110237 cb.cb_argv = argv; 2561fa9e4066Sahrens argc -= optind; 2562fa9e4066Sahrens argv += optind; 2563fa9e4066Sahrens 2564fa9e4066Sahrens if (argc < 1) { 2565fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 256699653d4eSeschrock usage(B_FALSE); 2567fa9e4066Sahrens } 2568fa9e4066Sahrens 2569b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2570fa9e4066Sahrens } 2571fa9e4066Sahrens 2572fa9e4066Sahrens typedef struct status_cbdata { 2573fa9e4066Sahrens int cb_count; 2574e9dbad6fSeschrock boolean_t cb_allpools; 257599653d4eSeschrock boolean_t cb_verbose; 257699653d4eSeschrock boolean_t cb_explain; 257799653d4eSeschrock boolean_t cb_first; 2578fa9e4066Sahrens } status_cbdata_t; 2579fa9e4066Sahrens 2580fa9e4066Sahrens /* 2581fa9e4066Sahrens * Print out detailed scrub status. 2582fa9e4066Sahrens */ 2583fa9e4066Sahrens void 2584fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot) 2585fa9e4066Sahrens { 2586fa9e4066Sahrens vdev_stat_t *vs; 2587fa9e4066Sahrens uint_t vsc; 2588fa9e4066Sahrens time_t start, end, now; 2589fa9e4066Sahrens double fraction_done; 259018ce54dfSek110237 uint64_t examined, total, minutes_left, minutes_taken; 2591fa9e4066Sahrens char *scrub_type; 2592fa9e4066Sahrens 2593fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2594fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 2595fa9e4066Sahrens 2596fa9e4066Sahrens /* 2597fa9e4066Sahrens * If there's never been a scrub, there's not much to say. 2598fa9e4066Sahrens */ 2599fa9e4066Sahrens if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2600fa9e4066Sahrens (void) printf(gettext("none requested\n")); 2601fa9e4066Sahrens return; 2602fa9e4066Sahrens } 2603fa9e4066Sahrens 2604fa9e4066Sahrens scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2605fa9e4066Sahrens "resilver" : "scrub"; 2606fa9e4066Sahrens 2607fa9e4066Sahrens start = vs->vs_scrub_start; 2608fa9e4066Sahrens end = vs->vs_scrub_end; 2609fa9e4066Sahrens now = time(NULL); 2610fa9e4066Sahrens examined = vs->vs_scrub_examined; 2611fa9e4066Sahrens total = vs->vs_alloc; 2612fa9e4066Sahrens 2613fa9e4066Sahrens if (end != 0) { 261418ce54dfSek110237 minutes_taken = (uint64_t)((end - start) / 60); 261518ce54dfSek110237 261618ce54dfSek110237 (void) printf(gettext("%s %s after %lluh%um with %llu errors " 261718ce54dfSek110237 "on %s"), 2618fa9e4066Sahrens scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 261918ce54dfSek110237 (u_longlong_t)(minutes_taken / 60), 262018ce54dfSek110237 (uint_t)(minutes_taken % 60), 2621fa9e4066Sahrens (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2622fa9e4066Sahrens return; 2623fa9e4066Sahrens } 2624fa9e4066Sahrens 2625fa9e4066Sahrens if (examined == 0) 2626fa9e4066Sahrens examined = 1; 2627fa9e4066Sahrens if (examined > total) 2628fa9e4066Sahrens total = examined; 2629fa9e4066Sahrens 2630fa9e4066Sahrens fraction_done = (double)examined / total; 2631fa9e4066Sahrens minutes_left = (uint64_t)((now - start) * 2632fa9e4066Sahrens (1 - fraction_done) / fraction_done / 60); 263318ce54dfSek110237 minutes_taken = (uint64_t)((now - start) / 60); 2634fa9e4066Sahrens 263518ce54dfSek110237 (void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, " 263618ce54dfSek110237 "%lluh%um to go\n"), 263718ce54dfSek110237 scrub_type, (u_longlong_t)(minutes_taken / 60), 263818ce54dfSek110237 (uint_t)(minutes_taken % 60), 100 * fraction_done, 2639fa9e4066Sahrens (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2640fa9e4066Sahrens } 2641fa9e4066Sahrens 264299653d4eSeschrock typedef struct spare_cbdata { 264399653d4eSeschrock uint64_t cb_guid; 264499653d4eSeschrock zpool_handle_t *cb_zhp; 264599653d4eSeschrock } spare_cbdata_t; 264699653d4eSeschrock 264799653d4eSeschrock static boolean_t 264899653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search) 264999653d4eSeschrock { 265099653d4eSeschrock uint64_t guid; 265199653d4eSeschrock nvlist_t **child; 265299653d4eSeschrock uint_t c, children; 265399653d4eSeschrock 265499653d4eSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 265599653d4eSeschrock search == guid) 265699653d4eSeschrock return (B_TRUE); 265799653d4eSeschrock 265899653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 265999653d4eSeschrock &child, &children) == 0) { 266099653d4eSeschrock for (c = 0; c < children; c++) 266199653d4eSeschrock if (find_vdev(child[c], search)) 266299653d4eSeschrock return (B_TRUE); 266399653d4eSeschrock } 266499653d4eSeschrock 266599653d4eSeschrock return (B_FALSE); 266699653d4eSeschrock } 266799653d4eSeschrock 266899653d4eSeschrock static int 266999653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data) 267099653d4eSeschrock { 267199653d4eSeschrock spare_cbdata_t *cbp = data; 267299653d4eSeschrock nvlist_t *config, *nvroot; 267399653d4eSeschrock 267499653d4eSeschrock config = zpool_get_config(zhp, NULL); 267599653d4eSeschrock verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 267699653d4eSeschrock &nvroot) == 0); 267799653d4eSeschrock 267899653d4eSeschrock if (find_vdev(nvroot, cbp->cb_guid)) { 267999653d4eSeschrock cbp->cb_zhp = zhp; 268099653d4eSeschrock return (1); 268199653d4eSeschrock } 268299653d4eSeschrock 268399653d4eSeschrock zpool_close(zhp); 268499653d4eSeschrock return (0); 268599653d4eSeschrock } 268699653d4eSeschrock 2687fa9e4066Sahrens /* 2688fa9e4066Sahrens * Print out configuration state as requested by status_callback. 2689fa9e4066Sahrens */ 2690fa9e4066Sahrens void 2691c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 26928654d025Sperrin int namewidth, int depth, boolean_t isspare, boolean_t print_logs) 2693fa9e4066Sahrens { 2694fa9e4066Sahrens nvlist_t **child; 2695fa9e4066Sahrens uint_t c, children; 2696fa9e4066Sahrens vdev_stat_t *vs; 2697ea8dc4b6Seschrock char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 2698afefbcddSeschrock char *vname; 2699ea8dc4b6Seschrock uint64_t notpresent; 270099653d4eSeschrock spare_cbdata_t cb; 2701990b4856Slling char *state; 2702fa9e4066Sahrens 2703fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2704fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 2705fa9e4066Sahrens 2706fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2707fa9e4066Sahrens &child, &children) != 0) 2708fa9e4066Sahrens children = 0; 2709fa9e4066Sahrens 2710990b4856Slling state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 271199653d4eSeschrock if (isspare) { 271299653d4eSeschrock /* 271399653d4eSeschrock * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 271499653d4eSeschrock * online drives. 271599653d4eSeschrock */ 271699653d4eSeschrock if (vs->vs_aux == VDEV_AUX_SPARED) 271799653d4eSeschrock state = "INUSE"; 271899653d4eSeschrock else if (vs->vs_state == VDEV_STATE_HEALTHY) 271999653d4eSeschrock state = "AVAIL"; 272099653d4eSeschrock } 2721fa9e4066Sahrens 272299653d4eSeschrock (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 272399653d4eSeschrock name, state); 272499653d4eSeschrock 272599653d4eSeschrock if (!isspare) { 2726fa9e4066Sahrens zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 2727fa9e4066Sahrens zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 2728fa9e4066Sahrens zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 2729fa9e4066Sahrens (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 273099653d4eSeschrock } 2731fa9e4066Sahrens 2732ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2733ea8dc4b6Seschrock ¬present) == 0) { 2734ea8dc4b6Seschrock char *path; 2735ea8dc4b6Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 27360917b783Seschrock (void) printf(" was %s", path); 2737ea8dc4b6Seschrock } else if (vs->vs_aux != 0) { 2738fa9e4066Sahrens (void) printf(" "); 2739fa9e4066Sahrens 2740fa9e4066Sahrens switch (vs->vs_aux) { 2741fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 2742fa9e4066Sahrens (void) printf(gettext("cannot open")); 2743fa9e4066Sahrens break; 2744fa9e4066Sahrens 2745fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 2746fa9e4066Sahrens (void) printf(gettext("missing device")); 2747fa9e4066Sahrens break; 2748fa9e4066Sahrens 2749fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 2750fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 2751fa9e4066Sahrens break; 2752fa9e4066Sahrens 2753eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 2754eaca9bbdSeschrock (void) printf(gettext("newer version")); 2755eaca9bbdSeschrock break; 2756eaca9bbdSeschrock 275799653d4eSeschrock case VDEV_AUX_SPARED: 275899653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 275999653d4eSeschrock &cb.cb_guid) == 0); 276099653d4eSeschrock if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 276199653d4eSeschrock if (strcmp(zpool_get_name(cb.cb_zhp), 276299653d4eSeschrock zpool_get_name(zhp)) == 0) 276399653d4eSeschrock (void) printf(gettext("currently in " 276499653d4eSeschrock "use")); 276599653d4eSeschrock else 276699653d4eSeschrock (void) printf(gettext("in use by " 276799653d4eSeschrock "pool '%s'"), 276899653d4eSeschrock zpool_get_name(cb.cb_zhp)); 276999653d4eSeschrock zpool_close(cb.cb_zhp); 277099653d4eSeschrock } else { 277199653d4eSeschrock (void) printf(gettext("currently in use")); 277299653d4eSeschrock } 277399653d4eSeschrock break; 277499653d4eSeschrock 27753d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 27763d7072f8Seschrock (void) printf(gettext("too many errors")); 27773d7072f8Seschrock break; 27783d7072f8Seschrock 2779*32b87932Sek110237 case VDEV_AUX_IO_FAILURE: 2780*32b87932Sek110237 (void) printf(gettext("experienced I/O failures")); 2781*32b87932Sek110237 break; 2782*32b87932Sek110237 2783fa9e4066Sahrens default: 2784fa9e4066Sahrens (void) printf(gettext("corrupted data")); 2785fa9e4066Sahrens break; 2786fa9e4066Sahrens } 2787fa9e4066Sahrens } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2788fa9e4066Sahrens /* 2789fa9e4066Sahrens * Report bytes resilvered/repaired on leaf devices. 2790fa9e4066Sahrens */ 2791fa9e4066Sahrens zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2792fa9e4066Sahrens (void) printf(gettext(" %s %s"), repaired, 2793fa9e4066Sahrens (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2794fa9e4066Sahrens "resilvered" : "repaired"); 2795fa9e4066Sahrens } 2796fa9e4066Sahrens 2797fa9e4066Sahrens (void) printf("\n"); 2798fa9e4066Sahrens 2799afefbcddSeschrock for (c = 0; c < children; c++) { 28008654d025Sperrin uint64_t is_log = B_FALSE; 28018654d025Sperrin 28028654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 28038654d025Sperrin &is_log); 28048654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 28058654d025Sperrin continue; 280699653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 2807c67d9675Seschrock print_status_config(zhp, vname, child[c], 28088654d025Sperrin namewidth, depth + 2, isspare, B_FALSE); 2809afefbcddSeschrock free(vname); 2810afefbcddSeschrock } 2811fa9e4066Sahrens } 2812fa9e4066Sahrens 2813ea8dc4b6Seschrock static void 2814ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 2815ea8dc4b6Seschrock { 281675519f38Sek110237 nvlist_t *nverrlist = NULL; 281755434c77Sek110237 nvpair_t *elem; 281855434c77Sek110237 char *pathname; 281955434c77Sek110237 size_t len = MAXPATHLEN * 2; 2820ea8dc4b6Seschrock 282155434c77Sek110237 if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2822ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 2823ea8dc4b6Seschrock "(insufficient privileges)\n"); 2824ea8dc4b6Seschrock return; 2825ea8dc4b6Seschrock } 2826ea8dc4b6Seschrock 282755434c77Sek110237 (void) printf("errors: Permanent errors have been " 282855434c77Sek110237 "detected in the following files:\n\n"); 2829ea8dc4b6Seschrock 283055434c77Sek110237 pathname = safe_malloc(len); 283155434c77Sek110237 elem = NULL; 283255434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 283355434c77Sek110237 nvlist_t *nv; 283455434c77Sek110237 uint64_t dsobj, obj; 2835ea8dc4b6Seschrock 283655434c77Sek110237 verify(nvpair_value_nvlist(elem, &nv) == 0); 283755434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 283855434c77Sek110237 &dsobj) == 0); 283955434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 284055434c77Sek110237 &obj) == 0); 284155434c77Sek110237 zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 284255434c77Sek110237 (void) printf("%7s %s\n", "", pathname); 2843ea8dc4b6Seschrock } 284455434c77Sek110237 free(pathname); 284555434c77Sek110237 nvlist_free(nverrlist); 2846ea8dc4b6Seschrock } 2847ea8dc4b6Seschrock 284899653d4eSeschrock static void 284999653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 285099653d4eSeschrock int namewidth) 285199653d4eSeschrock { 285299653d4eSeschrock uint_t i; 285399653d4eSeschrock char *name; 285499653d4eSeschrock 285599653d4eSeschrock if (nspares == 0) 285699653d4eSeschrock return; 285799653d4eSeschrock 285899653d4eSeschrock (void) printf(gettext("\tspares\n")); 285999653d4eSeschrock 286099653d4eSeschrock for (i = 0; i < nspares; i++) { 286199653d4eSeschrock name = zpool_vdev_name(g_zfs, zhp, spares[i]); 286299653d4eSeschrock print_status_config(zhp, name, spares[i], 28638654d025Sperrin namewidth, 2, B_TRUE, B_FALSE); 286499653d4eSeschrock free(name); 286599653d4eSeschrock } 286699653d4eSeschrock } 286799653d4eSeschrock 2868fa94a07fSbrendan static void 2869fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 2870fa94a07fSbrendan int namewidth) 2871fa94a07fSbrendan { 2872fa94a07fSbrendan uint_t i; 2873fa94a07fSbrendan char *name; 2874fa94a07fSbrendan 2875fa94a07fSbrendan if (nl2cache == 0) 2876fa94a07fSbrendan return; 2877fa94a07fSbrendan 2878fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 2879fa94a07fSbrendan 2880fa94a07fSbrendan for (i = 0; i < nl2cache; i++) { 2881fa94a07fSbrendan name = zpool_vdev_name(g_zfs, zhp, l2cache[i]); 2882fa94a07fSbrendan print_status_config(zhp, name, l2cache[i], 2883fa94a07fSbrendan namewidth, 2, B_FALSE, B_FALSE); 2884fa94a07fSbrendan free(name); 2885fa94a07fSbrendan } 2886fa94a07fSbrendan } 2887fa94a07fSbrendan 2888fa9e4066Sahrens /* 2889fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 2890fa9e4066Sahrens * 2891fa9e4066Sahrens * pool: tank 2892fa9e4066Sahrens * status: DEGRADED 2893fa9e4066Sahrens * reason: One or more devices ... 2894fa9e4066Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01 2895fa9e4066Sahrens * config: 2896fa9e4066Sahrens * mirror DEGRADED 2897fa9e4066Sahrens * c1t0d0 OK 2898ea8dc4b6Seschrock * c2t0d0 UNAVAIL 2899fa9e4066Sahrens * 2900fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 2901fa9e4066Sahrens * option is specified, then we print out error rate information as well. 2902fa9e4066Sahrens */ 2903fa9e4066Sahrens int 2904fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 2905fa9e4066Sahrens { 2906fa9e4066Sahrens status_cbdata_t *cbp = data; 2907fa9e4066Sahrens nvlist_t *config, *nvroot; 2908fa9e4066Sahrens char *msgid; 2909fa9e4066Sahrens int reason; 291046657f8dSmmusante const char *health; 291146657f8dSmmusante uint_t c; 291246657f8dSmmusante vdev_stat_t *vs; 2913fa9e4066Sahrens 2914088e9d47Seschrock config = zpool_get_config(zhp, NULL); 2915fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 2916fa9e4066Sahrens 2917fa9e4066Sahrens cbp->cb_count++; 2918fa9e4066Sahrens 2919fa9e4066Sahrens /* 2920fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 2921fa9e4066Sahrens * problems. 2922fa9e4066Sahrens */ 2923e9dbad6fSeschrock if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 2924e9dbad6fSeschrock if (!cbp->cb_allpools) { 2925e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 2926e9dbad6fSeschrock zpool_get_name(zhp)); 2927e9dbad6fSeschrock if (cbp->cb_first) 2928e9dbad6fSeschrock cbp->cb_first = B_FALSE; 2929e9dbad6fSeschrock } 2930fa9e4066Sahrens return (0); 2931e9dbad6fSeschrock } 2932fa9e4066Sahrens 2933fa9e4066Sahrens if (cbp->cb_first) 293499653d4eSeschrock cbp->cb_first = B_FALSE; 2935fa9e4066Sahrens else 2936fa9e4066Sahrens (void) printf("\n"); 2937fa9e4066Sahrens 293846657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 293946657f8dSmmusante &nvroot) == 0); 294046657f8dSmmusante verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 294146657f8dSmmusante (uint64_t **)&vs, &c) == 0); 2942990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 2943fa9e4066Sahrens 2944fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 2945fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 2946fa9e4066Sahrens 2947fa9e4066Sahrens switch (reason) { 2948fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 2949fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2950fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 2951fa9e4066Sahrens "continue functioning in a degraded state.\n")); 2952fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2953fa9e4066Sahrens "online it using 'zpool online'.\n")); 2954fa9e4066Sahrens break; 2955fa9e4066Sahrens 2956fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 2957fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2958fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 2959fa9e4066Sahrens "pool to continue functioning.\n")); 2960fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2961fa9e4066Sahrens "online it using 'zpool online'.\n")); 2962fa9e4066Sahrens break; 2963fa9e4066Sahrens 2964fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 2965fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2966fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 2967fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 2968fa9e4066Sahrens "functioning in a degraded state.\n")); 2969fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 2970fa9e4066Sahrens "'zpool replace'.\n")); 2971fa9e4066Sahrens break; 2972fa9e4066Sahrens 2973fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 2974fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2975b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 2976fa9e4066Sahrens "There are insufficient replicas for the pool to " 2977fa9e4066Sahrens "continue\n\tfunctioning.\n")); 2978fa9e4066Sahrens (void) printf(gettext("action: Destroy and re-create the pool " 2979fa9e4066Sahrens "from a backup source.\n")); 2980fa9e4066Sahrens break; 2981fa9e4066Sahrens 2982fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 2983fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2984fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 2985fa9e4066Sahrens "made to correct the error. Applications are " 2986fa9e4066Sahrens "unaffected.\n")); 2987fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 2988fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 2989ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 2990fa9e4066Sahrens "replace'.\n")); 2991fa9e4066Sahrens break; 2992fa9e4066Sahrens 2993fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 2994fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2995d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 2996fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 2997fa9e4066Sahrens "a\n\tdegraded state.\n")); 2998fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 2999fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 3000fa9e4066Sahrens "replace'.\n")); 3001fa9e4066Sahrens break; 3002fa9e4066Sahrens 3003fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 3004fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 3005fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 3006fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 3007fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 3008fa9e4066Sahrens "complete.\n")); 3009fa9e4066Sahrens break; 3010fa9e4066Sahrens 3011ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 3012ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 3013ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 3014ea8dc4b6Seschrock "Applications may be affected.\n")); 3015ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 3016ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 3017ea8dc4b6Seschrock "backup.\n")); 3018ea8dc4b6Seschrock break; 3019ea8dc4b6Seschrock 3020ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 3021ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 3022ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 3023ea8dc4b6Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 3024ea8dc4b6Seschrock "from a backup source.\n")); 3025ea8dc4b6Seschrock break; 3026ea8dc4b6Seschrock 3027eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 3028eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 3029eaca9bbdSeschrock "older on-disk format. The pool can\n\tstill be used, but " 3030eaca9bbdSeschrock "some features are unavailable.\n")); 3031eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 3032eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 3033eaca9bbdSeschrock "be accessible on older software versions.\n")); 3034eaca9bbdSeschrock break; 3035eaca9bbdSeschrock 3036eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 3037eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 3038eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 3039eaca9bbdSeschrock "be accessed on this system.\n")); 3040eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 3041eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 3042eaca9bbdSeschrock "backup.\n")); 3043eaca9bbdSeschrock break; 3044eaca9bbdSeschrock 30453d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 30463d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 30473d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 30483d7072f8Seschrock "replicas exist for the pool to continue functioning " 30493d7072f8Seschrock "in a\n\tdegraded state.\n")); 30503d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 30513d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 30523d7072f8Seschrock break; 30533d7072f8Seschrock 30543d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 30553d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 30563d7072f8Seschrock "faulted in response to persistent errors. There are " 30573d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 30583d7072f8Seschrock "functioning.\n")); 30593d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 30603d7072f8Seschrock "from a backup source. Manually marking the device\n" 30613d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 30623d7072f8Seschrock "to be recovered.\n")); 30633d7072f8Seschrock break; 30643d7072f8Seschrock 3065*32b87932Sek110237 case ZPOOL_STATUS_IO_FAILURE_WAIT: 3066*32b87932Sek110237 case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 3067*32b87932Sek110237 (void) printf(gettext("status: One or more devices are " 3068*32b87932Sek110237 "faultd in response to IO failures.\n")); 3069*32b87932Sek110237 (void) printf(gettext("action: Make sure the affected devices " 3070*32b87932Sek110237 "are connected, then run 'zpool clear'.\n")); 3071*32b87932Sek110237 break; 3072*32b87932Sek110237 3073fa9e4066Sahrens default: 3074fa9e4066Sahrens /* 3075fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 3076fa9e4066Sahrens */ 3077fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 3078fa9e4066Sahrens } 3079fa9e4066Sahrens 3080fa9e4066Sahrens if (msgid != NULL) 3081fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3082fa9e4066Sahrens msgid); 3083fa9e4066Sahrens 3084fa9e4066Sahrens if (config != NULL) { 3085fa9e4066Sahrens int namewidth; 3086ea8dc4b6Seschrock uint64_t nerr; 3087fa94a07fSbrendan nvlist_t **spares, **l2cache; 3088fa94a07fSbrendan uint_t nspares, nl2cache; 3089fa9e4066Sahrens 3090fa9e4066Sahrens 3091fa9e4066Sahrens (void) printf(gettext(" scrub: ")); 3092fa9e4066Sahrens print_scrub_status(nvroot); 3093fa9e4066Sahrens 3094c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 3095fa9e4066Sahrens if (namewidth < 10) 3096fa9e4066Sahrens namewidth = 10; 3097fa9e4066Sahrens 3098fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 3099fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3100fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3101c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 31028654d025Sperrin namewidth, 0, B_FALSE, B_FALSE); 31038654d025Sperrin if (num_logs(nvroot) > 0) 31048654d025Sperrin print_status_config(zhp, "logs", nvroot, namewidth, 0, 31058654d025Sperrin B_FALSE, B_TRUE); 310699653d4eSeschrock 3107fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 3108fa94a07fSbrendan &l2cache, &nl2cache) == 0) 3109fa94a07fSbrendan print_l2cache(zhp, l2cache, nl2cache, namewidth); 3110fa94a07fSbrendan 311199653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 311299653d4eSeschrock &spares, &nspares) == 0) 311399653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 3114ea8dc4b6Seschrock 3115ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3116ea8dc4b6Seschrock &nerr) == 0) { 311755434c77Sek110237 nvlist_t *nverrlist = NULL; 311855434c77Sek110237 3119ea8dc4b6Seschrock /* 3120ea8dc4b6Seschrock * If the approximate error count is small, get a 3121ea8dc4b6Seschrock * precise count by fetching the entire log and 3122ea8dc4b6Seschrock * uniquifying the results. 3123ea8dc4b6Seschrock */ 312475519f38Sek110237 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 312555434c77Sek110237 zpool_get_errlog(zhp, &nverrlist) == 0) { 312655434c77Sek110237 nvpair_t *elem; 312755434c77Sek110237 312855434c77Sek110237 elem = NULL; 312955434c77Sek110237 nerr = 0; 313055434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, 313155434c77Sek110237 elem)) != NULL) { 313255434c77Sek110237 nerr++; 313355434c77Sek110237 } 313455434c77Sek110237 } 313555434c77Sek110237 nvlist_free(nverrlist); 3136ea8dc4b6Seschrock 3137ea8dc4b6Seschrock (void) printf("\n"); 313899653d4eSeschrock 3139ea8dc4b6Seschrock if (nerr == 0) 3140ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 3141ea8dc4b6Seschrock "errors\n")); 3142ea8dc4b6Seschrock else if (!cbp->cb_verbose) 3143e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 31445ad82045Snd150628 "errors, use '-v' for a list\n"), 31455ad82045Snd150628 (u_longlong_t)nerr); 3146ea8dc4b6Seschrock else 3147ea8dc4b6Seschrock print_error_log(zhp); 3148ea8dc4b6Seschrock } 3149fa9e4066Sahrens } else { 3150fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 3151fa9e4066Sahrens "determined.\n")); 3152fa9e4066Sahrens } 3153fa9e4066Sahrens 3154fa9e4066Sahrens return (0); 3155fa9e4066Sahrens } 3156fa9e4066Sahrens 3157fa9e4066Sahrens /* 3158fa9e4066Sahrens * zpool status [-vx] [pool] ... 3159fa9e4066Sahrens * 3160fa9e4066Sahrens * -v Display complete error logs 3161fa9e4066Sahrens * -x Display only pools with potential problems 3162fa9e4066Sahrens * 3163fa9e4066Sahrens * Describes the health status of all pools or some subset. 3164fa9e4066Sahrens */ 3165fa9e4066Sahrens int 3166fa9e4066Sahrens zpool_do_status(int argc, char **argv) 3167fa9e4066Sahrens { 3168fa9e4066Sahrens int c; 3169fa9e4066Sahrens int ret; 3170fa9e4066Sahrens status_cbdata_t cb = { 0 }; 3171fa9e4066Sahrens 3172fa9e4066Sahrens /* check options */ 3173fa9e4066Sahrens while ((c = getopt(argc, argv, "vx")) != -1) { 3174fa9e4066Sahrens switch (c) { 3175fa9e4066Sahrens case 'v': 317699653d4eSeschrock cb.cb_verbose = B_TRUE; 3177fa9e4066Sahrens break; 3178fa9e4066Sahrens case 'x': 317999653d4eSeschrock cb.cb_explain = B_TRUE; 3180fa9e4066Sahrens break; 3181fa9e4066Sahrens case '?': 3182fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3183fa9e4066Sahrens optopt); 318499653d4eSeschrock usage(B_FALSE); 3185fa9e4066Sahrens } 3186fa9e4066Sahrens } 3187fa9e4066Sahrens 3188fa9e4066Sahrens argc -= optind; 3189fa9e4066Sahrens argv += optind; 3190fa9e4066Sahrens 319199653d4eSeschrock cb.cb_first = B_TRUE; 3192fa9e4066Sahrens 3193e9dbad6fSeschrock if (argc == 0) 3194e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 3195e9dbad6fSeschrock 3196b1b8ab34Slling ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3197fa9e4066Sahrens 3198fa9e4066Sahrens if (argc == 0 && cb.cb_count == 0) 3199fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 3200e9dbad6fSeschrock else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3201fa9e4066Sahrens (void) printf(gettext("all pools are healthy\n")); 3202fa9e4066Sahrens 3203fa9e4066Sahrens return (ret); 3204fa9e4066Sahrens } 3205fa9e4066Sahrens 3206eaca9bbdSeschrock typedef struct upgrade_cbdata { 3207eaca9bbdSeschrock int cb_all; 3208eaca9bbdSeschrock int cb_first; 3209eaca9bbdSeschrock int cb_newer; 321006eeb2adSek110237 int cb_argc; 3211990b4856Slling uint64_t cb_version; 321206eeb2adSek110237 char **cb_argv; 3213eaca9bbdSeschrock } upgrade_cbdata_t; 3214eaca9bbdSeschrock 3215eaca9bbdSeschrock static int 3216eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 3217eaca9bbdSeschrock { 3218eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 3219eaca9bbdSeschrock nvlist_t *config; 3220eaca9bbdSeschrock uint64_t version; 3221eaca9bbdSeschrock int ret = 0; 3222eaca9bbdSeschrock 3223eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 3224eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3225eaca9bbdSeschrock &version) == 0); 3226eaca9bbdSeschrock 3227e7437265Sahrens if (!cbp->cb_newer && version < SPA_VERSION) { 3228eaca9bbdSeschrock if (!cbp->cb_all) { 3229eaca9bbdSeschrock if (cbp->cb_first) { 3230eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3231eaca9bbdSeschrock "out of date, and can be upgraded. After " 3232eaca9bbdSeschrock "being\nupgraded, these pools will no " 3233eaca9bbdSeschrock "longer be accessible by older software " 3234eaca9bbdSeschrock "versions.\n\n")); 3235eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3236eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 323799653d4eSeschrock cbp->cb_first = B_FALSE; 3238eaca9bbdSeschrock } 3239eaca9bbdSeschrock 32405ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3241eaca9bbdSeschrock zpool_get_name(zhp)); 3242eaca9bbdSeschrock } else { 324399653d4eSeschrock cbp->cb_first = B_FALSE; 3244990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 324506eeb2adSek110237 if (!ret) { 3246eaca9bbdSeschrock (void) printf(gettext("Successfully upgraded " 3247990b4856Slling "'%s'\n\n"), zpool_get_name(zhp)); 3248eaca9bbdSeschrock } 324906eeb2adSek110237 } 3250e7437265Sahrens } else if (cbp->cb_newer && version > SPA_VERSION) { 3251eaca9bbdSeschrock assert(!cbp->cb_all); 3252eaca9bbdSeschrock 3253eaca9bbdSeschrock if (cbp->cb_first) { 3254eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3255eaca9bbdSeschrock "formatted using a newer software version and\n" 3256eaca9bbdSeschrock "cannot be accessed on the current system.\n\n")); 3257eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3258eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 325999653d4eSeschrock cbp->cb_first = B_FALSE; 3260eaca9bbdSeschrock } 3261eaca9bbdSeschrock 32625ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3263eaca9bbdSeschrock zpool_get_name(zhp)); 3264eaca9bbdSeschrock } 3265eaca9bbdSeschrock 3266eaca9bbdSeschrock zpool_close(zhp); 3267eaca9bbdSeschrock return (ret); 3268eaca9bbdSeschrock } 3269eaca9bbdSeschrock 3270eaca9bbdSeschrock /* ARGSUSED */ 3271eaca9bbdSeschrock static int 327206eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data) 3273eaca9bbdSeschrock { 3274990b4856Slling upgrade_cbdata_t *cbp = data; 3275990b4856Slling uint64_t cur_version; 3276eaca9bbdSeschrock int ret; 3277eaca9bbdSeschrock 32788654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 32798654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 32808654d025Sperrin "Pool 'log' must be renamed using export and import" 32818654d025Sperrin " to upgrade.\n")); 32828654d025Sperrin return (1); 32838654d025Sperrin } 3284990b4856Slling 3285990b4856Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 3286e6c728e1Sbrendan if (cur_version > cbp->cb_version) { 3287eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 3288e6c728e1Sbrendan "using more current version '%llu'.\n"), 3289e6c728e1Sbrendan zpool_get_name(zhp), cur_version); 3290e6c728e1Sbrendan return (0); 3291e6c728e1Sbrendan } 3292e6c728e1Sbrendan if (cur_version == cbp->cb_version) { 3293e6c728e1Sbrendan (void) printf(gettext("Pool '%s' is already formatted " 3294e6c728e1Sbrendan "using the current version.\n"), zpool_get_name(zhp)); 3295eaca9bbdSeschrock return (0); 3296eaca9bbdSeschrock } 3297eaca9bbdSeschrock 3298990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 329906eeb2adSek110237 330006eeb2adSek110237 if (!ret) { 330144cd46caSbillm (void) printf(gettext("Successfully upgraded '%s' " 3302990b4856Slling "from version %llu to version %llu\n\n"), 3303990b4856Slling zpool_get_name(zhp), (u_longlong_t)cur_version, 3304990b4856Slling (u_longlong_t)cbp->cb_version); 330506eeb2adSek110237 } 3306eaca9bbdSeschrock 3307eaca9bbdSeschrock return (ret != 0); 3308eaca9bbdSeschrock } 3309eaca9bbdSeschrock 3310eaca9bbdSeschrock /* 3311eaca9bbdSeschrock * zpool upgrade 3312eaca9bbdSeschrock * zpool upgrade -v 3313990b4856Slling * zpool upgrade [-V version] <-a | pool ...> 3314eaca9bbdSeschrock * 3315eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 3316eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 3317eaca9bbdSeschrock * upgrade all pools. 3318eaca9bbdSeschrock */ 3319eaca9bbdSeschrock int 3320eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 3321eaca9bbdSeschrock { 3322eaca9bbdSeschrock int c; 3323eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 3324eaca9bbdSeschrock int ret = 0; 3325eaca9bbdSeschrock boolean_t showversions = B_FALSE; 3326990b4856Slling char *end; 3327990b4856Slling 3328eaca9bbdSeschrock 3329eaca9bbdSeschrock /* check options */ 3330990b4856Slling while ((c = getopt(argc, argv, "avV:")) != -1) { 3331eaca9bbdSeschrock switch (c) { 3332eaca9bbdSeschrock case 'a': 333399653d4eSeschrock cb.cb_all = B_TRUE; 3334eaca9bbdSeschrock break; 3335eaca9bbdSeschrock case 'v': 3336eaca9bbdSeschrock showversions = B_TRUE; 3337eaca9bbdSeschrock break; 3338990b4856Slling case 'V': 3339990b4856Slling cb.cb_version = strtoll(optarg, &end, 10); 3340351420b3Slling if (*end != '\0' || cb.cb_version > SPA_VERSION || 3341351420b3Slling cb.cb_version < SPA_VERSION_1) { 3342990b4856Slling (void) fprintf(stderr, 3343990b4856Slling gettext("invalid version '%s'\n"), optarg); 3344990b4856Slling usage(B_FALSE); 3345990b4856Slling } 3346990b4856Slling break; 3347eaca9bbdSeschrock case '?': 3348eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3349eaca9bbdSeschrock optopt); 335099653d4eSeschrock usage(B_FALSE); 3351eaca9bbdSeschrock } 3352eaca9bbdSeschrock } 3353eaca9bbdSeschrock 335406eeb2adSek110237 cb.cb_argc = argc; 335506eeb2adSek110237 cb.cb_argv = argv; 3356eaca9bbdSeschrock argc -= optind; 3357eaca9bbdSeschrock argv += optind; 3358eaca9bbdSeschrock 3359351420b3Slling if (cb.cb_version == 0) { 3360351420b3Slling cb.cb_version = SPA_VERSION; 3361351420b3Slling } else if (!cb.cb_all && argc == 0) { 3362351420b3Slling (void) fprintf(stderr, gettext("-V option is " 3363351420b3Slling "incompatible with other arguments\n")); 3364351420b3Slling usage(B_FALSE); 3365351420b3Slling } 3366351420b3Slling 3367eaca9bbdSeschrock if (showversions) { 3368eaca9bbdSeschrock if (cb.cb_all || argc != 0) { 3369eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 3370eaca9bbdSeschrock "incompatible with other arguments\n")); 337199653d4eSeschrock usage(B_FALSE); 3372eaca9bbdSeschrock } 3373eaca9bbdSeschrock } else if (cb.cb_all) { 3374eaca9bbdSeschrock if (argc != 0) { 3375351420b3Slling (void) fprintf(stderr, gettext("-a option should not " 3376351420b3Slling "be used along with a pool name\n")); 337799653d4eSeschrock usage(B_FALSE); 3378eaca9bbdSeschrock } 3379eaca9bbdSeschrock } 3380eaca9bbdSeschrock 3381e7437265Sahrens (void) printf(gettext("This system is currently running " 3382e7437265Sahrens "ZFS pool version %llu.\n\n"), SPA_VERSION); 338399653d4eSeschrock cb.cb_first = B_TRUE; 3384eaca9bbdSeschrock if (showversions) { 3385eaca9bbdSeschrock (void) printf(gettext("The following versions are " 3386d7d4af51Smmusante "supported:\n\n")); 3387eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 3388eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 3389eaca9bbdSeschrock "---------------\n"); 339099653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 339144cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 339244cd46caSbillm "(replicated metadata)\n")); 339399653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 339499653d4eSeschrock "RAID-Z\n")); 3395d7306b64Sek110237 (void) printf(gettext(" 4 zpool history\n")); 3396c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 3397c9431fa1Sahl "algorithm\n")); 3398990b4856Slling (void) printf(gettext(" 6 bootfs pool property\n")); 33998654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 3400ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 3401a9799022Sck153898 (void) printf(gettext(" 9 refquota and refreservation " 3402a9799022Sck153898 "properties\n")); 3403fa94a07fSbrendan (void) printf(gettext(" 10 Cache devices\n")); 34048654d025Sperrin (void) printf(gettext("For more information on a particular " 3405eaca9bbdSeschrock "version, including supported releases, see:\n\n")); 3406eaca9bbdSeschrock (void) printf("http://www.opensolaris.org/os/community/zfs/" 3407eaca9bbdSeschrock "version/N\n\n"); 3408eaca9bbdSeschrock (void) printf(gettext("Where 'N' is the version number.\n")); 3409eaca9bbdSeschrock } else if (argc == 0) { 3410eaca9bbdSeschrock int notfound; 3411eaca9bbdSeschrock 341299653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3413eaca9bbdSeschrock notfound = cb.cb_first; 3414eaca9bbdSeschrock 3415eaca9bbdSeschrock if (!cb.cb_all && ret == 0) { 3416eaca9bbdSeschrock if (!cb.cb_first) 3417eaca9bbdSeschrock (void) printf("\n"); 3418eaca9bbdSeschrock cb.cb_first = B_TRUE; 3419eaca9bbdSeschrock cb.cb_newer = B_TRUE; 342099653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3421eaca9bbdSeschrock if (!cb.cb_first) { 3422eaca9bbdSeschrock notfound = B_FALSE; 3423eaca9bbdSeschrock (void) printf("\n"); 3424eaca9bbdSeschrock } 3425eaca9bbdSeschrock } 3426eaca9bbdSeschrock 3427eaca9bbdSeschrock if (ret == 0) { 3428eaca9bbdSeschrock if (notfound) 3429eaca9bbdSeschrock (void) printf(gettext("All pools are formatted " 3430eaca9bbdSeschrock "using this version.\n")); 3431eaca9bbdSeschrock else if (!cb.cb_all) 3432eaca9bbdSeschrock (void) printf(gettext("Use 'zpool upgrade -v' " 3433eaca9bbdSeschrock "for a list of available versions and " 3434eaca9bbdSeschrock "their associated\nfeatures.\n")); 3435eaca9bbdSeschrock } 3436eaca9bbdSeschrock } else { 3437b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 3438b1b8ab34Slling upgrade_one, &cb); 343906eeb2adSek110237 } 344006eeb2adSek110237 344106eeb2adSek110237 return (ret); 344206eeb2adSek110237 } 344306eeb2adSek110237 3444ecd6cf80Smarks typedef struct hist_cbdata { 3445ecd6cf80Smarks boolean_t first; 3446ecd6cf80Smarks int longfmt; 3447ecd6cf80Smarks int internal; 3448ecd6cf80Smarks } hist_cbdata_t; 3449ecd6cf80Smarks 3450ecd6cf80Smarks char *hist_event_table[LOG_END] = { 3451ecd6cf80Smarks "invalid event", 3452ecd6cf80Smarks "pool create", 3453ecd6cf80Smarks "vdev add", 3454ecd6cf80Smarks "pool remove", 3455ecd6cf80Smarks "pool destroy", 3456ecd6cf80Smarks "pool export", 3457ecd6cf80Smarks "pool import", 3458ecd6cf80Smarks "vdev attach", 3459ecd6cf80Smarks "vdev replace", 3460ecd6cf80Smarks "vdev detach", 3461ecd6cf80Smarks "vdev online", 3462ecd6cf80Smarks "vdev offline", 3463ecd6cf80Smarks "vdev upgrade", 3464ecd6cf80Smarks "pool clear", 3465ecd6cf80Smarks "pool scrub", 3466ecd6cf80Smarks "pool property set", 3467ecd6cf80Smarks "create", 3468ecd6cf80Smarks "clone", 3469ecd6cf80Smarks "destroy", 3470ecd6cf80Smarks "destroy_begin_sync", 3471ecd6cf80Smarks "inherit", 3472ecd6cf80Smarks "property set", 3473ecd6cf80Smarks "quota set", 3474ecd6cf80Smarks "permission update", 3475ecd6cf80Smarks "permission remove", 3476ecd6cf80Smarks "permission who remove", 3477ecd6cf80Smarks "promote", 3478ecd6cf80Smarks "receive", 3479ecd6cf80Smarks "rename", 3480ecd6cf80Smarks "reservation set", 3481ecd6cf80Smarks "replay_inc_sync", 3482ecd6cf80Smarks "replay_full_sync", 3483ecd6cf80Smarks "rollback", 3484ecd6cf80Smarks "snapshot", 3485e7437265Sahrens "filesystem version upgrade", 3486a9799022Sck153898 "refquota set", 3487a9799022Sck153898 "refreservation set", 3488ecd6cf80Smarks }; 3489ecd6cf80Smarks 349006eeb2adSek110237 /* 349106eeb2adSek110237 * Print out the command history for a specific pool. 349206eeb2adSek110237 */ 349306eeb2adSek110237 static int 349406eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data) 349506eeb2adSek110237 { 349606eeb2adSek110237 nvlist_t *nvhis; 349706eeb2adSek110237 nvlist_t **records; 349806eeb2adSek110237 uint_t numrecords; 349906eeb2adSek110237 char *cmdstr; 3500ecd6cf80Smarks char *pathstr; 350106eeb2adSek110237 uint64_t dst_time; 350206eeb2adSek110237 time_t tsec; 350306eeb2adSek110237 struct tm t; 350406eeb2adSek110237 char tbuf[30]; 350506eeb2adSek110237 int ret, i; 3506ecd6cf80Smarks uint64_t who; 3507ecd6cf80Smarks struct passwd *pwd; 3508ecd6cf80Smarks char *hostname; 3509ecd6cf80Smarks char *zonename; 3510ecd6cf80Smarks char internalstr[MAXPATHLEN]; 3511ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 3512ecd6cf80Smarks uint64_t txg; 3513ecd6cf80Smarks uint64_t ievent; 351406eeb2adSek110237 3515ecd6cf80Smarks cb->first = B_FALSE; 351606eeb2adSek110237 351706eeb2adSek110237 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 351806eeb2adSek110237 351906eeb2adSek110237 if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 352006eeb2adSek110237 return (ret); 352106eeb2adSek110237 352206eeb2adSek110237 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 352306eeb2adSek110237 &records, &numrecords) == 0); 352406eeb2adSek110237 for (i = 0; i < numrecords; i++) { 352506eeb2adSek110237 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3526ecd6cf80Smarks &dst_time) != 0) 3527ecd6cf80Smarks continue; 3528ecd6cf80Smarks 3529ecd6cf80Smarks /* is it an internal event or a standard event? */ 3530ecd6cf80Smarks if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3531ecd6cf80Smarks &cmdstr) != 0) { 3532ecd6cf80Smarks if (cb->internal == 0) 3533ecd6cf80Smarks continue; 3534ecd6cf80Smarks 3535ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3536ecd6cf80Smarks ZPOOL_HIST_INT_EVENT, &ievent) != 0) 3537ecd6cf80Smarks continue; 3538ecd6cf80Smarks verify(nvlist_lookup_uint64(records[i], 3539ecd6cf80Smarks ZPOOL_HIST_TXG, &txg) == 0); 3540ecd6cf80Smarks verify(nvlist_lookup_string(records[i], 3541ecd6cf80Smarks ZPOOL_HIST_INT_STR, &pathstr) == 0); 3542ecd6cf80Smarks if (ievent > LOG_END) 3543ecd6cf80Smarks continue; 3544ecd6cf80Smarks (void) snprintf(internalstr, 3545ecd6cf80Smarks sizeof (internalstr), 3546ecd6cf80Smarks "[internal %s txg:%lld] %s", 3547ecd6cf80Smarks hist_event_table[ievent], txg, 3548ecd6cf80Smarks pathstr); 3549ecd6cf80Smarks cmdstr = internalstr; 3550ecd6cf80Smarks } 355106eeb2adSek110237 tsec = dst_time; 355206eeb2adSek110237 (void) localtime_r(&tsec, &t); 355306eeb2adSek110237 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3554ecd6cf80Smarks (void) printf("%s %s", tbuf, cmdstr); 3555ecd6cf80Smarks 3556ecd6cf80Smarks if (!cb->longfmt) { 3557ecd6cf80Smarks (void) printf("\n"); 3558ecd6cf80Smarks continue; 355906eeb2adSek110237 } 3560ecd6cf80Smarks (void) printf(" ["); 3561ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3562ecd6cf80Smarks ZPOOL_HIST_WHO, &who) == 0) { 3563ecd6cf80Smarks pwd = getpwuid((uid_t)who); 3564ecd6cf80Smarks if (pwd) 3565ecd6cf80Smarks (void) printf("user %s on", 3566ecd6cf80Smarks pwd->pw_name); 3567ecd6cf80Smarks else 3568ecd6cf80Smarks (void) printf("user %d on", 3569ecd6cf80Smarks (int)who); 3570ecd6cf80Smarks } else { 3571ecd6cf80Smarks (void) printf(gettext("no info]\n")); 3572ecd6cf80Smarks continue; 3573ecd6cf80Smarks } 3574ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3575ecd6cf80Smarks ZPOOL_HIST_HOST, &hostname) == 0) { 3576ecd6cf80Smarks (void) printf(" %s", hostname); 3577ecd6cf80Smarks } 3578ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3579ecd6cf80Smarks ZPOOL_HIST_ZONE, &zonename) == 0) { 3580ecd6cf80Smarks (void) printf(":%s", zonename); 3581ecd6cf80Smarks } 3582ecd6cf80Smarks 3583ecd6cf80Smarks (void) printf("]"); 3584ecd6cf80Smarks (void) printf("\n"); 358506eeb2adSek110237 } 358606eeb2adSek110237 (void) printf("\n"); 358706eeb2adSek110237 nvlist_free(nvhis); 358806eeb2adSek110237 358906eeb2adSek110237 return (ret); 359006eeb2adSek110237 } 359106eeb2adSek110237 359206eeb2adSek110237 /* 359306eeb2adSek110237 * zpool history <pool> 359406eeb2adSek110237 * 359506eeb2adSek110237 * Displays the history of commands that modified pools. 359606eeb2adSek110237 */ 3597ecd6cf80Smarks 3598ecd6cf80Smarks 359906eeb2adSek110237 int 360006eeb2adSek110237 zpool_do_history(int argc, char **argv) 360106eeb2adSek110237 { 3602ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 360306eeb2adSek110237 int ret; 3604ecd6cf80Smarks int c; 360506eeb2adSek110237 3606ecd6cf80Smarks cbdata.first = B_TRUE; 3607ecd6cf80Smarks /* check options */ 3608ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 3609ecd6cf80Smarks switch (c) { 3610ecd6cf80Smarks case 'l': 3611ecd6cf80Smarks cbdata.longfmt = 1; 3612ecd6cf80Smarks break; 3613ecd6cf80Smarks case 'i': 3614ecd6cf80Smarks cbdata.internal = 1; 3615ecd6cf80Smarks break; 3616ecd6cf80Smarks case '?': 3617ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3618ecd6cf80Smarks optopt); 3619ecd6cf80Smarks usage(B_FALSE); 3620ecd6cf80Smarks } 3621ecd6cf80Smarks } 362206eeb2adSek110237 argc -= optind; 362306eeb2adSek110237 argv += optind; 362406eeb2adSek110237 3625b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3626ecd6cf80Smarks &cbdata); 362706eeb2adSek110237 3628ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 362906eeb2adSek110237 (void) printf(gettext("no pools available\n")); 363006eeb2adSek110237 return (0); 3631eaca9bbdSeschrock } 3632eaca9bbdSeschrock 3633eaca9bbdSeschrock return (ret); 3634eaca9bbdSeschrock } 3635eaca9bbdSeschrock 3636b1b8ab34Slling static int 3637b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 3638b1b8ab34Slling { 3639990b4856Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 3640b1b8ab34Slling char value[MAXNAMELEN]; 3641990b4856Slling zprop_source_t srctype; 3642990b4856Slling zprop_list_t *pl; 3643b1b8ab34Slling 3644b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3645b1b8ab34Slling 3646b1b8ab34Slling /* 3647990b4856Slling * Skip the special fake placeholder. This will also skip 3648990b4856Slling * over the name property when 'all' is specified. 3649b1b8ab34Slling */ 3650990b4856Slling if (pl->pl_prop == ZPOOL_PROP_NAME && 3651b1b8ab34Slling pl == cbp->cb_proplist) 3652b1b8ab34Slling continue; 3653b1b8ab34Slling 3654b1b8ab34Slling if (zpool_get_prop(zhp, pl->pl_prop, 3655b1b8ab34Slling value, sizeof (value), &srctype) != 0) 3656b1b8ab34Slling continue; 3657b1b8ab34Slling 3658990b4856Slling zprop_print_one_property(zpool_get_name(zhp), cbp, 3659b1b8ab34Slling zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3660b1b8ab34Slling } 3661b1b8ab34Slling return (0); 3662b1b8ab34Slling } 3663b1b8ab34Slling 3664b1b8ab34Slling int 3665b1b8ab34Slling zpool_do_get(int argc, char **argv) 3666b1b8ab34Slling { 3667990b4856Slling zprop_get_cbdata_t cb = { 0 }; 3668990b4856Slling zprop_list_t fake_name = { 0 }; 3669b1b8ab34Slling int ret; 3670b1b8ab34Slling 3671b1b8ab34Slling if (argc < 3) 3672b1b8ab34Slling usage(B_FALSE); 3673b1b8ab34Slling 3674b1b8ab34Slling cb.cb_first = B_TRUE; 3675990b4856Slling cb.cb_sources = ZPROP_SRC_ALL; 3676b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 3677b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 3678b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 3679b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 3680990b4856Slling cb.cb_type = ZFS_TYPE_POOL; 3681b1b8ab34Slling 3682990b4856Slling if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 3683990b4856Slling ZFS_TYPE_POOL) != 0) 3684b1b8ab34Slling usage(B_FALSE); 3685b1b8ab34Slling 3686b1b8ab34Slling if (cb.cb_proplist != NULL) { 3687990b4856Slling fake_name.pl_prop = ZPOOL_PROP_NAME; 3688b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 3689b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 3690b1b8ab34Slling cb.cb_proplist = &fake_name; 3691b1b8ab34Slling } 3692b1b8ab34Slling 3693b1b8ab34Slling ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3694b1b8ab34Slling get_callback, &cb); 3695b1b8ab34Slling 3696b1b8ab34Slling if (cb.cb_proplist == &fake_name) 3697990b4856Slling zprop_free_list(fake_name.pl_next); 3698b1b8ab34Slling else 3699990b4856Slling zprop_free_list(cb.cb_proplist); 3700b1b8ab34Slling 3701b1b8ab34Slling return (ret); 3702b1b8ab34Slling } 3703b1b8ab34Slling 3704b1b8ab34Slling typedef struct set_cbdata { 3705b1b8ab34Slling char *cb_propname; 3706b1b8ab34Slling char *cb_value; 3707b1b8ab34Slling boolean_t cb_any_successful; 3708b1b8ab34Slling } set_cbdata_t; 3709b1b8ab34Slling 3710b1b8ab34Slling int 3711b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 3712b1b8ab34Slling { 3713b1b8ab34Slling int error; 3714b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 3715b1b8ab34Slling 3716b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3717b1b8ab34Slling 3718b1b8ab34Slling if (!error) 3719b1b8ab34Slling cb->cb_any_successful = B_TRUE; 3720b1b8ab34Slling 3721b1b8ab34Slling return (error); 3722b1b8ab34Slling } 3723b1b8ab34Slling 3724b1b8ab34Slling int 3725b1b8ab34Slling zpool_do_set(int argc, char **argv) 3726b1b8ab34Slling { 3727b1b8ab34Slling set_cbdata_t cb = { 0 }; 3728b1b8ab34Slling int error; 3729b1b8ab34Slling 3730b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 3731b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3732b1b8ab34Slling argv[1][1]); 3733b1b8ab34Slling usage(B_FALSE); 3734b1b8ab34Slling } 3735b1b8ab34Slling 3736b1b8ab34Slling if (argc < 2) { 3737b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 3738b1b8ab34Slling "argument\n")); 3739b1b8ab34Slling usage(B_FALSE); 3740b1b8ab34Slling } 3741b1b8ab34Slling 3742b1b8ab34Slling if (argc < 3) { 3743b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 3744b1b8ab34Slling usage(B_FALSE); 3745b1b8ab34Slling } 3746b1b8ab34Slling 3747b1b8ab34Slling if (argc > 3) { 3748b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 3749b1b8ab34Slling usage(B_FALSE); 3750b1b8ab34Slling } 3751b1b8ab34Slling 3752b1b8ab34Slling cb.cb_propname = argv[1]; 3753b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 3754b1b8ab34Slling if (cb.cb_value == NULL) { 3755b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 3756b1b8ab34Slling "property=value argument\n")); 3757b1b8ab34Slling usage(B_FALSE); 3758b1b8ab34Slling } 3759b1b8ab34Slling 3760b1b8ab34Slling *(cb.cb_value) = '\0'; 3761b1b8ab34Slling cb.cb_value++; 3762b1b8ab34Slling 3763b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3764b1b8ab34Slling set_callback, &cb); 3765b1b8ab34Slling 3766b1b8ab34Slling return (error); 3767b1b8ab34Slling } 3768b1b8ab34Slling 3769b1b8ab34Slling static int 3770b1b8ab34Slling find_command_idx(char *command, int *idx) 3771b1b8ab34Slling { 3772b1b8ab34Slling int i; 3773b1b8ab34Slling 3774b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 3775b1b8ab34Slling if (command_table[i].name == NULL) 3776b1b8ab34Slling continue; 3777b1b8ab34Slling 3778b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 3779b1b8ab34Slling *idx = i; 3780b1b8ab34Slling return (0); 3781b1b8ab34Slling } 3782b1b8ab34Slling } 3783b1b8ab34Slling return (1); 3784b1b8ab34Slling } 3785b1b8ab34Slling 3786fa9e4066Sahrens int 3787fa9e4066Sahrens main(int argc, char **argv) 3788fa9e4066Sahrens { 3789fa9e4066Sahrens int ret; 3790fa9e4066Sahrens int i; 3791fa9e4066Sahrens char *cmdname; 3792fa9e4066Sahrens 3793fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 3794fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 3795fa9e4066Sahrens 379699653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 379799653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 3798203a47d8Snd150628 "initialize ZFS library\n")); 379999653d4eSeschrock return (1); 380099653d4eSeschrock } 380199653d4eSeschrock 380299653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 380399653d4eSeschrock 3804fa9e4066Sahrens opterr = 0; 3805fa9e4066Sahrens 3806fa9e4066Sahrens /* 3807fa9e4066Sahrens * Make sure the user has specified some command. 3808fa9e4066Sahrens */ 3809fa9e4066Sahrens if (argc < 2) { 3810fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 381199653d4eSeschrock usage(B_FALSE); 3812fa9e4066Sahrens } 3813fa9e4066Sahrens 3814fa9e4066Sahrens cmdname = argv[1]; 3815fa9e4066Sahrens 3816fa9e4066Sahrens /* 3817fa9e4066Sahrens * Special case '-?' 3818fa9e4066Sahrens */ 3819fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 382099653d4eSeschrock usage(B_TRUE); 3821fa9e4066Sahrens 38222a6b87f0Sek110237 zpool_set_history_str("zpool", argc, argv, history_str); 38232a6b87f0Sek110237 verify(zpool_stage_history(g_zfs, history_str) == 0); 38242a6b87f0Sek110237 3825fa9e4066Sahrens /* 3826fa9e4066Sahrens * Run the appropriate command. 3827fa9e4066Sahrens */ 3828b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 3829fa9e4066Sahrens current_command = &command_table[i]; 3830fa9e4066Sahrens ret = command_table[i].func(argc - 1, argv + 1); 383191ebeef5Sahrens } else if (strchr(cmdname, '=')) { 383291ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 383391ebeef5Sahrens current_command = &command_table[i]; 383491ebeef5Sahrens ret = command_table[i].func(argc, argv); 383591ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 3836fa9e4066Sahrens /* 383791ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 383891ebeef5Sahrens * it as such. 3839fa9e4066Sahrens */ 3840ea8dc4b6Seschrock char buf[16384]; 3841ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 3842fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 3843fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 384491ebeef5Sahrens } else { 3845fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 3846fa9e4066Sahrens "command '%s'\n"), cmdname); 384799653d4eSeschrock usage(B_FALSE); 3848fa9e4066Sahrens } 3849fa9e4066Sahrens 385099653d4eSeschrock libzfs_fini(g_zfs); 385199653d4eSeschrock 3852fa9e4066Sahrens /* 3853fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3854fa9e4066Sahrens * for the purposes of running ::findleaks. 3855fa9e4066Sahrens */ 3856fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 3857fa9e4066Sahrens (void) printf("dumping core by request\n"); 3858fa9e4066Sahrens abort(); 3859fa9e4066Sahrens } 3860fa9e4066Sahrens 3861fa9e4066Sahrens return (ret); 3862fa9e4066Sahrens } 3863