1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 2199653d4eSeschrock 22fa9e4066Sahrens /* 2339c23413Seschrock * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29fa9e4066Sahrens #include <assert.h> 30fa9e4066Sahrens #include <ctype.h> 31fa9e4066Sahrens #include <dirent.h> 32fa9e4066Sahrens #include <errno.h> 33fa9e4066Sahrens #include <fcntl.h> 34fa9e4066Sahrens #include <libgen.h> 35fa9e4066Sahrens #include <libintl.h> 36fa9e4066Sahrens #include <libuutil.h> 37fa9e4066Sahrens #include <locale.h> 38fa9e4066Sahrens #include <stdio.h> 39fa9e4066Sahrens #include <stdlib.h> 40fa9e4066Sahrens #include <string.h> 41fa9e4066Sahrens #include <strings.h> 42fa9e4066Sahrens #include <unistd.h> 43fa9e4066Sahrens #include <priv.h> 44ecd6cf80Smarks #include <pwd.h> 45ecd6cf80Smarks #include <zone.h> 46b1b8ab34Slling #include <sys/fs/zfs.h> 47fa9e4066Sahrens 48fa9e4066Sahrens #include <sys/stat.h> 49fa9e4066Sahrens 50fa9e4066Sahrens #include <libzfs.h> 51fa9e4066Sahrens 52fa9e4066Sahrens #include "zpool_util.h" 53fa9e4066Sahrens 54fa9e4066Sahrens static int zpool_do_create(int, char **); 55fa9e4066Sahrens static int zpool_do_destroy(int, char **); 56fa9e4066Sahrens 57fa9e4066Sahrens static int zpool_do_add(int, char **); 5899653d4eSeschrock static int zpool_do_remove(int, char **); 59fa9e4066Sahrens 60fa9e4066Sahrens static int zpool_do_list(int, char **); 61fa9e4066Sahrens static int zpool_do_iostat(int, char **); 62fa9e4066Sahrens static int zpool_do_status(int, char **); 63fa9e4066Sahrens 64fa9e4066Sahrens static int zpool_do_online(int, char **); 65fa9e4066Sahrens static int zpool_do_offline(int, char **); 66ea8dc4b6Seschrock static int zpool_do_clear(int, char **); 67fa9e4066Sahrens 68fa9e4066Sahrens static int zpool_do_attach(int, char **); 69fa9e4066Sahrens static int zpool_do_detach(int, char **); 70fa9e4066Sahrens static int zpool_do_replace(int, char **); 71fa9e4066Sahrens 72fa9e4066Sahrens static int zpool_do_scrub(int, char **); 73fa9e4066Sahrens 74fa9e4066Sahrens static int zpool_do_import(int, char **); 75fa9e4066Sahrens static int zpool_do_export(int, char **); 76fa9e4066Sahrens 77eaca9bbdSeschrock static int zpool_do_upgrade(int, char **); 78eaca9bbdSeschrock 7906eeb2adSek110237 static int zpool_do_history(int, char **); 8006eeb2adSek110237 81b1b8ab34Slling static int zpool_do_get(int, char **); 82b1b8ab34Slling static int zpool_do_set(int, char **); 83b1b8ab34Slling 84fa9e4066Sahrens /* 85fa9e4066Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 86fa9e4066Sahrens * debugging facilities. 87fa9e4066Sahrens */ 88fa9e4066Sahrens const char * 8999653d4eSeschrock _umem_debug_init(void) 90fa9e4066Sahrens { 91fa9e4066Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 92fa9e4066Sahrens } 93fa9e4066Sahrens 94fa9e4066Sahrens const char * 95fa9e4066Sahrens _umem_logging_init(void) 96fa9e4066Sahrens { 97fa9e4066Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 98fa9e4066Sahrens } 99fa9e4066Sahrens 10065cd9f28Seschrock typedef enum { 10165cd9f28Seschrock HELP_ADD, 10265cd9f28Seschrock HELP_ATTACH, 103ea8dc4b6Seschrock HELP_CLEAR, 10465cd9f28Seschrock HELP_CREATE, 10565cd9f28Seschrock HELP_DESTROY, 10665cd9f28Seschrock HELP_DETACH, 10765cd9f28Seschrock HELP_EXPORT, 10806eeb2adSek110237 HELP_HISTORY, 10965cd9f28Seschrock HELP_IMPORT, 11065cd9f28Seschrock HELP_IOSTAT, 11165cd9f28Seschrock HELP_LIST, 11265cd9f28Seschrock HELP_OFFLINE, 11365cd9f28Seschrock HELP_ONLINE, 11465cd9f28Seschrock HELP_REPLACE, 11599653d4eSeschrock HELP_REMOVE, 11665cd9f28Seschrock HELP_SCRUB, 117eaca9bbdSeschrock HELP_STATUS, 118b1b8ab34Slling HELP_UPGRADE, 119b1b8ab34Slling HELP_GET, 120b1b8ab34Slling HELP_SET 12165cd9f28Seschrock } zpool_help_t; 12265cd9f28Seschrock 12365cd9f28Seschrock 124fa9e4066Sahrens typedef struct zpool_command { 125fa9e4066Sahrens const char *name; 126fa9e4066Sahrens int (*func)(int, char **); 12765cd9f28Seschrock zpool_help_t usage; 128fa9e4066Sahrens } zpool_command_t; 129fa9e4066Sahrens 130fa9e4066Sahrens /* 131fa9e4066Sahrens * Master command table. Each ZFS command has a name, associated function, and 132ea8dc4b6Seschrock * usage message. The usage messages need to be internationalized, so we have 133ea8dc4b6Seschrock * to have a function to return the usage message based on a command index. 13465cd9f28Seschrock * 13565cd9f28Seschrock * These commands are organized according to how they are displayed in the usage 13665cd9f28Seschrock * message. An empty command (one with a NULL name) indicates an empty line in 13765cd9f28Seschrock * the generic usage message. 138fa9e4066Sahrens */ 139fa9e4066Sahrens static zpool_command_t command_table[] = { 14065cd9f28Seschrock { "create", zpool_do_create, HELP_CREATE }, 14165cd9f28Seschrock { "destroy", zpool_do_destroy, HELP_DESTROY }, 142fa9e4066Sahrens { NULL }, 14365cd9f28Seschrock { "add", zpool_do_add, HELP_ADD }, 14499653d4eSeschrock { "remove", zpool_do_remove, HELP_REMOVE }, 145fa9e4066Sahrens { NULL }, 14665cd9f28Seschrock { "list", zpool_do_list, HELP_LIST }, 14765cd9f28Seschrock { "iostat", zpool_do_iostat, HELP_IOSTAT }, 14865cd9f28Seschrock { "status", zpool_do_status, HELP_STATUS }, 149fa9e4066Sahrens { NULL }, 15065cd9f28Seschrock { "online", zpool_do_online, HELP_ONLINE }, 15165cd9f28Seschrock { "offline", zpool_do_offline, HELP_OFFLINE }, 152ea8dc4b6Seschrock { "clear", zpool_do_clear, HELP_CLEAR }, 153fa9e4066Sahrens { NULL }, 15465cd9f28Seschrock { "attach", zpool_do_attach, HELP_ATTACH }, 15565cd9f28Seschrock { "detach", zpool_do_detach, HELP_DETACH }, 15665cd9f28Seschrock { "replace", zpool_do_replace, HELP_REPLACE }, 157fa9e4066Sahrens { NULL }, 15865cd9f28Seschrock { "scrub", zpool_do_scrub, HELP_SCRUB }, 159fa9e4066Sahrens { NULL }, 16065cd9f28Seschrock { "import", zpool_do_import, HELP_IMPORT }, 16165cd9f28Seschrock { "export", zpool_do_export, HELP_EXPORT }, 16206eeb2adSek110237 { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 16306eeb2adSek110237 { NULL }, 164b1b8ab34Slling { "history", zpool_do_history, HELP_HISTORY }, 165b1b8ab34Slling { "get", zpool_do_get, HELP_GET }, 166b1b8ab34Slling { "set", zpool_do_set, HELP_SET }, 167fa9e4066Sahrens }; 168fa9e4066Sahrens 169fa9e4066Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 170fa9e4066Sahrens 171fa9e4066Sahrens zpool_command_t *current_command; 1722a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN]; 173fa9e4066Sahrens 17465cd9f28Seschrock static const char * 17565cd9f28Seschrock get_usage(zpool_help_t idx) { 17665cd9f28Seschrock switch (idx) { 17765cd9f28Seschrock case HELP_ADD: 17865cd9f28Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 17965cd9f28Seschrock case HELP_ATTACH: 18065cd9f28Seschrock return (gettext("\tattach [-f] <pool> <device> " 181e45ce728Sahrens "<new-device>\n")); 182ea8dc4b6Seschrock case HELP_CLEAR: 183ea8dc4b6Seschrock return (gettext("\tclear <pool> [device]\n")); 18465cd9f28Seschrock case HELP_CREATE: 185990b4856Slling return (gettext("\tcreate [-fn] [-o property=value] ... \n" 186990b4856Slling "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 18765cd9f28Seschrock case HELP_DESTROY: 18865cd9f28Seschrock return (gettext("\tdestroy [-f] <pool>\n")); 18965cd9f28Seschrock case HELP_DETACH: 19065cd9f28Seschrock return (gettext("\tdetach <pool> <device>\n")); 19165cd9f28Seschrock case HELP_EXPORT: 19265cd9f28Seschrock return (gettext("\texport [-f] <pool> ...\n")); 19306eeb2adSek110237 case HELP_HISTORY: 194ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 19565cd9f28Seschrock case HELP_IMPORT: 1964c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 1972f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 1982f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n" 1992f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 2002f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] " 2012f8aaab3Seschrock "<pool | id> [newpool]\n")); 20265cd9f28Seschrock case HELP_IOSTAT: 20365cd9f28Seschrock return (gettext("\tiostat [-v] [pool] ... [interval " 20465cd9f28Seschrock "[count]]\n")); 20565cd9f28Seschrock case HELP_LIST: 206990b4856Slling return (gettext("\tlist [-H] [-o property[,...]] " 207990b4856Slling "[pool] ...\n")); 20865cd9f28Seschrock case HELP_OFFLINE: 209441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 21065cd9f28Seschrock case HELP_ONLINE: 211441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 21265cd9f28Seschrock case HELP_REPLACE: 21365cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 214e45ce728Sahrens "[new-device]\n")); 21599653d4eSeschrock case HELP_REMOVE: 21699653d4eSeschrock return (gettext("\tremove <pool> <device>\n")); 21765cd9f28Seschrock case HELP_SCRUB: 21865cd9f28Seschrock return (gettext("\tscrub [-s] <pool> ...\n")); 21965cd9f28Seschrock case HELP_STATUS: 22065cd9f28Seschrock return (gettext("\tstatus [-vx] [pool] ...\n")); 221eaca9bbdSeschrock case HELP_UPGRADE: 222eaca9bbdSeschrock return (gettext("\tupgrade\n" 223eaca9bbdSeschrock "\tupgrade -v\n" 224990b4856Slling "\tupgrade [-V version] <-a | pool ...>\n")); 225b1b8ab34Slling case HELP_GET: 226e45ce728Sahrens return (gettext("\tget <\"all\" | property[,...]> " 227b1b8ab34Slling "<pool> ...\n")); 228b1b8ab34Slling case HELP_SET: 229b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 23065cd9f28Seschrock } 23165cd9f28Seschrock 23265cd9f28Seschrock abort(); 23365cd9f28Seschrock /* NOTREACHED */ 23465cd9f28Seschrock } 23565cd9f28Seschrock 236fa9e4066Sahrens 237fa9e4066Sahrens /* 238b1b8ab34Slling * Callback routine that will print out a pool property value. 239b1b8ab34Slling */ 240990b4856Slling static int 241990b4856Slling print_prop_cb(int prop, void *cb) 242b1b8ab34Slling { 243b1b8ab34Slling FILE *fp = cb; 244b1b8ab34Slling 245b1b8ab34Slling (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 246b1b8ab34Slling 247990b4856Slling if (zpool_prop_readonly(prop)) 248990b4856Slling (void) fprintf(fp, " NO "); 249990b4856Slling else 250990b4856Slling (void) fprintf(fp, " YES "); 251990b4856Slling 252b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 253b1b8ab34Slling (void) fprintf(fp, "-\n"); 254b1b8ab34Slling else 255b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 256b1b8ab34Slling 257990b4856Slling return (ZPROP_CONT); 258b1b8ab34Slling } 259b1b8ab34Slling 260b1b8ab34Slling /* 261fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 262fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 263fa9e4066Sahrens * a complete usage message. 264fa9e4066Sahrens */ 265fa9e4066Sahrens void 26699653d4eSeschrock usage(boolean_t requested) 267fa9e4066Sahrens { 268fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 269fa9e4066Sahrens 270fa9e4066Sahrens if (current_command == NULL) { 271fa9e4066Sahrens int i; 272fa9e4066Sahrens 273fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 274fa9e4066Sahrens (void) fprintf(fp, 275fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 276fa9e4066Sahrens 277fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 278fa9e4066Sahrens if (command_table[i].name == NULL) 279fa9e4066Sahrens (void) fprintf(fp, "\n"); 280fa9e4066Sahrens else 281fa9e4066Sahrens (void) fprintf(fp, "%s", 28265cd9f28Seschrock get_usage(command_table[i].usage)); 283fa9e4066Sahrens } 284fa9e4066Sahrens } else { 285fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 28665cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 287fa9e4066Sahrens } 288fa9e4066Sahrens 289b1b8ab34Slling if (current_command != NULL && 290b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 291990b4856Slling (strcmp(current_command->name, "get") == 0) || 292990b4856Slling (strcmp(current_command->name, "list") == 0))) { 293b1b8ab34Slling 294b1b8ab34Slling (void) fprintf(fp, 295b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 296b1b8ab34Slling 297990b4856Slling (void) fprintf(fp, "\n\t%-13s %s %s\n\n", 298990b4856Slling "PROPERTY", "EDIT", "VALUES"); 299b1b8ab34Slling 300b1b8ab34Slling /* Iterate over all properties */ 301990b4856Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 302990b4856Slling ZFS_TYPE_POOL); 303b1b8ab34Slling } 304b1b8ab34Slling 305e9dbad6fSeschrock /* 306e9dbad6fSeschrock * See comments at end of main(). 307e9dbad6fSeschrock */ 308e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 309e9dbad6fSeschrock (void) printf("dumping core by request\n"); 310e9dbad6fSeschrock abort(); 311e9dbad6fSeschrock } 312e9dbad6fSeschrock 313fa9e4066Sahrens exit(requested ? 0 : 2); 314fa9e4066Sahrens } 315fa9e4066Sahrens 316fa9e4066Sahrens void 3178654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 3188654d025Sperrin boolean_t print_logs) 319fa9e4066Sahrens { 320fa9e4066Sahrens nvlist_t **child; 321fa9e4066Sahrens uint_t c, children; 322afefbcddSeschrock char *vname; 323fa9e4066Sahrens 324fa9e4066Sahrens if (name != NULL) 325fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 326fa9e4066Sahrens 327fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 328fa9e4066Sahrens &child, &children) != 0) 329fa9e4066Sahrens return; 330fa9e4066Sahrens 331afefbcddSeschrock for (c = 0; c < children; c++) { 3328654d025Sperrin uint64_t is_log = B_FALSE; 3338654d025Sperrin 3348654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3358654d025Sperrin &is_log); 3368654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 3378654d025Sperrin continue; 3388654d025Sperrin 33999653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 3408654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 3418654d025Sperrin B_FALSE); 342afefbcddSeschrock free(vname); 343afefbcddSeschrock } 344fa9e4066Sahrens } 345fa9e4066Sahrens 346fa9e4066Sahrens /* 347990b4856Slling * Add a property pair (name, string-value) into a property nvlist. 348990b4856Slling */ 349990b4856Slling static int 350990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props) 351990b4856Slling { 352990b4856Slling char *strval; 353990b4856Slling nvlist_t *proplist; 354990b4856Slling zpool_prop_t prop; 355990b4856Slling 356990b4856Slling if (*props == NULL && 357990b4856Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 358990b4856Slling (void) fprintf(stderr, 359990b4856Slling gettext("internal error: out of memory\n")); 360990b4856Slling return (1); 361990b4856Slling } 362990b4856Slling 363990b4856Slling proplist = *props; 364990b4856Slling 365990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 366990b4856Slling (void) fprintf(stderr, gettext("property '%s' is " 367990b4856Slling "not a valid pool property\n"), propname); 368990b4856Slling return (2); 369990b4856Slling } 370990b4856Slling 371990b4856Slling /* Use normalized property name for nvlist operations */ 372990b4856Slling if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop), 3732f8aaab3Seschrock &strval) == 0 && prop != ZPOOL_PROP_CACHEFILE) { 374990b4856Slling (void) fprintf(stderr, gettext("property '%s' " 375990b4856Slling "specified multiple times\n"), propname); 376990b4856Slling return (2); 377990b4856Slling } 378990b4856Slling 379990b4856Slling if (nvlist_add_string(proplist, zpool_prop_to_name(prop), 380990b4856Slling propval) != 0) { 381990b4856Slling (void) fprintf(stderr, gettext("internal " 382990b4856Slling "error: out of memory\n")); 383990b4856Slling return (1); 384990b4856Slling } 385990b4856Slling 386990b4856Slling return (0); 387990b4856Slling } 388990b4856Slling 389990b4856Slling /* 390fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 391fa9e4066Sahrens * 392fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 393fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 394fa9e4066Sahrens * they were to be added. 395fa9e4066Sahrens * 396fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 397fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 398fa9e4066Sahrens * libzfs. 399fa9e4066Sahrens */ 400fa9e4066Sahrens int 401fa9e4066Sahrens zpool_do_add(int argc, char **argv) 402fa9e4066Sahrens { 40399653d4eSeschrock boolean_t force = B_FALSE; 40499653d4eSeschrock boolean_t dryrun = B_FALSE; 405fa9e4066Sahrens int c; 406fa9e4066Sahrens nvlist_t *nvroot; 407fa9e4066Sahrens char *poolname; 408fa9e4066Sahrens int ret; 409fa9e4066Sahrens zpool_handle_t *zhp; 410fa9e4066Sahrens nvlist_t *config; 411fa9e4066Sahrens 412fa9e4066Sahrens /* check options */ 413fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 414fa9e4066Sahrens switch (c) { 415fa9e4066Sahrens case 'f': 41699653d4eSeschrock force = B_TRUE; 417fa9e4066Sahrens break; 418fa9e4066Sahrens case 'n': 41999653d4eSeschrock dryrun = B_TRUE; 420fa9e4066Sahrens break; 421fa9e4066Sahrens case '?': 422fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 423fa9e4066Sahrens optopt); 42499653d4eSeschrock usage(B_FALSE); 425fa9e4066Sahrens } 426fa9e4066Sahrens } 427fa9e4066Sahrens 428fa9e4066Sahrens argc -= optind; 429fa9e4066Sahrens argv += optind; 430fa9e4066Sahrens 431fa9e4066Sahrens /* get pool name and check number of arguments */ 432fa9e4066Sahrens if (argc < 1) { 433fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 43499653d4eSeschrock usage(B_FALSE); 435fa9e4066Sahrens } 436fa9e4066Sahrens if (argc < 2) { 437fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 43899653d4eSeschrock usage(B_FALSE); 439fa9e4066Sahrens } 440fa9e4066Sahrens 441fa9e4066Sahrens poolname = argv[0]; 442fa9e4066Sahrens 443fa9e4066Sahrens argc--; 444fa9e4066Sahrens argv++; 445fa9e4066Sahrens 44699653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 447fa9e4066Sahrens return (1); 448fa9e4066Sahrens 449088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 450fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 451fa9e4066Sahrens poolname); 452fa9e4066Sahrens zpool_close(zhp); 453fa9e4066Sahrens return (1); 454fa9e4066Sahrens } 455fa9e4066Sahrens 456fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 4578488aeb5Staylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv); 458fa9e4066Sahrens if (nvroot == NULL) { 459fa9e4066Sahrens zpool_close(zhp); 460fa9e4066Sahrens return (1); 461fa9e4066Sahrens } 462fa9e4066Sahrens 463fa9e4066Sahrens if (dryrun) { 464fa9e4066Sahrens nvlist_t *poolnvroot; 465fa9e4066Sahrens 466fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 467fa9e4066Sahrens &poolnvroot) == 0); 468fa9e4066Sahrens 469fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 470fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 471fa9e4066Sahrens 4728654d025Sperrin /* print original main pool and new tree */ 4738654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 4748654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 4758654d025Sperrin 4768654d025Sperrin /* Do the same for the logs */ 4778654d025Sperrin if (num_logs(poolnvroot) > 0) { 4788654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 4798654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 4808654d025Sperrin } else if (num_logs(nvroot) > 0) { 4818654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 4828654d025Sperrin } 483fa9e4066Sahrens 484fa9e4066Sahrens ret = 0; 485fa9e4066Sahrens } else { 486fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 487fa9e4066Sahrens } 488fa9e4066Sahrens 48999653d4eSeschrock nvlist_free(nvroot); 49099653d4eSeschrock zpool_close(zhp); 49199653d4eSeschrock 49299653d4eSeschrock return (ret); 49399653d4eSeschrock } 49499653d4eSeschrock 49599653d4eSeschrock /* 49699653d4eSeschrock * zpool remove <pool> <vdev> 49799653d4eSeschrock * 49899653d4eSeschrock * Removes the given vdev from the pool. Currently, this only supports removing 49999653d4eSeschrock * spares from the pool. Eventually, we'll want to support removing leaf vdevs 50099653d4eSeschrock * (as an alias for 'detach') as well as toplevel vdevs. 50199653d4eSeschrock */ 50299653d4eSeschrock int 50399653d4eSeschrock zpool_do_remove(int argc, char **argv) 50499653d4eSeschrock { 50599653d4eSeschrock char *poolname; 50699653d4eSeschrock int ret; 50799653d4eSeschrock zpool_handle_t *zhp; 50899653d4eSeschrock 50999653d4eSeschrock argc--; 51099653d4eSeschrock argv++; 51199653d4eSeschrock 51299653d4eSeschrock /* get pool name and check number of arguments */ 51399653d4eSeschrock if (argc < 1) { 51499653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 51599653d4eSeschrock usage(B_FALSE); 51699653d4eSeschrock } 51799653d4eSeschrock if (argc < 2) { 51899653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 51999653d4eSeschrock usage(B_FALSE); 52099653d4eSeschrock } 52199653d4eSeschrock 52299653d4eSeschrock poolname = argv[0]; 52399653d4eSeschrock 52499653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 52599653d4eSeschrock return (1); 52699653d4eSeschrock 52799653d4eSeschrock ret = (zpool_vdev_remove(zhp, argv[1]) != 0); 52899653d4eSeschrock 529fa9e4066Sahrens return (ret); 530fa9e4066Sahrens } 531fa9e4066Sahrens 532fa9e4066Sahrens /* 533990b4856Slling * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint] 534990b4856Slling * <pool> <dev> ... 535fa9e4066Sahrens * 536fa9e4066Sahrens * -f Force creation, even if devices appear in use 537fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 538fa9e4066Sahrens * were to be created. 539fa9e4066Sahrens * -R Create a pool under an alternate root 540fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 541fa9e4066Sahrens * '/<pool>' 542990b4856Slling * -o Set property=value. 543fa9e4066Sahrens * 544b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 545fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 546fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 547fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 548fa9e4066Sahrens */ 549fa9e4066Sahrens int 550fa9e4066Sahrens zpool_do_create(int argc, char **argv) 551fa9e4066Sahrens { 55299653d4eSeschrock boolean_t force = B_FALSE; 55399653d4eSeschrock boolean_t dryrun = B_FALSE; 554fa9e4066Sahrens int c; 555990b4856Slling nvlist_t *nvroot = NULL; 556fa9e4066Sahrens char *poolname; 557990b4856Slling int ret = 1; 558fa9e4066Sahrens char *altroot = NULL; 559fa9e4066Sahrens char *mountpoint = NULL; 56099653d4eSeschrock nvlist_t **child; 56199653d4eSeschrock uint_t children; 562990b4856Slling nvlist_t *props = NULL; 5632f8aaab3Seschrock char *propval; 564fa9e4066Sahrens 565fa9e4066Sahrens /* check options */ 566990b4856Slling while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) { 567fa9e4066Sahrens switch (c) { 568fa9e4066Sahrens case 'f': 56999653d4eSeschrock force = B_TRUE; 570fa9e4066Sahrens break; 571fa9e4066Sahrens case 'n': 57299653d4eSeschrock dryrun = B_TRUE; 573fa9e4066Sahrens break; 574fa9e4066Sahrens case 'R': 575fa9e4066Sahrens altroot = optarg; 576990b4856Slling if (add_prop_list(zpool_prop_to_name( 577990b4856Slling ZPOOL_PROP_ALTROOT), optarg, &props)) 578990b4856Slling goto errout; 5792f8aaab3Seschrock if (nvlist_lookup_string(props, 5802f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 5812f8aaab3Seschrock &propval) == 0) 5822f8aaab3Seschrock break; 583990b4856Slling if (add_prop_list(zpool_prop_to_name( 5842f8aaab3Seschrock ZPOOL_PROP_CACHEFILE), "none", &props)) 585990b4856Slling goto errout; 586fa9e4066Sahrens break; 587fa9e4066Sahrens case 'm': 588fa9e4066Sahrens mountpoint = optarg; 589fa9e4066Sahrens break; 590990b4856Slling case 'o': 591990b4856Slling if ((propval = strchr(optarg, '=')) == NULL) { 592990b4856Slling (void) fprintf(stderr, gettext("missing " 593990b4856Slling "'=' for -o option\n")); 594990b4856Slling goto errout; 595990b4856Slling } 596990b4856Slling *propval = '\0'; 597990b4856Slling propval++; 598990b4856Slling 599990b4856Slling if (add_prop_list(optarg, propval, &props)) 600990b4856Slling goto errout; 601990b4856Slling break; 602fa9e4066Sahrens case ':': 603fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 604fa9e4066Sahrens "'%c' option\n"), optopt); 605990b4856Slling goto badusage; 606fa9e4066Sahrens case '?': 607fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 608fa9e4066Sahrens optopt); 609990b4856Slling goto badusage; 610fa9e4066Sahrens } 611fa9e4066Sahrens } 612fa9e4066Sahrens 613fa9e4066Sahrens argc -= optind; 614fa9e4066Sahrens argv += optind; 615fa9e4066Sahrens 616fa9e4066Sahrens /* get pool name and check number of arguments */ 617fa9e4066Sahrens if (argc < 1) { 618fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 619990b4856Slling goto badusage; 620fa9e4066Sahrens } 621fa9e4066Sahrens if (argc < 2) { 622fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 623990b4856Slling goto badusage; 624fa9e4066Sahrens } 625fa9e4066Sahrens 626fa9e4066Sahrens poolname = argv[0]; 627fa9e4066Sahrens 628fa9e4066Sahrens /* 629fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 630fa9e4066Sahrens * user to use 'zfs create' instead. 631fa9e4066Sahrens */ 632fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 633fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 634fa9e4066Sahrens "character '/' in pool name\n"), poolname); 635fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 636fa9e4066Sahrens "create a dataset\n")); 637990b4856Slling goto errout; 638fa9e4066Sahrens } 639fa9e4066Sahrens 640fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 64199653d4eSeschrock nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1, 64299653d4eSeschrock argv + 1); 643fa9e4066Sahrens if (nvroot == NULL) 644fa9e4066Sahrens return (1); 645fa9e4066Sahrens 64699653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 64799653d4eSeschrock verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 64899653d4eSeschrock &child, &children) == 0); 64999653d4eSeschrock if (children == 0) { 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]; 671fa9e4066Sahrens struct stat64 statbuf; 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 696fa9e4066Sahrens if (stat64(buf, &statbuf) == 0 && 697fa9e4066Sahrens statbuf.st_nlink != 2) { 698fa9e4066Sahrens if (mountpoint == NULL) 699fa9e4066Sahrens (void) fprintf(stderr, gettext("default " 700fa9e4066Sahrens "mountpoint '%s' exists and is not " 701fa9e4066Sahrens "empty\n"), buf); 702fa9e4066Sahrens else 703fa9e4066Sahrens (void) fprintf(stderr, gettext("mountpoint " 704fa9e4066Sahrens "'%s' exists and is not empty\n"), buf); 705fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 706fa9e4066Sahrens "option to provide a different default\n")); 707990b4856Slling goto errout; 708fa9e4066Sahrens } 709fa9e4066Sahrens } 710fa9e4066Sahrens 711fa9e4066Sahrens if (dryrun) { 712fa9e4066Sahrens /* 713fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 714fa9e4066Sahrens * through all the vdevs in the list and print out in an 715fa9e4066Sahrens * appropriate hierarchy. 716fa9e4066Sahrens */ 717fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 718fa9e4066Sahrens "following layout:\n\n"), poolname); 719fa9e4066Sahrens 7208654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 7218654d025Sperrin if (num_logs(nvroot) > 0) 7228654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 723fa9e4066Sahrens 724fa9e4066Sahrens ret = 0; 725fa9e4066Sahrens } else { 726fa9e4066Sahrens /* 727fa9e4066Sahrens * Hand off to libzfs. 728fa9e4066Sahrens */ 729990b4856Slling if (zpool_create(g_zfs, poolname, nvroot, props) == 0) { 73099653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 731fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 732fa9e4066Sahrens if (pool != NULL) { 733fa9e4066Sahrens if (mountpoint != NULL) 734fa9e4066Sahrens verify(zfs_prop_set(pool, 735e9dbad6fSeschrock zfs_prop_to_name( 736e9dbad6fSeschrock ZFS_PROP_MOUNTPOINT), 737fa9e4066Sahrens mountpoint) == 0); 738fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 739da6c28aaSamw ret = zfs_shareall(pool); 740fa9e4066Sahrens zfs_close(pool); 741fa9e4066Sahrens } 74299653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 74399653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 74499653d4eSeschrock "been omitted\n")); 745fa9e4066Sahrens } 746fa9e4066Sahrens } 747fa9e4066Sahrens 748990b4856Slling errout: 749fa9e4066Sahrens nvlist_free(nvroot); 750990b4856Slling nvlist_free(props); 751fa9e4066Sahrens return (ret); 752990b4856Slling badusage: 753990b4856Slling nvlist_free(props); 754990b4856Slling usage(B_FALSE); 755990b4856Slling return (2); 756fa9e4066Sahrens } 757fa9e4066Sahrens 758fa9e4066Sahrens /* 759fa9e4066Sahrens * zpool destroy <pool> 760fa9e4066Sahrens * 761fa9e4066Sahrens * -f Forcefully unmount any datasets 762fa9e4066Sahrens * 763fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 764fa9e4066Sahrens */ 765fa9e4066Sahrens int 766fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 767fa9e4066Sahrens { 76899653d4eSeschrock boolean_t force = B_FALSE; 769fa9e4066Sahrens int c; 770fa9e4066Sahrens char *pool; 771fa9e4066Sahrens zpool_handle_t *zhp; 772fa9e4066Sahrens int ret; 773fa9e4066Sahrens 774fa9e4066Sahrens /* check options */ 775fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 776fa9e4066Sahrens switch (c) { 777fa9e4066Sahrens case 'f': 77899653d4eSeschrock force = B_TRUE; 779fa9e4066Sahrens break; 780fa9e4066Sahrens case '?': 781fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 782fa9e4066Sahrens optopt); 78399653d4eSeschrock usage(B_FALSE); 784fa9e4066Sahrens } 785fa9e4066Sahrens } 786fa9e4066Sahrens 787fa9e4066Sahrens argc -= optind; 788fa9e4066Sahrens argv += optind; 789fa9e4066Sahrens 790fa9e4066Sahrens /* check arguments */ 791fa9e4066Sahrens if (argc < 1) { 792fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 79399653d4eSeschrock usage(B_FALSE); 794fa9e4066Sahrens } 795fa9e4066Sahrens if (argc > 1) { 796fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 79799653d4eSeschrock usage(B_FALSE); 798fa9e4066Sahrens } 799fa9e4066Sahrens 800fa9e4066Sahrens pool = argv[0]; 801fa9e4066Sahrens 80299653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 803fa9e4066Sahrens /* 804fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 805fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 806fa9e4066Sahrens */ 807fa9e4066Sahrens if (strchr(pool, '/') != NULL) 808fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 809fa9e4066Sahrens "destroy a dataset\n")); 810fa9e4066Sahrens return (1); 811fa9e4066Sahrens } 812fa9e4066Sahrens 813f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 814fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 815fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 816fa9e4066Sahrens return (1); 817fa9e4066Sahrens } 818fa9e4066Sahrens 819fa9e4066Sahrens ret = (zpool_destroy(zhp) != 0); 820fa9e4066Sahrens 821fa9e4066Sahrens zpool_close(zhp); 822fa9e4066Sahrens 823fa9e4066Sahrens return (ret); 824fa9e4066Sahrens } 825fa9e4066Sahrens 826fa9e4066Sahrens /* 827fa9e4066Sahrens * zpool export [-f] <pool> ... 828fa9e4066Sahrens * 829fa9e4066Sahrens * -f Forcefully unmount datasets 830fa9e4066Sahrens * 831b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 832fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 833fa9e4066Sahrens * then the datasets will be forcefully unmounted. 834fa9e4066Sahrens */ 835fa9e4066Sahrens int 836fa9e4066Sahrens zpool_do_export(int argc, char **argv) 837fa9e4066Sahrens { 83899653d4eSeschrock boolean_t force = B_FALSE; 839fa9e4066Sahrens int c; 840fa9e4066Sahrens zpool_handle_t *zhp; 841fa9e4066Sahrens int ret; 842fa9e4066Sahrens int i; 843fa9e4066Sahrens 844fa9e4066Sahrens /* check options */ 845fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 846fa9e4066Sahrens switch (c) { 847fa9e4066Sahrens case 'f': 84899653d4eSeschrock force = B_TRUE; 849fa9e4066Sahrens break; 850fa9e4066Sahrens case '?': 851fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 852fa9e4066Sahrens optopt); 85399653d4eSeschrock usage(B_FALSE); 854fa9e4066Sahrens } 855fa9e4066Sahrens } 856fa9e4066Sahrens 857fa9e4066Sahrens argc -= optind; 858fa9e4066Sahrens argv += optind; 859fa9e4066Sahrens 860fa9e4066Sahrens /* check arguments */ 861fa9e4066Sahrens if (argc < 1) { 862fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 86399653d4eSeschrock usage(B_FALSE); 864fa9e4066Sahrens } 865fa9e4066Sahrens 866fa9e4066Sahrens ret = 0; 867fa9e4066Sahrens for (i = 0; i < argc; i++) { 86899653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 869fa9e4066Sahrens ret = 1; 870fa9e4066Sahrens continue; 871fa9e4066Sahrens } 872fa9e4066Sahrens 873f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 874fa9e4066Sahrens ret = 1; 875fa9e4066Sahrens zpool_close(zhp); 876fa9e4066Sahrens continue; 877fa9e4066Sahrens } 878fa9e4066Sahrens 879fa9e4066Sahrens if (zpool_export(zhp) != 0) 880fa9e4066Sahrens ret = 1; 881fa9e4066Sahrens 882fa9e4066Sahrens zpool_close(zhp); 883fa9e4066Sahrens } 884fa9e4066Sahrens 885fa9e4066Sahrens return (ret); 886fa9e4066Sahrens } 887fa9e4066Sahrens 888fa9e4066Sahrens /* 889fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 890fa9e4066Sahrens * name column. 891fa9e4066Sahrens */ 892fa9e4066Sahrens static int 893c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 894fa9e4066Sahrens { 89599653d4eSeschrock char *name = zpool_vdev_name(g_zfs, zhp, nv); 896fa9e4066Sahrens nvlist_t **child; 897fa9e4066Sahrens uint_t c, children; 898fa9e4066Sahrens int ret; 899fa9e4066Sahrens 900fa9e4066Sahrens if (strlen(name) + depth > max) 901fa9e4066Sahrens max = strlen(name) + depth; 902fa9e4066Sahrens 903afefbcddSeschrock free(name); 904afefbcddSeschrock 90599653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 90699653d4eSeschrock &child, &children) == 0) { 907fa9e4066Sahrens for (c = 0; c < children; c++) 90899653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 90999653d4eSeschrock max)) > max) 910fa9e4066Sahrens max = ret; 91199653d4eSeschrock } 91299653d4eSeschrock 91399653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 91499653d4eSeschrock &child, &children) == 0) { 91599653d4eSeschrock for (c = 0; c < children; c++) 91699653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 91799653d4eSeschrock max)) > max) 91899653d4eSeschrock max = ret; 91999653d4eSeschrock } 92099653d4eSeschrock 921fa9e4066Sahrens 922fa9e4066Sahrens return (max); 923fa9e4066Sahrens } 924fa9e4066Sahrens 925fa9e4066Sahrens 926fa9e4066Sahrens /* 927fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 928fa9e4066Sahrens * pool, printing out the name and status for each one. 929fa9e4066Sahrens */ 930fa9e4066Sahrens void 9318654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth, 9328654d025Sperrin boolean_t print_logs) 933fa9e4066Sahrens { 934fa9e4066Sahrens nvlist_t **child; 935fa9e4066Sahrens uint_t c, children; 936fa9e4066Sahrens vdev_stat_t *vs; 937afefbcddSeschrock char *type, *vname; 938fa9e4066Sahrens 939fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 940fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_MISSING) == 0) 941fa9e4066Sahrens return; 942fa9e4066Sahrens 943fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 944fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 945fa9e4066Sahrens 946fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 947990b4856Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 948fa9e4066Sahrens 949fa9e4066Sahrens if (vs->vs_aux != 0) { 9503d7072f8Seschrock (void) printf(" "); 951fa9e4066Sahrens 952fa9e4066Sahrens switch (vs->vs_aux) { 953fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 954fa9e4066Sahrens (void) printf(gettext("cannot open")); 955fa9e4066Sahrens break; 956fa9e4066Sahrens 957fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 958fa9e4066Sahrens (void) printf(gettext("missing device")); 959fa9e4066Sahrens break; 960fa9e4066Sahrens 961fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 962fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 963fa9e4066Sahrens break; 964fa9e4066Sahrens 965eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 966eaca9bbdSeschrock (void) printf(gettext("newer version")); 967eaca9bbdSeschrock break; 968eaca9bbdSeschrock 9693d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 9703d7072f8Seschrock (void) printf(gettext("too many errors")); 9713d7072f8Seschrock break; 9723d7072f8Seschrock 973fa9e4066Sahrens default: 974fa9e4066Sahrens (void) printf(gettext("corrupted data")); 975fa9e4066Sahrens break; 976fa9e4066Sahrens } 977fa9e4066Sahrens } 978fa9e4066Sahrens (void) printf("\n"); 979fa9e4066Sahrens 980fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 981fa9e4066Sahrens &child, &children) != 0) 982fa9e4066Sahrens return; 983fa9e4066Sahrens 984afefbcddSeschrock for (c = 0; c < children; c++) { 9858654d025Sperrin uint64_t is_log = B_FALSE; 9868654d025Sperrin 9878654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 9888654d025Sperrin &is_log); 9898654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 9908654d025Sperrin continue; 9918654d025Sperrin 99299653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 993afefbcddSeschrock print_import_config(vname, child[c], 9948654d025Sperrin namewidth, depth + 2, B_FALSE); 995afefbcddSeschrock free(vname); 996afefbcddSeschrock } 99799653d4eSeschrock 99899653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 99999653d4eSeschrock &child, &children) != 0) 100099653d4eSeschrock return; 100199653d4eSeschrock 100299653d4eSeschrock (void) printf(gettext("\tspares\n")); 100399653d4eSeschrock for (c = 0; c < children; c++) { 100499653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 100599653d4eSeschrock (void) printf("\t %s\n", vname); 100699653d4eSeschrock free(vname); 100799653d4eSeschrock } 1008fa9e4066Sahrens } 1009fa9e4066Sahrens 1010fa9e4066Sahrens /* 1011fa9e4066Sahrens * Display the status for the given pool. 1012fa9e4066Sahrens */ 1013fa9e4066Sahrens static void 1014fa9e4066Sahrens show_import(nvlist_t *config) 1015fa9e4066Sahrens { 1016fa9e4066Sahrens uint64_t pool_state; 1017fa9e4066Sahrens vdev_stat_t *vs; 1018fa9e4066Sahrens char *name; 1019fa9e4066Sahrens uint64_t guid; 1020fa9e4066Sahrens char *msgid; 1021fa9e4066Sahrens nvlist_t *nvroot; 1022fa9e4066Sahrens int reason; 102346657f8dSmmusante const char *health; 1024fa9e4066Sahrens uint_t vsc; 1025fa9e4066Sahrens int namewidth; 1026fa9e4066Sahrens 1027fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1028fa9e4066Sahrens &name) == 0); 1029fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1030fa9e4066Sahrens &guid) == 0); 1031fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1032fa9e4066Sahrens &pool_state) == 0); 1033fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1034fa9e4066Sahrens &nvroot) == 0); 1035fa9e4066Sahrens 1036fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1037fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 1038990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1039fa9e4066Sahrens 1040fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1041fa9e4066Sahrens 104246657f8dSmmusante (void) printf(gettext(" pool: %s\n"), name); 104346657f8dSmmusante (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 104446657f8dSmmusante (void) printf(gettext(" state: %s"), health); 10454c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 104646657f8dSmmusante (void) printf(gettext(" (DESTROYED)")); 10474c58d714Sdarrenm (void) printf("\n"); 1048fa9e4066Sahrens 1049fa9e4066Sahrens switch (reason) { 1050fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1051fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1052fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 1053fa9e4066Sahrens (void) printf(gettext("status: One or more devices are missing " 1054fa9e4066Sahrens "from the system.\n")); 1055fa9e4066Sahrens break; 1056fa9e4066Sahrens 1057fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1058fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1059fa9e4066Sahrens (void) printf(gettext("status: One or more devices contains " 1060fa9e4066Sahrens "corrupted data.\n")); 1061fa9e4066Sahrens break; 1062fa9e4066Sahrens 1063fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 1064fa9e4066Sahrens (void) printf(gettext("status: The pool data is corrupted.\n")); 1065fa9e4066Sahrens break; 1066fa9e4066Sahrens 1067441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 1068441d80aaSlling (void) printf(gettext("status: One or more devices " 1069441d80aaSlling "are offlined.\n")); 1070441d80aaSlling break; 1071441d80aaSlling 1072ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 1073ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is " 1074ea8dc4b6Seschrock "corrupted.\n")); 1075ea8dc4b6Seschrock break; 1076ea8dc4b6Seschrock 1077eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 1078eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1079eaca9bbdSeschrock "older on-disk version.\n")); 1080eaca9bbdSeschrock break; 1081eaca9bbdSeschrock 1082eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1083eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1084eaca9bbdSeschrock "incompatible version.\n")); 1085eaca9bbdSeschrock break; 108695173954Sek110237 case ZPOOL_STATUS_HOSTID_MISMATCH: 108795173954Sek110237 (void) printf(gettext("status: The pool was last accessed by " 108895173954Sek110237 "another system.\n")); 108995173954Sek110237 break; 10903d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 10913d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 10923d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 10933d7072f8Seschrock "faulted.\n")); 10943d7072f8Seschrock break; 10953d7072f8Seschrock 1096fa9e4066Sahrens default: 1097fa9e4066Sahrens /* 1098fa9e4066Sahrens * No other status can be seen when importing pools. 1099fa9e4066Sahrens */ 1100fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1101fa9e4066Sahrens } 1102fa9e4066Sahrens 1103fa9e4066Sahrens /* 1104fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1105fa9e4066Sahrens */ 110646657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 1107eaca9bbdSeschrock if (reason == ZPOOL_STATUS_VERSION_OLDER) 1108eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1109eaca9bbdSeschrock "imported using its name or numeric identifier, " 1110eaca9bbdSeschrock "though\n\tsome features will not be available " 1111eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 111295173954Sek110237 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 111395173954Sek110237 (void) printf(gettext("action: The pool can be " 111495173954Sek110237 "imported using its name or numeric " 111595173954Sek110237 "identifier and\n\tthe '-f' flag.\n")); 1116fa9e4066Sahrens else 1117eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1118eaca9bbdSeschrock "imported using its name or numeric " 1119eaca9bbdSeschrock "identifier.\n")); 112046657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1121fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported " 1122fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1123eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1124fa9e4066Sahrens } else { 1125eaca9bbdSeschrock switch (reason) { 1126eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1127eaca9bbdSeschrock (void) printf(gettext("action: The pool cannot be " 1128eaca9bbdSeschrock "imported. Access the pool on a system running " 1129eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1130eaca9bbdSeschrock "backup.\n")); 1131eaca9bbdSeschrock break; 1132eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1133eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1134eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 1135fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1136fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1137fa9e4066Sahrens "again.\n")); 1138eaca9bbdSeschrock break; 1139eaca9bbdSeschrock default: 1140fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1141fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1142fa9e4066Sahrens } 1143eaca9bbdSeschrock } 1144eaca9bbdSeschrock 114546657f8dSmmusante /* 114646657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 114746657f8dSmmusante * is "corrupt data": 114846657f8dSmmusante */ 114946657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 115046657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 115146657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1152eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1153eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1154eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1155eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1156eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 1157eaca9bbdSeschrock "on another system, but can be imported using\n\t" 1158eaca9bbdSeschrock "the '-f' flag.\n")); 1159eaca9bbdSeschrock } 1160fa9e4066Sahrens 1161fa9e4066Sahrens if (msgid != NULL) 1162fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1163fa9e4066Sahrens msgid); 1164fa9e4066Sahrens 1165fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 1166fa9e4066Sahrens 1167c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1168fa9e4066Sahrens if (namewidth < 10) 1169fa9e4066Sahrens namewidth = 10; 11708654d025Sperrin 11718654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_FALSE); 11728654d025Sperrin if (num_logs(nvroot) > 0) { 11738654d025Sperrin (void) printf(gettext("\tlogs\n")); 11748654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_TRUE); 11758654d025Sperrin } 1176fa9e4066Sahrens 1177fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 117846657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1179fa9e4066Sahrens "be part of this pool, though their\n\texact " 118046657f8dSmmusante "configuration cannot be determined.\n")); 1181fa9e4066Sahrens } 1182fa9e4066Sahrens } 1183fa9e4066Sahrens 1184fa9e4066Sahrens /* 1185fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1186990b4856Slling * lifting off to zpool_import_props(), and then mounts the datasets contained 1187990b4856Slling * within the pool. 1188fa9e4066Sahrens */ 1189fa9e4066Sahrens static int 1190fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 1191990b4856Slling int force, nvlist_t *props) 1192fa9e4066Sahrens { 1193fa9e4066Sahrens zpool_handle_t *zhp; 1194fa9e4066Sahrens char *name; 1195fa9e4066Sahrens uint64_t state; 1196eaca9bbdSeschrock uint64_t version; 1197ecd6cf80Smarks int error = 0; 1198fa9e4066Sahrens 1199fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1200fa9e4066Sahrens &name) == 0); 1201fa9e4066Sahrens 1202fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1203fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1204eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1205eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1206e7437265Sahrens if (version > SPA_VERSION) { 1207eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1208eaca9bbdSeschrock "is formatted using a newer ZFS version\n"), name); 1209eaca9bbdSeschrock return (1); 1210eaca9bbdSeschrock } else if (state != POOL_STATE_EXPORTED && !force) { 121195173954Sek110237 uint64_t hostid; 121295173954Sek110237 121395173954Sek110237 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 121495173954Sek110237 &hostid) == 0) { 121595173954Sek110237 if ((unsigned long)hostid != gethostid()) { 121695173954Sek110237 char *hostname; 121795173954Sek110237 uint64_t timestamp; 121895173954Sek110237 time_t t; 121995173954Sek110237 122095173954Sek110237 verify(nvlist_lookup_string(config, 122195173954Sek110237 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 122295173954Sek110237 verify(nvlist_lookup_uint64(config, 122395173954Sek110237 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 122495173954Sek110237 t = timestamp; 122595173954Sek110237 (void) fprintf(stderr, gettext("cannot import " 122695173954Sek110237 "'%s': pool may be in use from other " 122795173954Sek110237 "system, it was last accessed by %s " 122895173954Sek110237 "(hostid: 0x%lx) on %s"), name, hostname, 122995173954Sek110237 (unsigned long)hostid, 123095173954Sek110237 asctime(localtime(&t))); 123195173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to " 123295173954Sek110237 "import anyway\n")); 1233fa9e4066Sahrens return (1); 1234fa9e4066Sahrens } 123595173954Sek110237 } else { 123695173954Sek110237 (void) fprintf(stderr, gettext("cannot import '%s': " 123795173954Sek110237 "pool may be in use from other system\n"), name); 123895173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to import " 123995173954Sek110237 "anyway\n")); 124095173954Sek110237 return (1); 124195173954Sek110237 } 124295173954Sek110237 } 1243fa9e4066Sahrens 1244990b4856Slling if (zpool_import_props(g_zfs, config, newname, props) != 0) 1245fa9e4066Sahrens return (1); 1246fa9e4066Sahrens 1247fa9e4066Sahrens if (newname != NULL) 1248fa9e4066Sahrens name = (char *)newname; 1249fa9e4066Sahrens 125099653d4eSeschrock verify((zhp = zpool_open(g_zfs, name)) != NULL); 1251fa9e4066Sahrens 1252f3861e1aSahl if (zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1253fa9e4066Sahrens zpool_close(zhp); 1254fa9e4066Sahrens return (1); 1255fa9e4066Sahrens } 1256fa9e4066Sahrens 1257fa9e4066Sahrens zpool_close(zhp); 1258ecd6cf80Smarks return (error); 1259fa9e4066Sahrens } 1260fa9e4066Sahrens 1261fa9e4066Sahrens /* 12624c58d714Sdarrenm * zpool import [-d dir] [-D] 12632f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 12642f8aaab3Seschrock * [-d dir | -c cachefile] [-f] -a 12652f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 12662f8aaab3Seschrock * [-d dir | -c cachefile] [-f] <pool | id> [newpool] 12672f8aaab3Seschrock * 12682f8aaab3Seschrock * -c Read pool information from a cachefile instead of searching 12692f8aaab3Seschrock * devices. 1270fa9e4066Sahrens * 1271fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1272fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1273fa9e4066Sahrens * 12744c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 12754c58d714Sdarrenm * specified destroyed pools. 12764c58d714Sdarrenm * 1277fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1278fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1279fa9e4066Sahrens * is rebooted. 1280fa9e4066Sahrens * 1281fa9e4066Sahrens * -f Force import, even if it appears that the pool is active. 1282fa9e4066Sahrens * 1283fa9e4066Sahrens * -a Import all pools found. 1284fa9e4066Sahrens * 1285990b4856Slling * -o Set property=value and/or temporary mount options (without '='). 1286ecd6cf80Smarks * 1287fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 1288fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 1289fa9e4066Sahrens */ 1290fa9e4066Sahrens int 1291fa9e4066Sahrens zpool_do_import(int argc, char **argv) 1292fa9e4066Sahrens { 1293fa9e4066Sahrens char **searchdirs = NULL; 1294fa9e4066Sahrens int nsearch = 0; 1295fa9e4066Sahrens int c; 1296fa9e4066Sahrens int err; 12972f8aaab3Seschrock nvlist_t *pools = NULL; 129899653d4eSeschrock boolean_t do_all = B_FALSE; 129999653d4eSeschrock boolean_t do_destroyed = B_FALSE; 1300fa9e4066Sahrens char *mntopts = NULL; 130199653d4eSeschrock boolean_t do_force = B_FALSE; 1302fa9e4066Sahrens nvpair_t *elem; 1303fa9e4066Sahrens nvlist_t *config; 1304fa9e4066Sahrens uint64_t searchguid; 1305fa9e4066Sahrens char *searchname; 1306990b4856Slling char *propval; 1307fa9e4066Sahrens nvlist_t *found_config; 1308ecd6cf80Smarks nvlist_t *props = NULL; 130999653d4eSeschrock boolean_t first; 13104c58d714Sdarrenm uint64_t pool_state; 13112f8aaab3Seschrock char *cachefile = NULL; 1312fa9e4066Sahrens 1313fa9e4066Sahrens /* check options */ 13142f8aaab3Seschrock while ((c = getopt(argc, argv, ":afc:d:Do:p:R:")) != -1) { 1315fa9e4066Sahrens switch (c) { 1316fa9e4066Sahrens case 'a': 131799653d4eSeschrock do_all = B_TRUE; 1318fa9e4066Sahrens break; 13192f8aaab3Seschrock case 'c': 13202f8aaab3Seschrock cachefile = optarg; 13212f8aaab3Seschrock break; 1322fa9e4066Sahrens case 'd': 1323fa9e4066Sahrens if (searchdirs == NULL) { 1324fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1325fa9e4066Sahrens } else { 1326fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 1327fa9e4066Sahrens sizeof (char *)); 1328fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 1329fa9e4066Sahrens sizeof (char *)); 1330fa9e4066Sahrens free(searchdirs); 1331fa9e4066Sahrens searchdirs = tmp; 1332fa9e4066Sahrens } 1333fa9e4066Sahrens searchdirs[nsearch++] = optarg; 1334fa9e4066Sahrens break; 13354c58d714Sdarrenm case 'D': 133699653d4eSeschrock do_destroyed = B_TRUE; 13374c58d714Sdarrenm break; 1338fa9e4066Sahrens case 'f': 133999653d4eSeschrock do_force = B_TRUE; 1340fa9e4066Sahrens break; 1341fa9e4066Sahrens case 'o': 1342990b4856Slling if ((propval = strchr(optarg, '=')) != NULL) { 1343990b4856Slling *propval = '\0'; 1344990b4856Slling propval++; 1345990b4856Slling if (add_prop_list(optarg, propval, &props)) 1346990b4856Slling goto error; 1347990b4856Slling } else { 1348fa9e4066Sahrens mntopts = optarg; 1349990b4856Slling } 1350fa9e4066Sahrens break; 1351fa9e4066Sahrens case 'R': 1352990b4856Slling if (add_prop_list(zpool_prop_to_name( 1353990b4856Slling ZPOOL_PROP_ALTROOT), optarg, &props)) 1354990b4856Slling goto error; 13552f8aaab3Seschrock if (nvlist_lookup_string(props, 13562f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 13572f8aaab3Seschrock &propval) == 0) 13582f8aaab3Seschrock break; 1359990b4856Slling if (add_prop_list(zpool_prop_to_name( 13602f8aaab3Seschrock ZPOOL_PROP_CACHEFILE), "none", &props)) 1361990b4856Slling goto error; 1362fa9e4066Sahrens break; 1363fa9e4066Sahrens case ':': 1364fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 1365fa9e4066Sahrens "'%c' option\n"), optopt); 136699653d4eSeschrock usage(B_FALSE); 1367fa9e4066Sahrens break; 1368fa9e4066Sahrens case '?': 1369fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1370fa9e4066Sahrens optopt); 137199653d4eSeschrock usage(B_FALSE); 1372fa9e4066Sahrens } 1373fa9e4066Sahrens } 1374fa9e4066Sahrens 1375fa9e4066Sahrens argc -= optind; 1376fa9e4066Sahrens argv += optind; 1377fa9e4066Sahrens 13782f8aaab3Seschrock if (cachefile && nsearch != 0) { 13792f8aaab3Seschrock (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 13802f8aaab3Seschrock usage(B_FALSE); 13812f8aaab3Seschrock } 13822f8aaab3Seschrock 1383fa9e4066Sahrens if (searchdirs == NULL) { 1384fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1385fa9e4066Sahrens searchdirs[0] = "/dev/dsk"; 1386fa9e4066Sahrens nsearch = 1; 1387fa9e4066Sahrens } 1388fa9e4066Sahrens 1389fa9e4066Sahrens /* check argument count */ 1390fa9e4066Sahrens if (do_all) { 1391fa9e4066Sahrens if (argc != 0) { 1392fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 139399653d4eSeschrock usage(B_FALSE); 1394fa9e4066Sahrens } 1395fa9e4066Sahrens } else { 1396fa9e4066Sahrens if (argc > 2) { 1397fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 139899653d4eSeschrock usage(B_FALSE); 1399fa9e4066Sahrens } 1400fa9e4066Sahrens 1401fa9e4066Sahrens /* 1402fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 1403fa9e4066Sahrens * here because otherwise any attempt to discover pools will 1404fa9e4066Sahrens * silently fail. 1405fa9e4066Sahrens */ 1406fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1407fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 1408fa9e4066Sahrens "discover pools: permission denied\n")); 140999653d4eSeschrock free(searchdirs); 1410fa9e4066Sahrens return (1); 1411fa9e4066Sahrens } 1412fa9e4066Sahrens } 1413fa9e4066Sahrens 14142f8aaab3Seschrock if (cachefile) 14152f8aaab3Seschrock pools = zpool_find_import_cached(g_zfs, cachefile); 14162f8aaab3Seschrock else 14172f8aaab3Seschrock pools = zpool_find_import(g_zfs, nsearch, searchdirs); 14182f8aaab3Seschrock 14192f8aaab3Seschrock if (pools == NULL) { 142099653d4eSeschrock free(searchdirs); 1421fa9e4066Sahrens return (1); 142299653d4eSeschrock } 1423fa9e4066Sahrens 1424fa9e4066Sahrens /* 1425fa9e4066Sahrens * We now have a list of all available pools in the given directories. 1426fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 1427fa9e4066Sahrens * 1428fa9e4066Sahrens * <none> Iterate through all pools and display information about 1429fa9e4066Sahrens * each one. 1430fa9e4066Sahrens * 1431fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 1432fa9e4066Sahrens * 1433fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 1434fa9e4066Sahrens * name and import that one. 14354c58d714Sdarrenm * 14364c58d714Sdarrenm * -D Above options applies only to destroyed pools. 1437fa9e4066Sahrens */ 1438fa9e4066Sahrens if (argc != 0) { 1439fa9e4066Sahrens char *endptr; 1440fa9e4066Sahrens 1441fa9e4066Sahrens errno = 0; 1442fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 1443fa9e4066Sahrens if (errno != 0 || *endptr != '\0') 1444fa9e4066Sahrens searchname = argv[0]; 1445fa9e4066Sahrens else 1446fa9e4066Sahrens searchname = NULL; 1447fa9e4066Sahrens found_config = NULL; 1448fa9e4066Sahrens } 1449fa9e4066Sahrens 1450fa9e4066Sahrens err = 0; 1451fa9e4066Sahrens elem = NULL; 145299653d4eSeschrock first = B_TRUE; 1453fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1454fa9e4066Sahrens 1455fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 1456fa9e4066Sahrens 14574c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 14584c58d714Sdarrenm &pool_state) == 0); 14594c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 14604c58d714Sdarrenm continue; 14614c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 14624c58d714Sdarrenm continue; 14634c58d714Sdarrenm 1464fa9e4066Sahrens if (argc == 0) { 1465fa9e4066Sahrens if (first) 146699653d4eSeschrock first = B_FALSE; 14673bb79becSeschrock else if (!do_all) 1468fa9e4066Sahrens (void) printf("\n"); 1469fa9e4066Sahrens 1470fa9e4066Sahrens if (do_all) 1471fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 1472990b4856Slling do_force, props); 1473fa9e4066Sahrens else 1474fa9e4066Sahrens show_import(config); 1475fa9e4066Sahrens } else if (searchname != NULL) { 1476fa9e4066Sahrens char *name; 1477fa9e4066Sahrens 1478fa9e4066Sahrens /* 1479fa9e4066Sahrens * We are searching for a pool based on name. 1480fa9e4066Sahrens */ 1481fa9e4066Sahrens verify(nvlist_lookup_string(config, 1482fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1483fa9e4066Sahrens 1484fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 1485fa9e4066Sahrens if (found_config != NULL) { 1486fa9e4066Sahrens (void) fprintf(stderr, gettext( 1487fa9e4066Sahrens "cannot import '%s': more than " 1488fa9e4066Sahrens "one matching pool\n"), searchname); 1489fa9e4066Sahrens (void) fprintf(stderr, gettext( 1490fa9e4066Sahrens "import by numeric ID instead\n")); 149199653d4eSeschrock err = B_TRUE; 1492fa9e4066Sahrens } 1493fa9e4066Sahrens found_config = config; 1494fa9e4066Sahrens } 1495fa9e4066Sahrens } else { 1496fa9e4066Sahrens uint64_t guid; 1497fa9e4066Sahrens 1498fa9e4066Sahrens /* 1499fa9e4066Sahrens * Search for a pool by guid. 1500fa9e4066Sahrens */ 1501fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1502fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1503fa9e4066Sahrens 1504fa9e4066Sahrens if (guid == searchguid) 1505fa9e4066Sahrens found_config = config; 1506fa9e4066Sahrens } 1507fa9e4066Sahrens } 1508fa9e4066Sahrens 1509fa9e4066Sahrens /* 1510fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 1511fa9e4066Sahrens * pool, and then do the import. 1512fa9e4066Sahrens */ 1513fa9e4066Sahrens if (argc != 0 && err == 0) { 1514fa9e4066Sahrens if (found_config == NULL) { 1515fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 1516fa9e4066Sahrens "no such pool available\n"), argv[0]); 151799653d4eSeschrock err = B_TRUE; 1518fa9e4066Sahrens } else { 1519fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 1520990b4856Slling argv[1], mntopts, do_force, props); 1521fa9e4066Sahrens } 1522fa9e4066Sahrens } 1523fa9e4066Sahrens 1524fa9e4066Sahrens /* 1525fa9e4066Sahrens * If we were just looking for pools, report an error if none were 1526fa9e4066Sahrens * found. 1527fa9e4066Sahrens */ 1528fa9e4066Sahrens if (argc == 0 && first) 1529fa9e4066Sahrens (void) fprintf(stderr, 1530fa9e4066Sahrens gettext("no pools available to import\n")); 1531fa9e4066Sahrens 1532ecd6cf80Smarks error: 1533ecd6cf80Smarks nvlist_free(props); 1534fa9e4066Sahrens nvlist_free(pools); 153599653d4eSeschrock free(searchdirs); 1536fa9e4066Sahrens 1537fa9e4066Sahrens return (err ? 1 : 0); 1538fa9e4066Sahrens } 1539fa9e4066Sahrens 1540fa9e4066Sahrens typedef struct iostat_cbdata { 1541fa9e4066Sahrens zpool_list_t *cb_list; 1542fa9e4066Sahrens int cb_verbose; 1543fa9e4066Sahrens int cb_iteration; 1544fa9e4066Sahrens int cb_namewidth; 1545fa9e4066Sahrens } iostat_cbdata_t; 1546fa9e4066Sahrens 1547fa9e4066Sahrens static void 1548fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 1549fa9e4066Sahrens { 1550fa9e4066Sahrens int i = 0; 1551fa9e4066Sahrens 1552fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 1553fa9e4066Sahrens (void) printf("-"); 1554fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1555fa9e4066Sahrens } 1556fa9e4066Sahrens 1557fa9e4066Sahrens static void 1558fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 1559fa9e4066Sahrens { 1560fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 1561fa9e4066Sahrens cb->cb_namewidth, ""); 1562fa9e4066Sahrens (void) printf("%-*s used avail read write read write\n", 1563fa9e4066Sahrens cb->cb_namewidth, "pool"); 1564fa9e4066Sahrens print_iostat_separator(cb); 1565fa9e4066Sahrens } 1566fa9e4066Sahrens 1567fa9e4066Sahrens /* 1568fa9e4066Sahrens * Display a single statistic. 1569fa9e4066Sahrens */ 1570990b4856Slling static void 1571fa9e4066Sahrens print_one_stat(uint64_t value) 1572fa9e4066Sahrens { 1573fa9e4066Sahrens char buf[64]; 1574fa9e4066Sahrens 1575fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 1576fa9e4066Sahrens (void) printf(" %5s", buf); 1577fa9e4066Sahrens } 1578fa9e4066Sahrens 1579fa9e4066Sahrens /* 1580fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 1581fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 1582fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 1583fa9e4066Sahrens */ 1584fa9e4066Sahrens void 1585c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1586c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1587fa9e4066Sahrens { 1588fa9e4066Sahrens nvlist_t **oldchild, **newchild; 1589fa9e4066Sahrens uint_t c, children; 1590fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 1591fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 1592fa9e4066Sahrens uint64_t tdelta; 1593fa9e4066Sahrens double scale; 1594afefbcddSeschrock char *vname; 1595fa9e4066Sahrens 1596fa9e4066Sahrens if (oldnv != NULL) { 1597fa9e4066Sahrens verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1598fa9e4066Sahrens (uint64_t **)&oldvs, &c) == 0); 1599fa9e4066Sahrens } else { 1600fa9e4066Sahrens oldvs = &zerovs; 1601fa9e4066Sahrens } 1602fa9e4066Sahrens 1603fa9e4066Sahrens verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1604fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 1605fa9e4066Sahrens 1606fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 1607fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 1608fa9e4066Sahrens else 1609fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 1610fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1611fa9e4066Sahrens 1612fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1613fa9e4066Sahrens 1614fa9e4066Sahrens if (tdelta == 0) 1615fa9e4066Sahrens scale = 1.0; 1616fa9e4066Sahrens else 1617fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 1618fa9e4066Sahrens 1619fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 1620fa9e4066Sahrens if (newvs->vs_space == 0) { 1621fa9e4066Sahrens (void) printf(" - -"); 1622fa9e4066Sahrens } else { 1623fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 1624fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 1625fa9e4066Sahrens } 1626fa9e4066Sahrens 1627fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1628fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 1629fa9e4066Sahrens 1630fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1631fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1632fa9e4066Sahrens 1633fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1634fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 1635fa9e4066Sahrens 1636fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1637fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1638fa9e4066Sahrens 1639fa9e4066Sahrens (void) printf("\n"); 1640fa9e4066Sahrens 1641fa9e4066Sahrens if (!cb->cb_verbose) 1642fa9e4066Sahrens return; 1643fa9e4066Sahrens 1644fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1645fa9e4066Sahrens &newchild, &children) != 0) 1646fa9e4066Sahrens return; 1647fa9e4066Sahrens 1648fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1649fa9e4066Sahrens &oldchild, &c) != 0) 1650fa9e4066Sahrens return; 1651fa9e4066Sahrens 1652afefbcddSeschrock for (c = 0; c < children; c++) { 165399653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1654c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1655afefbcddSeschrock newchild[c], cb, depth + 2); 1656afefbcddSeschrock free(vname); 1657afefbcddSeschrock } 1658fa9e4066Sahrens } 1659fa9e4066Sahrens 1660088e9d47Seschrock static int 1661088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 1662088e9d47Seschrock { 1663088e9d47Seschrock iostat_cbdata_t *cb = data; 166494de1d4cSeschrock boolean_t missing; 1665088e9d47Seschrock 1666088e9d47Seschrock /* 1667088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 1668088e9d47Seschrock */ 166994de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 167094de1d4cSeschrock return (-1); 167194de1d4cSeschrock 167294de1d4cSeschrock if (missing) 1673088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 1674088e9d47Seschrock 1675088e9d47Seschrock return (0); 1676088e9d47Seschrock } 1677088e9d47Seschrock 1678fa9e4066Sahrens /* 1679fa9e4066Sahrens * Callback to print out the iostats for the given pool. 1680fa9e4066Sahrens */ 1681fa9e4066Sahrens int 1682fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 1683fa9e4066Sahrens { 1684fa9e4066Sahrens iostat_cbdata_t *cb = data; 1685fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 1686fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 1687fa9e4066Sahrens 1688088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 1689fa9e4066Sahrens 1690088e9d47Seschrock if (cb->cb_iteration == 1) 1691fa9e4066Sahrens oldconfig = NULL; 1692fa9e4066Sahrens 1693fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1694fa9e4066Sahrens &newnvroot) == 0); 1695fa9e4066Sahrens 1696088e9d47Seschrock if (oldconfig == NULL) 1697fa9e4066Sahrens oldnvroot = NULL; 1698088e9d47Seschrock else 1699088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 1700088e9d47Seschrock &oldnvroot) == 0); 1701fa9e4066Sahrens 1702fa9e4066Sahrens /* 1703fa9e4066Sahrens * Print out the statistics for the pool. 1704fa9e4066Sahrens */ 1705c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1706fa9e4066Sahrens 1707fa9e4066Sahrens if (cb->cb_verbose) 1708fa9e4066Sahrens print_iostat_separator(cb); 1709fa9e4066Sahrens 1710fa9e4066Sahrens return (0); 1711fa9e4066Sahrens } 1712fa9e4066Sahrens 1713fa9e4066Sahrens int 1714fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 1715fa9e4066Sahrens { 1716fa9e4066Sahrens iostat_cbdata_t *cb = data; 1717fa9e4066Sahrens nvlist_t *config, *nvroot; 1718fa9e4066Sahrens 1719088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 1720fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1721fa9e4066Sahrens &nvroot) == 0); 1722fa9e4066Sahrens if (!cb->cb_verbose) 1723fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1724fa9e4066Sahrens else 1725c67d9675Seschrock cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 1726fa9e4066Sahrens } 1727fa9e4066Sahrens 1728fa9e4066Sahrens /* 1729fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 1730fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 1731fa9e4066Sahrens */ 1732fa9e4066Sahrens if (cb->cb_namewidth < 10) 1733fa9e4066Sahrens cb->cb_namewidth = 10; 1734fa9e4066Sahrens if (cb->cb_namewidth > 38) 1735fa9e4066Sahrens cb->cb_namewidth = 38; 1736fa9e4066Sahrens 1737fa9e4066Sahrens return (0); 1738fa9e4066Sahrens } 1739fa9e4066Sahrens 1740fa9e4066Sahrens /* 1741fa9e4066Sahrens * zpool iostat [-v] [pool] ... [interval [count]] 1742fa9e4066Sahrens * 1743fa9e4066Sahrens * -v Display statistics for individual vdevs 1744fa9e4066Sahrens * 1745fa9e4066Sahrens * This command can be tricky because we want to be able to deal with pool 1746fa9e4066Sahrens * creation/destruction as well as vdev configuration changes. The bulk of this 1747fa9e4066Sahrens * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1748fa9e4066Sahrens * on pool_list_update() to detect the addition of new pools. Configuration 1749fa9e4066Sahrens * changes are all handled within libzfs. 1750fa9e4066Sahrens */ 1751fa9e4066Sahrens int 1752fa9e4066Sahrens zpool_do_iostat(int argc, char **argv) 1753fa9e4066Sahrens { 1754fa9e4066Sahrens int c; 1755fa9e4066Sahrens int ret; 1756fa9e4066Sahrens int npools; 1757fa9e4066Sahrens unsigned long interval = 0, count = 0; 1758fa9e4066Sahrens zpool_list_t *list; 175999653d4eSeschrock boolean_t verbose = B_FALSE; 1760fa9e4066Sahrens iostat_cbdata_t cb; 1761fa9e4066Sahrens 1762fa9e4066Sahrens /* check options */ 1763fa9e4066Sahrens while ((c = getopt(argc, argv, "v")) != -1) { 1764fa9e4066Sahrens switch (c) { 1765fa9e4066Sahrens case 'v': 176699653d4eSeschrock verbose = B_TRUE; 1767fa9e4066Sahrens break; 1768fa9e4066Sahrens case '?': 1769fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1770fa9e4066Sahrens optopt); 177199653d4eSeschrock usage(B_FALSE); 1772fa9e4066Sahrens } 1773fa9e4066Sahrens } 1774fa9e4066Sahrens 1775fa9e4066Sahrens argc -= optind; 1776fa9e4066Sahrens argv += optind; 1777fa9e4066Sahrens 1778fa9e4066Sahrens /* 1779fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 1780fa9e4066Sahrens */ 1781fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1782fa9e4066Sahrens char *end; 1783fa9e4066Sahrens 1784fa9e4066Sahrens errno = 0; 1785fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1786fa9e4066Sahrens 1787fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1788fa9e4066Sahrens if (interval == 0) { 1789fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1790fa9e4066Sahrens "cannot be zero\n")); 179199653d4eSeschrock usage(B_FALSE); 1792fa9e4066Sahrens } 1793fa9e4066Sahrens 1794fa9e4066Sahrens /* 1795fa9e4066Sahrens * Ignore the last parameter 1796fa9e4066Sahrens */ 1797fa9e4066Sahrens argc--; 1798fa9e4066Sahrens } else { 1799fa9e4066Sahrens /* 1800fa9e4066Sahrens * If this is not a valid number, just plow on. The 1801fa9e4066Sahrens * user will get a more informative error message later 1802fa9e4066Sahrens * on. 1803fa9e4066Sahrens */ 1804fa9e4066Sahrens interval = 0; 1805fa9e4066Sahrens } 1806fa9e4066Sahrens } 1807fa9e4066Sahrens 1808fa9e4066Sahrens /* 1809fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 1810fa9e4066Sahrens * and an integer. 1811fa9e4066Sahrens */ 1812fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1813fa9e4066Sahrens char *end; 1814fa9e4066Sahrens 1815fa9e4066Sahrens errno = 0; 1816fa9e4066Sahrens count = interval; 1817fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1818fa9e4066Sahrens 1819fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1820fa9e4066Sahrens if (interval == 0) { 1821fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1822fa9e4066Sahrens "cannot be zero\n")); 182399653d4eSeschrock usage(B_FALSE); 1824fa9e4066Sahrens } 1825fa9e4066Sahrens 1826fa9e4066Sahrens /* 1827fa9e4066Sahrens * Ignore the last parameter 1828fa9e4066Sahrens */ 1829fa9e4066Sahrens argc--; 1830fa9e4066Sahrens } else { 1831fa9e4066Sahrens interval = 0; 1832fa9e4066Sahrens } 1833fa9e4066Sahrens } 1834fa9e4066Sahrens 1835fa9e4066Sahrens /* 1836fa9e4066Sahrens * Construct the list of all interesting pools. 1837fa9e4066Sahrens */ 1838fa9e4066Sahrens ret = 0; 1839b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 1840fa9e4066Sahrens return (1); 1841fa9e4066Sahrens 184299653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 184399653d4eSeschrock pool_list_free(list); 1844fa9e4066Sahrens return (1); 184599653d4eSeschrock } 1846fa9e4066Sahrens 1847fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 184899653d4eSeschrock pool_list_free(list); 1849fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 1850fa9e4066Sahrens return (1); 1851fa9e4066Sahrens } 1852fa9e4066Sahrens 1853fa9e4066Sahrens /* 1854fa9e4066Sahrens * Enter the main iostat loop. 1855fa9e4066Sahrens */ 1856fa9e4066Sahrens cb.cb_list = list; 1857fa9e4066Sahrens cb.cb_verbose = verbose; 1858fa9e4066Sahrens cb.cb_iteration = 0; 1859fa9e4066Sahrens cb.cb_namewidth = 0; 1860fa9e4066Sahrens 1861fa9e4066Sahrens for (;;) { 1862fa9e4066Sahrens pool_list_update(list); 1863fa9e4066Sahrens 1864fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 1865fa9e4066Sahrens break; 1866fa9e4066Sahrens 1867fa9e4066Sahrens /* 1868088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 1869088e9d47Seschrock * before calculating the maximum name width, so that any 1870088e9d47Seschrock * configuration changes are properly accounted for. 1871088e9d47Seschrock */ 187299653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 1873088e9d47Seschrock 1874088e9d47Seschrock /* 1875fa9e4066Sahrens * Iterate over all pools to determine the maximum width 1876fa9e4066Sahrens * for the pool / device name column across all pools. 1877fa9e4066Sahrens */ 1878fa9e4066Sahrens cb.cb_namewidth = 0; 187999653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 1880fa9e4066Sahrens 1881fa9e4066Sahrens /* 1882fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 1883fa9e4066Sahrens */ 1884fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 1885fa9e4066Sahrens print_iostat_header(&cb); 1886fa9e4066Sahrens 188799653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 1888fa9e4066Sahrens 1889fa9e4066Sahrens /* 1890fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 1891fa9e4066Sahrens * (which prints a separator for us), then print a separator. 1892fa9e4066Sahrens */ 1893fa9e4066Sahrens if (npools > 1 && !verbose) 1894fa9e4066Sahrens print_iostat_separator(&cb); 1895fa9e4066Sahrens 1896fa9e4066Sahrens if (verbose) 1897fa9e4066Sahrens (void) printf("\n"); 1898fa9e4066Sahrens 189939c23413Seschrock /* 190039c23413Seschrock * Flush the output so that redirection to a file isn't buffered 190139c23413Seschrock * indefinitely. 190239c23413Seschrock */ 190339c23413Seschrock (void) fflush(stdout); 190439c23413Seschrock 1905fa9e4066Sahrens if (interval == 0) 1906fa9e4066Sahrens break; 1907fa9e4066Sahrens 1908fa9e4066Sahrens if (count != 0 && --count == 0) 1909fa9e4066Sahrens break; 1910fa9e4066Sahrens 1911fa9e4066Sahrens (void) sleep(interval); 1912fa9e4066Sahrens } 1913fa9e4066Sahrens 1914fa9e4066Sahrens pool_list_free(list); 1915fa9e4066Sahrens 1916fa9e4066Sahrens return (ret); 1917fa9e4066Sahrens } 1918fa9e4066Sahrens 1919fa9e4066Sahrens typedef struct list_cbdata { 192099653d4eSeschrock boolean_t cb_scripted; 192199653d4eSeschrock boolean_t cb_first; 1922990b4856Slling zprop_list_t *cb_proplist; 1923fa9e4066Sahrens } list_cbdata_t; 1924fa9e4066Sahrens 1925fa9e4066Sahrens /* 1926fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 1927fa9e4066Sahrens */ 1928990b4856Slling static void 1929990b4856Slling print_header(zprop_list_t *pl) 1930fa9e4066Sahrens { 1931990b4856Slling const char *header; 1932990b4856Slling boolean_t first = B_TRUE; 1933990b4856Slling boolean_t right_justify; 1934fa9e4066Sahrens 1935990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 1936990b4856Slling if (pl->pl_prop == ZPROP_INVAL) 1937990b4856Slling continue; 1938990b4856Slling 1939990b4856Slling if (!first) 1940fa9e4066Sahrens (void) printf(" "); 1941fa9e4066Sahrens else 1942990b4856Slling first = B_FALSE; 1943fa9e4066Sahrens 1944990b4856Slling header = zpool_prop_column_name(pl->pl_prop); 1945990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 1946990b4856Slling 1947990b4856Slling if (pl->pl_next == NULL && !right_justify) 1948990b4856Slling (void) printf("%s", header); 1949990b4856Slling else if (right_justify) 1950990b4856Slling (void) printf("%*s", pl->pl_width, header); 1951990b4856Slling else 1952990b4856Slling (void) printf("%-*s", pl->pl_width, header); 1953fa9e4066Sahrens } 1954fa9e4066Sahrens 1955fa9e4066Sahrens (void) printf("\n"); 1956fa9e4066Sahrens } 1957fa9e4066Sahrens 1958990b4856Slling /* 1959990b4856Slling * Given a pool and a list of properties, print out all the properties according 1960990b4856Slling * to the described layout. 1961990b4856Slling */ 1962990b4856Slling static void 1963990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 1964990b4856Slling { 1965990b4856Slling boolean_t first = B_TRUE; 1966990b4856Slling char property[ZPOOL_MAXPROPLEN]; 1967990b4856Slling char *propstr; 1968990b4856Slling boolean_t right_justify; 1969990b4856Slling int width; 1970990b4856Slling 1971990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 1972990b4856Slling if (!first) { 1973990b4856Slling if (scripted) 1974990b4856Slling (void) printf("\t"); 1975990b4856Slling else 1976990b4856Slling (void) printf(" "); 1977990b4856Slling } else { 1978990b4856Slling first = B_FALSE; 1979990b4856Slling } 1980990b4856Slling 1981990b4856Slling right_justify = B_FALSE; 1982990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 1983990b4856Slling if (zpool_get_prop(zhp, pl->pl_prop, property, 1984990b4856Slling sizeof (property), NULL) != 0) 1985990b4856Slling propstr = "-"; 1986990b4856Slling else 1987990b4856Slling propstr = property; 1988990b4856Slling 1989990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 1990990b4856Slling } else { 1991990b4856Slling propstr = "-"; 1992990b4856Slling } 1993990b4856Slling 1994990b4856Slling width = pl->pl_width; 1995990b4856Slling 1996990b4856Slling /* 1997990b4856Slling * If this is being called in scripted mode, or if this is the 1998990b4856Slling * last column and it is left-justified, don't include a width 1999990b4856Slling * format specifier. 2000990b4856Slling */ 2001990b4856Slling if (scripted || (pl->pl_next == NULL && !right_justify)) 2002990b4856Slling (void) printf("%s", propstr); 2003990b4856Slling else if (right_justify) 2004990b4856Slling (void) printf("%*s", width, propstr); 2005990b4856Slling else 2006990b4856Slling (void) printf("%-*s", width, propstr); 2007990b4856Slling } 2008990b4856Slling 2009990b4856Slling (void) printf("\n"); 2010990b4856Slling } 2011990b4856Slling 2012990b4856Slling /* 2013990b4856Slling * Generic callback function to list a pool. 2014990b4856Slling */ 2015fa9e4066Sahrens int 2016fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data) 2017fa9e4066Sahrens { 2018fa9e4066Sahrens list_cbdata_t *cbp = data; 2019fa9e4066Sahrens 2020fa9e4066Sahrens if (cbp->cb_first) { 2021fa9e4066Sahrens if (!cbp->cb_scripted) 2022990b4856Slling print_header(cbp->cb_proplist); 202399653d4eSeschrock cbp->cb_first = B_FALSE; 2024fa9e4066Sahrens } 2025fa9e4066Sahrens 2026990b4856Slling print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2027fa9e4066Sahrens 2028fa9e4066Sahrens return (0); 2029fa9e4066Sahrens } 2030fa9e4066Sahrens 2031fa9e4066Sahrens /* 2032990b4856Slling * zpool list [-H] [-o prop[,prop]*] [pool] ... 2033fa9e4066Sahrens * 2034990b4856Slling * -H Scripted mode. Don't display headers, and separate properties 2035990b4856Slling * by a single tab. 2036990b4856Slling * -o List of properties to display. Defaults to 2037990b4856Slling * "name,size,used,available,capacity,health,altroot" 2038fa9e4066Sahrens * 2039fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 2040fa9e4066Sahrens * statistics for each one, as well as health status summary. 2041fa9e4066Sahrens */ 2042fa9e4066Sahrens int 2043fa9e4066Sahrens zpool_do_list(int argc, char **argv) 2044fa9e4066Sahrens { 2045fa9e4066Sahrens int c; 2046fa9e4066Sahrens int ret; 2047fa9e4066Sahrens list_cbdata_t cb = { 0 }; 2048990b4856Slling static char default_props[] = 2049990b4856Slling "name,size,used,available,capacity,health,altroot"; 2050990b4856Slling char *props = default_props; 2051fa9e4066Sahrens 2052fa9e4066Sahrens /* check options */ 2053fa9e4066Sahrens while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2054fa9e4066Sahrens switch (c) { 2055fa9e4066Sahrens case 'H': 205699653d4eSeschrock cb.cb_scripted = B_TRUE; 2057fa9e4066Sahrens break; 2058fa9e4066Sahrens case 'o': 2059990b4856Slling props = optarg; 2060fa9e4066Sahrens break; 2061fa9e4066Sahrens case ':': 2062fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2063fa9e4066Sahrens "'%c' option\n"), optopt); 206499653d4eSeschrock usage(B_FALSE); 2065fa9e4066Sahrens break; 2066fa9e4066Sahrens case '?': 2067fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2068fa9e4066Sahrens optopt); 206999653d4eSeschrock usage(B_FALSE); 2070fa9e4066Sahrens } 2071fa9e4066Sahrens } 2072fa9e4066Sahrens 2073fa9e4066Sahrens argc -= optind; 2074fa9e4066Sahrens argv += optind; 2075fa9e4066Sahrens 2076990b4856Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 207799653d4eSeschrock usage(B_FALSE); 2078fa9e4066Sahrens 207999653d4eSeschrock cb.cb_first = B_TRUE; 2080fa9e4066Sahrens 2081990b4856Slling ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2082990b4856Slling list_callback, &cb); 2083990b4856Slling 2084990b4856Slling zprop_free_list(cb.cb_proplist); 2085fa9e4066Sahrens 2086fce7d82bSmmusante if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2087fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 2088fa9e4066Sahrens return (0); 2089fa9e4066Sahrens } 2090fa9e4066Sahrens 2091fa9e4066Sahrens return (ret); 2092fa9e4066Sahrens } 2093fa9e4066Sahrens 2094fa9e4066Sahrens static nvlist_t * 2095fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name) 2096fa9e4066Sahrens { 2097fa9e4066Sahrens nvlist_t **child; 2098fa9e4066Sahrens uint_t c, children; 2099fa9e4066Sahrens nvlist_t *match; 2100fa9e4066Sahrens char *path; 2101fa9e4066Sahrens 2102fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2103fa9e4066Sahrens &child, &children) != 0) { 2104fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2105fa9e4066Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0) 2106fa9e4066Sahrens name += 9; 2107fa9e4066Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0) 2108fa9e4066Sahrens path += 9; 2109fa9e4066Sahrens if (strcmp(name, path) == 0) 2110fa9e4066Sahrens return (nv); 2111fa9e4066Sahrens return (NULL); 2112fa9e4066Sahrens } 2113fa9e4066Sahrens 2114fa9e4066Sahrens for (c = 0; c < children; c++) 2115fa9e4066Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2116fa9e4066Sahrens return (match); 2117fa9e4066Sahrens 2118fa9e4066Sahrens return (NULL); 2119fa9e4066Sahrens } 2120fa9e4066Sahrens 2121fa9e4066Sahrens static int 2122fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 2123fa9e4066Sahrens { 212499653d4eSeschrock boolean_t force = B_FALSE; 2125fa9e4066Sahrens int c; 2126fa9e4066Sahrens nvlist_t *nvroot; 2127fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 2128fa9e4066Sahrens zpool_handle_t *zhp; 212999653d4eSeschrock int ret; 2130fa9e4066Sahrens 2131fa9e4066Sahrens /* check options */ 2132fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2133fa9e4066Sahrens switch (c) { 2134fa9e4066Sahrens case 'f': 213599653d4eSeschrock force = B_TRUE; 2136fa9e4066Sahrens break; 2137fa9e4066Sahrens case '?': 2138fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2139fa9e4066Sahrens optopt); 214099653d4eSeschrock usage(B_FALSE); 2141fa9e4066Sahrens } 2142fa9e4066Sahrens } 2143fa9e4066Sahrens 2144fa9e4066Sahrens argc -= optind; 2145fa9e4066Sahrens argv += optind; 2146fa9e4066Sahrens 2147fa9e4066Sahrens /* get pool name and check number of arguments */ 2148fa9e4066Sahrens if (argc < 1) { 2149fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 215099653d4eSeschrock usage(B_FALSE); 2151fa9e4066Sahrens } 2152fa9e4066Sahrens 2153fa9e4066Sahrens poolname = argv[0]; 2154fa9e4066Sahrens 2155fa9e4066Sahrens if (argc < 2) { 2156fa9e4066Sahrens (void) fprintf(stderr, 2157fa9e4066Sahrens gettext("missing <device> specification\n")); 215899653d4eSeschrock usage(B_FALSE); 2159fa9e4066Sahrens } 2160fa9e4066Sahrens 2161fa9e4066Sahrens old_disk = argv[1]; 2162fa9e4066Sahrens 2163fa9e4066Sahrens if (argc < 3) { 2164fa9e4066Sahrens if (!replacing) { 2165fa9e4066Sahrens (void) fprintf(stderr, 2166fa9e4066Sahrens gettext("missing <new_device> specification\n")); 216799653d4eSeschrock usage(B_FALSE); 2168fa9e4066Sahrens } 2169fa9e4066Sahrens new_disk = old_disk; 2170fa9e4066Sahrens argc -= 1; 2171fa9e4066Sahrens argv += 1; 2172fa9e4066Sahrens } else { 2173fa9e4066Sahrens new_disk = argv[2]; 2174fa9e4066Sahrens argc -= 2; 2175fa9e4066Sahrens argv += 2; 2176fa9e4066Sahrens } 2177fa9e4066Sahrens 2178fa9e4066Sahrens if (argc > 1) { 2179fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 218099653d4eSeschrock usage(B_FALSE); 2181fa9e4066Sahrens } 2182fa9e4066Sahrens 218399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2184fa9e4066Sahrens return (1); 2185fa9e4066Sahrens 21868488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 2187fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2188fa9e4066Sahrens poolname); 2189fa9e4066Sahrens zpool_close(zhp); 2190fa9e4066Sahrens return (1); 2191fa9e4066Sahrens } 2192fa9e4066Sahrens 21938488aeb5Staylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv); 2194fa9e4066Sahrens if (nvroot == NULL) { 2195fa9e4066Sahrens zpool_close(zhp); 2196fa9e4066Sahrens return (1); 2197fa9e4066Sahrens } 2198fa9e4066Sahrens 219999653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 220099653d4eSeschrock 220199653d4eSeschrock nvlist_free(nvroot); 220299653d4eSeschrock zpool_close(zhp); 220399653d4eSeschrock 220499653d4eSeschrock return (ret); 2205fa9e4066Sahrens } 2206fa9e4066Sahrens 2207fa9e4066Sahrens /* 2208fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 2209fa9e4066Sahrens * 2210fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2211fa9e4066Sahrens * 2212fa9e4066Sahrens * Replace <device> with <new_device>. 2213fa9e4066Sahrens */ 2214fa9e4066Sahrens /* ARGSUSED */ 2215fa9e4066Sahrens int 2216fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 2217fa9e4066Sahrens { 2218fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2219fa9e4066Sahrens } 2220fa9e4066Sahrens 2221fa9e4066Sahrens /* 2222fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 2223fa9e4066Sahrens * 2224fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2225fa9e4066Sahrens * 2226fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 2227fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 2228fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 2229fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 2230fa9e4066Sahrens */ 2231fa9e4066Sahrens int 2232fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 2233fa9e4066Sahrens { 2234fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2235fa9e4066Sahrens } 2236fa9e4066Sahrens 2237fa9e4066Sahrens /* 2238fa9e4066Sahrens * zpool detach [-f] <pool> <device> 2239fa9e4066Sahrens * 2240fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 2241fa9e4066Sahrens * (not supported yet) 2242fa9e4066Sahrens * 2243fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 2244fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 2245fa9e4066Sahrens * has the only valid copy of some data. 2246fa9e4066Sahrens */ 2247fa9e4066Sahrens /* ARGSUSED */ 2248fa9e4066Sahrens int 2249fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 2250fa9e4066Sahrens { 2251fa9e4066Sahrens int c; 2252fa9e4066Sahrens char *poolname, *path; 2253fa9e4066Sahrens zpool_handle_t *zhp; 225499653d4eSeschrock int ret; 2255fa9e4066Sahrens 2256fa9e4066Sahrens /* check options */ 2257fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2258fa9e4066Sahrens switch (c) { 2259fa9e4066Sahrens case 'f': 2260fa9e4066Sahrens case '?': 2261fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2262fa9e4066Sahrens optopt); 226399653d4eSeschrock usage(B_FALSE); 2264fa9e4066Sahrens } 2265fa9e4066Sahrens } 2266fa9e4066Sahrens 2267fa9e4066Sahrens argc -= optind; 2268fa9e4066Sahrens argv += optind; 2269fa9e4066Sahrens 2270fa9e4066Sahrens /* get pool name and check number of arguments */ 2271fa9e4066Sahrens if (argc < 1) { 2272fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 227399653d4eSeschrock usage(B_FALSE); 2274fa9e4066Sahrens } 2275fa9e4066Sahrens 2276fa9e4066Sahrens if (argc < 2) { 2277fa9e4066Sahrens (void) fprintf(stderr, 2278fa9e4066Sahrens gettext("missing <device> specification\n")); 227999653d4eSeschrock usage(B_FALSE); 2280fa9e4066Sahrens } 2281fa9e4066Sahrens 2282fa9e4066Sahrens poolname = argv[0]; 2283fa9e4066Sahrens path = argv[1]; 2284fa9e4066Sahrens 228599653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2286fa9e4066Sahrens return (1); 2287fa9e4066Sahrens 228899653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 228999653d4eSeschrock 229099653d4eSeschrock zpool_close(zhp); 229199653d4eSeschrock 229299653d4eSeschrock return (ret); 2293fa9e4066Sahrens } 2294fa9e4066Sahrens 2295fa9e4066Sahrens /* 2296441d80aaSlling * zpool online <pool> <device> ... 2297fa9e4066Sahrens */ 2298fa9e4066Sahrens int 2299fa9e4066Sahrens zpool_do_online(int argc, char **argv) 2300fa9e4066Sahrens { 2301fa9e4066Sahrens int c, i; 2302fa9e4066Sahrens char *poolname; 2303fa9e4066Sahrens zpool_handle_t *zhp; 2304fa9e4066Sahrens int ret = 0; 23053d7072f8Seschrock vdev_state_t newstate; 2306fa9e4066Sahrens 2307fa9e4066Sahrens /* check options */ 2308fa9e4066Sahrens while ((c = getopt(argc, argv, "t")) != -1) { 2309fa9e4066Sahrens switch (c) { 2310fa9e4066Sahrens case 't': 2311fa9e4066Sahrens case '?': 2312fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2313fa9e4066Sahrens optopt); 231499653d4eSeschrock usage(B_FALSE); 2315fa9e4066Sahrens } 2316fa9e4066Sahrens } 2317fa9e4066Sahrens 2318fa9e4066Sahrens argc -= optind; 2319fa9e4066Sahrens argv += optind; 2320fa9e4066Sahrens 2321fa9e4066Sahrens /* get pool name and check number of arguments */ 2322fa9e4066Sahrens if (argc < 1) { 2323fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 232499653d4eSeschrock usage(B_FALSE); 2325fa9e4066Sahrens } 2326fa9e4066Sahrens if (argc < 2) { 2327fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 232899653d4eSeschrock usage(B_FALSE); 2329fa9e4066Sahrens } 2330fa9e4066Sahrens 2331fa9e4066Sahrens poolname = argv[0]; 2332fa9e4066Sahrens 233399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2334fa9e4066Sahrens return (1); 2335fa9e4066Sahrens 23363d7072f8Seschrock for (i = 1; i < argc; i++) { 23373d7072f8Seschrock if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) { 23383d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 23393d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 23403d7072f8Seschrock "onlined, but remains in faulted state\n"), 2341fa9e4066Sahrens argv[i]); 23423d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 23433d7072f8Seschrock (void) printf(gettext("use 'zpool " 23443d7072f8Seschrock "clear' to restore a faulted " 23453d7072f8Seschrock "device\n")); 2346fa9e4066Sahrens else 23473d7072f8Seschrock (void) printf(gettext("use 'zpool " 23483d7072f8Seschrock "replace' to replace devices " 23493d7072f8Seschrock "that are no longer present\n")); 23503d7072f8Seschrock } 23513d7072f8Seschrock } else { 2352fa9e4066Sahrens ret = 1; 23533d7072f8Seschrock } 23543d7072f8Seschrock } 2355fa9e4066Sahrens 235699653d4eSeschrock zpool_close(zhp); 235799653d4eSeschrock 2358fa9e4066Sahrens return (ret); 2359fa9e4066Sahrens } 2360fa9e4066Sahrens 2361fa9e4066Sahrens /* 2362441d80aaSlling * zpool offline [-ft] <pool> <device> ... 2363fa9e4066Sahrens * 2364fa9e4066Sahrens * -f Force the device into the offline state, even if doing 2365fa9e4066Sahrens * so would appear to compromise pool availability. 2366fa9e4066Sahrens * (not supported yet) 2367fa9e4066Sahrens * 2368fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 2369fa9e4066Sahrens * state will not be persistent across reboots. 2370fa9e4066Sahrens */ 2371fa9e4066Sahrens /* ARGSUSED */ 2372fa9e4066Sahrens int 2373fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 2374fa9e4066Sahrens { 2375fa9e4066Sahrens int c, i; 2376fa9e4066Sahrens char *poolname; 2377fa9e4066Sahrens zpool_handle_t *zhp; 237899653d4eSeschrock int ret = 0; 237999653d4eSeschrock boolean_t istmp = B_FALSE; 2380fa9e4066Sahrens 2381fa9e4066Sahrens /* check options */ 2382fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 2383fa9e4066Sahrens switch (c) { 2384fa9e4066Sahrens case 't': 238599653d4eSeschrock istmp = B_TRUE; 2386441d80aaSlling break; 2387441d80aaSlling case 'f': 2388fa9e4066Sahrens case '?': 2389fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2390fa9e4066Sahrens optopt); 239199653d4eSeschrock usage(B_FALSE); 2392fa9e4066Sahrens } 2393fa9e4066Sahrens } 2394fa9e4066Sahrens 2395fa9e4066Sahrens argc -= optind; 2396fa9e4066Sahrens argv += optind; 2397fa9e4066Sahrens 2398fa9e4066Sahrens /* get pool name and check number of arguments */ 2399fa9e4066Sahrens if (argc < 1) { 2400fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 240199653d4eSeschrock usage(B_FALSE); 2402fa9e4066Sahrens } 2403fa9e4066Sahrens if (argc < 2) { 2404fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 240599653d4eSeschrock usage(B_FALSE); 2406fa9e4066Sahrens } 2407fa9e4066Sahrens 2408fa9e4066Sahrens poolname = argv[0]; 2409fa9e4066Sahrens 241099653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2411fa9e4066Sahrens return (1); 2412fa9e4066Sahrens 24133d7072f8Seschrock for (i = 1; i < argc; i++) { 24143d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2415fa9e4066Sahrens ret = 1; 24163d7072f8Seschrock } 2417fa9e4066Sahrens 241899653d4eSeschrock zpool_close(zhp); 241999653d4eSeschrock 2420fa9e4066Sahrens return (ret); 2421fa9e4066Sahrens } 2422fa9e4066Sahrens 2423ea8dc4b6Seschrock /* 2424ea8dc4b6Seschrock * zpool clear <pool> [device] 2425ea8dc4b6Seschrock * 2426ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 2427ea8dc4b6Seschrock */ 2428ea8dc4b6Seschrock int 2429ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 2430ea8dc4b6Seschrock { 2431ea8dc4b6Seschrock int ret = 0; 2432ea8dc4b6Seschrock zpool_handle_t *zhp; 2433ea8dc4b6Seschrock char *pool, *device; 2434ea8dc4b6Seschrock 2435ea8dc4b6Seschrock if (argc < 2) { 2436ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 243799653d4eSeschrock usage(B_FALSE); 2438ea8dc4b6Seschrock } 2439ea8dc4b6Seschrock 2440ea8dc4b6Seschrock if (argc > 3) { 2441ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 244299653d4eSeschrock usage(B_FALSE); 2443ea8dc4b6Seschrock } 2444ea8dc4b6Seschrock 2445ea8dc4b6Seschrock pool = argv[1]; 2446ea8dc4b6Seschrock device = argc == 3 ? argv[2] : NULL; 2447ea8dc4b6Seschrock 244899653d4eSeschrock if ((zhp = zpool_open(g_zfs, pool)) == NULL) 2449ea8dc4b6Seschrock return (1); 2450ea8dc4b6Seschrock 2451ea8dc4b6Seschrock if (zpool_clear(zhp, device) != 0) 2452ea8dc4b6Seschrock ret = 1; 2453ea8dc4b6Seschrock 2454ea8dc4b6Seschrock zpool_close(zhp); 2455ea8dc4b6Seschrock 2456ea8dc4b6Seschrock return (ret); 2457ea8dc4b6Seschrock } 2458ea8dc4b6Seschrock 2459fa9e4066Sahrens typedef struct scrub_cbdata { 2460fa9e4066Sahrens int cb_type; 246106eeb2adSek110237 int cb_argc; 246206eeb2adSek110237 char **cb_argv; 2463fa9e4066Sahrens } scrub_cbdata_t; 2464fa9e4066Sahrens 2465fa9e4066Sahrens int 2466fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 2467fa9e4066Sahrens { 2468fa9e4066Sahrens scrub_cbdata_t *cb = data; 246906eeb2adSek110237 int err; 2470fa9e4066Sahrens 2471ea8dc4b6Seschrock /* 2472ea8dc4b6Seschrock * Ignore faulted pools. 2473ea8dc4b6Seschrock */ 2474ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2475ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2476ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 2477ea8dc4b6Seschrock return (1); 2478ea8dc4b6Seschrock } 2479ea8dc4b6Seschrock 248006eeb2adSek110237 err = zpool_scrub(zhp, cb->cb_type); 248106eeb2adSek110237 248206eeb2adSek110237 return (err != 0); 2483fa9e4066Sahrens } 2484fa9e4066Sahrens 2485fa9e4066Sahrens /* 2486fa9e4066Sahrens * zpool scrub [-s] <pool> ... 2487fa9e4066Sahrens * 2488fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 2489fa9e4066Sahrens */ 2490fa9e4066Sahrens int 2491fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 2492fa9e4066Sahrens { 2493fa9e4066Sahrens int c; 2494fa9e4066Sahrens scrub_cbdata_t cb; 2495fa9e4066Sahrens 2496fa9e4066Sahrens cb.cb_type = POOL_SCRUB_EVERYTHING; 2497fa9e4066Sahrens 2498fa9e4066Sahrens /* check options */ 2499fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 2500fa9e4066Sahrens switch (c) { 2501fa9e4066Sahrens case 's': 2502fa9e4066Sahrens cb.cb_type = POOL_SCRUB_NONE; 2503fa9e4066Sahrens break; 2504fa9e4066Sahrens case '?': 2505fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2506fa9e4066Sahrens optopt); 250799653d4eSeschrock usage(B_FALSE); 2508fa9e4066Sahrens } 2509fa9e4066Sahrens } 2510fa9e4066Sahrens 251106eeb2adSek110237 cb.cb_argc = argc; 251206eeb2adSek110237 cb.cb_argv = argv; 2513fa9e4066Sahrens argc -= optind; 2514fa9e4066Sahrens argv += optind; 2515fa9e4066Sahrens 2516fa9e4066Sahrens if (argc < 1) { 2517fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 251899653d4eSeschrock usage(B_FALSE); 2519fa9e4066Sahrens } 2520fa9e4066Sahrens 2521b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2522fa9e4066Sahrens } 2523fa9e4066Sahrens 2524fa9e4066Sahrens typedef struct status_cbdata { 2525fa9e4066Sahrens int cb_count; 2526e9dbad6fSeschrock boolean_t cb_allpools; 252799653d4eSeschrock boolean_t cb_verbose; 252899653d4eSeschrock boolean_t cb_explain; 252999653d4eSeschrock boolean_t cb_first; 2530fa9e4066Sahrens } status_cbdata_t; 2531fa9e4066Sahrens 2532fa9e4066Sahrens /* 2533fa9e4066Sahrens * Print out detailed scrub status. 2534fa9e4066Sahrens */ 2535fa9e4066Sahrens void 2536fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot) 2537fa9e4066Sahrens { 2538fa9e4066Sahrens vdev_stat_t *vs; 2539fa9e4066Sahrens uint_t vsc; 2540fa9e4066Sahrens time_t start, end, now; 2541fa9e4066Sahrens double fraction_done; 2542fa9e4066Sahrens uint64_t examined, total, minutes_left; 2543fa9e4066Sahrens char *scrub_type; 2544fa9e4066Sahrens 2545fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2546fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 2547fa9e4066Sahrens 2548fa9e4066Sahrens /* 2549fa9e4066Sahrens * If there's never been a scrub, there's not much to say. 2550fa9e4066Sahrens */ 2551fa9e4066Sahrens if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2552fa9e4066Sahrens (void) printf(gettext("none requested\n")); 2553fa9e4066Sahrens return; 2554fa9e4066Sahrens } 2555fa9e4066Sahrens 2556fa9e4066Sahrens scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2557fa9e4066Sahrens "resilver" : "scrub"; 2558fa9e4066Sahrens 2559fa9e4066Sahrens start = vs->vs_scrub_start; 2560fa9e4066Sahrens end = vs->vs_scrub_end; 2561fa9e4066Sahrens now = time(NULL); 2562fa9e4066Sahrens examined = vs->vs_scrub_examined; 2563fa9e4066Sahrens total = vs->vs_alloc; 2564fa9e4066Sahrens 2565fa9e4066Sahrens if (end != 0) { 2566fa9e4066Sahrens (void) printf(gettext("%s %s with %llu errors on %s"), 2567fa9e4066Sahrens scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 2568fa9e4066Sahrens (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2569fa9e4066Sahrens return; 2570fa9e4066Sahrens } 2571fa9e4066Sahrens 2572fa9e4066Sahrens if (examined == 0) 2573fa9e4066Sahrens examined = 1; 2574fa9e4066Sahrens if (examined > total) 2575fa9e4066Sahrens total = examined; 2576fa9e4066Sahrens 2577fa9e4066Sahrens fraction_done = (double)examined / total; 2578fa9e4066Sahrens minutes_left = (uint64_t)((now - start) * 2579fa9e4066Sahrens (1 - fraction_done) / fraction_done / 60); 2580fa9e4066Sahrens 2581fa9e4066Sahrens (void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"), 2582fa9e4066Sahrens scrub_type, 100 * fraction_done, 2583fa9e4066Sahrens (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2584fa9e4066Sahrens } 2585fa9e4066Sahrens 258699653d4eSeschrock typedef struct spare_cbdata { 258799653d4eSeschrock uint64_t cb_guid; 258899653d4eSeschrock zpool_handle_t *cb_zhp; 258999653d4eSeschrock } spare_cbdata_t; 259099653d4eSeschrock 259199653d4eSeschrock static boolean_t 259299653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search) 259399653d4eSeschrock { 259499653d4eSeschrock uint64_t guid; 259599653d4eSeschrock nvlist_t **child; 259699653d4eSeschrock uint_t c, children; 259799653d4eSeschrock 259899653d4eSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 259999653d4eSeschrock search == guid) 260099653d4eSeschrock return (B_TRUE); 260199653d4eSeschrock 260299653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 260399653d4eSeschrock &child, &children) == 0) { 260499653d4eSeschrock for (c = 0; c < children; c++) 260599653d4eSeschrock if (find_vdev(child[c], search)) 260699653d4eSeschrock return (B_TRUE); 260799653d4eSeschrock } 260899653d4eSeschrock 260999653d4eSeschrock return (B_FALSE); 261099653d4eSeschrock } 261199653d4eSeschrock 261299653d4eSeschrock static int 261399653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data) 261499653d4eSeschrock { 261599653d4eSeschrock spare_cbdata_t *cbp = data; 261699653d4eSeschrock nvlist_t *config, *nvroot; 261799653d4eSeschrock 261899653d4eSeschrock config = zpool_get_config(zhp, NULL); 261999653d4eSeschrock verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 262099653d4eSeschrock &nvroot) == 0); 262199653d4eSeschrock 262299653d4eSeschrock if (find_vdev(nvroot, cbp->cb_guid)) { 262399653d4eSeschrock cbp->cb_zhp = zhp; 262499653d4eSeschrock return (1); 262599653d4eSeschrock } 262699653d4eSeschrock 262799653d4eSeschrock zpool_close(zhp); 262899653d4eSeschrock return (0); 262999653d4eSeschrock } 263099653d4eSeschrock 2631fa9e4066Sahrens /* 2632fa9e4066Sahrens * Print out configuration state as requested by status_callback. 2633fa9e4066Sahrens */ 2634fa9e4066Sahrens void 2635c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 26368654d025Sperrin int namewidth, int depth, boolean_t isspare, boolean_t print_logs) 2637fa9e4066Sahrens { 2638fa9e4066Sahrens nvlist_t **child; 2639fa9e4066Sahrens uint_t c, children; 2640fa9e4066Sahrens vdev_stat_t *vs; 2641ea8dc4b6Seschrock char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 2642afefbcddSeschrock char *vname; 2643ea8dc4b6Seschrock uint64_t notpresent; 264499653d4eSeschrock spare_cbdata_t cb; 2645990b4856Slling char *state; 2646fa9e4066Sahrens 2647fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2648fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 2649fa9e4066Sahrens 2650fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2651fa9e4066Sahrens &child, &children) != 0) 2652fa9e4066Sahrens children = 0; 2653fa9e4066Sahrens 2654990b4856Slling state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 265599653d4eSeschrock if (isspare) { 265699653d4eSeschrock /* 265799653d4eSeschrock * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 265899653d4eSeschrock * online drives. 265999653d4eSeschrock */ 266099653d4eSeschrock if (vs->vs_aux == VDEV_AUX_SPARED) 266199653d4eSeschrock state = "INUSE"; 266299653d4eSeschrock else if (vs->vs_state == VDEV_STATE_HEALTHY) 266399653d4eSeschrock state = "AVAIL"; 266499653d4eSeschrock } 2665fa9e4066Sahrens 266699653d4eSeschrock (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 266799653d4eSeschrock name, state); 266899653d4eSeschrock 266999653d4eSeschrock if (!isspare) { 2670fa9e4066Sahrens zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 2671fa9e4066Sahrens zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 2672fa9e4066Sahrens zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 2673fa9e4066Sahrens (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 267499653d4eSeschrock } 2675fa9e4066Sahrens 2676ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2677ea8dc4b6Seschrock ¬present) == 0) { 2678ea8dc4b6Seschrock char *path; 2679ea8dc4b6Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 26800917b783Seschrock (void) printf(" was %s", path); 2681ea8dc4b6Seschrock } else if (vs->vs_aux != 0) { 2682fa9e4066Sahrens (void) printf(" "); 2683fa9e4066Sahrens 2684fa9e4066Sahrens switch (vs->vs_aux) { 2685fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 2686fa9e4066Sahrens (void) printf(gettext("cannot open")); 2687fa9e4066Sahrens break; 2688fa9e4066Sahrens 2689fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 2690fa9e4066Sahrens (void) printf(gettext("missing device")); 2691fa9e4066Sahrens break; 2692fa9e4066Sahrens 2693fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 2694fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 2695fa9e4066Sahrens break; 2696fa9e4066Sahrens 2697eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 2698eaca9bbdSeschrock (void) printf(gettext("newer version")); 2699eaca9bbdSeschrock break; 2700eaca9bbdSeschrock 270199653d4eSeschrock case VDEV_AUX_SPARED: 270299653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 270399653d4eSeschrock &cb.cb_guid) == 0); 270499653d4eSeschrock if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 270599653d4eSeschrock if (strcmp(zpool_get_name(cb.cb_zhp), 270699653d4eSeschrock zpool_get_name(zhp)) == 0) 270799653d4eSeschrock (void) printf(gettext("currently in " 270899653d4eSeschrock "use")); 270999653d4eSeschrock else 271099653d4eSeschrock (void) printf(gettext("in use by " 271199653d4eSeschrock "pool '%s'"), 271299653d4eSeschrock zpool_get_name(cb.cb_zhp)); 271399653d4eSeschrock zpool_close(cb.cb_zhp); 271499653d4eSeschrock } else { 271599653d4eSeschrock (void) printf(gettext("currently in use")); 271699653d4eSeschrock } 271799653d4eSeschrock break; 271899653d4eSeschrock 27193d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 27203d7072f8Seschrock (void) printf(gettext("too many errors")); 27213d7072f8Seschrock break; 27223d7072f8Seschrock 2723fa9e4066Sahrens default: 2724fa9e4066Sahrens (void) printf(gettext("corrupted data")); 2725fa9e4066Sahrens break; 2726fa9e4066Sahrens } 2727fa9e4066Sahrens } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2728fa9e4066Sahrens /* 2729fa9e4066Sahrens * Report bytes resilvered/repaired on leaf devices. 2730fa9e4066Sahrens */ 2731fa9e4066Sahrens zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2732fa9e4066Sahrens (void) printf(gettext(" %s %s"), repaired, 2733fa9e4066Sahrens (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2734fa9e4066Sahrens "resilvered" : "repaired"); 2735fa9e4066Sahrens } 2736fa9e4066Sahrens 2737fa9e4066Sahrens (void) printf("\n"); 2738fa9e4066Sahrens 2739afefbcddSeschrock for (c = 0; c < children; c++) { 27408654d025Sperrin uint64_t is_log = B_FALSE; 27418654d025Sperrin 27428654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 27438654d025Sperrin &is_log); 27448654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 27458654d025Sperrin continue; 274699653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 2747c67d9675Seschrock print_status_config(zhp, vname, child[c], 27488654d025Sperrin namewidth, depth + 2, isspare, B_FALSE); 2749afefbcddSeschrock free(vname); 2750afefbcddSeschrock } 2751fa9e4066Sahrens } 2752fa9e4066Sahrens 2753ea8dc4b6Seschrock static void 2754ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 2755ea8dc4b6Seschrock { 275675519f38Sek110237 nvlist_t *nverrlist = NULL; 275755434c77Sek110237 nvpair_t *elem; 275855434c77Sek110237 char *pathname; 275955434c77Sek110237 size_t len = MAXPATHLEN * 2; 2760ea8dc4b6Seschrock 276155434c77Sek110237 if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2762ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 2763ea8dc4b6Seschrock "(insufficient privileges)\n"); 2764ea8dc4b6Seschrock return; 2765ea8dc4b6Seschrock } 2766ea8dc4b6Seschrock 276755434c77Sek110237 (void) printf("errors: Permanent errors have been " 276855434c77Sek110237 "detected in the following files:\n\n"); 2769ea8dc4b6Seschrock 277055434c77Sek110237 pathname = safe_malloc(len); 277155434c77Sek110237 elem = NULL; 277255434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 277355434c77Sek110237 nvlist_t *nv; 277455434c77Sek110237 uint64_t dsobj, obj; 2775ea8dc4b6Seschrock 277655434c77Sek110237 verify(nvpair_value_nvlist(elem, &nv) == 0); 277755434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 277855434c77Sek110237 &dsobj) == 0); 277955434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 278055434c77Sek110237 &obj) == 0); 278155434c77Sek110237 zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 278255434c77Sek110237 (void) printf("%7s %s\n", "", pathname); 2783ea8dc4b6Seschrock } 278455434c77Sek110237 free(pathname); 278555434c77Sek110237 nvlist_free(nverrlist); 2786ea8dc4b6Seschrock } 2787ea8dc4b6Seschrock 278899653d4eSeschrock static void 278999653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 279099653d4eSeschrock int namewidth) 279199653d4eSeschrock { 279299653d4eSeschrock uint_t i; 279399653d4eSeschrock char *name; 279499653d4eSeschrock 279599653d4eSeschrock if (nspares == 0) 279699653d4eSeschrock return; 279799653d4eSeschrock 279899653d4eSeschrock (void) printf(gettext("\tspares\n")); 279999653d4eSeschrock 280099653d4eSeschrock for (i = 0; i < nspares; i++) { 280199653d4eSeschrock name = zpool_vdev_name(g_zfs, zhp, spares[i]); 280299653d4eSeschrock print_status_config(zhp, name, spares[i], 28038654d025Sperrin namewidth, 2, B_TRUE, B_FALSE); 280499653d4eSeschrock free(name); 280599653d4eSeschrock } 280699653d4eSeschrock } 280799653d4eSeschrock 2808fa9e4066Sahrens /* 2809fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 2810fa9e4066Sahrens * 2811fa9e4066Sahrens * pool: tank 2812fa9e4066Sahrens * status: DEGRADED 2813fa9e4066Sahrens * reason: One or more devices ... 2814fa9e4066Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01 2815fa9e4066Sahrens * config: 2816fa9e4066Sahrens * mirror DEGRADED 2817fa9e4066Sahrens * c1t0d0 OK 2818ea8dc4b6Seschrock * c2t0d0 UNAVAIL 2819fa9e4066Sahrens * 2820fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 2821fa9e4066Sahrens * option is specified, then we print out error rate information as well. 2822fa9e4066Sahrens */ 2823fa9e4066Sahrens int 2824fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 2825fa9e4066Sahrens { 2826fa9e4066Sahrens status_cbdata_t *cbp = data; 2827fa9e4066Sahrens nvlist_t *config, *nvroot; 2828fa9e4066Sahrens char *msgid; 2829fa9e4066Sahrens int reason; 283046657f8dSmmusante const char *health; 283146657f8dSmmusante uint_t c; 283246657f8dSmmusante vdev_stat_t *vs; 2833fa9e4066Sahrens 2834088e9d47Seschrock config = zpool_get_config(zhp, NULL); 2835fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 2836fa9e4066Sahrens 2837fa9e4066Sahrens cbp->cb_count++; 2838fa9e4066Sahrens 2839fa9e4066Sahrens /* 2840fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 2841fa9e4066Sahrens * problems. 2842fa9e4066Sahrens */ 2843e9dbad6fSeschrock if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 2844e9dbad6fSeschrock if (!cbp->cb_allpools) { 2845e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 2846e9dbad6fSeschrock zpool_get_name(zhp)); 2847e9dbad6fSeschrock if (cbp->cb_first) 2848e9dbad6fSeschrock cbp->cb_first = B_FALSE; 2849e9dbad6fSeschrock } 2850fa9e4066Sahrens return (0); 2851e9dbad6fSeschrock } 2852fa9e4066Sahrens 2853fa9e4066Sahrens if (cbp->cb_first) 285499653d4eSeschrock cbp->cb_first = B_FALSE; 2855fa9e4066Sahrens else 2856fa9e4066Sahrens (void) printf("\n"); 2857fa9e4066Sahrens 285846657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 285946657f8dSmmusante &nvroot) == 0); 286046657f8dSmmusante verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 286146657f8dSmmusante (uint64_t **)&vs, &c) == 0); 2862990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 2863fa9e4066Sahrens 2864fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 2865fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 2866fa9e4066Sahrens 2867fa9e4066Sahrens switch (reason) { 2868fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 2869fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2870fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 2871fa9e4066Sahrens "continue functioning in a degraded state.\n")); 2872fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2873fa9e4066Sahrens "online it using 'zpool online'.\n")); 2874fa9e4066Sahrens break; 2875fa9e4066Sahrens 2876fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 2877fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2878fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 2879fa9e4066Sahrens "pool to continue functioning.\n")); 2880fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2881fa9e4066Sahrens "online it using 'zpool online'.\n")); 2882fa9e4066Sahrens break; 2883fa9e4066Sahrens 2884fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 2885fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2886fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 2887fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 2888fa9e4066Sahrens "functioning in a degraded state.\n")); 2889fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 2890fa9e4066Sahrens "'zpool replace'.\n")); 2891fa9e4066Sahrens break; 2892fa9e4066Sahrens 2893fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 2894fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2895b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 2896fa9e4066Sahrens "There are insufficient replicas for the pool to " 2897fa9e4066Sahrens "continue\n\tfunctioning.\n")); 2898fa9e4066Sahrens (void) printf(gettext("action: Destroy and re-create the pool " 2899fa9e4066Sahrens "from a backup source.\n")); 2900fa9e4066Sahrens break; 2901fa9e4066Sahrens 2902fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 2903fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2904fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 2905fa9e4066Sahrens "made to correct the error. Applications are " 2906fa9e4066Sahrens "unaffected.\n")); 2907fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 2908fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 2909ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 2910fa9e4066Sahrens "replace'.\n")); 2911fa9e4066Sahrens break; 2912fa9e4066Sahrens 2913fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 2914fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2915d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 2916fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 2917fa9e4066Sahrens "a\n\tdegraded state.\n")); 2918fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 2919fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 2920fa9e4066Sahrens "replace'.\n")); 2921fa9e4066Sahrens break; 2922fa9e4066Sahrens 2923fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 2924fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 2925fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 2926fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 2927fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 2928fa9e4066Sahrens "complete.\n")); 2929fa9e4066Sahrens break; 2930fa9e4066Sahrens 2931ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 2932ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 2933ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 2934ea8dc4b6Seschrock "Applications may be affected.\n")); 2935ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 2936ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 2937ea8dc4b6Seschrock "backup.\n")); 2938ea8dc4b6Seschrock break; 2939ea8dc4b6Seschrock 2940ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 2941ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 2942ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 2943ea8dc4b6Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 2944ea8dc4b6Seschrock "from a backup source.\n")); 2945ea8dc4b6Seschrock break; 2946ea8dc4b6Seschrock 2947eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 2948eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 2949eaca9bbdSeschrock "older on-disk format. The pool can\n\tstill be used, but " 2950eaca9bbdSeschrock "some features are unavailable.\n")); 2951eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 2952eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 2953eaca9bbdSeschrock "be accessible on older software versions.\n")); 2954eaca9bbdSeschrock break; 2955eaca9bbdSeschrock 2956eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 2957eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 2958eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 2959eaca9bbdSeschrock "be accessed on this system.\n")); 2960eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 2961eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 2962eaca9bbdSeschrock "backup.\n")); 2963eaca9bbdSeschrock break; 2964eaca9bbdSeschrock 29653d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 29663d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 29673d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 29683d7072f8Seschrock "replicas exist for the pool to continue functioning " 29693d7072f8Seschrock "in a\n\tdegraded state.\n")); 29703d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 29713d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 29723d7072f8Seschrock break; 29733d7072f8Seschrock 29743d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 29753d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 29763d7072f8Seschrock "faulted in response to persistent errors. There are " 29773d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 29783d7072f8Seschrock "functioning.\n")); 29793d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 29803d7072f8Seschrock "from a backup source. Manually marking the device\n" 29813d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 29823d7072f8Seschrock "to be recovered.\n")); 29833d7072f8Seschrock break; 29843d7072f8Seschrock 2985fa9e4066Sahrens default: 2986fa9e4066Sahrens /* 2987fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 2988fa9e4066Sahrens */ 2989fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 2990fa9e4066Sahrens } 2991fa9e4066Sahrens 2992fa9e4066Sahrens if (msgid != NULL) 2993fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 2994fa9e4066Sahrens msgid); 2995fa9e4066Sahrens 2996fa9e4066Sahrens if (config != NULL) { 2997fa9e4066Sahrens int namewidth; 2998ea8dc4b6Seschrock uint64_t nerr; 299999653d4eSeschrock nvlist_t **spares; 300099653d4eSeschrock uint_t nspares; 3001fa9e4066Sahrens 3002fa9e4066Sahrens 3003fa9e4066Sahrens (void) printf(gettext(" scrub: ")); 3004fa9e4066Sahrens print_scrub_status(nvroot); 3005fa9e4066Sahrens 3006c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 3007fa9e4066Sahrens if (namewidth < 10) 3008fa9e4066Sahrens namewidth = 10; 3009fa9e4066Sahrens 3010fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 3011fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3012fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3013c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 30148654d025Sperrin namewidth, 0, B_FALSE, B_FALSE); 30158654d025Sperrin if (num_logs(nvroot) > 0) 30168654d025Sperrin print_status_config(zhp, "logs", nvroot, namewidth, 0, 30178654d025Sperrin B_FALSE, B_TRUE); 301899653d4eSeschrock 301999653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 302099653d4eSeschrock &spares, &nspares) == 0) 302199653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 3022ea8dc4b6Seschrock 3023ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3024ea8dc4b6Seschrock &nerr) == 0) { 302555434c77Sek110237 nvlist_t *nverrlist = NULL; 302655434c77Sek110237 3027ea8dc4b6Seschrock /* 3028ea8dc4b6Seschrock * If the approximate error count is small, get a 3029ea8dc4b6Seschrock * precise count by fetching the entire log and 3030ea8dc4b6Seschrock * uniquifying the results. 3031ea8dc4b6Seschrock */ 303275519f38Sek110237 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 303355434c77Sek110237 zpool_get_errlog(zhp, &nverrlist) == 0) { 303455434c77Sek110237 nvpair_t *elem; 303555434c77Sek110237 303655434c77Sek110237 elem = NULL; 303755434c77Sek110237 nerr = 0; 303855434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, 303955434c77Sek110237 elem)) != NULL) { 304055434c77Sek110237 nerr++; 304155434c77Sek110237 } 304255434c77Sek110237 } 304355434c77Sek110237 nvlist_free(nverrlist); 3044ea8dc4b6Seschrock 3045ea8dc4b6Seschrock (void) printf("\n"); 304699653d4eSeschrock 3047ea8dc4b6Seschrock if (nerr == 0) 3048ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 3049ea8dc4b6Seschrock "errors\n")); 3050ea8dc4b6Seschrock else if (!cbp->cb_verbose) 3051e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 30525ad82045Snd150628 "errors, use '-v' for a list\n"), 30535ad82045Snd150628 (u_longlong_t)nerr); 3054ea8dc4b6Seschrock else 3055ea8dc4b6Seschrock print_error_log(zhp); 3056ea8dc4b6Seschrock } 3057fa9e4066Sahrens } else { 3058fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 3059fa9e4066Sahrens "determined.\n")); 3060fa9e4066Sahrens } 3061fa9e4066Sahrens 3062fa9e4066Sahrens return (0); 3063fa9e4066Sahrens } 3064fa9e4066Sahrens 3065fa9e4066Sahrens /* 3066fa9e4066Sahrens * zpool status [-vx] [pool] ... 3067fa9e4066Sahrens * 3068fa9e4066Sahrens * -v Display complete error logs 3069fa9e4066Sahrens * -x Display only pools with potential problems 3070fa9e4066Sahrens * 3071fa9e4066Sahrens * Describes the health status of all pools or some subset. 3072fa9e4066Sahrens */ 3073fa9e4066Sahrens int 3074fa9e4066Sahrens zpool_do_status(int argc, char **argv) 3075fa9e4066Sahrens { 3076fa9e4066Sahrens int c; 3077fa9e4066Sahrens int ret; 3078fa9e4066Sahrens status_cbdata_t cb = { 0 }; 3079fa9e4066Sahrens 3080fa9e4066Sahrens /* check options */ 3081fa9e4066Sahrens while ((c = getopt(argc, argv, "vx")) != -1) { 3082fa9e4066Sahrens switch (c) { 3083fa9e4066Sahrens case 'v': 308499653d4eSeschrock cb.cb_verbose = B_TRUE; 3085fa9e4066Sahrens break; 3086fa9e4066Sahrens case 'x': 308799653d4eSeschrock cb.cb_explain = B_TRUE; 3088fa9e4066Sahrens break; 3089fa9e4066Sahrens case '?': 3090fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3091fa9e4066Sahrens optopt); 309299653d4eSeschrock usage(B_FALSE); 3093fa9e4066Sahrens } 3094fa9e4066Sahrens } 3095fa9e4066Sahrens 3096fa9e4066Sahrens argc -= optind; 3097fa9e4066Sahrens argv += optind; 3098fa9e4066Sahrens 309999653d4eSeschrock cb.cb_first = B_TRUE; 3100fa9e4066Sahrens 3101e9dbad6fSeschrock if (argc == 0) 3102e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 3103e9dbad6fSeschrock 3104b1b8ab34Slling ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3105fa9e4066Sahrens 3106fa9e4066Sahrens if (argc == 0 && cb.cb_count == 0) 3107fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 3108e9dbad6fSeschrock else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3109fa9e4066Sahrens (void) printf(gettext("all pools are healthy\n")); 3110fa9e4066Sahrens 3111fa9e4066Sahrens return (ret); 3112fa9e4066Sahrens } 3113fa9e4066Sahrens 3114eaca9bbdSeschrock typedef struct upgrade_cbdata { 3115eaca9bbdSeschrock int cb_all; 3116eaca9bbdSeschrock int cb_first; 3117eaca9bbdSeschrock int cb_newer; 311806eeb2adSek110237 int cb_argc; 3119990b4856Slling uint64_t cb_version; 312006eeb2adSek110237 char **cb_argv; 3121eaca9bbdSeschrock } upgrade_cbdata_t; 3122eaca9bbdSeschrock 3123eaca9bbdSeschrock static int 3124eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 3125eaca9bbdSeschrock { 3126eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 3127eaca9bbdSeschrock nvlist_t *config; 3128eaca9bbdSeschrock uint64_t version; 3129eaca9bbdSeschrock int ret = 0; 3130eaca9bbdSeschrock 3131eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 3132eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3133eaca9bbdSeschrock &version) == 0); 3134eaca9bbdSeschrock 3135e7437265Sahrens if (!cbp->cb_newer && version < SPA_VERSION) { 3136eaca9bbdSeschrock if (!cbp->cb_all) { 3137eaca9bbdSeschrock if (cbp->cb_first) { 3138eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3139eaca9bbdSeschrock "out of date, and can be upgraded. After " 3140eaca9bbdSeschrock "being\nupgraded, these pools will no " 3141eaca9bbdSeschrock "longer be accessible by older software " 3142eaca9bbdSeschrock "versions.\n\n")); 3143eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3144eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 314599653d4eSeschrock cbp->cb_first = B_FALSE; 3146eaca9bbdSeschrock } 3147eaca9bbdSeschrock 31485ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3149eaca9bbdSeschrock zpool_get_name(zhp)); 3150eaca9bbdSeschrock } else { 315199653d4eSeschrock cbp->cb_first = B_FALSE; 3152990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 315306eeb2adSek110237 if (!ret) { 3154eaca9bbdSeschrock (void) printf(gettext("Successfully upgraded " 3155990b4856Slling "'%s'\n\n"), zpool_get_name(zhp)); 3156eaca9bbdSeschrock } 315706eeb2adSek110237 } 3158e7437265Sahrens } else if (cbp->cb_newer && version > SPA_VERSION) { 3159eaca9bbdSeschrock assert(!cbp->cb_all); 3160eaca9bbdSeschrock 3161eaca9bbdSeschrock if (cbp->cb_first) { 3162eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3163eaca9bbdSeschrock "formatted using a newer software version and\n" 3164eaca9bbdSeschrock "cannot be accessed on the current system.\n\n")); 3165eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3166eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 316799653d4eSeschrock cbp->cb_first = B_FALSE; 3168eaca9bbdSeschrock } 3169eaca9bbdSeschrock 31705ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3171eaca9bbdSeschrock zpool_get_name(zhp)); 3172eaca9bbdSeschrock } 3173eaca9bbdSeschrock 3174eaca9bbdSeschrock zpool_close(zhp); 3175eaca9bbdSeschrock return (ret); 3176eaca9bbdSeschrock } 3177eaca9bbdSeschrock 3178eaca9bbdSeschrock /* ARGSUSED */ 3179eaca9bbdSeschrock static int 318006eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data) 3181eaca9bbdSeschrock { 3182990b4856Slling upgrade_cbdata_t *cbp = data; 3183990b4856Slling uint64_t cur_version; 3184eaca9bbdSeschrock int ret; 3185eaca9bbdSeschrock 31868654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 31878654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 31888654d025Sperrin "Pool 'log' must be renamed using export and import" 31898654d025Sperrin " to upgrade.\n")); 31908654d025Sperrin return (1); 31918654d025Sperrin } 3192990b4856Slling 3193990b4856Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 3194990b4856Slling if (cur_version >= cbp->cb_version) { 3195eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 3196990b4856Slling "using more current version '%d'.\n"), zpool_get_name(zhp), 3197990b4856Slling cur_version); 3198eaca9bbdSeschrock return (0); 3199eaca9bbdSeschrock } 3200eaca9bbdSeschrock 3201990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 320206eeb2adSek110237 320306eeb2adSek110237 if (!ret) { 320444cd46caSbillm (void) printf(gettext("Successfully upgraded '%s' " 3205990b4856Slling "from version %llu to version %llu\n\n"), 3206990b4856Slling zpool_get_name(zhp), (u_longlong_t)cur_version, 3207990b4856Slling (u_longlong_t)cbp->cb_version); 320806eeb2adSek110237 } 3209eaca9bbdSeschrock 3210eaca9bbdSeschrock return (ret != 0); 3211eaca9bbdSeschrock } 3212eaca9bbdSeschrock 3213eaca9bbdSeschrock /* 3214eaca9bbdSeschrock * zpool upgrade 3215eaca9bbdSeschrock * zpool upgrade -v 3216990b4856Slling * zpool upgrade [-V version] <-a | pool ...> 3217eaca9bbdSeschrock * 3218eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 3219eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 3220eaca9bbdSeschrock * upgrade all pools. 3221eaca9bbdSeschrock */ 3222eaca9bbdSeschrock int 3223eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 3224eaca9bbdSeschrock { 3225eaca9bbdSeschrock int c; 3226eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 3227eaca9bbdSeschrock int ret = 0; 3228eaca9bbdSeschrock boolean_t showversions = B_FALSE; 3229990b4856Slling char *end; 3230990b4856Slling 3231eaca9bbdSeschrock 3232eaca9bbdSeschrock /* check options */ 3233990b4856Slling while ((c = getopt(argc, argv, "avV:")) != -1) { 3234eaca9bbdSeschrock switch (c) { 3235eaca9bbdSeschrock case 'a': 323699653d4eSeschrock cb.cb_all = B_TRUE; 3237eaca9bbdSeschrock break; 3238eaca9bbdSeschrock case 'v': 3239eaca9bbdSeschrock showversions = B_TRUE; 3240eaca9bbdSeschrock break; 3241990b4856Slling case 'V': 3242990b4856Slling cb.cb_version = strtoll(optarg, &end, 10); 3243351420b3Slling if (*end != '\0' || cb.cb_version > SPA_VERSION || 3244351420b3Slling cb.cb_version < SPA_VERSION_1) { 3245990b4856Slling (void) fprintf(stderr, 3246990b4856Slling gettext("invalid version '%s'\n"), optarg); 3247990b4856Slling usage(B_FALSE); 3248990b4856Slling } 3249990b4856Slling break; 3250eaca9bbdSeschrock case '?': 3251eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3252eaca9bbdSeschrock optopt); 325399653d4eSeschrock usage(B_FALSE); 3254eaca9bbdSeschrock } 3255eaca9bbdSeschrock } 3256eaca9bbdSeschrock 325706eeb2adSek110237 cb.cb_argc = argc; 325806eeb2adSek110237 cb.cb_argv = argv; 3259eaca9bbdSeschrock argc -= optind; 3260eaca9bbdSeschrock argv += optind; 3261eaca9bbdSeschrock 3262351420b3Slling if (cb.cb_version == 0) { 3263351420b3Slling cb.cb_version = SPA_VERSION; 3264351420b3Slling } else if (!cb.cb_all && argc == 0) { 3265351420b3Slling (void) fprintf(stderr, gettext("-V option is " 3266351420b3Slling "incompatible with other arguments\n")); 3267351420b3Slling usage(B_FALSE); 3268351420b3Slling } 3269351420b3Slling 3270eaca9bbdSeschrock if (showversions) { 3271eaca9bbdSeschrock if (cb.cb_all || argc != 0) { 3272eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 3273eaca9bbdSeschrock "incompatible with other arguments\n")); 327499653d4eSeschrock usage(B_FALSE); 3275eaca9bbdSeschrock } 3276eaca9bbdSeschrock } else if (cb.cb_all) { 3277eaca9bbdSeschrock if (argc != 0) { 3278351420b3Slling (void) fprintf(stderr, gettext("-a option should not " 3279351420b3Slling "be used along with a pool name\n")); 328099653d4eSeschrock usage(B_FALSE); 3281eaca9bbdSeschrock } 3282eaca9bbdSeschrock } 3283eaca9bbdSeschrock 3284e7437265Sahrens (void) printf(gettext("This system is currently running " 3285e7437265Sahrens "ZFS pool version %llu.\n\n"), SPA_VERSION); 328699653d4eSeschrock cb.cb_first = B_TRUE; 3287eaca9bbdSeschrock if (showversions) { 3288eaca9bbdSeschrock (void) printf(gettext("The following versions are " 3289d7d4af51Smmusante "supported:\n\n")); 3290eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 3291eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 3292eaca9bbdSeschrock "---------------\n"); 329399653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 329444cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 329544cd46caSbillm "(replicated metadata)\n")); 329699653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 329799653d4eSeschrock "RAID-Z\n")); 3298d7306b64Sek110237 (void) printf(gettext(" 4 zpool history\n")); 3299c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 3300c9431fa1Sahl "algorithm\n")); 3301990b4856Slling (void) printf(gettext(" 6 bootfs pool property\n")); 33028654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 3303ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 3304*a9799022Sck153898 (void) printf(gettext(" 9 refquota and refreservation " 3305*a9799022Sck153898 "properties\n")); 33068654d025Sperrin (void) printf(gettext("For more information on a particular " 3307eaca9bbdSeschrock "version, including supported releases, see:\n\n")); 3308eaca9bbdSeschrock (void) printf("http://www.opensolaris.org/os/community/zfs/" 3309eaca9bbdSeschrock "version/N\n\n"); 3310eaca9bbdSeschrock (void) printf(gettext("Where 'N' is the version number.\n")); 3311eaca9bbdSeschrock } else if (argc == 0) { 3312eaca9bbdSeschrock int notfound; 3313eaca9bbdSeschrock 331499653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3315eaca9bbdSeschrock notfound = cb.cb_first; 3316eaca9bbdSeschrock 3317eaca9bbdSeschrock if (!cb.cb_all && ret == 0) { 3318eaca9bbdSeschrock if (!cb.cb_first) 3319eaca9bbdSeschrock (void) printf("\n"); 3320eaca9bbdSeschrock cb.cb_first = B_TRUE; 3321eaca9bbdSeschrock cb.cb_newer = B_TRUE; 332299653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3323eaca9bbdSeschrock if (!cb.cb_first) { 3324eaca9bbdSeschrock notfound = B_FALSE; 3325eaca9bbdSeschrock (void) printf("\n"); 3326eaca9bbdSeschrock } 3327eaca9bbdSeschrock } 3328eaca9bbdSeschrock 3329eaca9bbdSeschrock if (ret == 0) { 3330eaca9bbdSeschrock if (notfound) 3331eaca9bbdSeschrock (void) printf(gettext("All pools are formatted " 3332eaca9bbdSeschrock "using this version.\n")); 3333eaca9bbdSeschrock else if (!cb.cb_all) 3334eaca9bbdSeschrock (void) printf(gettext("Use 'zpool upgrade -v' " 3335eaca9bbdSeschrock "for a list of available versions and " 3336eaca9bbdSeschrock "their associated\nfeatures.\n")); 3337eaca9bbdSeschrock } 3338eaca9bbdSeschrock } else { 3339b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 3340b1b8ab34Slling upgrade_one, &cb); 334106eeb2adSek110237 } 334206eeb2adSek110237 334306eeb2adSek110237 return (ret); 334406eeb2adSek110237 } 334506eeb2adSek110237 3346ecd6cf80Smarks typedef struct hist_cbdata { 3347ecd6cf80Smarks boolean_t first; 3348ecd6cf80Smarks int longfmt; 3349ecd6cf80Smarks int internal; 3350ecd6cf80Smarks } hist_cbdata_t; 3351ecd6cf80Smarks 3352ecd6cf80Smarks char *hist_event_table[LOG_END] = { 3353ecd6cf80Smarks "invalid event", 3354ecd6cf80Smarks "pool create", 3355ecd6cf80Smarks "vdev add", 3356ecd6cf80Smarks "pool remove", 3357ecd6cf80Smarks "pool destroy", 3358ecd6cf80Smarks "pool export", 3359ecd6cf80Smarks "pool import", 3360ecd6cf80Smarks "vdev attach", 3361ecd6cf80Smarks "vdev replace", 3362ecd6cf80Smarks "vdev detach", 3363ecd6cf80Smarks "vdev online", 3364ecd6cf80Smarks "vdev offline", 3365ecd6cf80Smarks "vdev upgrade", 3366ecd6cf80Smarks "pool clear", 3367ecd6cf80Smarks "pool scrub", 3368ecd6cf80Smarks "pool property set", 3369ecd6cf80Smarks "create", 3370ecd6cf80Smarks "clone", 3371ecd6cf80Smarks "destroy", 3372ecd6cf80Smarks "destroy_begin_sync", 3373ecd6cf80Smarks "inherit", 3374ecd6cf80Smarks "property set", 3375ecd6cf80Smarks "quota set", 3376ecd6cf80Smarks "permission update", 3377ecd6cf80Smarks "permission remove", 3378ecd6cf80Smarks "permission who remove", 3379ecd6cf80Smarks "promote", 3380ecd6cf80Smarks "receive", 3381ecd6cf80Smarks "rename", 3382ecd6cf80Smarks "reservation set", 3383ecd6cf80Smarks "replay_inc_sync", 3384ecd6cf80Smarks "replay_full_sync", 3385ecd6cf80Smarks "rollback", 3386ecd6cf80Smarks "snapshot", 3387e7437265Sahrens "filesystem version upgrade", 3388*a9799022Sck153898 "refquota set", 3389*a9799022Sck153898 "refreservation set", 3390ecd6cf80Smarks }; 3391ecd6cf80Smarks 339206eeb2adSek110237 /* 339306eeb2adSek110237 * Print out the command history for a specific pool. 339406eeb2adSek110237 */ 339506eeb2adSek110237 static int 339606eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data) 339706eeb2adSek110237 { 339806eeb2adSek110237 nvlist_t *nvhis; 339906eeb2adSek110237 nvlist_t **records; 340006eeb2adSek110237 uint_t numrecords; 340106eeb2adSek110237 char *cmdstr; 3402ecd6cf80Smarks char *pathstr; 340306eeb2adSek110237 uint64_t dst_time; 340406eeb2adSek110237 time_t tsec; 340506eeb2adSek110237 struct tm t; 340606eeb2adSek110237 char tbuf[30]; 340706eeb2adSek110237 int ret, i; 3408ecd6cf80Smarks uint64_t who; 3409ecd6cf80Smarks struct passwd *pwd; 3410ecd6cf80Smarks char *hostname; 3411ecd6cf80Smarks char *zonename; 3412ecd6cf80Smarks char internalstr[MAXPATHLEN]; 3413ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 3414ecd6cf80Smarks uint64_t txg; 3415ecd6cf80Smarks uint64_t ievent; 341606eeb2adSek110237 3417ecd6cf80Smarks cb->first = B_FALSE; 341806eeb2adSek110237 341906eeb2adSek110237 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 342006eeb2adSek110237 342106eeb2adSek110237 if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 342206eeb2adSek110237 return (ret); 342306eeb2adSek110237 342406eeb2adSek110237 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 342506eeb2adSek110237 &records, &numrecords) == 0); 342606eeb2adSek110237 for (i = 0; i < numrecords; i++) { 342706eeb2adSek110237 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3428ecd6cf80Smarks &dst_time) != 0) 3429ecd6cf80Smarks continue; 3430ecd6cf80Smarks 3431ecd6cf80Smarks /* is it an internal event or a standard event? */ 3432ecd6cf80Smarks if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3433ecd6cf80Smarks &cmdstr) != 0) { 3434ecd6cf80Smarks if (cb->internal == 0) 3435ecd6cf80Smarks continue; 3436ecd6cf80Smarks 3437ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3438ecd6cf80Smarks ZPOOL_HIST_INT_EVENT, &ievent) != 0) 3439ecd6cf80Smarks continue; 3440ecd6cf80Smarks verify(nvlist_lookup_uint64(records[i], 3441ecd6cf80Smarks ZPOOL_HIST_TXG, &txg) == 0); 3442ecd6cf80Smarks verify(nvlist_lookup_string(records[i], 3443ecd6cf80Smarks ZPOOL_HIST_INT_STR, &pathstr) == 0); 3444ecd6cf80Smarks if (ievent > LOG_END) 3445ecd6cf80Smarks continue; 3446ecd6cf80Smarks (void) snprintf(internalstr, 3447ecd6cf80Smarks sizeof (internalstr), 3448ecd6cf80Smarks "[internal %s txg:%lld] %s", 3449ecd6cf80Smarks hist_event_table[ievent], txg, 3450ecd6cf80Smarks pathstr); 3451ecd6cf80Smarks cmdstr = internalstr; 3452ecd6cf80Smarks } 345306eeb2adSek110237 tsec = dst_time; 345406eeb2adSek110237 (void) localtime_r(&tsec, &t); 345506eeb2adSek110237 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3456ecd6cf80Smarks (void) printf("%s %s", tbuf, cmdstr); 3457ecd6cf80Smarks 3458ecd6cf80Smarks if (!cb->longfmt) { 3459ecd6cf80Smarks (void) printf("\n"); 3460ecd6cf80Smarks continue; 346106eeb2adSek110237 } 3462ecd6cf80Smarks (void) printf(" ["); 3463ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3464ecd6cf80Smarks ZPOOL_HIST_WHO, &who) == 0) { 3465ecd6cf80Smarks pwd = getpwuid((uid_t)who); 3466ecd6cf80Smarks if (pwd) 3467ecd6cf80Smarks (void) printf("user %s on", 3468ecd6cf80Smarks pwd->pw_name); 3469ecd6cf80Smarks else 3470ecd6cf80Smarks (void) printf("user %d on", 3471ecd6cf80Smarks (int)who); 3472ecd6cf80Smarks } else { 3473ecd6cf80Smarks (void) printf(gettext("no info]\n")); 3474ecd6cf80Smarks continue; 3475ecd6cf80Smarks } 3476ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3477ecd6cf80Smarks ZPOOL_HIST_HOST, &hostname) == 0) { 3478ecd6cf80Smarks (void) printf(" %s", hostname); 3479ecd6cf80Smarks } 3480ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3481ecd6cf80Smarks ZPOOL_HIST_ZONE, &zonename) == 0) { 3482ecd6cf80Smarks (void) printf(":%s", zonename); 3483ecd6cf80Smarks } 3484ecd6cf80Smarks 3485ecd6cf80Smarks (void) printf("]"); 3486ecd6cf80Smarks (void) printf("\n"); 348706eeb2adSek110237 } 348806eeb2adSek110237 (void) printf("\n"); 348906eeb2adSek110237 nvlist_free(nvhis); 349006eeb2adSek110237 349106eeb2adSek110237 return (ret); 349206eeb2adSek110237 } 349306eeb2adSek110237 349406eeb2adSek110237 /* 349506eeb2adSek110237 * zpool history <pool> 349606eeb2adSek110237 * 349706eeb2adSek110237 * Displays the history of commands that modified pools. 349806eeb2adSek110237 */ 3499ecd6cf80Smarks 3500ecd6cf80Smarks 350106eeb2adSek110237 int 350206eeb2adSek110237 zpool_do_history(int argc, char **argv) 350306eeb2adSek110237 { 3504ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 350506eeb2adSek110237 int ret; 3506ecd6cf80Smarks int c; 350706eeb2adSek110237 3508ecd6cf80Smarks cbdata.first = B_TRUE; 3509ecd6cf80Smarks /* check options */ 3510ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 3511ecd6cf80Smarks switch (c) { 3512ecd6cf80Smarks case 'l': 3513ecd6cf80Smarks cbdata.longfmt = 1; 3514ecd6cf80Smarks break; 3515ecd6cf80Smarks case 'i': 3516ecd6cf80Smarks cbdata.internal = 1; 3517ecd6cf80Smarks break; 3518ecd6cf80Smarks case '?': 3519ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3520ecd6cf80Smarks optopt); 3521ecd6cf80Smarks usage(B_FALSE); 3522ecd6cf80Smarks } 3523ecd6cf80Smarks } 352406eeb2adSek110237 argc -= optind; 352506eeb2adSek110237 argv += optind; 352606eeb2adSek110237 3527b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3528ecd6cf80Smarks &cbdata); 352906eeb2adSek110237 3530ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 353106eeb2adSek110237 (void) printf(gettext("no pools available\n")); 353206eeb2adSek110237 return (0); 3533eaca9bbdSeschrock } 3534eaca9bbdSeschrock 3535eaca9bbdSeschrock return (ret); 3536eaca9bbdSeschrock } 3537eaca9bbdSeschrock 3538b1b8ab34Slling static int 3539b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 3540b1b8ab34Slling { 3541990b4856Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 3542b1b8ab34Slling char value[MAXNAMELEN]; 3543990b4856Slling zprop_source_t srctype; 3544990b4856Slling zprop_list_t *pl; 3545b1b8ab34Slling 3546b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3547b1b8ab34Slling 3548b1b8ab34Slling /* 3549990b4856Slling * Skip the special fake placeholder. This will also skip 3550990b4856Slling * over the name property when 'all' is specified. 3551b1b8ab34Slling */ 3552990b4856Slling if (pl->pl_prop == ZPOOL_PROP_NAME && 3553b1b8ab34Slling pl == cbp->cb_proplist) 3554b1b8ab34Slling continue; 3555b1b8ab34Slling 3556b1b8ab34Slling if (zpool_get_prop(zhp, pl->pl_prop, 3557b1b8ab34Slling value, sizeof (value), &srctype) != 0) 3558b1b8ab34Slling continue; 3559b1b8ab34Slling 3560990b4856Slling zprop_print_one_property(zpool_get_name(zhp), cbp, 3561b1b8ab34Slling zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3562b1b8ab34Slling } 3563b1b8ab34Slling return (0); 3564b1b8ab34Slling } 3565b1b8ab34Slling 3566b1b8ab34Slling int 3567b1b8ab34Slling zpool_do_get(int argc, char **argv) 3568b1b8ab34Slling { 3569990b4856Slling zprop_get_cbdata_t cb = { 0 }; 3570990b4856Slling zprop_list_t fake_name = { 0 }; 3571b1b8ab34Slling int ret; 3572b1b8ab34Slling 3573b1b8ab34Slling if (argc < 3) 3574b1b8ab34Slling usage(B_FALSE); 3575b1b8ab34Slling 3576b1b8ab34Slling cb.cb_first = B_TRUE; 3577990b4856Slling cb.cb_sources = ZPROP_SRC_ALL; 3578b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 3579b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 3580b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 3581b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 3582990b4856Slling cb.cb_type = ZFS_TYPE_POOL; 3583b1b8ab34Slling 3584990b4856Slling if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 3585990b4856Slling ZFS_TYPE_POOL) != 0) 3586b1b8ab34Slling usage(B_FALSE); 3587b1b8ab34Slling 3588b1b8ab34Slling if (cb.cb_proplist != NULL) { 3589990b4856Slling fake_name.pl_prop = ZPOOL_PROP_NAME; 3590b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 3591b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 3592b1b8ab34Slling cb.cb_proplist = &fake_name; 3593b1b8ab34Slling } 3594b1b8ab34Slling 3595b1b8ab34Slling ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3596b1b8ab34Slling get_callback, &cb); 3597b1b8ab34Slling 3598b1b8ab34Slling if (cb.cb_proplist == &fake_name) 3599990b4856Slling zprop_free_list(fake_name.pl_next); 3600b1b8ab34Slling else 3601990b4856Slling zprop_free_list(cb.cb_proplist); 3602b1b8ab34Slling 3603b1b8ab34Slling return (ret); 3604b1b8ab34Slling } 3605b1b8ab34Slling 3606b1b8ab34Slling typedef struct set_cbdata { 3607b1b8ab34Slling char *cb_propname; 3608b1b8ab34Slling char *cb_value; 3609b1b8ab34Slling boolean_t cb_any_successful; 3610b1b8ab34Slling } set_cbdata_t; 3611b1b8ab34Slling 3612b1b8ab34Slling int 3613b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 3614b1b8ab34Slling { 3615b1b8ab34Slling int error; 3616b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 3617b1b8ab34Slling 3618b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3619b1b8ab34Slling 3620b1b8ab34Slling if (!error) 3621b1b8ab34Slling cb->cb_any_successful = B_TRUE; 3622b1b8ab34Slling 3623b1b8ab34Slling return (error); 3624b1b8ab34Slling } 3625b1b8ab34Slling 3626b1b8ab34Slling int 3627b1b8ab34Slling zpool_do_set(int argc, char **argv) 3628b1b8ab34Slling { 3629b1b8ab34Slling set_cbdata_t cb = { 0 }; 3630b1b8ab34Slling int error; 3631b1b8ab34Slling 3632b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 3633b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3634b1b8ab34Slling argv[1][1]); 3635b1b8ab34Slling usage(B_FALSE); 3636b1b8ab34Slling } 3637b1b8ab34Slling 3638b1b8ab34Slling if (argc < 2) { 3639b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 3640b1b8ab34Slling "argument\n")); 3641b1b8ab34Slling usage(B_FALSE); 3642b1b8ab34Slling } 3643b1b8ab34Slling 3644b1b8ab34Slling if (argc < 3) { 3645b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 3646b1b8ab34Slling usage(B_FALSE); 3647b1b8ab34Slling } 3648b1b8ab34Slling 3649b1b8ab34Slling if (argc > 3) { 3650b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 3651b1b8ab34Slling usage(B_FALSE); 3652b1b8ab34Slling } 3653b1b8ab34Slling 3654b1b8ab34Slling cb.cb_propname = argv[1]; 3655b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 3656b1b8ab34Slling if (cb.cb_value == NULL) { 3657b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 3658b1b8ab34Slling "property=value argument\n")); 3659b1b8ab34Slling usage(B_FALSE); 3660b1b8ab34Slling } 3661b1b8ab34Slling 3662b1b8ab34Slling *(cb.cb_value) = '\0'; 3663b1b8ab34Slling cb.cb_value++; 3664b1b8ab34Slling 3665b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3666b1b8ab34Slling set_callback, &cb); 3667b1b8ab34Slling 3668b1b8ab34Slling return (error); 3669b1b8ab34Slling } 3670b1b8ab34Slling 3671b1b8ab34Slling static int 3672b1b8ab34Slling find_command_idx(char *command, int *idx) 3673b1b8ab34Slling { 3674b1b8ab34Slling int i; 3675b1b8ab34Slling 3676b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 3677b1b8ab34Slling if (command_table[i].name == NULL) 3678b1b8ab34Slling continue; 3679b1b8ab34Slling 3680b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 3681b1b8ab34Slling *idx = i; 3682b1b8ab34Slling return (0); 3683b1b8ab34Slling } 3684b1b8ab34Slling } 3685b1b8ab34Slling return (1); 3686b1b8ab34Slling } 3687b1b8ab34Slling 3688fa9e4066Sahrens int 3689fa9e4066Sahrens main(int argc, char **argv) 3690fa9e4066Sahrens { 3691fa9e4066Sahrens int ret; 3692fa9e4066Sahrens int i; 3693fa9e4066Sahrens char *cmdname; 3694fa9e4066Sahrens 3695fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 3696fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 3697fa9e4066Sahrens 369899653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 369999653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 3700203a47d8Snd150628 "initialize ZFS library\n")); 370199653d4eSeschrock return (1); 370299653d4eSeschrock } 370399653d4eSeschrock 370499653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 370599653d4eSeschrock 3706fa9e4066Sahrens opterr = 0; 3707fa9e4066Sahrens 3708fa9e4066Sahrens /* 3709fa9e4066Sahrens * Make sure the user has specified some command. 3710fa9e4066Sahrens */ 3711fa9e4066Sahrens if (argc < 2) { 3712fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 371399653d4eSeschrock usage(B_FALSE); 3714fa9e4066Sahrens } 3715fa9e4066Sahrens 3716fa9e4066Sahrens cmdname = argv[1]; 3717fa9e4066Sahrens 3718fa9e4066Sahrens /* 3719fa9e4066Sahrens * Special case '-?' 3720fa9e4066Sahrens */ 3721fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 372299653d4eSeschrock usage(B_TRUE); 3723fa9e4066Sahrens 37242a6b87f0Sek110237 zpool_set_history_str("zpool", argc, argv, history_str); 37252a6b87f0Sek110237 verify(zpool_stage_history(g_zfs, history_str) == 0); 37262a6b87f0Sek110237 3727fa9e4066Sahrens /* 3728fa9e4066Sahrens * Run the appropriate command. 3729fa9e4066Sahrens */ 3730b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 3731fa9e4066Sahrens current_command = &command_table[i]; 3732fa9e4066Sahrens ret = command_table[i].func(argc - 1, argv + 1); 373391ebeef5Sahrens } else if (strchr(cmdname, '=')) { 373491ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 373591ebeef5Sahrens current_command = &command_table[i]; 373691ebeef5Sahrens ret = command_table[i].func(argc, argv); 373791ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 3738fa9e4066Sahrens /* 373991ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 374091ebeef5Sahrens * it as such. 3741fa9e4066Sahrens */ 3742ea8dc4b6Seschrock char buf[16384]; 3743ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 3744fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 3745fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 374691ebeef5Sahrens } else { 3747fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 3748fa9e4066Sahrens "command '%s'\n"), cmdname); 374999653d4eSeschrock usage(B_FALSE); 3750fa9e4066Sahrens } 3751fa9e4066Sahrens 375299653d4eSeschrock libzfs_fini(g_zfs); 375399653d4eSeschrock 3754fa9e4066Sahrens /* 3755fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3756fa9e4066Sahrens * for the purposes of running ::findleaks. 3757fa9e4066Sahrens */ 3758fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 3759fa9e4066Sahrens (void) printf("dumping core by request\n"); 3760fa9e4066Sahrens abort(); 3761fa9e4066Sahrens } 3762fa9e4066Sahrens 3763fa9e4066Sahrens return (ret); 3764fa9e4066Sahrens } 3765