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 /* 23379c004dSEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #include <assert.h> 28fa9e4066Sahrens #include <ctype.h> 29fa9e4066Sahrens #include <dirent.h> 30fa9e4066Sahrens #include <errno.h> 31fa9e4066Sahrens #include <fcntl.h> 32fa9e4066Sahrens #include <libgen.h> 33fa9e4066Sahrens #include <libintl.h> 34fa9e4066Sahrens #include <libuutil.h> 35fa9e4066Sahrens #include <locale.h> 36fa9e4066Sahrens #include <stdio.h> 37fa9e4066Sahrens #include <stdlib.h> 38fa9e4066Sahrens #include <string.h> 39fa9e4066Sahrens #include <strings.h> 40fa9e4066Sahrens #include <unistd.h> 41fa9e4066Sahrens #include <priv.h> 42ecd6cf80Smarks #include <pwd.h> 43ecd6cf80Smarks #include <zone.h> 44b1b8ab34Slling #include <sys/fs/zfs.h> 45fa9e4066Sahrens 46fa9e4066Sahrens #include <sys/stat.h> 47fa9e4066Sahrens 48fa9e4066Sahrens #include <libzfs.h> 49fa9e4066Sahrens 50fa9e4066Sahrens #include "zpool_util.h" 51b7b97454Sperrin #include "zfs_comutil.h" 52fa9e4066Sahrens 53fa9e4066Sahrens static int zpool_do_create(int, char **); 54fa9e4066Sahrens static int zpool_do_destroy(int, char **); 55fa9e4066Sahrens 56fa9e4066Sahrens static int zpool_do_add(int, char **); 5799653d4eSeschrock static int zpool_do_remove(int, char **); 58fa9e4066Sahrens 59fa9e4066Sahrens static int zpool_do_list(int, char **); 60fa9e4066Sahrens static int zpool_do_iostat(int, char **); 61fa9e4066Sahrens static int zpool_do_status(int, char **); 62fa9e4066Sahrens 63fa9e4066Sahrens static int zpool_do_online(int, char **); 64fa9e4066Sahrens static int zpool_do_offline(int, char **); 65ea8dc4b6Seschrock static int zpool_do_clear(int, char **); 66fa9e4066Sahrens 67fa9e4066Sahrens static int zpool_do_attach(int, char **); 68fa9e4066Sahrens static int zpool_do_detach(int, char **); 69fa9e4066Sahrens static int zpool_do_replace(int, char **); 70fa9e4066Sahrens 71fa9e4066Sahrens static int zpool_do_scrub(int, char **); 72fa9e4066Sahrens 73fa9e4066Sahrens static int zpool_do_import(int, char **); 74fa9e4066Sahrens static int zpool_do_export(int, char **); 75fa9e4066Sahrens 76eaca9bbdSeschrock static int zpool_do_upgrade(int, char **); 77eaca9bbdSeschrock 7806eeb2adSek110237 static int zpool_do_history(int, char **); 7906eeb2adSek110237 80b1b8ab34Slling static int zpool_do_get(int, char **); 81b1b8ab34Slling static int zpool_do_set(int, char **); 82b1b8ab34Slling 83fa9e4066Sahrens /* 84fa9e4066Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 85fa9e4066Sahrens * debugging facilities. 86fa9e4066Sahrens */ 8729ab75c9Srm160521 8829ab75c9Srm160521 #ifdef DEBUG 89fa9e4066Sahrens const char * 9099653d4eSeschrock _umem_debug_init(void) 91fa9e4066Sahrens { 92fa9e4066Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 93fa9e4066Sahrens } 94fa9e4066Sahrens 95fa9e4066Sahrens const char * 96fa9e4066Sahrens _umem_logging_init(void) 97fa9e4066Sahrens { 98fa9e4066Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 99fa9e4066Sahrens } 10029ab75c9Srm160521 #endif 101fa9e4066Sahrens 10265cd9f28Seschrock typedef enum { 10365cd9f28Seschrock HELP_ADD, 10465cd9f28Seschrock HELP_ATTACH, 105ea8dc4b6Seschrock HELP_CLEAR, 10665cd9f28Seschrock HELP_CREATE, 10765cd9f28Seschrock HELP_DESTROY, 10865cd9f28Seschrock HELP_DETACH, 10965cd9f28Seschrock HELP_EXPORT, 11006eeb2adSek110237 HELP_HISTORY, 11165cd9f28Seschrock HELP_IMPORT, 11265cd9f28Seschrock HELP_IOSTAT, 11365cd9f28Seschrock HELP_LIST, 11465cd9f28Seschrock HELP_OFFLINE, 11565cd9f28Seschrock HELP_ONLINE, 11665cd9f28Seschrock HELP_REPLACE, 11799653d4eSeschrock HELP_REMOVE, 11865cd9f28Seschrock HELP_SCRUB, 119eaca9bbdSeschrock HELP_STATUS, 120b1b8ab34Slling HELP_UPGRADE, 121b1b8ab34Slling HELP_GET, 122b1b8ab34Slling HELP_SET 12365cd9f28Seschrock } zpool_help_t; 12465cd9f28Seschrock 12565cd9f28Seschrock 126fa9e4066Sahrens typedef struct zpool_command { 127fa9e4066Sahrens const char *name; 128fa9e4066Sahrens int (*func)(int, char **); 12965cd9f28Seschrock zpool_help_t usage; 130fa9e4066Sahrens } zpool_command_t; 131fa9e4066Sahrens 132fa9e4066Sahrens /* 133fa9e4066Sahrens * Master command table. Each ZFS command has a name, associated function, and 134ea8dc4b6Seschrock * usage message. The usage messages need to be internationalized, so we have 135ea8dc4b6Seschrock * to have a function to return the usage message based on a command index. 13665cd9f28Seschrock * 13765cd9f28Seschrock * These commands are organized according to how they are displayed in the usage 13865cd9f28Seschrock * message. An empty command (one with a NULL name) indicates an empty line in 13965cd9f28Seschrock * the generic usage message. 140fa9e4066Sahrens */ 141fa9e4066Sahrens static zpool_command_t command_table[] = { 14265cd9f28Seschrock { "create", zpool_do_create, HELP_CREATE }, 14365cd9f28Seschrock { "destroy", zpool_do_destroy, HELP_DESTROY }, 144fa9e4066Sahrens { NULL }, 14565cd9f28Seschrock { "add", zpool_do_add, HELP_ADD }, 14699653d4eSeschrock { "remove", zpool_do_remove, HELP_REMOVE }, 147fa9e4066Sahrens { NULL }, 14865cd9f28Seschrock { "list", zpool_do_list, HELP_LIST }, 14965cd9f28Seschrock { "iostat", zpool_do_iostat, HELP_IOSTAT }, 15065cd9f28Seschrock { "status", zpool_do_status, HELP_STATUS }, 151fa9e4066Sahrens { NULL }, 15265cd9f28Seschrock { "online", zpool_do_online, HELP_ONLINE }, 15365cd9f28Seschrock { "offline", zpool_do_offline, HELP_OFFLINE }, 154ea8dc4b6Seschrock { "clear", zpool_do_clear, HELP_CLEAR }, 155fa9e4066Sahrens { NULL }, 15665cd9f28Seschrock { "attach", zpool_do_attach, HELP_ATTACH }, 15765cd9f28Seschrock { "detach", zpool_do_detach, HELP_DETACH }, 15865cd9f28Seschrock { "replace", zpool_do_replace, HELP_REPLACE }, 159fa9e4066Sahrens { NULL }, 16065cd9f28Seschrock { "scrub", zpool_do_scrub, HELP_SCRUB }, 161fa9e4066Sahrens { NULL }, 16265cd9f28Seschrock { "import", zpool_do_import, HELP_IMPORT }, 16365cd9f28Seschrock { "export", zpool_do_export, HELP_EXPORT }, 16406eeb2adSek110237 { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 16506eeb2adSek110237 { NULL }, 166b1b8ab34Slling { "history", zpool_do_history, HELP_HISTORY }, 167b1b8ab34Slling { "get", zpool_do_get, HELP_GET }, 168b1b8ab34Slling { "set", zpool_do_set, HELP_SET }, 169fa9e4066Sahrens }; 170fa9e4066Sahrens 171fa9e4066Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 172fa9e4066Sahrens 173fa9e4066Sahrens zpool_command_t *current_command; 1742a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN]; 175fa9e4066Sahrens 17665cd9f28Seschrock static const char * 17765cd9f28Seschrock get_usage(zpool_help_t idx) { 17865cd9f28Seschrock switch (idx) { 17965cd9f28Seschrock case HELP_ADD: 18065cd9f28Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 18165cd9f28Seschrock case HELP_ATTACH: 18265cd9f28Seschrock return (gettext("\tattach [-f] <pool> <device> " 183e45ce728Sahrens "<new-device>\n")); 184ea8dc4b6Seschrock case HELP_CLEAR: 185ea8dc4b6Seschrock return (gettext("\tclear <pool> [device]\n")); 18665cd9f28Seschrock case HELP_CREATE: 187990b4856Slling return (gettext("\tcreate [-fn] [-o property=value] ... \n" 1880a48a24eStimh "\t [-O file-system-property=value] ... \n" 189990b4856Slling "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 19065cd9f28Seschrock case HELP_DESTROY: 19165cd9f28Seschrock return (gettext("\tdestroy [-f] <pool>\n")); 19265cd9f28Seschrock case HELP_DETACH: 19365cd9f28Seschrock return (gettext("\tdetach <pool> <device>\n")); 19465cd9f28Seschrock case HELP_EXPORT: 19565cd9f28Seschrock return (gettext("\texport [-f] <pool> ...\n")); 19606eeb2adSek110237 case HELP_HISTORY: 197ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 19865cd9f28Seschrock case HELP_IMPORT: 1994c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 2002f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 2012f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n" 2022f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 2032f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] " 2042f8aaab3Seschrock "<pool | id> [newpool]\n")); 20565cd9f28Seschrock case HELP_IOSTAT: 20665cd9f28Seschrock return (gettext("\tiostat [-v] [pool] ... [interval " 20765cd9f28Seschrock "[count]]\n")); 20865cd9f28Seschrock case HELP_LIST: 209990b4856Slling return (gettext("\tlist [-H] [-o property[,...]] " 210990b4856Slling "[pool] ...\n")); 21165cd9f28Seschrock case HELP_OFFLINE: 212441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 21365cd9f28Seschrock case HELP_ONLINE: 214441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 21565cd9f28Seschrock case HELP_REPLACE: 21665cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 217e45ce728Sahrens "[new-device]\n")); 21899653d4eSeschrock case HELP_REMOVE: 219fa94a07fSbrendan return (gettext("\tremove <pool> <device> ...\n")); 22065cd9f28Seschrock case HELP_SCRUB: 22165cd9f28Seschrock return (gettext("\tscrub [-s] <pool> ...\n")); 22265cd9f28Seschrock case HELP_STATUS: 22365cd9f28Seschrock return (gettext("\tstatus [-vx] [pool] ...\n")); 224eaca9bbdSeschrock case HELP_UPGRADE: 225eaca9bbdSeschrock return (gettext("\tupgrade\n" 226eaca9bbdSeschrock "\tupgrade -v\n" 227990b4856Slling "\tupgrade [-V version] <-a | pool ...>\n")); 228b1b8ab34Slling case HELP_GET: 229e45ce728Sahrens return (gettext("\tget <\"all\" | property[,...]> " 230b1b8ab34Slling "<pool> ...\n")); 231b1b8ab34Slling case HELP_SET: 232b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 23365cd9f28Seschrock } 23465cd9f28Seschrock 23565cd9f28Seschrock abort(); 23665cd9f28Seschrock /* NOTREACHED */ 23765cd9f28Seschrock } 23865cd9f28Seschrock 239fa9e4066Sahrens 240fa9e4066Sahrens /* 241b1b8ab34Slling * Callback routine that will print out a pool property value. 242b1b8ab34Slling */ 243990b4856Slling static int 244990b4856Slling print_prop_cb(int prop, void *cb) 245b1b8ab34Slling { 246b1b8ab34Slling FILE *fp = cb; 247b1b8ab34Slling 248b1b8ab34Slling (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 249b1b8ab34Slling 250990b4856Slling if (zpool_prop_readonly(prop)) 251990b4856Slling (void) fprintf(fp, " NO "); 252990b4856Slling else 253990b4856Slling (void) fprintf(fp, " YES "); 254990b4856Slling 255b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 256b1b8ab34Slling (void) fprintf(fp, "-\n"); 257b1b8ab34Slling else 258b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 259b1b8ab34Slling 260990b4856Slling return (ZPROP_CONT); 261b1b8ab34Slling } 262b1b8ab34Slling 263b1b8ab34Slling /* 264fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 265fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 266fa9e4066Sahrens * a complete usage message. 267fa9e4066Sahrens */ 268fa9e4066Sahrens void 26999653d4eSeschrock usage(boolean_t requested) 270fa9e4066Sahrens { 271fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 272fa9e4066Sahrens 273fa9e4066Sahrens if (current_command == NULL) { 274fa9e4066Sahrens int i; 275fa9e4066Sahrens 276fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 277fa9e4066Sahrens (void) fprintf(fp, 278fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 279fa9e4066Sahrens 280fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 281fa9e4066Sahrens if (command_table[i].name == NULL) 282fa9e4066Sahrens (void) fprintf(fp, "\n"); 283fa9e4066Sahrens else 284fa9e4066Sahrens (void) fprintf(fp, "%s", 28565cd9f28Seschrock get_usage(command_table[i].usage)); 286fa9e4066Sahrens } 287fa9e4066Sahrens } else { 288fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 28965cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 290fa9e4066Sahrens } 291fa9e4066Sahrens 292b1b8ab34Slling if (current_command != NULL && 293b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 294990b4856Slling (strcmp(current_command->name, "get") == 0) || 295990b4856Slling (strcmp(current_command->name, "list") == 0))) { 296b1b8ab34Slling 297b1b8ab34Slling (void) fprintf(fp, 298b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 299b1b8ab34Slling 300990b4856Slling (void) fprintf(fp, "\n\t%-13s %s %s\n\n", 301990b4856Slling "PROPERTY", "EDIT", "VALUES"); 302b1b8ab34Slling 303b1b8ab34Slling /* Iterate over all properties */ 304990b4856Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 305990b4856Slling ZFS_TYPE_POOL); 306b1b8ab34Slling } 307b1b8ab34Slling 308e9dbad6fSeschrock /* 309e9dbad6fSeschrock * See comments at end of main(). 310e9dbad6fSeschrock */ 311e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 312e9dbad6fSeschrock (void) printf("dumping core by request\n"); 313e9dbad6fSeschrock abort(); 314e9dbad6fSeschrock } 315e9dbad6fSeschrock 316fa9e4066Sahrens exit(requested ? 0 : 2); 317fa9e4066Sahrens } 318fa9e4066Sahrens 319fa9e4066Sahrens void 3208654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 3218654d025Sperrin boolean_t print_logs) 322fa9e4066Sahrens { 323fa9e4066Sahrens nvlist_t **child; 324fa9e4066Sahrens uint_t c, children; 325afefbcddSeschrock char *vname; 326fa9e4066Sahrens 327fa9e4066Sahrens if (name != NULL) 328fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 329fa9e4066Sahrens 330fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 331fa9e4066Sahrens &child, &children) != 0) 332fa9e4066Sahrens return; 333fa9e4066Sahrens 334afefbcddSeschrock for (c = 0; c < children; c++) { 3358654d025Sperrin uint64_t is_log = B_FALSE; 3368654d025Sperrin 3378654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3388654d025Sperrin &is_log); 3398654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 3408654d025Sperrin continue; 3418654d025Sperrin 34299653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 3438654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 3448654d025Sperrin B_FALSE); 345afefbcddSeschrock free(vname); 346afefbcddSeschrock } 347fa9e4066Sahrens } 348fa9e4066Sahrens 349fa9e4066Sahrens /* 350990b4856Slling * Add a property pair (name, string-value) into a property nvlist. 351990b4856Slling */ 352990b4856Slling static int 3530a48a24eStimh add_prop_list(const char *propname, char *propval, nvlist_t **props, 3540a48a24eStimh boolean_t poolprop) 355990b4856Slling { 3560a48a24eStimh zpool_prop_t prop = ZPROP_INVAL; 3570a48a24eStimh zfs_prop_t fprop; 358990b4856Slling nvlist_t *proplist; 3590a48a24eStimh const char *normnm; 3600a48a24eStimh char *strval; 361990b4856Slling 362990b4856Slling if (*props == NULL && 363990b4856Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 364990b4856Slling (void) fprintf(stderr, 365990b4856Slling gettext("internal error: out of memory\n")); 366990b4856Slling return (1); 367990b4856Slling } 368990b4856Slling 369990b4856Slling proplist = *props; 370990b4856Slling 3710a48a24eStimh if (poolprop) { 372990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 373990b4856Slling (void) fprintf(stderr, gettext("property '%s' is " 374990b4856Slling "not a valid pool property\n"), propname); 375990b4856Slling return (2); 376990b4856Slling } 3770a48a24eStimh normnm = zpool_prop_to_name(prop); 3780a48a24eStimh } else { 3790a48a24eStimh if ((fprop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 3800a48a24eStimh (void) fprintf(stderr, gettext("property '%s' is " 3810a48a24eStimh "not a valid file system property\n"), propname); 3820a48a24eStimh return (2); 3830a48a24eStimh } 3840a48a24eStimh normnm = zfs_prop_to_name(fprop); 3850a48a24eStimh } 386990b4856Slling 3870a48a24eStimh if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 3880a48a24eStimh prop != ZPOOL_PROP_CACHEFILE) { 389990b4856Slling (void) fprintf(stderr, gettext("property '%s' " 390990b4856Slling "specified multiple times\n"), propname); 391990b4856Slling return (2); 392990b4856Slling } 393990b4856Slling 3940a48a24eStimh if (nvlist_add_string(proplist, normnm, propval) != 0) { 395990b4856Slling (void) fprintf(stderr, gettext("internal " 396990b4856Slling "error: out of memory\n")); 397990b4856Slling return (1); 398990b4856Slling } 399990b4856Slling 400990b4856Slling return (0); 401990b4856Slling } 402990b4856Slling 403990b4856Slling /* 404fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 405fa9e4066Sahrens * 406fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 407fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 408fa9e4066Sahrens * they were to be added. 409fa9e4066Sahrens * 410fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 411fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 412fa9e4066Sahrens * libzfs. 413fa9e4066Sahrens */ 414fa9e4066Sahrens int 415fa9e4066Sahrens zpool_do_add(int argc, char **argv) 416fa9e4066Sahrens { 41799653d4eSeschrock boolean_t force = B_FALSE; 41899653d4eSeschrock boolean_t dryrun = B_FALSE; 419fa9e4066Sahrens int c; 420fa9e4066Sahrens nvlist_t *nvroot; 421fa9e4066Sahrens char *poolname; 422fa9e4066Sahrens int ret; 423fa9e4066Sahrens zpool_handle_t *zhp; 424fa9e4066Sahrens nvlist_t *config; 425fa9e4066Sahrens 426fa9e4066Sahrens /* check options */ 427fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 428fa9e4066Sahrens switch (c) { 429fa9e4066Sahrens case 'f': 43099653d4eSeschrock force = B_TRUE; 431fa9e4066Sahrens break; 432fa9e4066Sahrens case 'n': 43399653d4eSeschrock dryrun = B_TRUE; 434fa9e4066Sahrens break; 435fa9e4066Sahrens case '?': 436fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 437fa9e4066Sahrens optopt); 43899653d4eSeschrock usage(B_FALSE); 439fa9e4066Sahrens } 440fa9e4066Sahrens } 441fa9e4066Sahrens 442fa9e4066Sahrens argc -= optind; 443fa9e4066Sahrens argv += optind; 444fa9e4066Sahrens 445fa9e4066Sahrens /* get pool name and check number of arguments */ 446fa9e4066Sahrens if (argc < 1) { 447fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 44899653d4eSeschrock usage(B_FALSE); 449fa9e4066Sahrens } 450fa9e4066Sahrens if (argc < 2) { 451fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 45299653d4eSeschrock usage(B_FALSE); 453fa9e4066Sahrens } 454fa9e4066Sahrens 455fa9e4066Sahrens poolname = argv[0]; 456fa9e4066Sahrens 457fa9e4066Sahrens argc--; 458fa9e4066Sahrens argv++; 459fa9e4066Sahrens 46099653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 461fa9e4066Sahrens return (1); 462fa9e4066Sahrens 463088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 464fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 465fa9e4066Sahrens poolname); 466fa9e4066Sahrens zpool_close(zhp); 467fa9e4066Sahrens return (1); 468fa9e4066Sahrens } 469fa9e4066Sahrens 470fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 471705040edSEric Taylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 472705040edSEric Taylor argc, argv); 473fa9e4066Sahrens if (nvroot == NULL) { 474fa9e4066Sahrens zpool_close(zhp); 475fa9e4066Sahrens return (1); 476fa9e4066Sahrens } 477fa9e4066Sahrens 478fa9e4066Sahrens if (dryrun) { 479fa9e4066Sahrens nvlist_t *poolnvroot; 480fa9e4066Sahrens 481fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 482fa9e4066Sahrens &poolnvroot) == 0); 483fa9e4066Sahrens 484fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 485fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 486fa9e4066Sahrens 4878654d025Sperrin /* print original main pool and new tree */ 4888654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 4898654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 4908654d025Sperrin 4918654d025Sperrin /* Do the same for the logs */ 4928654d025Sperrin if (num_logs(poolnvroot) > 0) { 4938654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 4948654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 4958654d025Sperrin } else if (num_logs(nvroot) > 0) { 4968654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 4978654d025Sperrin } 498fa9e4066Sahrens 499fa9e4066Sahrens ret = 0; 500fa9e4066Sahrens } else { 501fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 502fa9e4066Sahrens } 503fa9e4066Sahrens 50499653d4eSeschrock nvlist_free(nvroot); 50599653d4eSeschrock zpool_close(zhp); 50699653d4eSeschrock 50799653d4eSeschrock return (ret); 50899653d4eSeschrock } 50999653d4eSeschrock 51099653d4eSeschrock /* 511fa94a07fSbrendan * zpool remove <pool> <vdev> ... 51299653d4eSeschrock * 51399653d4eSeschrock * Removes the given vdev from the pool. Currently, this only supports removing 514fa94a07fSbrendan * spares and cache devices from the pool. Eventually, we'll want to support 515fa94a07fSbrendan * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs. 51699653d4eSeschrock */ 51799653d4eSeschrock int 51899653d4eSeschrock zpool_do_remove(int argc, char **argv) 51999653d4eSeschrock { 52099653d4eSeschrock char *poolname; 521fa94a07fSbrendan int i, ret = 0; 52299653d4eSeschrock zpool_handle_t *zhp; 52399653d4eSeschrock 52499653d4eSeschrock argc--; 52599653d4eSeschrock argv++; 52699653d4eSeschrock 52799653d4eSeschrock /* get pool name and check number of arguments */ 52899653d4eSeschrock if (argc < 1) { 52999653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 53099653d4eSeschrock usage(B_FALSE); 53199653d4eSeschrock } 53299653d4eSeschrock if (argc < 2) { 53399653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 53499653d4eSeschrock usage(B_FALSE); 53599653d4eSeschrock } 53699653d4eSeschrock 53799653d4eSeschrock poolname = argv[0]; 53899653d4eSeschrock 53999653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 54099653d4eSeschrock return (1); 54199653d4eSeschrock 542fa94a07fSbrendan for (i = 1; i < argc; i++) { 543fa94a07fSbrendan if (zpool_vdev_remove(zhp, argv[i]) != 0) 544fa94a07fSbrendan ret = 1; 545fa94a07fSbrendan } 54699653d4eSeschrock 547fa9e4066Sahrens return (ret); 548fa9e4066Sahrens } 549fa9e4066Sahrens 550fa9e4066Sahrens /* 5510a48a24eStimh * zpool create [-fn] [-o property=value] ... 5520a48a24eStimh * [-O file-system-property=value] ... 5530a48a24eStimh * [-R root] [-m mountpoint] <pool> <dev> ... 554fa9e4066Sahrens * 555fa9e4066Sahrens * -f Force creation, even if devices appear in use 556fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 557fa9e4066Sahrens * were to be created. 558fa9e4066Sahrens * -R Create a pool under an alternate root 559fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 560fa9e4066Sahrens * '/<pool>' 561990b4856Slling * -o Set property=value. 5620a48a24eStimh * -O Set fsproperty=value in the pool's root file system 563fa9e4066Sahrens * 564b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 565fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 566fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 567fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 568fa9e4066Sahrens */ 569fa9e4066Sahrens int 570fa9e4066Sahrens zpool_do_create(int argc, char **argv) 571fa9e4066Sahrens { 57299653d4eSeschrock boolean_t force = B_FALSE; 57399653d4eSeschrock boolean_t dryrun = B_FALSE; 574fa9e4066Sahrens int c; 575990b4856Slling nvlist_t *nvroot = NULL; 576fa9e4066Sahrens char *poolname; 577990b4856Slling int ret = 1; 578fa9e4066Sahrens char *altroot = NULL; 579fa9e4066Sahrens char *mountpoint = NULL; 5800a48a24eStimh nvlist_t *fsprops = NULL; 581990b4856Slling nvlist_t *props = NULL; 5822f8aaab3Seschrock char *propval; 583fa9e4066Sahrens 584fa9e4066Sahrens /* check options */ 5850a48a24eStimh while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) { 586fa9e4066Sahrens switch (c) { 587fa9e4066Sahrens case 'f': 58899653d4eSeschrock force = B_TRUE; 589fa9e4066Sahrens break; 590fa9e4066Sahrens case 'n': 59199653d4eSeschrock dryrun = B_TRUE; 592fa9e4066Sahrens break; 593fa9e4066Sahrens case 'R': 594fa9e4066Sahrens altroot = optarg; 595990b4856Slling if (add_prop_list(zpool_prop_to_name( 5960a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 597990b4856Slling goto errout; 5982f8aaab3Seschrock if (nvlist_lookup_string(props, 5992f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 6002f8aaab3Seschrock &propval) == 0) 6012f8aaab3Seschrock break; 602990b4856Slling if (add_prop_list(zpool_prop_to_name( 6030a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 604990b4856Slling goto errout; 605fa9e4066Sahrens break; 606fa9e4066Sahrens case 'm': 607fa9e4066Sahrens mountpoint = optarg; 608fa9e4066Sahrens break; 609990b4856Slling case 'o': 610990b4856Slling if ((propval = strchr(optarg, '=')) == NULL) { 611990b4856Slling (void) fprintf(stderr, gettext("missing " 612990b4856Slling "'=' for -o option\n")); 613990b4856Slling goto errout; 614990b4856Slling } 615990b4856Slling *propval = '\0'; 616990b4856Slling propval++; 617990b4856Slling 6180a48a24eStimh if (add_prop_list(optarg, propval, &props, B_TRUE)) 6190a48a24eStimh goto errout; 6200a48a24eStimh break; 6210a48a24eStimh case 'O': 6220a48a24eStimh if ((propval = strchr(optarg, '=')) == NULL) { 6230a48a24eStimh (void) fprintf(stderr, gettext("missing " 6240a48a24eStimh "'=' for -O option\n")); 6250a48a24eStimh goto errout; 6260a48a24eStimh } 6270a48a24eStimh *propval = '\0'; 6280a48a24eStimh propval++; 6290a48a24eStimh 6300a48a24eStimh if (add_prop_list(optarg, propval, &fsprops, B_FALSE)) 631990b4856Slling goto errout; 632990b4856Slling break; 633fa9e4066Sahrens case ':': 634fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 635fa9e4066Sahrens "'%c' option\n"), optopt); 636990b4856Slling goto badusage; 637fa9e4066Sahrens case '?': 638fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 639fa9e4066Sahrens optopt); 640990b4856Slling goto badusage; 641fa9e4066Sahrens } 642fa9e4066Sahrens } 643fa9e4066Sahrens 644fa9e4066Sahrens argc -= optind; 645fa9e4066Sahrens argv += optind; 646fa9e4066Sahrens 647fa9e4066Sahrens /* get pool name and check number of arguments */ 648fa9e4066Sahrens if (argc < 1) { 649fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 650990b4856Slling goto badusage; 651fa9e4066Sahrens } 652fa9e4066Sahrens if (argc < 2) { 653fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 654990b4856Slling goto badusage; 655fa9e4066Sahrens } 656fa9e4066Sahrens 657fa9e4066Sahrens poolname = argv[0]; 658fa9e4066Sahrens 659fa9e4066Sahrens /* 660fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 661fa9e4066Sahrens * user to use 'zfs create' instead. 662fa9e4066Sahrens */ 663fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 664fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 665fa9e4066Sahrens "character '/' in pool name\n"), poolname); 666fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 667fa9e4066Sahrens "create a dataset\n")); 668990b4856Slling goto errout; 669fa9e4066Sahrens } 670fa9e4066Sahrens 671fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 672705040edSEric Taylor nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 673705040edSEric Taylor argc - 1, argv + 1); 674fa9e4066Sahrens if (nvroot == NULL) 6750a48a24eStimh goto errout; 676fa9e4066Sahrens 67799653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 678b7b97454Sperrin if (!zfs_allocatable_devs(nvroot)) { 67999653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 68099653d4eSeschrock "specification: at least one toplevel vdev must be " 68199653d4eSeschrock "specified\n")); 682990b4856Slling goto errout; 68399653d4eSeschrock } 68499653d4eSeschrock 68599653d4eSeschrock 686fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 687fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 688e9dbad6fSeschrock "must be an absolute path\n"), altroot); 689990b4856Slling goto errout; 690fa9e4066Sahrens } 691fa9e4066Sahrens 692fa9e4066Sahrens /* 693fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 694fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 695fa9e4066Sahrens */ 696fa9e4066Sahrens if (mountpoint == NULL || 697fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 698fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 699fa9e4066Sahrens char buf[MAXPATHLEN]; 70011022c7cStimh DIR *dirp; 701fa9e4066Sahrens 702fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 703fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 704fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 705fa9e4066Sahrens "'none'\n"), mountpoint); 706990b4856Slling goto errout; 707fa9e4066Sahrens } 708fa9e4066Sahrens 709fa9e4066Sahrens if (mountpoint == NULL) { 710fa9e4066Sahrens if (altroot != NULL) 711fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 712fa9e4066Sahrens altroot, poolname); 713fa9e4066Sahrens else 714fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 715fa9e4066Sahrens poolname); 716fa9e4066Sahrens } else { 717fa9e4066Sahrens if (altroot != NULL) 718fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 719fa9e4066Sahrens altroot, mountpoint); 720fa9e4066Sahrens else 721fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 722fa9e4066Sahrens mountpoint); 723fa9e4066Sahrens } 724fa9e4066Sahrens 72511022c7cStimh if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 72611022c7cStimh (void) fprintf(stderr, gettext("mountpoint '%s' : " 72711022c7cStimh "%s\n"), buf, strerror(errno)); 728fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 729fa9e4066Sahrens "option to provide a different default\n")); 730990b4856Slling goto errout; 73111022c7cStimh } else if (dirp) { 73211022c7cStimh int count = 0; 73311022c7cStimh 73411022c7cStimh while (count < 3 && readdir(dirp) != NULL) 73511022c7cStimh count++; 73611022c7cStimh (void) closedir(dirp); 73711022c7cStimh 73811022c7cStimh if (count > 2) { 73911022c7cStimh (void) fprintf(stderr, gettext("mountpoint " 74011022c7cStimh "'%s' exists and is not empty\n"), buf); 74111022c7cStimh (void) fprintf(stderr, gettext("use '-m' " 74211022c7cStimh "option to provide a " 74311022c7cStimh "different default\n")); 74411022c7cStimh goto errout; 74511022c7cStimh } 746fa9e4066Sahrens } 747fa9e4066Sahrens } 748fa9e4066Sahrens 749fa9e4066Sahrens if (dryrun) { 750fa9e4066Sahrens /* 751fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 752fa9e4066Sahrens * through all the vdevs in the list and print out in an 753fa9e4066Sahrens * appropriate hierarchy. 754fa9e4066Sahrens */ 755fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 756fa9e4066Sahrens "following layout:\n\n"), poolname); 757fa9e4066Sahrens 7588654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 7598654d025Sperrin if (num_logs(nvroot) > 0) 7608654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 761fa9e4066Sahrens 762fa9e4066Sahrens ret = 0; 763fa9e4066Sahrens } else { 764fa9e4066Sahrens /* 765fa9e4066Sahrens * Hand off to libzfs. 766fa9e4066Sahrens */ 7670a48a24eStimh if (zpool_create(g_zfs, poolname, 7680a48a24eStimh nvroot, props, fsprops) == 0) { 76999653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 770fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 771fa9e4066Sahrens if (pool != NULL) { 772fa9e4066Sahrens if (mountpoint != NULL) 773fa9e4066Sahrens verify(zfs_prop_set(pool, 774e9dbad6fSeschrock zfs_prop_to_name( 775e9dbad6fSeschrock ZFS_PROP_MOUNTPOINT), 776fa9e4066Sahrens mountpoint) == 0); 777fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 778da6c28aaSamw ret = zfs_shareall(pool); 779fa9e4066Sahrens zfs_close(pool); 780fa9e4066Sahrens } 78199653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 78299653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 78399653d4eSeschrock "been omitted\n")); 784fa9e4066Sahrens } 785fa9e4066Sahrens } 786fa9e4066Sahrens 787990b4856Slling errout: 788fa9e4066Sahrens nvlist_free(nvroot); 7890a48a24eStimh nvlist_free(fsprops); 790990b4856Slling nvlist_free(props); 791fa9e4066Sahrens return (ret); 792990b4856Slling badusage: 7930a48a24eStimh nvlist_free(fsprops); 794990b4856Slling nvlist_free(props); 795990b4856Slling usage(B_FALSE); 796990b4856Slling return (2); 797fa9e4066Sahrens } 798fa9e4066Sahrens 799fa9e4066Sahrens /* 800fa9e4066Sahrens * zpool destroy <pool> 801fa9e4066Sahrens * 802fa9e4066Sahrens * -f Forcefully unmount any datasets 803fa9e4066Sahrens * 804fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 805fa9e4066Sahrens */ 806fa9e4066Sahrens int 807fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 808fa9e4066Sahrens { 80999653d4eSeschrock boolean_t force = B_FALSE; 810fa9e4066Sahrens int c; 811fa9e4066Sahrens char *pool; 812fa9e4066Sahrens zpool_handle_t *zhp; 813fa9e4066Sahrens int ret; 814fa9e4066Sahrens 815fa9e4066Sahrens /* check options */ 816fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 817fa9e4066Sahrens switch (c) { 818fa9e4066Sahrens case 'f': 81999653d4eSeschrock force = B_TRUE; 820fa9e4066Sahrens break; 821fa9e4066Sahrens case '?': 822fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 823fa9e4066Sahrens optopt); 82499653d4eSeschrock usage(B_FALSE); 825fa9e4066Sahrens } 826fa9e4066Sahrens } 827fa9e4066Sahrens 828fa9e4066Sahrens argc -= optind; 829fa9e4066Sahrens argv += optind; 830fa9e4066Sahrens 831fa9e4066Sahrens /* check arguments */ 832fa9e4066Sahrens if (argc < 1) { 833fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 83499653d4eSeschrock usage(B_FALSE); 835fa9e4066Sahrens } 836fa9e4066Sahrens if (argc > 1) { 837fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 83899653d4eSeschrock usage(B_FALSE); 839fa9e4066Sahrens } 840fa9e4066Sahrens 841fa9e4066Sahrens pool = argv[0]; 842fa9e4066Sahrens 84399653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 844fa9e4066Sahrens /* 845fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 846fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 847fa9e4066Sahrens */ 848fa9e4066Sahrens if (strchr(pool, '/') != NULL) 849fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 850fa9e4066Sahrens "destroy a dataset\n")); 851fa9e4066Sahrens return (1); 852fa9e4066Sahrens } 853fa9e4066Sahrens 854f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 855fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 856fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 857fa9e4066Sahrens return (1); 858fa9e4066Sahrens } 859fa9e4066Sahrens 860fa9e4066Sahrens ret = (zpool_destroy(zhp) != 0); 861fa9e4066Sahrens 862fa9e4066Sahrens zpool_close(zhp); 863fa9e4066Sahrens 864fa9e4066Sahrens return (ret); 865fa9e4066Sahrens } 866fa9e4066Sahrens 867fa9e4066Sahrens /* 868fa9e4066Sahrens * zpool export [-f] <pool> ... 869fa9e4066Sahrens * 870fa9e4066Sahrens * -f Forcefully unmount datasets 871fa9e4066Sahrens * 872b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 873fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 874fa9e4066Sahrens * then the datasets will be forcefully unmounted. 875fa9e4066Sahrens */ 876fa9e4066Sahrens int 877fa9e4066Sahrens zpool_do_export(int argc, char **argv) 878fa9e4066Sahrens { 87999653d4eSeschrock boolean_t force = B_FALSE; 880394ab0cbSGeorge Wilson boolean_t hardforce = B_FALSE; 881fa9e4066Sahrens int c; 882fa9e4066Sahrens zpool_handle_t *zhp; 883fa9e4066Sahrens int ret; 884fa9e4066Sahrens int i; 885fa9e4066Sahrens 886fa9e4066Sahrens /* check options */ 887394ab0cbSGeorge Wilson while ((c = getopt(argc, argv, "fF")) != -1) { 888fa9e4066Sahrens switch (c) { 889fa9e4066Sahrens case 'f': 89099653d4eSeschrock force = B_TRUE; 891fa9e4066Sahrens break; 892394ab0cbSGeorge Wilson case 'F': 893394ab0cbSGeorge Wilson hardforce = B_TRUE; 894394ab0cbSGeorge Wilson break; 895fa9e4066Sahrens case '?': 896fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 897fa9e4066Sahrens optopt); 89899653d4eSeschrock usage(B_FALSE); 899fa9e4066Sahrens } 900fa9e4066Sahrens } 901fa9e4066Sahrens 902fa9e4066Sahrens argc -= optind; 903fa9e4066Sahrens argv += optind; 904fa9e4066Sahrens 905fa9e4066Sahrens /* check arguments */ 906fa9e4066Sahrens if (argc < 1) { 907fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 90899653d4eSeschrock usage(B_FALSE); 909fa9e4066Sahrens } 910fa9e4066Sahrens 911fa9e4066Sahrens ret = 0; 912fa9e4066Sahrens for (i = 0; i < argc; i++) { 91399653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 914fa9e4066Sahrens ret = 1; 915fa9e4066Sahrens continue; 916fa9e4066Sahrens } 917fa9e4066Sahrens 918f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 919fa9e4066Sahrens ret = 1; 920fa9e4066Sahrens zpool_close(zhp); 921fa9e4066Sahrens continue; 922fa9e4066Sahrens } 923fa9e4066Sahrens 924394ab0cbSGeorge Wilson if (hardforce) { 925394ab0cbSGeorge Wilson if (zpool_export_force(zhp) != 0) 926fa9e4066Sahrens ret = 1; 927394ab0cbSGeorge Wilson } else if (zpool_export(zhp, force) != 0) { 928394ab0cbSGeorge Wilson ret = 1; 929394ab0cbSGeorge Wilson } 930fa9e4066Sahrens 931fa9e4066Sahrens zpool_close(zhp); 932fa9e4066Sahrens } 933fa9e4066Sahrens 934fa9e4066Sahrens return (ret); 935fa9e4066Sahrens } 936fa9e4066Sahrens 937fa9e4066Sahrens /* 938fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 939fa9e4066Sahrens * name column. 940fa9e4066Sahrens */ 941fa9e4066Sahrens static int 942c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 943fa9e4066Sahrens { 94499653d4eSeschrock char *name = zpool_vdev_name(g_zfs, zhp, nv); 945fa9e4066Sahrens nvlist_t **child; 946fa9e4066Sahrens uint_t c, children; 947fa9e4066Sahrens int ret; 948fa9e4066Sahrens 949fa9e4066Sahrens if (strlen(name) + depth > max) 950fa9e4066Sahrens max = strlen(name) + depth; 951fa9e4066Sahrens 952afefbcddSeschrock free(name); 953afefbcddSeschrock 95499653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 95599653d4eSeschrock &child, &children) == 0) { 956fa9e4066Sahrens for (c = 0; c < children; c++) 95799653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 95899653d4eSeschrock max)) > max) 959fa9e4066Sahrens max = ret; 96099653d4eSeschrock } 96199653d4eSeschrock 962fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 963fa94a07fSbrendan &child, &children) == 0) { 964fa94a07fSbrendan for (c = 0; c < children; c++) 965fa94a07fSbrendan if ((ret = max_width(zhp, child[c], depth + 2, 966fa94a07fSbrendan max)) > max) 967fa94a07fSbrendan max = ret; 968fa94a07fSbrendan } 969fa94a07fSbrendan 97099653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 97199653d4eSeschrock &child, &children) == 0) { 97299653d4eSeschrock for (c = 0; c < children; c++) 97399653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 97499653d4eSeschrock max)) > max) 97599653d4eSeschrock max = ret; 97699653d4eSeschrock } 97799653d4eSeschrock 978fa9e4066Sahrens 979fa9e4066Sahrens return (max); 980fa9e4066Sahrens } 981fa9e4066Sahrens 982fa9e4066Sahrens 983fa9e4066Sahrens /* 984fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 985fa9e4066Sahrens * pool, printing out the name and status for each one. 986fa9e4066Sahrens */ 987fa9e4066Sahrens void 9888654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth, 9898654d025Sperrin boolean_t print_logs) 990fa9e4066Sahrens { 991fa9e4066Sahrens nvlist_t **child; 992fa9e4066Sahrens uint_t c, children; 993fa9e4066Sahrens vdev_stat_t *vs; 994afefbcddSeschrock char *type, *vname; 995fa9e4066Sahrens 996fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 997fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_MISSING) == 0) 998fa9e4066Sahrens return; 999fa9e4066Sahrens 1000fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 1001fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 1002fa9e4066Sahrens 1003fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1004990b4856Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1005fa9e4066Sahrens 1006fa9e4066Sahrens if (vs->vs_aux != 0) { 10073d7072f8Seschrock (void) printf(" "); 1008fa9e4066Sahrens 1009fa9e4066Sahrens switch (vs->vs_aux) { 1010fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 1011fa9e4066Sahrens (void) printf(gettext("cannot open")); 1012fa9e4066Sahrens break; 1013fa9e4066Sahrens 1014fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 1015fa9e4066Sahrens (void) printf(gettext("missing device")); 1016fa9e4066Sahrens break; 1017fa9e4066Sahrens 1018fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 1019fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 1020fa9e4066Sahrens break; 1021fa9e4066Sahrens 1022eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 1023eaca9bbdSeschrock (void) printf(gettext("newer version")); 1024eaca9bbdSeschrock break; 1025eaca9bbdSeschrock 10263d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 10273d7072f8Seschrock (void) printf(gettext("too many errors")); 10283d7072f8Seschrock break; 10293d7072f8Seschrock 1030fa9e4066Sahrens default: 1031fa9e4066Sahrens (void) printf(gettext("corrupted data")); 1032fa9e4066Sahrens break; 1033fa9e4066Sahrens } 1034fa9e4066Sahrens } 1035fa9e4066Sahrens (void) printf("\n"); 1036fa9e4066Sahrens 1037fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1038fa9e4066Sahrens &child, &children) != 0) 1039fa9e4066Sahrens return; 1040fa9e4066Sahrens 1041afefbcddSeschrock for (c = 0; c < children; c++) { 10428654d025Sperrin uint64_t is_log = B_FALSE; 10438654d025Sperrin 10448654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 10458654d025Sperrin &is_log); 10468654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 10478654d025Sperrin continue; 10488654d025Sperrin 104999653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1050afefbcddSeschrock print_import_config(vname, child[c], 10518654d025Sperrin namewidth, depth + 2, B_FALSE); 1052afefbcddSeschrock free(vname); 1053afefbcddSeschrock } 105499653d4eSeschrock 1055fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1056fa94a07fSbrendan &child, &children) == 0) { 1057fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 1058fa94a07fSbrendan for (c = 0; c < children; c++) { 1059fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1060fa94a07fSbrendan (void) printf("\t %s\n", vname); 1061fa94a07fSbrendan free(vname); 1062fa94a07fSbrendan } 1063fa94a07fSbrendan } 106499653d4eSeschrock 1065fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1066fa94a07fSbrendan &child, &children) == 0) { 106799653d4eSeschrock (void) printf(gettext("\tspares\n")); 106899653d4eSeschrock for (c = 0; c < children; c++) { 106999653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 107099653d4eSeschrock (void) printf("\t %s\n", vname); 107199653d4eSeschrock free(vname); 107299653d4eSeschrock } 1073fa9e4066Sahrens } 1074fa94a07fSbrendan } 1075fa9e4066Sahrens 1076fa9e4066Sahrens /* 1077fa9e4066Sahrens * Display the status for the given pool. 1078fa9e4066Sahrens */ 1079fa9e4066Sahrens static void 1080fa9e4066Sahrens show_import(nvlist_t *config) 1081fa9e4066Sahrens { 1082fa9e4066Sahrens uint64_t pool_state; 1083fa9e4066Sahrens vdev_stat_t *vs; 1084fa9e4066Sahrens char *name; 1085fa9e4066Sahrens uint64_t guid; 1086fa9e4066Sahrens char *msgid; 1087fa9e4066Sahrens nvlist_t *nvroot; 1088fa9e4066Sahrens int reason; 108946657f8dSmmusante const char *health; 1090fa9e4066Sahrens uint_t vsc; 1091fa9e4066Sahrens int namewidth; 1092fa9e4066Sahrens 1093fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1094fa9e4066Sahrens &name) == 0); 1095fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1096fa9e4066Sahrens &guid) == 0); 1097fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1098fa9e4066Sahrens &pool_state) == 0); 1099fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1100fa9e4066Sahrens &nvroot) == 0); 1101fa9e4066Sahrens 1102fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1103fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 1104990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1105fa9e4066Sahrens 1106fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1107fa9e4066Sahrens 110846657f8dSmmusante (void) printf(gettext(" pool: %s\n"), name); 110946657f8dSmmusante (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 111046657f8dSmmusante (void) printf(gettext(" state: %s"), health); 11114c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 111246657f8dSmmusante (void) printf(gettext(" (DESTROYED)")); 11134c58d714Sdarrenm (void) printf("\n"); 1114fa9e4066Sahrens 1115fa9e4066Sahrens switch (reason) { 1116fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1117fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1118fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 1119fa9e4066Sahrens (void) printf(gettext("status: One or more devices are missing " 1120fa9e4066Sahrens "from the system.\n")); 1121fa9e4066Sahrens break; 1122fa9e4066Sahrens 1123fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1124fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1125fa9e4066Sahrens (void) printf(gettext("status: One or more devices contains " 1126fa9e4066Sahrens "corrupted data.\n")); 1127fa9e4066Sahrens break; 1128fa9e4066Sahrens 1129fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 1130fa9e4066Sahrens (void) printf(gettext("status: The pool data is corrupted.\n")); 1131fa9e4066Sahrens break; 1132fa9e4066Sahrens 1133441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 1134441d80aaSlling (void) printf(gettext("status: One or more devices " 1135441d80aaSlling "are offlined.\n")); 1136441d80aaSlling break; 1137441d80aaSlling 1138ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 1139ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is " 1140ea8dc4b6Seschrock "corrupted.\n")); 1141ea8dc4b6Seschrock break; 1142ea8dc4b6Seschrock 1143eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 1144eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1145eaca9bbdSeschrock "older on-disk version.\n")); 1146eaca9bbdSeschrock break; 1147eaca9bbdSeschrock 1148eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1149eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1150eaca9bbdSeschrock "incompatible version.\n")); 1151eaca9bbdSeschrock break; 1152b87f3af3Sperrin 115395173954Sek110237 case ZPOOL_STATUS_HOSTID_MISMATCH: 115495173954Sek110237 (void) printf(gettext("status: The pool was last accessed by " 115595173954Sek110237 "another system.\n")); 115695173954Sek110237 break; 1157b87f3af3Sperrin 11583d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 11593d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 11603d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 11613d7072f8Seschrock "faulted.\n")); 11623d7072f8Seschrock break; 11633d7072f8Seschrock 1164b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 1165b87f3af3Sperrin (void) printf(gettext("status: An intent log record cannot be " 1166b87f3af3Sperrin "read.\n")); 1167b87f3af3Sperrin break; 1168b87f3af3Sperrin 1169fa9e4066Sahrens default: 1170fa9e4066Sahrens /* 1171fa9e4066Sahrens * No other status can be seen when importing pools. 1172fa9e4066Sahrens */ 1173fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1174fa9e4066Sahrens } 1175fa9e4066Sahrens 1176fa9e4066Sahrens /* 1177fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1178fa9e4066Sahrens */ 117946657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 1180eaca9bbdSeschrock if (reason == ZPOOL_STATUS_VERSION_OLDER) 1181eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1182eaca9bbdSeschrock "imported using its name or numeric identifier, " 1183eaca9bbdSeschrock "though\n\tsome features will not be available " 1184eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 118595173954Sek110237 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 118695173954Sek110237 (void) printf(gettext("action: The pool can be " 118795173954Sek110237 "imported using its name or numeric " 118895173954Sek110237 "identifier and\n\tthe '-f' flag.\n")); 1189fa9e4066Sahrens else 1190eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1191eaca9bbdSeschrock "imported using its name or numeric " 1192eaca9bbdSeschrock "identifier.\n")); 119346657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1194fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported " 1195fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1196eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1197fa9e4066Sahrens } else { 1198eaca9bbdSeschrock switch (reason) { 1199eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1200eaca9bbdSeschrock (void) printf(gettext("action: The pool cannot be " 1201eaca9bbdSeschrock "imported. Access the pool on a system running " 1202eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1203eaca9bbdSeschrock "backup.\n")); 1204eaca9bbdSeschrock break; 1205eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1206eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1207eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 1208fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1209fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1210fa9e4066Sahrens "again.\n")); 1211eaca9bbdSeschrock break; 1212eaca9bbdSeschrock default: 1213fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1214fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1215fa9e4066Sahrens } 1216eaca9bbdSeschrock } 1217eaca9bbdSeschrock 121846657f8dSmmusante /* 121946657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 122046657f8dSmmusante * is "corrupt data": 122146657f8dSmmusante */ 122246657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 122346657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 122446657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1225eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1226eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1227eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1228eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1229eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 123018ce54dfSek110237 "another system, but can be imported using\n\t" 1231eaca9bbdSeschrock "the '-f' flag.\n")); 1232eaca9bbdSeschrock } 1233fa9e4066Sahrens 1234fa9e4066Sahrens if (msgid != NULL) 1235fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1236fa9e4066Sahrens msgid); 1237fa9e4066Sahrens 1238fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 1239fa9e4066Sahrens 1240c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1241fa9e4066Sahrens if (namewidth < 10) 1242fa9e4066Sahrens namewidth = 10; 12438654d025Sperrin 12448654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_FALSE); 12458654d025Sperrin if (num_logs(nvroot) > 0) { 12468654d025Sperrin (void) printf(gettext("\tlogs\n")); 12478654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_TRUE); 12488654d025Sperrin } 1249fa9e4066Sahrens 1250fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 125146657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1252fa9e4066Sahrens "be part of this pool, though their\n\texact " 125346657f8dSmmusante "configuration cannot be determined.\n")); 1254fa9e4066Sahrens } 1255fa9e4066Sahrens } 1256fa9e4066Sahrens 1257fa9e4066Sahrens /* 1258fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1259990b4856Slling * lifting off to zpool_import_props(), and then mounts the datasets contained 1260990b4856Slling * within the pool. 1261fa9e4066Sahrens */ 1262fa9e4066Sahrens static int 1263fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 1264c5904d13Seschrock int force, nvlist_t *props, boolean_t allowfaulted) 1265fa9e4066Sahrens { 1266fa9e4066Sahrens zpool_handle_t *zhp; 1267fa9e4066Sahrens char *name; 1268fa9e4066Sahrens uint64_t state; 1269eaca9bbdSeschrock uint64_t version; 1270ecd6cf80Smarks int error = 0; 1271fa9e4066Sahrens 1272fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1273fa9e4066Sahrens &name) == 0); 1274fa9e4066Sahrens 1275fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1276fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1277eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1278eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1279e7437265Sahrens if (version > SPA_VERSION) { 1280eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1281eaca9bbdSeschrock "is formatted using a newer ZFS version\n"), name); 1282eaca9bbdSeschrock return (1); 1283eaca9bbdSeschrock } else if (state != POOL_STATE_EXPORTED && !force) { 128495173954Sek110237 uint64_t hostid; 128595173954Sek110237 128695173954Sek110237 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 128795173954Sek110237 &hostid) == 0) { 128895173954Sek110237 if ((unsigned long)hostid != gethostid()) { 128995173954Sek110237 char *hostname; 129095173954Sek110237 uint64_t timestamp; 129195173954Sek110237 time_t t; 129295173954Sek110237 129395173954Sek110237 verify(nvlist_lookup_string(config, 129495173954Sek110237 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 129595173954Sek110237 verify(nvlist_lookup_uint64(config, 129695173954Sek110237 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 129795173954Sek110237 t = timestamp; 129895173954Sek110237 (void) fprintf(stderr, gettext("cannot import " 129995173954Sek110237 "'%s': pool may be in use from other " 130095173954Sek110237 "system, it was last accessed by %s " 130195173954Sek110237 "(hostid: 0x%lx) on %s"), name, hostname, 130295173954Sek110237 (unsigned long)hostid, 130395173954Sek110237 asctime(localtime(&t))); 130495173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to " 130595173954Sek110237 "import anyway\n")); 1306fa9e4066Sahrens return (1); 1307fa9e4066Sahrens } 130895173954Sek110237 } else { 130995173954Sek110237 (void) fprintf(stderr, gettext("cannot import '%s': " 131095173954Sek110237 "pool may be in use from other system\n"), name); 131195173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to import " 131295173954Sek110237 "anyway\n")); 131395173954Sek110237 return (1); 131495173954Sek110237 } 131595173954Sek110237 } 1316fa9e4066Sahrens 1317c5904d13Seschrock if (zpool_import_props(g_zfs, config, newname, props, 1318c5904d13Seschrock allowfaulted) != 0) 1319fa9e4066Sahrens return (1); 1320fa9e4066Sahrens 1321fa9e4066Sahrens if (newname != NULL) 1322fa9e4066Sahrens name = (char *)newname; 1323fa9e4066Sahrens 1324c5904d13Seschrock verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL); 1325fa9e4066Sahrens 1326379c004dSEric Schrock if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1327379c004dSEric Schrock zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1328fa9e4066Sahrens zpool_close(zhp); 1329fa9e4066Sahrens return (1); 1330fa9e4066Sahrens } 1331fa9e4066Sahrens 1332fa9e4066Sahrens zpool_close(zhp); 1333ecd6cf80Smarks return (error); 1334fa9e4066Sahrens } 1335fa9e4066Sahrens 1336fa9e4066Sahrens /* 13374c58d714Sdarrenm * zpool import [-d dir] [-D] 13382f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 13392f8aaab3Seschrock * [-d dir | -c cachefile] [-f] -a 13402f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 13412f8aaab3Seschrock * [-d dir | -c cachefile] [-f] <pool | id> [newpool] 13422f8aaab3Seschrock * 13432f8aaab3Seschrock * -c Read pool information from a cachefile instead of searching 13442f8aaab3Seschrock * devices. 1345fa9e4066Sahrens * 1346fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1347fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1348fa9e4066Sahrens * 13494c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 13504c58d714Sdarrenm * specified destroyed pools. 13514c58d714Sdarrenm * 1352fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1353fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1354fa9e4066Sahrens * is rebooted. 1355fa9e4066Sahrens * 1356fa9e4066Sahrens * -f Force import, even if it appears that the pool is active. 1357fa9e4066Sahrens * 1358c5904d13Seschrock * -F Import even in the presence of faulted vdevs. This is an 1359c5904d13Seschrock * intentionally undocumented option for testing purposes, and 1360c5904d13Seschrock * treats the pool configuration as complete, leaving any bad 1361c5904d13Seschrock * vdevs in the FAULTED state. 1362c5904d13Seschrock * 1363fa9e4066Sahrens * -a Import all pools found. 1364fa9e4066Sahrens * 1365990b4856Slling * -o Set property=value and/or temporary mount options (without '='). 1366ecd6cf80Smarks * 1367fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 1368fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 1369fa9e4066Sahrens */ 1370fa9e4066Sahrens int 1371fa9e4066Sahrens zpool_do_import(int argc, char **argv) 1372fa9e4066Sahrens { 1373fa9e4066Sahrens char **searchdirs = NULL; 1374fa9e4066Sahrens int nsearch = 0; 1375fa9e4066Sahrens int c; 1376fa9e4066Sahrens int err; 13772f8aaab3Seschrock nvlist_t *pools = NULL; 137899653d4eSeschrock boolean_t do_all = B_FALSE; 137999653d4eSeschrock boolean_t do_destroyed = B_FALSE; 1380fa9e4066Sahrens char *mntopts = NULL; 138199653d4eSeschrock boolean_t do_force = B_FALSE; 1382fa9e4066Sahrens nvpair_t *elem; 1383fa9e4066Sahrens nvlist_t *config; 138424e697d4Sck153898 uint64_t searchguid = 0; 138524e697d4Sck153898 char *searchname = NULL; 1386990b4856Slling char *propval; 1387fa9e4066Sahrens nvlist_t *found_config; 1388ecd6cf80Smarks nvlist_t *props = NULL; 138999653d4eSeschrock boolean_t first; 1390c5904d13Seschrock boolean_t allow_faulted = B_FALSE; 13914c58d714Sdarrenm uint64_t pool_state; 13922f8aaab3Seschrock char *cachefile = NULL; 1393fa9e4066Sahrens 1394fa9e4066Sahrens /* check options */ 1395c5904d13Seschrock while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) { 1396fa9e4066Sahrens switch (c) { 1397fa9e4066Sahrens case 'a': 139899653d4eSeschrock do_all = B_TRUE; 1399fa9e4066Sahrens break; 14002f8aaab3Seschrock case 'c': 14012f8aaab3Seschrock cachefile = optarg; 14022f8aaab3Seschrock break; 1403fa9e4066Sahrens case 'd': 1404fa9e4066Sahrens if (searchdirs == NULL) { 1405fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1406fa9e4066Sahrens } else { 1407fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 1408fa9e4066Sahrens sizeof (char *)); 1409fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 1410fa9e4066Sahrens sizeof (char *)); 1411fa9e4066Sahrens free(searchdirs); 1412fa9e4066Sahrens searchdirs = tmp; 1413fa9e4066Sahrens } 1414fa9e4066Sahrens searchdirs[nsearch++] = optarg; 1415fa9e4066Sahrens break; 14164c58d714Sdarrenm case 'D': 141799653d4eSeschrock do_destroyed = B_TRUE; 14184c58d714Sdarrenm break; 1419fa9e4066Sahrens case 'f': 142099653d4eSeschrock do_force = B_TRUE; 1421fa9e4066Sahrens break; 1422c5904d13Seschrock case 'F': 1423c5904d13Seschrock allow_faulted = B_TRUE; 1424c5904d13Seschrock break; 1425fa9e4066Sahrens case 'o': 1426990b4856Slling if ((propval = strchr(optarg, '=')) != NULL) { 1427990b4856Slling *propval = '\0'; 1428990b4856Slling propval++; 14290a48a24eStimh if (add_prop_list(optarg, propval, 14300a48a24eStimh &props, B_TRUE)) 1431990b4856Slling goto error; 1432990b4856Slling } else { 1433fa9e4066Sahrens mntopts = optarg; 1434990b4856Slling } 1435fa9e4066Sahrens break; 1436fa9e4066Sahrens case 'R': 1437990b4856Slling if (add_prop_list(zpool_prop_to_name( 14380a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 1439990b4856Slling goto error; 14402f8aaab3Seschrock if (nvlist_lookup_string(props, 14412f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 14422f8aaab3Seschrock &propval) == 0) 14432f8aaab3Seschrock break; 1444990b4856Slling if (add_prop_list(zpool_prop_to_name( 14450a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1446990b4856Slling goto error; 1447fa9e4066Sahrens break; 1448fa9e4066Sahrens case ':': 1449fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 1450fa9e4066Sahrens "'%c' option\n"), optopt); 145199653d4eSeschrock usage(B_FALSE); 1452fa9e4066Sahrens break; 1453fa9e4066Sahrens case '?': 1454fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1455fa9e4066Sahrens optopt); 145699653d4eSeschrock usage(B_FALSE); 1457fa9e4066Sahrens } 1458fa9e4066Sahrens } 1459fa9e4066Sahrens 1460fa9e4066Sahrens argc -= optind; 1461fa9e4066Sahrens argv += optind; 1462fa9e4066Sahrens 14632f8aaab3Seschrock if (cachefile && nsearch != 0) { 14642f8aaab3Seschrock (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 14652f8aaab3Seschrock usage(B_FALSE); 14662f8aaab3Seschrock } 14672f8aaab3Seschrock 1468fa9e4066Sahrens if (searchdirs == NULL) { 1469fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1470fa9e4066Sahrens searchdirs[0] = "/dev/dsk"; 1471fa9e4066Sahrens nsearch = 1; 1472fa9e4066Sahrens } 1473fa9e4066Sahrens 1474fa9e4066Sahrens /* check argument count */ 1475fa9e4066Sahrens if (do_all) { 1476fa9e4066Sahrens if (argc != 0) { 1477fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 147899653d4eSeschrock usage(B_FALSE); 1479fa9e4066Sahrens } 1480fa9e4066Sahrens } else { 1481fa9e4066Sahrens if (argc > 2) { 1482fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 148399653d4eSeschrock usage(B_FALSE); 1484fa9e4066Sahrens } 1485fa9e4066Sahrens 1486fa9e4066Sahrens /* 1487fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 1488fa9e4066Sahrens * here because otherwise any attempt to discover pools will 1489fa9e4066Sahrens * silently fail. 1490fa9e4066Sahrens */ 1491fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1492fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 1493fa9e4066Sahrens "discover pools: permission denied\n")); 149499653d4eSeschrock free(searchdirs); 1495fa9e4066Sahrens return (1); 1496fa9e4066Sahrens } 1497fa9e4066Sahrens } 1498fa9e4066Sahrens 1499fa9e4066Sahrens /* 1500fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 1501fa9e4066Sahrens * 1502fa9e4066Sahrens * <none> Iterate through all pools and display information about 1503fa9e4066Sahrens * each one. 1504fa9e4066Sahrens * 1505fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 1506fa9e4066Sahrens * 1507fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 1508fa9e4066Sahrens * name and import that one. 15094c58d714Sdarrenm * 15104c58d714Sdarrenm * -D Above options applies only to destroyed pools. 1511fa9e4066Sahrens */ 1512fa9e4066Sahrens if (argc != 0) { 1513fa9e4066Sahrens char *endptr; 1514fa9e4066Sahrens 1515fa9e4066Sahrens errno = 0; 1516fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 1517fa9e4066Sahrens if (errno != 0 || *endptr != '\0') 1518fa9e4066Sahrens searchname = argv[0]; 1519fa9e4066Sahrens found_config = NULL; 1520fa9e4066Sahrens } 1521fa9e4066Sahrens 152224e697d4Sck153898 if (cachefile) { 1523e829d913Sck153898 pools = zpool_find_import_cached(g_zfs, cachefile, searchname, 1524e829d913Sck153898 searchguid); 152524e697d4Sck153898 } else if (searchname != NULL) { 152624e697d4Sck153898 pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs, 152724e697d4Sck153898 searchname); 152824e697d4Sck153898 } else { 152924e697d4Sck153898 /* 153024e697d4Sck153898 * It's OK to search by guid even if searchguid is 0. 153124e697d4Sck153898 */ 153224e697d4Sck153898 pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs, 153324e697d4Sck153898 searchguid); 153424e697d4Sck153898 } 153524e697d4Sck153898 153624e697d4Sck153898 if (pools == NULL) { 153724e697d4Sck153898 if (argc != 0) { 153824e697d4Sck153898 (void) fprintf(stderr, gettext("cannot import '%s': " 153924e697d4Sck153898 "no such pool available\n"), argv[0]); 154024e697d4Sck153898 } 154124e697d4Sck153898 free(searchdirs); 154224e697d4Sck153898 return (1); 154324e697d4Sck153898 } 154424e697d4Sck153898 154524e697d4Sck153898 /* 154624e697d4Sck153898 * At this point we have a list of import candidate configs. Even if 154724e697d4Sck153898 * we were searching by pool name or guid, we still need to 154824e697d4Sck153898 * post-process the list to deal with pool state and possible 154924e697d4Sck153898 * duplicate names. 155024e697d4Sck153898 */ 1551fa9e4066Sahrens err = 0; 1552fa9e4066Sahrens elem = NULL; 155399653d4eSeschrock first = B_TRUE; 1554fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1555fa9e4066Sahrens 1556fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 1557fa9e4066Sahrens 15584c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 15594c58d714Sdarrenm &pool_state) == 0); 15604c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 15614c58d714Sdarrenm continue; 15624c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 15634c58d714Sdarrenm continue; 15644c58d714Sdarrenm 1565fa9e4066Sahrens if (argc == 0) { 1566fa9e4066Sahrens if (first) 156799653d4eSeschrock first = B_FALSE; 15683bb79becSeschrock else if (!do_all) 1569fa9e4066Sahrens (void) printf("\n"); 1570fa9e4066Sahrens 1571fa9e4066Sahrens if (do_all) 1572fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 1573c5904d13Seschrock do_force, props, allow_faulted); 1574fa9e4066Sahrens else 1575fa9e4066Sahrens show_import(config); 1576fa9e4066Sahrens } else if (searchname != NULL) { 1577fa9e4066Sahrens char *name; 1578fa9e4066Sahrens 1579fa9e4066Sahrens /* 1580fa9e4066Sahrens * We are searching for a pool based on name. 1581fa9e4066Sahrens */ 1582fa9e4066Sahrens verify(nvlist_lookup_string(config, 1583fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1584fa9e4066Sahrens 1585fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 1586fa9e4066Sahrens if (found_config != NULL) { 1587fa9e4066Sahrens (void) fprintf(stderr, gettext( 1588fa9e4066Sahrens "cannot import '%s': more than " 1589fa9e4066Sahrens "one matching pool\n"), searchname); 1590fa9e4066Sahrens (void) fprintf(stderr, gettext( 1591fa9e4066Sahrens "import by numeric ID instead\n")); 159299653d4eSeschrock err = B_TRUE; 1593fa9e4066Sahrens } 1594fa9e4066Sahrens found_config = config; 1595fa9e4066Sahrens } 1596fa9e4066Sahrens } else { 1597fa9e4066Sahrens uint64_t guid; 1598fa9e4066Sahrens 1599fa9e4066Sahrens /* 1600fa9e4066Sahrens * Search for a pool by guid. 1601fa9e4066Sahrens */ 1602fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1603fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1604fa9e4066Sahrens 1605fa9e4066Sahrens if (guid == searchguid) 1606fa9e4066Sahrens found_config = config; 1607fa9e4066Sahrens } 1608fa9e4066Sahrens } 1609fa9e4066Sahrens 1610fa9e4066Sahrens /* 1611fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 1612fa9e4066Sahrens * pool, and then do the import. 1613fa9e4066Sahrens */ 1614fa9e4066Sahrens if (argc != 0 && err == 0) { 1615fa9e4066Sahrens if (found_config == NULL) { 1616fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 1617fa9e4066Sahrens "no such pool available\n"), argv[0]); 161899653d4eSeschrock err = B_TRUE; 1619fa9e4066Sahrens } else { 1620fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 1621c5904d13Seschrock argv[1], mntopts, do_force, props, allow_faulted); 1622fa9e4066Sahrens } 1623fa9e4066Sahrens } 1624fa9e4066Sahrens 1625fa9e4066Sahrens /* 1626fa9e4066Sahrens * If we were just looking for pools, report an error if none were 1627fa9e4066Sahrens * found. 1628fa9e4066Sahrens */ 1629fa9e4066Sahrens if (argc == 0 && first) 1630fa9e4066Sahrens (void) fprintf(stderr, 1631fa9e4066Sahrens gettext("no pools available to import\n")); 1632fa9e4066Sahrens 1633ecd6cf80Smarks error: 1634ecd6cf80Smarks nvlist_free(props); 1635fa9e4066Sahrens nvlist_free(pools); 163699653d4eSeschrock free(searchdirs); 1637fa9e4066Sahrens 1638fa9e4066Sahrens return (err ? 1 : 0); 1639fa9e4066Sahrens } 1640fa9e4066Sahrens 1641fa9e4066Sahrens typedef struct iostat_cbdata { 1642fa9e4066Sahrens zpool_list_t *cb_list; 1643fa9e4066Sahrens int cb_verbose; 1644fa9e4066Sahrens int cb_iteration; 1645fa9e4066Sahrens int cb_namewidth; 1646fa9e4066Sahrens } iostat_cbdata_t; 1647fa9e4066Sahrens 1648fa9e4066Sahrens static void 1649fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 1650fa9e4066Sahrens { 1651fa9e4066Sahrens int i = 0; 1652fa9e4066Sahrens 1653fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 1654fa9e4066Sahrens (void) printf("-"); 1655fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1656fa9e4066Sahrens } 1657fa9e4066Sahrens 1658fa9e4066Sahrens static void 1659fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 1660fa9e4066Sahrens { 1661fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 1662fa9e4066Sahrens cb->cb_namewidth, ""); 1663fa9e4066Sahrens (void) printf("%-*s used avail read write read write\n", 1664fa9e4066Sahrens cb->cb_namewidth, "pool"); 1665fa9e4066Sahrens print_iostat_separator(cb); 1666fa9e4066Sahrens } 1667fa9e4066Sahrens 1668fa9e4066Sahrens /* 1669fa9e4066Sahrens * Display a single statistic. 1670fa9e4066Sahrens */ 1671990b4856Slling static void 1672fa9e4066Sahrens print_one_stat(uint64_t value) 1673fa9e4066Sahrens { 1674fa9e4066Sahrens char buf[64]; 1675fa9e4066Sahrens 1676fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 1677fa9e4066Sahrens (void) printf(" %5s", buf); 1678fa9e4066Sahrens } 1679fa9e4066Sahrens 1680fa9e4066Sahrens /* 1681fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 1682fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 1683fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 1684fa9e4066Sahrens */ 1685fa9e4066Sahrens void 1686c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1687c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1688fa9e4066Sahrens { 1689fa9e4066Sahrens nvlist_t **oldchild, **newchild; 1690fa9e4066Sahrens uint_t c, children; 1691fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 1692fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 1693fa9e4066Sahrens uint64_t tdelta; 1694fa9e4066Sahrens double scale; 1695afefbcddSeschrock char *vname; 1696fa9e4066Sahrens 1697fa9e4066Sahrens if (oldnv != NULL) { 1698fa9e4066Sahrens verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1699fa9e4066Sahrens (uint64_t **)&oldvs, &c) == 0); 1700fa9e4066Sahrens } else { 1701fa9e4066Sahrens oldvs = &zerovs; 1702fa9e4066Sahrens } 1703fa9e4066Sahrens 1704fa9e4066Sahrens verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1705fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 1706fa9e4066Sahrens 1707fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 1708fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 1709fa9e4066Sahrens else 1710fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 1711fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1712fa9e4066Sahrens 1713fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1714fa9e4066Sahrens 1715fa9e4066Sahrens if (tdelta == 0) 1716fa9e4066Sahrens scale = 1.0; 1717fa9e4066Sahrens else 1718fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 1719fa9e4066Sahrens 1720fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 1721fa9e4066Sahrens if (newvs->vs_space == 0) { 1722fa9e4066Sahrens (void) printf(" - -"); 1723fa9e4066Sahrens } else { 1724fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 1725fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 1726fa9e4066Sahrens } 1727fa9e4066Sahrens 1728fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1729fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 1730fa9e4066Sahrens 1731fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1732fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1733fa9e4066Sahrens 1734fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1735fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 1736fa9e4066Sahrens 1737fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1738fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1739fa9e4066Sahrens 1740fa9e4066Sahrens (void) printf("\n"); 1741fa9e4066Sahrens 1742fa9e4066Sahrens if (!cb->cb_verbose) 1743fa9e4066Sahrens return; 1744fa9e4066Sahrens 1745fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1746fa9e4066Sahrens &newchild, &children) != 0) 1747fa9e4066Sahrens return; 1748fa9e4066Sahrens 1749fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1750fa9e4066Sahrens &oldchild, &c) != 0) 1751fa9e4066Sahrens return; 1752fa9e4066Sahrens 1753afefbcddSeschrock for (c = 0; c < children; c++) { 175499653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1755c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1756afefbcddSeschrock newchild[c], cb, depth + 2); 1757afefbcddSeschrock free(vname); 1758afefbcddSeschrock } 1759fa94a07fSbrendan 1760fa94a07fSbrendan /* 1761fa94a07fSbrendan * Include level 2 ARC devices in iostat output 1762fa94a07fSbrendan */ 1763fa94a07fSbrendan if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 1764fa94a07fSbrendan &newchild, &children) != 0) 1765fa94a07fSbrendan return; 1766fa94a07fSbrendan 1767fa94a07fSbrendan if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 1768fa94a07fSbrendan &oldchild, &c) != 0) 1769fa94a07fSbrendan return; 1770fa94a07fSbrendan 1771fa94a07fSbrendan if (children > 0) { 1772fa94a07fSbrendan (void) printf("%-*s - - - - - " 1773fa94a07fSbrendan "-\n", cb->cb_namewidth, "cache"); 1774fa94a07fSbrendan for (c = 0; c < children; c++) { 1775fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1776fa94a07fSbrendan print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1777fa94a07fSbrendan newchild[c], cb, depth + 2); 1778fa94a07fSbrendan free(vname); 1779fa94a07fSbrendan } 1780fa94a07fSbrendan } 1781fa9e4066Sahrens } 1782fa9e4066Sahrens 1783088e9d47Seschrock static int 1784088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 1785088e9d47Seschrock { 1786088e9d47Seschrock iostat_cbdata_t *cb = data; 178794de1d4cSeschrock boolean_t missing; 1788088e9d47Seschrock 1789088e9d47Seschrock /* 1790088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 1791088e9d47Seschrock */ 179294de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 179394de1d4cSeschrock return (-1); 179494de1d4cSeschrock 179594de1d4cSeschrock if (missing) 1796088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 1797088e9d47Seschrock 1798088e9d47Seschrock return (0); 1799088e9d47Seschrock } 1800088e9d47Seschrock 1801fa9e4066Sahrens /* 1802fa9e4066Sahrens * Callback to print out the iostats for the given pool. 1803fa9e4066Sahrens */ 1804fa9e4066Sahrens int 1805fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 1806fa9e4066Sahrens { 1807fa9e4066Sahrens iostat_cbdata_t *cb = data; 1808fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 1809fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 1810fa9e4066Sahrens 1811088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 1812fa9e4066Sahrens 1813088e9d47Seschrock if (cb->cb_iteration == 1) 1814fa9e4066Sahrens oldconfig = NULL; 1815fa9e4066Sahrens 1816fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1817fa9e4066Sahrens &newnvroot) == 0); 1818fa9e4066Sahrens 1819088e9d47Seschrock if (oldconfig == NULL) 1820fa9e4066Sahrens oldnvroot = NULL; 1821088e9d47Seschrock else 1822088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 1823088e9d47Seschrock &oldnvroot) == 0); 1824fa9e4066Sahrens 1825fa9e4066Sahrens /* 1826fa9e4066Sahrens * Print out the statistics for the pool. 1827fa9e4066Sahrens */ 1828c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1829fa9e4066Sahrens 1830fa9e4066Sahrens if (cb->cb_verbose) 1831fa9e4066Sahrens print_iostat_separator(cb); 1832fa9e4066Sahrens 1833fa9e4066Sahrens return (0); 1834fa9e4066Sahrens } 1835fa9e4066Sahrens 1836fa9e4066Sahrens int 1837fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 1838fa9e4066Sahrens { 1839fa9e4066Sahrens iostat_cbdata_t *cb = data; 1840fa9e4066Sahrens nvlist_t *config, *nvroot; 1841fa9e4066Sahrens 1842088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 1843fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1844fa9e4066Sahrens &nvroot) == 0); 1845fa9e4066Sahrens if (!cb->cb_verbose) 1846fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1847fa9e4066Sahrens else 1848c67d9675Seschrock cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 1849fa9e4066Sahrens } 1850fa9e4066Sahrens 1851fa9e4066Sahrens /* 1852fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 1853fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 1854fa9e4066Sahrens */ 1855fa9e4066Sahrens if (cb->cb_namewidth < 10) 1856fa9e4066Sahrens cb->cb_namewidth = 10; 1857fa9e4066Sahrens if (cb->cb_namewidth > 38) 1858fa9e4066Sahrens cb->cb_namewidth = 38; 1859fa9e4066Sahrens 1860fa9e4066Sahrens return (0); 1861fa9e4066Sahrens } 1862fa9e4066Sahrens 1863fa9e4066Sahrens /* 1864fa9e4066Sahrens * zpool iostat [-v] [pool] ... [interval [count]] 1865fa9e4066Sahrens * 1866fa9e4066Sahrens * -v Display statistics for individual vdevs 1867fa9e4066Sahrens * 1868fa9e4066Sahrens * This command can be tricky because we want to be able to deal with pool 1869fa9e4066Sahrens * creation/destruction as well as vdev configuration changes. The bulk of this 1870fa9e4066Sahrens * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1871fa9e4066Sahrens * on pool_list_update() to detect the addition of new pools. Configuration 1872fa9e4066Sahrens * changes are all handled within libzfs. 1873fa9e4066Sahrens */ 1874fa9e4066Sahrens int 1875fa9e4066Sahrens zpool_do_iostat(int argc, char **argv) 1876fa9e4066Sahrens { 1877fa9e4066Sahrens int c; 1878fa9e4066Sahrens int ret; 1879fa9e4066Sahrens int npools; 1880fa9e4066Sahrens unsigned long interval = 0, count = 0; 1881fa9e4066Sahrens zpool_list_t *list; 188299653d4eSeschrock boolean_t verbose = B_FALSE; 1883fa9e4066Sahrens iostat_cbdata_t cb; 1884fa9e4066Sahrens 1885fa9e4066Sahrens /* check options */ 1886fa9e4066Sahrens while ((c = getopt(argc, argv, "v")) != -1) { 1887fa9e4066Sahrens switch (c) { 1888fa9e4066Sahrens case 'v': 188999653d4eSeschrock verbose = B_TRUE; 1890fa9e4066Sahrens break; 1891fa9e4066Sahrens case '?': 1892fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1893fa9e4066Sahrens optopt); 189499653d4eSeschrock usage(B_FALSE); 1895fa9e4066Sahrens } 1896fa9e4066Sahrens } 1897fa9e4066Sahrens 1898fa9e4066Sahrens argc -= optind; 1899fa9e4066Sahrens argv += optind; 1900fa9e4066Sahrens 1901fa9e4066Sahrens /* 1902fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 1903fa9e4066Sahrens */ 1904fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1905fa9e4066Sahrens char *end; 1906fa9e4066Sahrens 1907fa9e4066Sahrens errno = 0; 1908fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1909fa9e4066Sahrens 1910fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1911fa9e4066Sahrens if (interval == 0) { 1912fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1913fa9e4066Sahrens "cannot be zero\n")); 191499653d4eSeschrock usage(B_FALSE); 1915fa9e4066Sahrens } 1916fa9e4066Sahrens 1917fa9e4066Sahrens /* 1918fa9e4066Sahrens * Ignore the last parameter 1919fa9e4066Sahrens */ 1920fa9e4066Sahrens argc--; 1921fa9e4066Sahrens } else { 1922fa9e4066Sahrens /* 1923fa9e4066Sahrens * If this is not a valid number, just plow on. The 1924fa9e4066Sahrens * user will get a more informative error message later 1925fa9e4066Sahrens * on. 1926fa9e4066Sahrens */ 1927fa9e4066Sahrens interval = 0; 1928fa9e4066Sahrens } 1929fa9e4066Sahrens } 1930fa9e4066Sahrens 1931fa9e4066Sahrens /* 1932fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 1933fa9e4066Sahrens * and an integer. 1934fa9e4066Sahrens */ 1935fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1936fa9e4066Sahrens char *end; 1937fa9e4066Sahrens 1938fa9e4066Sahrens errno = 0; 1939fa9e4066Sahrens count = interval; 1940fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1941fa9e4066Sahrens 1942fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1943fa9e4066Sahrens if (interval == 0) { 1944fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1945fa9e4066Sahrens "cannot be zero\n")); 194699653d4eSeschrock usage(B_FALSE); 1947fa9e4066Sahrens } 1948fa9e4066Sahrens 1949fa9e4066Sahrens /* 1950fa9e4066Sahrens * Ignore the last parameter 1951fa9e4066Sahrens */ 1952fa9e4066Sahrens argc--; 1953fa9e4066Sahrens } else { 1954fa9e4066Sahrens interval = 0; 1955fa9e4066Sahrens } 1956fa9e4066Sahrens } 1957fa9e4066Sahrens 1958fa9e4066Sahrens /* 1959fa9e4066Sahrens * Construct the list of all interesting pools. 1960fa9e4066Sahrens */ 1961fa9e4066Sahrens ret = 0; 1962b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 1963fa9e4066Sahrens return (1); 1964fa9e4066Sahrens 196599653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 196699653d4eSeschrock pool_list_free(list); 1967fa9e4066Sahrens return (1); 196899653d4eSeschrock } 1969fa9e4066Sahrens 1970fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 197199653d4eSeschrock pool_list_free(list); 1972fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 1973fa9e4066Sahrens return (1); 1974fa9e4066Sahrens } 1975fa9e4066Sahrens 1976fa9e4066Sahrens /* 1977fa9e4066Sahrens * Enter the main iostat loop. 1978fa9e4066Sahrens */ 1979fa9e4066Sahrens cb.cb_list = list; 1980fa9e4066Sahrens cb.cb_verbose = verbose; 1981fa9e4066Sahrens cb.cb_iteration = 0; 1982fa9e4066Sahrens cb.cb_namewidth = 0; 1983fa9e4066Sahrens 1984fa9e4066Sahrens for (;;) { 1985fa9e4066Sahrens pool_list_update(list); 1986fa9e4066Sahrens 1987fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 1988fa9e4066Sahrens break; 1989fa9e4066Sahrens 1990fa9e4066Sahrens /* 1991088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 1992088e9d47Seschrock * before calculating the maximum name width, so that any 1993088e9d47Seschrock * configuration changes are properly accounted for. 1994088e9d47Seschrock */ 199599653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 1996088e9d47Seschrock 1997088e9d47Seschrock /* 1998fa9e4066Sahrens * Iterate over all pools to determine the maximum width 1999fa9e4066Sahrens * for the pool / device name column across all pools. 2000fa9e4066Sahrens */ 2001fa9e4066Sahrens cb.cb_namewidth = 0; 200299653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2003fa9e4066Sahrens 2004fa9e4066Sahrens /* 2005fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 2006fa9e4066Sahrens */ 2007fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 2008fa9e4066Sahrens print_iostat_header(&cb); 2009fa9e4066Sahrens 201099653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2011fa9e4066Sahrens 2012fa9e4066Sahrens /* 2013fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 2014fa9e4066Sahrens * (which prints a separator for us), then print a separator. 2015fa9e4066Sahrens */ 2016fa9e4066Sahrens if (npools > 1 && !verbose) 2017fa9e4066Sahrens print_iostat_separator(&cb); 2018fa9e4066Sahrens 2019fa9e4066Sahrens if (verbose) 2020fa9e4066Sahrens (void) printf("\n"); 2021fa9e4066Sahrens 202239c23413Seschrock /* 202339c23413Seschrock * Flush the output so that redirection to a file isn't buffered 202439c23413Seschrock * indefinitely. 202539c23413Seschrock */ 202639c23413Seschrock (void) fflush(stdout); 202739c23413Seschrock 2028fa9e4066Sahrens if (interval == 0) 2029fa9e4066Sahrens break; 2030fa9e4066Sahrens 2031fa9e4066Sahrens if (count != 0 && --count == 0) 2032fa9e4066Sahrens break; 2033fa9e4066Sahrens 2034fa9e4066Sahrens (void) sleep(interval); 2035fa9e4066Sahrens } 2036fa9e4066Sahrens 2037fa9e4066Sahrens pool_list_free(list); 2038fa9e4066Sahrens 2039fa9e4066Sahrens return (ret); 2040fa9e4066Sahrens } 2041fa9e4066Sahrens 2042fa9e4066Sahrens typedef struct list_cbdata { 204399653d4eSeschrock boolean_t cb_scripted; 204499653d4eSeschrock boolean_t cb_first; 2045990b4856Slling zprop_list_t *cb_proplist; 2046fa9e4066Sahrens } list_cbdata_t; 2047fa9e4066Sahrens 2048fa9e4066Sahrens /* 2049fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 2050fa9e4066Sahrens */ 2051990b4856Slling static void 2052990b4856Slling print_header(zprop_list_t *pl) 2053fa9e4066Sahrens { 2054990b4856Slling const char *header; 2055990b4856Slling boolean_t first = B_TRUE; 2056990b4856Slling boolean_t right_justify; 2057fa9e4066Sahrens 2058990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 2059990b4856Slling if (pl->pl_prop == ZPROP_INVAL) 2060990b4856Slling continue; 2061990b4856Slling 2062990b4856Slling if (!first) 2063fa9e4066Sahrens (void) printf(" "); 2064fa9e4066Sahrens else 2065990b4856Slling first = B_FALSE; 2066fa9e4066Sahrens 2067990b4856Slling header = zpool_prop_column_name(pl->pl_prop); 2068990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2069990b4856Slling 2070990b4856Slling if (pl->pl_next == NULL && !right_justify) 2071990b4856Slling (void) printf("%s", header); 2072990b4856Slling else if (right_justify) 2073990b4856Slling (void) printf("%*s", pl->pl_width, header); 2074990b4856Slling else 2075990b4856Slling (void) printf("%-*s", pl->pl_width, header); 2076fa9e4066Sahrens } 2077fa9e4066Sahrens 2078fa9e4066Sahrens (void) printf("\n"); 2079fa9e4066Sahrens } 2080fa9e4066Sahrens 2081990b4856Slling /* 2082990b4856Slling * Given a pool and a list of properties, print out all the properties according 2083990b4856Slling * to the described layout. 2084990b4856Slling */ 2085990b4856Slling static void 2086990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 2087990b4856Slling { 2088990b4856Slling boolean_t first = B_TRUE; 2089990b4856Slling char property[ZPOOL_MAXPROPLEN]; 2090990b4856Slling char *propstr; 2091990b4856Slling boolean_t right_justify; 2092990b4856Slling int width; 2093990b4856Slling 2094990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 2095990b4856Slling if (!first) { 2096990b4856Slling if (scripted) 2097990b4856Slling (void) printf("\t"); 2098990b4856Slling else 2099990b4856Slling (void) printf(" "); 2100990b4856Slling } else { 2101990b4856Slling first = B_FALSE; 2102990b4856Slling } 2103990b4856Slling 2104990b4856Slling right_justify = B_FALSE; 2105990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 2106990b4856Slling if (zpool_get_prop(zhp, pl->pl_prop, property, 2107990b4856Slling sizeof (property), NULL) != 0) 2108990b4856Slling propstr = "-"; 2109990b4856Slling else 2110990b4856Slling propstr = property; 2111990b4856Slling 2112990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2113990b4856Slling } else { 2114990b4856Slling propstr = "-"; 2115990b4856Slling } 2116990b4856Slling 2117990b4856Slling width = pl->pl_width; 2118990b4856Slling 2119990b4856Slling /* 2120990b4856Slling * If this is being called in scripted mode, or if this is the 2121990b4856Slling * last column and it is left-justified, don't include a width 2122990b4856Slling * format specifier. 2123990b4856Slling */ 2124990b4856Slling if (scripted || (pl->pl_next == NULL && !right_justify)) 2125990b4856Slling (void) printf("%s", propstr); 2126990b4856Slling else if (right_justify) 2127990b4856Slling (void) printf("%*s", width, propstr); 2128990b4856Slling else 2129990b4856Slling (void) printf("%-*s", width, propstr); 2130990b4856Slling } 2131990b4856Slling 2132990b4856Slling (void) printf("\n"); 2133990b4856Slling } 2134990b4856Slling 2135990b4856Slling /* 2136990b4856Slling * Generic callback function to list a pool. 2137990b4856Slling */ 2138fa9e4066Sahrens int 2139fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data) 2140fa9e4066Sahrens { 2141fa9e4066Sahrens list_cbdata_t *cbp = data; 2142fa9e4066Sahrens 2143fa9e4066Sahrens if (cbp->cb_first) { 2144fa9e4066Sahrens if (!cbp->cb_scripted) 2145990b4856Slling print_header(cbp->cb_proplist); 214699653d4eSeschrock cbp->cb_first = B_FALSE; 2147fa9e4066Sahrens } 2148fa9e4066Sahrens 2149990b4856Slling print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2150fa9e4066Sahrens 2151fa9e4066Sahrens return (0); 2152fa9e4066Sahrens } 2153fa9e4066Sahrens 2154fa9e4066Sahrens /* 2155990b4856Slling * zpool list [-H] [-o prop[,prop]*] [pool] ... 2156fa9e4066Sahrens * 2157990b4856Slling * -H Scripted mode. Don't display headers, and separate properties 2158990b4856Slling * by a single tab. 2159990b4856Slling * -o List of properties to display. Defaults to 2160990b4856Slling * "name,size,used,available,capacity,health,altroot" 2161fa9e4066Sahrens * 2162fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 2163fa9e4066Sahrens * statistics for each one, as well as health status summary. 2164fa9e4066Sahrens */ 2165fa9e4066Sahrens int 2166fa9e4066Sahrens zpool_do_list(int argc, char **argv) 2167fa9e4066Sahrens { 2168fa9e4066Sahrens int c; 2169fa9e4066Sahrens int ret; 2170fa9e4066Sahrens list_cbdata_t cb = { 0 }; 2171990b4856Slling static char default_props[] = 2172990b4856Slling "name,size,used,available,capacity,health,altroot"; 2173990b4856Slling char *props = default_props; 2174fa9e4066Sahrens 2175fa9e4066Sahrens /* check options */ 2176fa9e4066Sahrens while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2177fa9e4066Sahrens switch (c) { 2178fa9e4066Sahrens case 'H': 217999653d4eSeschrock cb.cb_scripted = B_TRUE; 2180fa9e4066Sahrens break; 2181fa9e4066Sahrens case 'o': 2182990b4856Slling props = optarg; 2183fa9e4066Sahrens break; 2184fa9e4066Sahrens case ':': 2185fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2186fa9e4066Sahrens "'%c' option\n"), optopt); 218799653d4eSeschrock usage(B_FALSE); 2188fa9e4066Sahrens break; 2189fa9e4066Sahrens case '?': 2190fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2191fa9e4066Sahrens optopt); 219299653d4eSeschrock usage(B_FALSE); 2193fa9e4066Sahrens } 2194fa9e4066Sahrens } 2195fa9e4066Sahrens 2196fa9e4066Sahrens argc -= optind; 2197fa9e4066Sahrens argv += optind; 2198fa9e4066Sahrens 2199990b4856Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 220099653d4eSeschrock usage(B_FALSE); 2201fa9e4066Sahrens 220299653d4eSeschrock cb.cb_first = B_TRUE; 2203fa9e4066Sahrens 2204990b4856Slling ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2205990b4856Slling list_callback, &cb); 2206990b4856Slling 2207990b4856Slling zprop_free_list(cb.cb_proplist); 2208fa9e4066Sahrens 2209fce7d82bSmmusante if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2210fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 2211fa9e4066Sahrens return (0); 2212fa9e4066Sahrens } 2213fa9e4066Sahrens 2214fa9e4066Sahrens return (ret); 2215fa9e4066Sahrens } 2216fa9e4066Sahrens 2217fa9e4066Sahrens static nvlist_t * 2218fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name) 2219fa9e4066Sahrens { 2220fa9e4066Sahrens nvlist_t **child; 2221fa9e4066Sahrens uint_t c, children; 2222fa9e4066Sahrens nvlist_t *match; 2223fa9e4066Sahrens char *path; 2224fa9e4066Sahrens 2225fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2226fa9e4066Sahrens &child, &children) != 0) { 2227fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2228fa9e4066Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0) 2229fa9e4066Sahrens name += 9; 2230fa9e4066Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0) 2231fa9e4066Sahrens path += 9; 2232fa9e4066Sahrens if (strcmp(name, path) == 0) 2233fa9e4066Sahrens return (nv); 2234fa9e4066Sahrens return (NULL); 2235fa9e4066Sahrens } 2236fa9e4066Sahrens 2237fa9e4066Sahrens for (c = 0; c < children; c++) 2238fa9e4066Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2239fa9e4066Sahrens return (match); 2240fa9e4066Sahrens 2241fa9e4066Sahrens return (NULL); 2242fa9e4066Sahrens } 2243fa9e4066Sahrens 2244fa9e4066Sahrens static int 2245fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 2246fa9e4066Sahrens { 224799653d4eSeschrock boolean_t force = B_FALSE; 2248fa9e4066Sahrens int c; 2249fa9e4066Sahrens nvlist_t *nvroot; 2250fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 2251fa9e4066Sahrens zpool_handle_t *zhp; 225299653d4eSeschrock int ret; 2253fa9e4066Sahrens 2254fa9e4066Sahrens /* check options */ 2255fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2256fa9e4066Sahrens switch (c) { 2257fa9e4066Sahrens case 'f': 225899653d4eSeschrock force = B_TRUE; 2259fa9e4066Sahrens break; 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 poolname = argv[0]; 2277fa9e4066Sahrens 2278fa9e4066Sahrens if (argc < 2) { 2279fa9e4066Sahrens (void) fprintf(stderr, 2280fa9e4066Sahrens gettext("missing <device> specification\n")); 228199653d4eSeschrock usage(B_FALSE); 2282fa9e4066Sahrens } 2283fa9e4066Sahrens 2284fa9e4066Sahrens old_disk = argv[1]; 2285fa9e4066Sahrens 2286fa9e4066Sahrens if (argc < 3) { 2287fa9e4066Sahrens if (!replacing) { 2288fa9e4066Sahrens (void) fprintf(stderr, 2289fa9e4066Sahrens gettext("missing <new_device> specification\n")); 229099653d4eSeschrock usage(B_FALSE); 2291fa9e4066Sahrens } 2292fa9e4066Sahrens new_disk = old_disk; 2293fa9e4066Sahrens argc -= 1; 2294fa9e4066Sahrens argv += 1; 2295fa9e4066Sahrens } else { 2296fa9e4066Sahrens new_disk = argv[2]; 2297fa9e4066Sahrens argc -= 2; 2298fa9e4066Sahrens argv += 2; 2299fa9e4066Sahrens } 2300fa9e4066Sahrens 2301fa9e4066Sahrens if (argc > 1) { 2302fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 230399653d4eSeschrock usage(B_FALSE); 2304fa9e4066Sahrens } 2305fa9e4066Sahrens 230699653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2307fa9e4066Sahrens return (1); 2308fa9e4066Sahrens 23098488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 2310fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2311fa9e4066Sahrens poolname); 2312fa9e4066Sahrens zpool_close(zhp); 2313fa9e4066Sahrens return (1); 2314fa9e4066Sahrens } 2315fa9e4066Sahrens 2316705040edSEric Taylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 2317705040edSEric Taylor argc, argv); 2318fa9e4066Sahrens if (nvroot == NULL) { 2319fa9e4066Sahrens zpool_close(zhp); 2320fa9e4066Sahrens return (1); 2321fa9e4066Sahrens } 2322fa9e4066Sahrens 232399653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 232499653d4eSeschrock 232599653d4eSeschrock nvlist_free(nvroot); 232699653d4eSeschrock zpool_close(zhp); 232799653d4eSeschrock 232899653d4eSeschrock return (ret); 2329fa9e4066Sahrens } 2330fa9e4066Sahrens 2331fa9e4066Sahrens /* 2332fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 2333fa9e4066Sahrens * 2334fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2335fa9e4066Sahrens * 2336fa9e4066Sahrens * Replace <device> with <new_device>. 2337fa9e4066Sahrens */ 2338fa9e4066Sahrens /* ARGSUSED */ 2339fa9e4066Sahrens int 2340fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 2341fa9e4066Sahrens { 2342fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2343fa9e4066Sahrens } 2344fa9e4066Sahrens 2345fa9e4066Sahrens /* 2346fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 2347fa9e4066Sahrens * 2348fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2349fa9e4066Sahrens * 2350fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 2351fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 2352fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 2353fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 2354fa9e4066Sahrens */ 2355fa9e4066Sahrens int 2356fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 2357fa9e4066Sahrens { 2358fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2359fa9e4066Sahrens } 2360fa9e4066Sahrens 2361fa9e4066Sahrens /* 2362fa9e4066Sahrens * zpool detach [-f] <pool> <device> 2363fa9e4066Sahrens * 2364fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 2365fa9e4066Sahrens * (not supported yet) 2366fa9e4066Sahrens * 2367fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 2368fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 2369fa9e4066Sahrens * has the only valid copy of some data. 2370fa9e4066Sahrens */ 2371fa9e4066Sahrens /* ARGSUSED */ 2372fa9e4066Sahrens int 2373fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 2374fa9e4066Sahrens { 2375fa9e4066Sahrens int c; 2376fa9e4066Sahrens char *poolname, *path; 2377fa9e4066Sahrens zpool_handle_t *zhp; 237899653d4eSeschrock int ret; 2379fa9e4066Sahrens 2380fa9e4066Sahrens /* check options */ 2381fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2382fa9e4066Sahrens switch (c) { 2383fa9e4066Sahrens case 'f': 2384fa9e4066Sahrens case '?': 2385fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2386fa9e4066Sahrens optopt); 238799653d4eSeschrock usage(B_FALSE); 2388fa9e4066Sahrens } 2389fa9e4066Sahrens } 2390fa9e4066Sahrens 2391fa9e4066Sahrens argc -= optind; 2392fa9e4066Sahrens argv += optind; 2393fa9e4066Sahrens 2394fa9e4066Sahrens /* get pool name and check number of arguments */ 2395fa9e4066Sahrens if (argc < 1) { 2396fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 239799653d4eSeschrock usage(B_FALSE); 2398fa9e4066Sahrens } 2399fa9e4066Sahrens 2400fa9e4066Sahrens if (argc < 2) { 2401fa9e4066Sahrens (void) fprintf(stderr, 2402fa9e4066Sahrens gettext("missing <device> specification\n")); 240399653d4eSeschrock usage(B_FALSE); 2404fa9e4066Sahrens } 2405fa9e4066Sahrens 2406fa9e4066Sahrens poolname = argv[0]; 2407fa9e4066Sahrens path = argv[1]; 2408fa9e4066Sahrens 240999653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2410fa9e4066Sahrens return (1); 2411fa9e4066Sahrens 241299653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 241399653d4eSeschrock 241499653d4eSeschrock zpool_close(zhp); 241599653d4eSeschrock 241699653d4eSeschrock return (ret); 2417fa9e4066Sahrens } 2418fa9e4066Sahrens 2419fa9e4066Sahrens /* 2420441d80aaSlling * zpool online <pool> <device> ... 2421fa9e4066Sahrens */ 2422fa9e4066Sahrens int 2423fa9e4066Sahrens zpool_do_online(int argc, char **argv) 2424fa9e4066Sahrens { 2425fa9e4066Sahrens int c, i; 2426fa9e4066Sahrens char *poolname; 2427fa9e4066Sahrens zpool_handle_t *zhp; 2428fa9e4066Sahrens int ret = 0; 24293d7072f8Seschrock vdev_state_t newstate; 2430fa9e4066Sahrens 2431fa9e4066Sahrens /* check options */ 2432fa9e4066Sahrens while ((c = getopt(argc, argv, "t")) != -1) { 2433fa9e4066Sahrens switch (c) { 2434fa9e4066Sahrens case 't': 2435fa9e4066Sahrens case '?': 2436fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2437fa9e4066Sahrens optopt); 243899653d4eSeschrock usage(B_FALSE); 2439fa9e4066Sahrens } 2440fa9e4066Sahrens } 2441fa9e4066Sahrens 2442fa9e4066Sahrens argc -= optind; 2443fa9e4066Sahrens argv += optind; 2444fa9e4066Sahrens 2445fa9e4066Sahrens /* get pool name and check number of arguments */ 2446fa9e4066Sahrens if (argc < 1) { 2447fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 244899653d4eSeschrock usage(B_FALSE); 2449fa9e4066Sahrens } 2450fa9e4066Sahrens if (argc < 2) { 2451fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 245299653d4eSeschrock usage(B_FALSE); 2453fa9e4066Sahrens } 2454fa9e4066Sahrens 2455fa9e4066Sahrens poolname = argv[0]; 2456fa9e4066Sahrens 245799653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2458fa9e4066Sahrens return (1); 2459fa9e4066Sahrens 24603d7072f8Seschrock for (i = 1; i < argc; i++) { 24613d7072f8Seschrock if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) { 24623d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 24633d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 24643d7072f8Seschrock "onlined, but remains in faulted state\n"), 2465fa9e4066Sahrens argv[i]); 24663d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 24673d7072f8Seschrock (void) printf(gettext("use 'zpool " 24683d7072f8Seschrock "clear' to restore a faulted " 24693d7072f8Seschrock "device\n")); 2470fa9e4066Sahrens else 24713d7072f8Seschrock (void) printf(gettext("use 'zpool " 24723d7072f8Seschrock "replace' to replace devices " 24733d7072f8Seschrock "that are no longer present\n")); 24743d7072f8Seschrock } 24753d7072f8Seschrock } else { 2476fa9e4066Sahrens ret = 1; 24773d7072f8Seschrock } 24783d7072f8Seschrock } 2479fa9e4066Sahrens 248099653d4eSeschrock zpool_close(zhp); 248199653d4eSeschrock 2482fa9e4066Sahrens return (ret); 2483fa9e4066Sahrens } 2484fa9e4066Sahrens 2485fa9e4066Sahrens /* 2486441d80aaSlling * zpool offline [-ft] <pool> <device> ... 2487fa9e4066Sahrens * 2488fa9e4066Sahrens * -f Force the device into the offline state, even if doing 2489fa9e4066Sahrens * so would appear to compromise pool availability. 2490fa9e4066Sahrens * (not supported yet) 2491fa9e4066Sahrens * 2492fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 2493fa9e4066Sahrens * state will not be persistent across reboots. 2494fa9e4066Sahrens */ 2495fa9e4066Sahrens /* ARGSUSED */ 2496fa9e4066Sahrens int 2497fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 2498fa9e4066Sahrens { 2499fa9e4066Sahrens int c, i; 2500fa9e4066Sahrens char *poolname; 2501fa9e4066Sahrens zpool_handle_t *zhp; 250299653d4eSeschrock int ret = 0; 250399653d4eSeschrock boolean_t istmp = B_FALSE; 2504fa9e4066Sahrens 2505fa9e4066Sahrens /* check options */ 2506fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 2507fa9e4066Sahrens switch (c) { 2508fa9e4066Sahrens case 't': 250999653d4eSeschrock istmp = B_TRUE; 2510441d80aaSlling break; 2511441d80aaSlling case 'f': 2512fa9e4066Sahrens case '?': 2513fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2514fa9e4066Sahrens optopt); 251599653d4eSeschrock usage(B_FALSE); 2516fa9e4066Sahrens } 2517fa9e4066Sahrens } 2518fa9e4066Sahrens 2519fa9e4066Sahrens argc -= optind; 2520fa9e4066Sahrens argv += optind; 2521fa9e4066Sahrens 2522fa9e4066Sahrens /* get pool name and check number of arguments */ 2523fa9e4066Sahrens if (argc < 1) { 2524fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 252599653d4eSeschrock usage(B_FALSE); 2526fa9e4066Sahrens } 2527fa9e4066Sahrens if (argc < 2) { 2528fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 252999653d4eSeschrock usage(B_FALSE); 2530fa9e4066Sahrens } 2531fa9e4066Sahrens 2532fa9e4066Sahrens poolname = argv[0]; 2533fa9e4066Sahrens 253499653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2535fa9e4066Sahrens return (1); 2536fa9e4066Sahrens 25373d7072f8Seschrock for (i = 1; i < argc; i++) { 25383d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2539fa9e4066Sahrens ret = 1; 25403d7072f8Seschrock } 2541fa9e4066Sahrens 254299653d4eSeschrock zpool_close(zhp); 254399653d4eSeschrock 2544fa9e4066Sahrens return (ret); 2545fa9e4066Sahrens } 2546fa9e4066Sahrens 2547ea8dc4b6Seschrock /* 2548ea8dc4b6Seschrock * zpool clear <pool> [device] 2549ea8dc4b6Seschrock * 2550ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 2551ea8dc4b6Seschrock */ 2552ea8dc4b6Seschrock int 2553ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 2554ea8dc4b6Seschrock { 2555ea8dc4b6Seschrock int ret = 0; 2556ea8dc4b6Seschrock zpool_handle_t *zhp; 2557ea8dc4b6Seschrock char *pool, *device; 2558ea8dc4b6Seschrock 2559ea8dc4b6Seschrock if (argc < 2) { 2560ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 256199653d4eSeschrock usage(B_FALSE); 2562ea8dc4b6Seschrock } 2563ea8dc4b6Seschrock 2564ea8dc4b6Seschrock if (argc > 3) { 2565ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 256699653d4eSeschrock usage(B_FALSE); 2567ea8dc4b6Seschrock } 2568ea8dc4b6Seschrock 2569ea8dc4b6Seschrock pool = argv[1]; 2570ea8dc4b6Seschrock device = argc == 3 ? argv[2] : NULL; 2571ea8dc4b6Seschrock 2572b87f3af3Sperrin if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 2573ea8dc4b6Seschrock return (1); 2574ea8dc4b6Seschrock 2575ea8dc4b6Seschrock if (zpool_clear(zhp, device) != 0) 2576ea8dc4b6Seschrock ret = 1; 2577ea8dc4b6Seschrock 2578ea8dc4b6Seschrock zpool_close(zhp); 2579ea8dc4b6Seschrock 2580ea8dc4b6Seschrock return (ret); 2581ea8dc4b6Seschrock } 2582ea8dc4b6Seschrock 2583fa9e4066Sahrens typedef struct scrub_cbdata { 2584fa9e4066Sahrens int cb_type; 258506eeb2adSek110237 int cb_argc; 258606eeb2adSek110237 char **cb_argv; 2587fa9e4066Sahrens } scrub_cbdata_t; 2588fa9e4066Sahrens 2589fa9e4066Sahrens int 2590fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 2591fa9e4066Sahrens { 2592fa9e4066Sahrens scrub_cbdata_t *cb = data; 259306eeb2adSek110237 int err; 2594fa9e4066Sahrens 2595ea8dc4b6Seschrock /* 2596ea8dc4b6Seschrock * Ignore faulted pools. 2597ea8dc4b6Seschrock */ 2598ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2599ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2600ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 2601ea8dc4b6Seschrock return (1); 2602ea8dc4b6Seschrock } 2603ea8dc4b6Seschrock 260406eeb2adSek110237 err = zpool_scrub(zhp, cb->cb_type); 260506eeb2adSek110237 260606eeb2adSek110237 return (err != 0); 2607fa9e4066Sahrens } 2608fa9e4066Sahrens 2609fa9e4066Sahrens /* 2610fa9e4066Sahrens * zpool scrub [-s] <pool> ... 2611fa9e4066Sahrens * 2612fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 2613fa9e4066Sahrens */ 2614fa9e4066Sahrens int 2615fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 2616fa9e4066Sahrens { 2617fa9e4066Sahrens int c; 2618fa9e4066Sahrens scrub_cbdata_t cb; 2619fa9e4066Sahrens 2620fa9e4066Sahrens cb.cb_type = POOL_SCRUB_EVERYTHING; 2621fa9e4066Sahrens 2622fa9e4066Sahrens /* check options */ 2623fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 2624fa9e4066Sahrens switch (c) { 2625fa9e4066Sahrens case 's': 2626fa9e4066Sahrens cb.cb_type = POOL_SCRUB_NONE; 2627fa9e4066Sahrens break; 2628fa9e4066Sahrens case '?': 2629fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2630fa9e4066Sahrens optopt); 263199653d4eSeschrock usage(B_FALSE); 2632fa9e4066Sahrens } 2633fa9e4066Sahrens } 2634fa9e4066Sahrens 263506eeb2adSek110237 cb.cb_argc = argc; 263606eeb2adSek110237 cb.cb_argv = argv; 2637fa9e4066Sahrens argc -= optind; 2638fa9e4066Sahrens argv += optind; 2639fa9e4066Sahrens 2640fa9e4066Sahrens if (argc < 1) { 2641fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 264299653d4eSeschrock usage(B_FALSE); 2643fa9e4066Sahrens } 2644fa9e4066Sahrens 2645b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2646fa9e4066Sahrens } 2647fa9e4066Sahrens 2648fa9e4066Sahrens typedef struct status_cbdata { 2649fa9e4066Sahrens int cb_count; 2650e9dbad6fSeschrock boolean_t cb_allpools; 265199653d4eSeschrock boolean_t cb_verbose; 265299653d4eSeschrock boolean_t cb_explain; 265399653d4eSeschrock boolean_t cb_first; 2654fa9e4066Sahrens } status_cbdata_t; 2655fa9e4066Sahrens 2656fa9e4066Sahrens /* 2657fa9e4066Sahrens * Print out detailed scrub status. 2658fa9e4066Sahrens */ 2659fa9e4066Sahrens void 2660fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot) 2661fa9e4066Sahrens { 2662fa9e4066Sahrens vdev_stat_t *vs; 2663fa9e4066Sahrens uint_t vsc; 2664fa9e4066Sahrens time_t start, end, now; 2665fa9e4066Sahrens double fraction_done; 266618ce54dfSek110237 uint64_t examined, total, minutes_left, minutes_taken; 2667fa9e4066Sahrens char *scrub_type; 2668fa9e4066Sahrens 2669fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2670fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 2671fa9e4066Sahrens 2672fa9e4066Sahrens /* 2673fa9e4066Sahrens * If there's never been a scrub, there's not much to say. 2674fa9e4066Sahrens */ 2675fa9e4066Sahrens if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2676fa9e4066Sahrens (void) printf(gettext("none requested\n")); 2677fa9e4066Sahrens return; 2678fa9e4066Sahrens } 2679fa9e4066Sahrens 2680fa9e4066Sahrens scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2681fa9e4066Sahrens "resilver" : "scrub"; 2682fa9e4066Sahrens 2683fa9e4066Sahrens start = vs->vs_scrub_start; 2684fa9e4066Sahrens end = vs->vs_scrub_end; 2685fa9e4066Sahrens now = time(NULL); 2686fa9e4066Sahrens examined = vs->vs_scrub_examined; 2687fa9e4066Sahrens total = vs->vs_alloc; 2688fa9e4066Sahrens 2689fa9e4066Sahrens if (end != 0) { 269018ce54dfSek110237 minutes_taken = (uint64_t)((end - start) / 60); 269118ce54dfSek110237 269218ce54dfSek110237 (void) printf(gettext("%s %s after %lluh%um with %llu errors " 269318ce54dfSek110237 "on %s"), 2694fa9e4066Sahrens scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 269518ce54dfSek110237 (u_longlong_t)(minutes_taken / 60), 269618ce54dfSek110237 (uint_t)(minutes_taken % 60), 2697fa9e4066Sahrens (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2698fa9e4066Sahrens return; 2699fa9e4066Sahrens } 2700fa9e4066Sahrens 2701fa9e4066Sahrens if (examined == 0) 2702fa9e4066Sahrens examined = 1; 2703fa9e4066Sahrens if (examined > total) 2704fa9e4066Sahrens total = examined; 2705fa9e4066Sahrens 2706fa9e4066Sahrens fraction_done = (double)examined / total; 2707fa9e4066Sahrens minutes_left = (uint64_t)((now - start) * 2708fa9e4066Sahrens (1 - fraction_done) / fraction_done / 60); 270918ce54dfSek110237 minutes_taken = (uint64_t)((now - start) / 60); 2710fa9e4066Sahrens 271118ce54dfSek110237 (void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, " 271218ce54dfSek110237 "%lluh%um to go\n"), 271318ce54dfSek110237 scrub_type, (u_longlong_t)(minutes_taken / 60), 271418ce54dfSek110237 (uint_t)(minutes_taken % 60), 100 * fraction_done, 2715fa9e4066Sahrens (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2716fa9e4066Sahrens } 2717fa9e4066Sahrens 271899653d4eSeschrock typedef struct spare_cbdata { 271999653d4eSeschrock uint64_t cb_guid; 272099653d4eSeschrock zpool_handle_t *cb_zhp; 272199653d4eSeschrock } spare_cbdata_t; 272299653d4eSeschrock 272399653d4eSeschrock static boolean_t 272499653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search) 272599653d4eSeschrock { 272699653d4eSeschrock uint64_t guid; 272799653d4eSeschrock nvlist_t **child; 272899653d4eSeschrock uint_t c, children; 272999653d4eSeschrock 273099653d4eSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 273199653d4eSeschrock search == guid) 273299653d4eSeschrock return (B_TRUE); 273399653d4eSeschrock 273499653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 273599653d4eSeschrock &child, &children) == 0) { 273699653d4eSeschrock for (c = 0; c < children; c++) 273799653d4eSeschrock if (find_vdev(child[c], search)) 273899653d4eSeschrock return (B_TRUE); 273999653d4eSeschrock } 274099653d4eSeschrock 274199653d4eSeschrock return (B_FALSE); 274299653d4eSeschrock } 274399653d4eSeschrock 274499653d4eSeschrock static int 274599653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data) 274699653d4eSeschrock { 274799653d4eSeschrock spare_cbdata_t *cbp = data; 274899653d4eSeschrock nvlist_t *config, *nvroot; 274999653d4eSeschrock 275099653d4eSeschrock config = zpool_get_config(zhp, NULL); 275199653d4eSeschrock verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 275299653d4eSeschrock &nvroot) == 0); 275399653d4eSeschrock 275499653d4eSeschrock if (find_vdev(nvroot, cbp->cb_guid)) { 275599653d4eSeschrock cbp->cb_zhp = zhp; 275699653d4eSeschrock return (1); 275799653d4eSeschrock } 275899653d4eSeschrock 275999653d4eSeschrock zpool_close(zhp); 276099653d4eSeschrock return (0); 276199653d4eSeschrock } 276299653d4eSeschrock 2763fa9e4066Sahrens /* 2764fa9e4066Sahrens * Print out configuration state as requested by status_callback. 2765fa9e4066Sahrens */ 2766fa9e4066Sahrens void 2767c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 2768*aa8cf21aSNeil Perrin int namewidth, int depth, boolean_t isspare) 2769fa9e4066Sahrens { 2770fa9e4066Sahrens nvlist_t **child; 2771fa9e4066Sahrens uint_t c, children; 2772fa9e4066Sahrens vdev_stat_t *vs; 2773ea8dc4b6Seschrock char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 2774afefbcddSeschrock char *vname; 2775ea8dc4b6Seschrock uint64_t notpresent; 277699653d4eSeschrock spare_cbdata_t cb; 2777990b4856Slling char *state; 2778fa9e4066Sahrens 2779fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2780fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 2781fa9e4066Sahrens 2782fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2783fa9e4066Sahrens &child, &children) != 0) 2784fa9e4066Sahrens children = 0; 2785fa9e4066Sahrens 2786990b4856Slling state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 278799653d4eSeschrock if (isspare) { 278899653d4eSeschrock /* 278999653d4eSeschrock * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 279099653d4eSeschrock * online drives. 279199653d4eSeschrock */ 279299653d4eSeschrock if (vs->vs_aux == VDEV_AUX_SPARED) 279399653d4eSeschrock state = "INUSE"; 279499653d4eSeschrock else if (vs->vs_state == VDEV_STATE_HEALTHY) 279599653d4eSeschrock state = "AVAIL"; 279699653d4eSeschrock } 2797fa9e4066Sahrens 279899653d4eSeschrock (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 279999653d4eSeschrock name, state); 280099653d4eSeschrock 280199653d4eSeschrock if (!isspare) { 2802fa9e4066Sahrens zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 2803fa9e4066Sahrens zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 2804fa9e4066Sahrens zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 2805fa9e4066Sahrens (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 280699653d4eSeschrock } 2807fa9e4066Sahrens 2808ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2809ea8dc4b6Seschrock ¬present) == 0) { 2810ea8dc4b6Seschrock char *path; 2811ea8dc4b6Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 28120917b783Seschrock (void) printf(" was %s", path); 2813ea8dc4b6Seschrock } else if (vs->vs_aux != 0) { 2814fa9e4066Sahrens (void) printf(" "); 2815fa9e4066Sahrens 2816fa9e4066Sahrens switch (vs->vs_aux) { 2817fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 2818fa9e4066Sahrens (void) printf(gettext("cannot open")); 2819fa9e4066Sahrens break; 2820fa9e4066Sahrens 2821fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 2822fa9e4066Sahrens (void) printf(gettext("missing device")); 2823fa9e4066Sahrens break; 2824fa9e4066Sahrens 2825fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 2826fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 2827fa9e4066Sahrens break; 2828fa9e4066Sahrens 2829eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 2830eaca9bbdSeschrock (void) printf(gettext("newer version")); 2831eaca9bbdSeschrock break; 2832eaca9bbdSeschrock 283399653d4eSeschrock case VDEV_AUX_SPARED: 283499653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 283599653d4eSeschrock &cb.cb_guid) == 0); 283699653d4eSeschrock if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 283799653d4eSeschrock if (strcmp(zpool_get_name(cb.cb_zhp), 283899653d4eSeschrock zpool_get_name(zhp)) == 0) 283999653d4eSeschrock (void) printf(gettext("currently in " 284099653d4eSeschrock "use")); 284199653d4eSeschrock else 284299653d4eSeschrock (void) printf(gettext("in use by " 284399653d4eSeschrock "pool '%s'"), 284499653d4eSeschrock zpool_get_name(cb.cb_zhp)); 284599653d4eSeschrock zpool_close(cb.cb_zhp); 284699653d4eSeschrock } else { 284799653d4eSeschrock (void) printf(gettext("currently in use")); 284899653d4eSeschrock } 284999653d4eSeschrock break; 285099653d4eSeschrock 28513d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 28523d7072f8Seschrock (void) printf(gettext("too many errors")); 28533d7072f8Seschrock break; 28543d7072f8Seschrock 285532b87932Sek110237 case VDEV_AUX_IO_FAILURE: 285632b87932Sek110237 (void) printf(gettext("experienced I/O failures")); 285732b87932Sek110237 break; 285832b87932Sek110237 2859b87f3af3Sperrin case VDEV_AUX_BAD_LOG: 2860b87f3af3Sperrin (void) printf(gettext("bad intent log")); 2861b87f3af3Sperrin break; 2862b87f3af3Sperrin 2863fa9e4066Sahrens default: 2864fa9e4066Sahrens (void) printf(gettext("corrupted data")); 2865fa9e4066Sahrens break; 2866fa9e4066Sahrens } 2867fa9e4066Sahrens } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2868fa9e4066Sahrens /* 2869fa9e4066Sahrens * Report bytes resilvered/repaired on leaf devices. 2870fa9e4066Sahrens */ 2871fa9e4066Sahrens zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2872fa9e4066Sahrens (void) printf(gettext(" %s %s"), repaired, 2873fa9e4066Sahrens (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2874fa9e4066Sahrens "resilvered" : "repaired"); 2875fa9e4066Sahrens } 2876fa9e4066Sahrens 2877fa9e4066Sahrens (void) printf("\n"); 2878fa9e4066Sahrens 2879afefbcddSeschrock for (c = 0; c < children; c++) { 28808654d025Sperrin uint64_t is_log = B_FALSE; 28818654d025Sperrin 2882*aa8cf21aSNeil Perrin /* Don't print logs here */ 28838654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 28848654d025Sperrin &is_log); 2885*aa8cf21aSNeil Perrin if (is_log) 28868654d025Sperrin continue; 288799653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 2888c67d9675Seschrock print_status_config(zhp, vname, child[c], 2889*aa8cf21aSNeil Perrin namewidth, depth + 2, isspare); 2890afefbcddSeschrock free(vname); 2891afefbcddSeschrock } 2892fa9e4066Sahrens } 2893fa9e4066Sahrens 2894ea8dc4b6Seschrock static void 2895ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 2896ea8dc4b6Seschrock { 289775519f38Sek110237 nvlist_t *nverrlist = NULL; 289855434c77Sek110237 nvpair_t *elem; 289955434c77Sek110237 char *pathname; 290055434c77Sek110237 size_t len = MAXPATHLEN * 2; 2901ea8dc4b6Seschrock 290255434c77Sek110237 if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2903ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 2904ea8dc4b6Seschrock "(insufficient privileges)\n"); 2905ea8dc4b6Seschrock return; 2906ea8dc4b6Seschrock } 2907ea8dc4b6Seschrock 290855434c77Sek110237 (void) printf("errors: Permanent errors have been " 290955434c77Sek110237 "detected in the following files:\n\n"); 2910ea8dc4b6Seschrock 291155434c77Sek110237 pathname = safe_malloc(len); 291255434c77Sek110237 elem = NULL; 291355434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 291455434c77Sek110237 nvlist_t *nv; 291555434c77Sek110237 uint64_t dsobj, obj; 2916ea8dc4b6Seschrock 291755434c77Sek110237 verify(nvpair_value_nvlist(elem, &nv) == 0); 291855434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 291955434c77Sek110237 &dsobj) == 0); 292055434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 292155434c77Sek110237 &obj) == 0); 292255434c77Sek110237 zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 292355434c77Sek110237 (void) printf("%7s %s\n", "", pathname); 2924ea8dc4b6Seschrock } 292555434c77Sek110237 free(pathname); 292655434c77Sek110237 nvlist_free(nverrlist); 2927ea8dc4b6Seschrock } 2928ea8dc4b6Seschrock 292999653d4eSeschrock static void 293099653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 293199653d4eSeschrock int namewidth) 293299653d4eSeschrock { 293399653d4eSeschrock uint_t i; 293499653d4eSeschrock char *name; 293599653d4eSeschrock 293699653d4eSeschrock if (nspares == 0) 293799653d4eSeschrock return; 293899653d4eSeschrock 293999653d4eSeschrock (void) printf(gettext("\tspares\n")); 294099653d4eSeschrock 294199653d4eSeschrock for (i = 0; i < nspares; i++) { 294299653d4eSeschrock name = zpool_vdev_name(g_zfs, zhp, spares[i]); 294399653d4eSeschrock print_status_config(zhp, name, spares[i], 2944*aa8cf21aSNeil Perrin namewidth, 2, B_TRUE); 294599653d4eSeschrock free(name); 294699653d4eSeschrock } 294799653d4eSeschrock } 294899653d4eSeschrock 2949fa94a07fSbrendan static void 2950fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 2951fa94a07fSbrendan int namewidth) 2952fa94a07fSbrendan { 2953fa94a07fSbrendan uint_t i; 2954fa94a07fSbrendan char *name; 2955fa94a07fSbrendan 2956fa94a07fSbrendan if (nl2cache == 0) 2957fa94a07fSbrendan return; 2958fa94a07fSbrendan 2959fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 2960fa94a07fSbrendan 2961fa94a07fSbrendan for (i = 0; i < nl2cache; i++) { 2962fa94a07fSbrendan name = zpool_vdev_name(g_zfs, zhp, l2cache[i]); 2963fa94a07fSbrendan print_status_config(zhp, name, l2cache[i], 2964*aa8cf21aSNeil Perrin namewidth, 2, B_FALSE); 2965*aa8cf21aSNeil Perrin free(name); 2966*aa8cf21aSNeil Perrin } 2967*aa8cf21aSNeil Perrin } 2968*aa8cf21aSNeil Perrin 2969*aa8cf21aSNeil Perrin /* 2970*aa8cf21aSNeil Perrin * Print log vdevs. 2971*aa8cf21aSNeil Perrin * Logs are recorded as top level vdevs in the main pool child array but with 2972*aa8cf21aSNeil Perrin * "is_log" set to 1. We use print_status_config() to print the top level logs 2973*aa8cf21aSNeil Perrin * then any log children (eg mirrored slogs) are printed recursively - which 2974*aa8cf21aSNeil Perrin * works because only the top level vdev is marked "is_log" 2975*aa8cf21aSNeil Perrin */ 2976*aa8cf21aSNeil Perrin static void 2977*aa8cf21aSNeil Perrin print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth) 2978*aa8cf21aSNeil Perrin { 2979*aa8cf21aSNeil Perrin uint_t c, children; 2980*aa8cf21aSNeil Perrin nvlist_t **child; 2981*aa8cf21aSNeil Perrin 2982*aa8cf21aSNeil Perrin if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 2983*aa8cf21aSNeil Perrin &children) != 0) 2984*aa8cf21aSNeil Perrin return; 2985*aa8cf21aSNeil Perrin 2986*aa8cf21aSNeil Perrin (void) printf(gettext("\tlogs\n")); 2987*aa8cf21aSNeil Perrin 2988*aa8cf21aSNeil Perrin for (c = 0; c < children; c++) { 2989*aa8cf21aSNeil Perrin uint64_t is_log = B_FALSE; 2990*aa8cf21aSNeil Perrin char *name; 2991*aa8cf21aSNeil Perrin 2992*aa8cf21aSNeil Perrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 2993*aa8cf21aSNeil Perrin &is_log); 2994*aa8cf21aSNeil Perrin if (!is_log) 2995*aa8cf21aSNeil Perrin continue; 2996*aa8cf21aSNeil Perrin name = zpool_vdev_name(g_zfs, zhp, child[c]); 2997*aa8cf21aSNeil Perrin print_status_config(zhp, name, child[c], namewidth, 2, B_FALSE); 2998fa94a07fSbrendan free(name); 2999fa94a07fSbrendan } 3000fa94a07fSbrendan } 3001fa94a07fSbrendan 3002fa9e4066Sahrens /* 3003fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 3004fa9e4066Sahrens * 3005fa9e4066Sahrens * pool: tank 3006fa9e4066Sahrens * status: DEGRADED 3007fa9e4066Sahrens * reason: One or more devices ... 3008fa9e4066Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01 3009fa9e4066Sahrens * config: 3010fa9e4066Sahrens * mirror DEGRADED 3011fa9e4066Sahrens * c1t0d0 OK 3012ea8dc4b6Seschrock * c2t0d0 UNAVAIL 3013fa9e4066Sahrens * 3014fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 3015fa9e4066Sahrens * option is specified, then we print out error rate information as well. 3016fa9e4066Sahrens */ 3017fa9e4066Sahrens int 3018fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 3019fa9e4066Sahrens { 3020fa9e4066Sahrens status_cbdata_t *cbp = data; 3021fa9e4066Sahrens nvlist_t *config, *nvroot; 3022fa9e4066Sahrens char *msgid; 3023fa9e4066Sahrens int reason; 302446657f8dSmmusante const char *health; 302546657f8dSmmusante uint_t c; 302646657f8dSmmusante vdev_stat_t *vs; 3027fa9e4066Sahrens 3028088e9d47Seschrock config = zpool_get_config(zhp, NULL); 3029fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 3030fa9e4066Sahrens 3031fa9e4066Sahrens cbp->cb_count++; 3032fa9e4066Sahrens 3033fa9e4066Sahrens /* 3034fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 3035fa9e4066Sahrens * problems. 3036fa9e4066Sahrens */ 3037e9dbad6fSeschrock if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 3038e9dbad6fSeschrock if (!cbp->cb_allpools) { 3039e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 3040e9dbad6fSeschrock zpool_get_name(zhp)); 3041e9dbad6fSeschrock if (cbp->cb_first) 3042e9dbad6fSeschrock cbp->cb_first = B_FALSE; 3043e9dbad6fSeschrock } 3044fa9e4066Sahrens return (0); 3045e9dbad6fSeschrock } 3046fa9e4066Sahrens 3047fa9e4066Sahrens if (cbp->cb_first) 304899653d4eSeschrock cbp->cb_first = B_FALSE; 3049fa9e4066Sahrens else 3050fa9e4066Sahrens (void) printf("\n"); 3051fa9e4066Sahrens 305246657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 305346657f8dSmmusante &nvroot) == 0); 305446657f8dSmmusante verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 305546657f8dSmmusante (uint64_t **)&vs, &c) == 0); 3056990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 3057fa9e4066Sahrens 3058fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 3059fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 3060fa9e4066Sahrens 3061fa9e4066Sahrens switch (reason) { 3062fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 3063fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3064fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 3065fa9e4066Sahrens "continue functioning in a degraded state.\n")); 3066fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 3067fa9e4066Sahrens "online it using 'zpool online'.\n")); 3068fa9e4066Sahrens break; 3069fa9e4066Sahrens 3070fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 3071fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3072fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 3073fa9e4066Sahrens "pool to continue functioning.\n")); 3074fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 3075fa9e4066Sahrens "online it using 'zpool online'.\n")); 3076fa9e4066Sahrens break; 3077fa9e4066Sahrens 3078fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 3079fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3080fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 3081fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 3082fa9e4066Sahrens "functioning in a degraded state.\n")); 3083fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 3084fa9e4066Sahrens "'zpool replace'.\n")); 3085fa9e4066Sahrens break; 3086fa9e4066Sahrens 3087fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 3088fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3089b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 3090fa9e4066Sahrens "There are insufficient replicas for the pool to " 3091fa9e4066Sahrens "continue\n\tfunctioning.\n")); 3092fa9e4066Sahrens (void) printf(gettext("action: Destroy and re-create the pool " 3093fa9e4066Sahrens "from a backup source.\n")); 3094fa9e4066Sahrens break; 3095fa9e4066Sahrens 3096fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 3097fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 3098fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 3099fa9e4066Sahrens "made to correct the error. Applications are " 3100fa9e4066Sahrens "unaffected.\n")); 3101fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 3102fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 3103ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 3104fa9e4066Sahrens "replace'.\n")); 3105fa9e4066Sahrens break; 3106fa9e4066Sahrens 3107fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 3108fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 3109d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 3110fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 3111fa9e4066Sahrens "a\n\tdegraded state.\n")); 3112fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 3113fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 3114fa9e4066Sahrens "replace'.\n")); 3115fa9e4066Sahrens break; 3116fa9e4066Sahrens 3117fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 3118fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 3119fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 3120fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 3121fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 3122fa9e4066Sahrens "complete.\n")); 3123fa9e4066Sahrens break; 3124fa9e4066Sahrens 3125ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 3126ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 3127ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 3128ea8dc4b6Seschrock "Applications may be affected.\n")); 3129ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 3130ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 3131ea8dc4b6Seschrock "backup.\n")); 3132ea8dc4b6Seschrock break; 3133ea8dc4b6Seschrock 3134ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 3135ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 3136ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 3137ea8dc4b6Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 3138ea8dc4b6Seschrock "from a backup source.\n")); 3139ea8dc4b6Seschrock break; 3140ea8dc4b6Seschrock 3141eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 3142eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 3143eaca9bbdSeschrock "older on-disk format. The pool can\n\tstill be used, but " 3144eaca9bbdSeschrock "some features are unavailable.\n")); 3145eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 3146eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 3147eaca9bbdSeschrock "be accessible on older software versions.\n")); 3148eaca9bbdSeschrock break; 3149eaca9bbdSeschrock 3150eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 3151eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 3152eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 3153eaca9bbdSeschrock "be accessed on this system.\n")); 3154eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 3155eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 3156eaca9bbdSeschrock "backup.\n")); 3157eaca9bbdSeschrock break; 3158eaca9bbdSeschrock 31593d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 31603d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 31613d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 31623d7072f8Seschrock "replicas exist for the pool to continue functioning " 31633d7072f8Seschrock "in a\n\tdegraded state.\n")); 31643d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 31653d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 31663d7072f8Seschrock break; 31673d7072f8Seschrock 31683d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 31693d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 31703d7072f8Seschrock "faulted in response to persistent errors. There are " 31713d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 31723d7072f8Seschrock "functioning.\n")); 31733d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 31743d7072f8Seschrock "from a backup source. Manually marking the device\n" 31753d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 31763d7072f8Seschrock "to be recovered.\n")); 31773d7072f8Seschrock break; 31783d7072f8Seschrock 317932b87932Sek110237 case ZPOOL_STATUS_IO_FAILURE_WAIT: 318032b87932Sek110237 case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 318132b87932Sek110237 (void) printf(gettext("status: One or more devices are " 31828a79c1b5Sek110237 "faulted in response to IO failures.\n")); 318332b87932Sek110237 (void) printf(gettext("action: Make sure the affected devices " 318432b87932Sek110237 "are connected, then run 'zpool clear'.\n")); 318532b87932Sek110237 break; 318632b87932Sek110237 3187b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 3188b87f3af3Sperrin (void) printf(gettext("status: An intent log record " 3189b87f3af3Sperrin "could not be read.\n" 3190b87f3af3Sperrin "\tWaiting for adminstrator intervention to fix the " 3191b87f3af3Sperrin "faulted pool.\n")); 3192b87f3af3Sperrin (void) printf(gettext("action: Either restore the affected " 3193b87f3af3Sperrin "device(s) and run 'zpool online',\n" 3194b87f3af3Sperrin "\tor ignore the intent log records by running " 3195b87f3af3Sperrin "'zpool clear'.\n")); 3196b87f3af3Sperrin break; 3197b87f3af3Sperrin 3198fa9e4066Sahrens default: 3199fa9e4066Sahrens /* 3200fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 3201fa9e4066Sahrens */ 3202fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 3203fa9e4066Sahrens } 3204fa9e4066Sahrens 3205fa9e4066Sahrens if (msgid != NULL) 3206fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3207fa9e4066Sahrens msgid); 3208fa9e4066Sahrens 3209fa9e4066Sahrens if (config != NULL) { 3210fa9e4066Sahrens int namewidth; 3211ea8dc4b6Seschrock uint64_t nerr; 3212fa94a07fSbrendan nvlist_t **spares, **l2cache; 3213fa94a07fSbrendan uint_t nspares, nl2cache; 3214fa9e4066Sahrens 3215fa9e4066Sahrens 3216fa9e4066Sahrens (void) printf(gettext(" scrub: ")); 3217fa9e4066Sahrens print_scrub_status(nvroot); 3218fa9e4066Sahrens 3219c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 3220fa9e4066Sahrens if (namewidth < 10) 3221fa9e4066Sahrens namewidth = 10; 3222fa9e4066Sahrens 3223fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 3224fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3225fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3226c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 3227*aa8cf21aSNeil Perrin namewidth, 0, B_FALSE); 322899653d4eSeschrock 3229*aa8cf21aSNeil Perrin print_logs(zhp, nvroot, namewidth); 3230fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 3231fa94a07fSbrendan &l2cache, &nl2cache) == 0) 3232fa94a07fSbrendan print_l2cache(zhp, l2cache, nl2cache, namewidth); 3233fa94a07fSbrendan 323499653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 323599653d4eSeschrock &spares, &nspares) == 0) 323699653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 3237ea8dc4b6Seschrock 3238ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3239ea8dc4b6Seschrock &nerr) == 0) { 324055434c77Sek110237 nvlist_t *nverrlist = NULL; 324155434c77Sek110237 3242ea8dc4b6Seschrock /* 3243ea8dc4b6Seschrock * If the approximate error count is small, get a 3244ea8dc4b6Seschrock * precise count by fetching the entire log and 3245ea8dc4b6Seschrock * uniquifying the results. 3246ea8dc4b6Seschrock */ 324775519f38Sek110237 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 324855434c77Sek110237 zpool_get_errlog(zhp, &nverrlist) == 0) { 324955434c77Sek110237 nvpair_t *elem; 325055434c77Sek110237 325155434c77Sek110237 elem = NULL; 325255434c77Sek110237 nerr = 0; 325355434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, 325455434c77Sek110237 elem)) != NULL) { 325555434c77Sek110237 nerr++; 325655434c77Sek110237 } 325755434c77Sek110237 } 325855434c77Sek110237 nvlist_free(nverrlist); 3259ea8dc4b6Seschrock 3260ea8dc4b6Seschrock (void) printf("\n"); 326199653d4eSeschrock 3262ea8dc4b6Seschrock if (nerr == 0) 3263ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 3264ea8dc4b6Seschrock "errors\n")); 3265ea8dc4b6Seschrock else if (!cbp->cb_verbose) 3266e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 32675ad82045Snd150628 "errors, use '-v' for a list\n"), 32685ad82045Snd150628 (u_longlong_t)nerr); 3269ea8dc4b6Seschrock else 3270ea8dc4b6Seschrock print_error_log(zhp); 3271ea8dc4b6Seschrock } 3272fa9e4066Sahrens } else { 3273fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 3274fa9e4066Sahrens "determined.\n")); 3275fa9e4066Sahrens } 3276fa9e4066Sahrens 3277fa9e4066Sahrens return (0); 3278fa9e4066Sahrens } 3279fa9e4066Sahrens 3280fa9e4066Sahrens /* 3281fa9e4066Sahrens * zpool status [-vx] [pool] ... 3282fa9e4066Sahrens * 3283fa9e4066Sahrens * -v Display complete error logs 3284fa9e4066Sahrens * -x Display only pools with potential problems 3285fa9e4066Sahrens * 3286fa9e4066Sahrens * Describes the health status of all pools or some subset. 3287fa9e4066Sahrens */ 3288fa9e4066Sahrens int 3289fa9e4066Sahrens zpool_do_status(int argc, char **argv) 3290fa9e4066Sahrens { 3291fa9e4066Sahrens int c; 3292fa9e4066Sahrens int ret; 3293fa9e4066Sahrens status_cbdata_t cb = { 0 }; 3294fa9e4066Sahrens 3295fa9e4066Sahrens /* check options */ 3296fa9e4066Sahrens while ((c = getopt(argc, argv, "vx")) != -1) { 3297fa9e4066Sahrens switch (c) { 3298fa9e4066Sahrens case 'v': 329999653d4eSeschrock cb.cb_verbose = B_TRUE; 3300fa9e4066Sahrens break; 3301fa9e4066Sahrens case 'x': 330299653d4eSeschrock cb.cb_explain = B_TRUE; 3303fa9e4066Sahrens break; 3304fa9e4066Sahrens case '?': 3305fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3306fa9e4066Sahrens optopt); 330799653d4eSeschrock usage(B_FALSE); 3308fa9e4066Sahrens } 3309fa9e4066Sahrens } 3310fa9e4066Sahrens 3311fa9e4066Sahrens argc -= optind; 3312fa9e4066Sahrens argv += optind; 3313fa9e4066Sahrens 331499653d4eSeschrock cb.cb_first = B_TRUE; 3315fa9e4066Sahrens 3316e9dbad6fSeschrock if (argc == 0) 3317e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 3318e9dbad6fSeschrock 3319b1b8ab34Slling ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3320fa9e4066Sahrens 3321fa9e4066Sahrens if (argc == 0 && cb.cb_count == 0) 3322fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 3323e9dbad6fSeschrock else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3324fa9e4066Sahrens (void) printf(gettext("all pools are healthy\n")); 3325fa9e4066Sahrens 3326fa9e4066Sahrens return (ret); 3327fa9e4066Sahrens } 3328fa9e4066Sahrens 3329eaca9bbdSeschrock typedef struct upgrade_cbdata { 3330eaca9bbdSeschrock int cb_all; 3331eaca9bbdSeschrock int cb_first; 3332eaca9bbdSeschrock int cb_newer; 333306eeb2adSek110237 int cb_argc; 3334990b4856Slling uint64_t cb_version; 333506eeb2adSek110237 char **cb_argv; 3336eaca9bbdSeschrock } upgrade_cbdata_t; 3337eaca9bbdSeschrock 3338eaca9bbdSeschrock static int 3339eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 3340eaca9bbdSeschrock { 3341eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 3342eaca9bbdSeschrock nvlist_t *config; 3343eaca9bbdSeschrock uint64_t version; 3344eaca9bbdSeschrock int ret = 0; 3345eaca9bbdSeschrock 3346eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 3347eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3348eaca9bbdSeschrock &version) == 0); 3349eaca9bbdSeschrock 3350e7437265Sahrens if (!cbp->cb_newer && version < SPA_VERSION) { 3351eaca9bbdSeschrock if (!cbp->cb_all) { 3352eaca9bbdSeschrock if (cbp->cb_first) { 3353eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3354eaca9bbdSeschrock "out of date, and can be upgraded. After " 3355eaca9bbdSeschrock "being\nupgraded, these pools will no " 3356eaca9bbdSeschrock "longer be accessible by older software " 3357eaca9bbdSeschrock "versions.\n\n")); 3358eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3359eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 336099653d4eSeschrock cbp->cb_first = B_FALSE; 3361eaca9bbdSeschrock } 3362eaca9bbdSeschrock 33635ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3364eaca9bbdSeschrock zpool_get_name(zhp)); 3365eaca9bbdSeschrock } else { 336699653d4eSeschrock cbp->cb_first = B_FALSE; 3367990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 336806eeb2adSek110237 if (!ret) { 3369eaca9bbdSeschrock (void) printf(gettext("Successfully upgraded " 3370990b4856Slling "'%s'\n\n"), zpool_get_name(zhp)); 3371eaca9bbdSeschrock } 337206eeb2adSek110237 } 3373e7437265Sahrens } else if (cbp->cb_newer && version > SPA_VERSION) { 3374eaca9bbdSeschrock assert(!cbp->cb_all); 3375eaca9bbdSeschrock 3376eaca9bbdSeschrock if (cbp->cb_first) { 3377eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3378eaca9bbdSeschrock "formatted using a newer software version and\n" 3379eaca9bbdSeschrock "cannot be accessed on the current system.\n\n")); 3380eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3381eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 338299653d4eSeschrock cbp->cb_first = B_FALSE; 3383eaca9bbdSeschrock } 3384eaca9bbdSeschrock 33855ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3386eaca9bbdSeschrock zpool_get_name(zhp)); 3387eaca9bbdSeschrock } 3388eaca9bbdSeschrock 3389eaca9bbdSeschrock zpool_close(zhp); 3390eaca9bbdSeschrock return (ret); 3391eaca9bbdSeschrock } 3392eaca9bbdSeschrock 3393eaca9bbdSeschrock /* ARGSUSED */ 3394eaca9bbdSeschrock static int 339506eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data) 3396eaca9bbdSeschrock { 3397990b4856Slling upgrade_cbdata_t *cbp = data; 3398990b4856Slling uint64_t cur_version; 3399eaca9bbdSeschrock int ret; 3400eaca9bbdSeschrock 34018654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 34028654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 34038654d025Sperrin "Pool 'log' must be renamed using export and import" 34048654d025Sperrin " to upgrade.\n")); 34058654d025Sperrin return (1); 34068654d025Sperrin } 3407990b4856Slling 3408990b4856Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 3409e6c728e1Sbrendan if (cur_version > cbp->cb_version) { 3410eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 3411e6c728e1Sbrendan "using more current version '%llu'.\n"), 3412e6c728e1Sbrendan zpool_get_name(zhp), cur_version); 3413e6c728e1Sbrendan return (0); 3414e6c728e1Sbrendan } 3415e6c728e1Sbrendan if (cur_version == cbp->cb_version) { 3416e6c728e1Sbrendan (void) printf(gettext("Pool '%s' is already formatted " 3417e6c728e1Sbrendan "using the current version.\n"), zpool_get_name(zhp)); 3418eaca9bbdSeschrock return (0); 3419eaca9bbdSeschrock } 3420eaca9bbdSeschrock 3421990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 342206eeb2adSek110237 342306eeb2adSek110237 if (!ret) { 342444cd46caSbillm (void) printf(gettext("Successfully upgraded '%s' " 3425990b4856Slling "from version %llu to version %llu\n\n"), 3426990b4856Slling zpool_get_name(zhp), (u_longlong_t)cur_version, 3427990b4856Slling (u_longlong_t)cbp->cb_version); 342806eeb2adSek110237 } 3429eaca9bbdSeschrock 3430eaca9bbdSeschrock return (ret != 0); 3431eaca9bbdSeschrock } 3432eaca9bbdSeschrock 3433eaca9bbdSeschrock /* 3434eaca9bbdSeschrock * zpool upgrade 3435eaca9bbdSeschrock * zpool upgrade -v 3436990b4856Slling * zpool upgrade [-V version] <-a | pool ...> 3437eaca9bbdSeschrock * 3438eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 3439eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 3440eaca9bbdSeschrock * upgrade all pools. 3441eaca9bbdSeschrock */ 3442eaca9bbdSeschrock int 3443eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 3444eaca9bbdSeschrock { 3445eaca9bbdSeschrock int c; 3446eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 3447eaca9bbdSeschrock int ret = 0; 3448eaca9bbdSeschrock boolean_t showversions = B_FALSE; 3449990b4856Slling char *end; 3450990b4856Slling 3451eaca9bbdSeschrock 3452eaca9bbdSeschrock /* check options */ 3453990b4856Slling while ((c = getopt(argc, argv, "avV:")) != -1) { 3454eaca9bbdSeschrock switch (c) { 3455eaca9bbdSeschrock case 'a': 345699653d4eSeschrock cb.cb_all = B_TRUE; 3457eaca9bbdSeschrock break; 3458eaca9bbdSeschrock case 'v': 3459eaca9bbdSeschrock showversions = B_TRUE; 3460eaca9bbdSeschrock break; 3461990b4856Slling case 'V': 3462990b4856Slling cb.cb_version = strtoll(optarg, &end, 10); 3463351420b3Slling if (*end != '\0' || cb.cb_version > SPA_VERSION || 3464351420b3Slling cb.cb_version < SPA_VERSION_1) { 3465990b4856Slling (void) fprintf(stderr, 3466990b4856Slling gettext("invalid version '%s'\n"), optarg); 3467990b4856Slling usage(B_FALSE); 3468990b4856Slling } 3469990b4856Slling break; 3470eaca9bbdSeschrock case '?': 3471eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3472eaca9bbdSeschrock optopt); 347399653d4eSeschrock usage(B_FALSE); 3474eaca9bbdSeschrock } 3475eaca9bbdSeschrock } 3476eaca9bbdSeschrock 347706eeb2adSek110237 cb.cb_argc = argc; 347806eeb2adSek110237 cb.cb_argv = argv; 3479eaca9bbdSeschrock argc -= optind; 3480eaca9bbdSeschrock argv += optind; 3481eaca9bbdSeschrock 3482351420b3Slling if (cb.cb_version == 0) { 3483351420b3Slling cb.cb_version = SPA_VERSION; 3484351420b3Slling } else if (!cb.cb_all && argc == 0) { 3485351420b3Slling (void) fprintf(stderr, gettext("-V option is " 3486351420b3Slling "incompatible with other arguments\n")); 3487351420b3Slling usage(B_FALSE); 3488351420b3Slling } 3489351420b3Slling 3490eaca9bbdSeschrock if (showversions) { 3491eaca9bbdSeschrock if (cb.cb_all || argc != 0) { 3492eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 3493eaca9bbdSeschrock "incompatible with other arguments\n")); 349499653d4eSeschrock usage(B_FALSE); 3495eaca9bbdSeschrock } 3496eaca9bbdSeschrock } else if (cb.cb_all) { 3497eaca9bbdSeschrock if (argc != 0) { 3498351420b3Slling (void) fprintf(stderr, gettext("-a option should not " 3499351420b3Slling "be used along with a pool name\n")); 350099653d4eSeschrock usage(B_FALSE); 3501eaca9bbdSeschrock } 3502eaca9bbdSeschrock } 3503eaca9bbdSeschrock 3504e7437265Sahrens (void) printf(gettext("This system is currently running " 3505e7437265Sahrens "ZFS pool version %llu.\n\n"), SPA_VERSION); 350699653d4eSeschrock cb.cb_first = B_TRUE; 3507eaca9bbdSeschrock if (showversions) { 3508eaca9bbdSeschrock (void) printf(gettext("The following versions are " 3509d7d4af51Smmusante "supported:\n\n")); 3510eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 3511eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 3512eaca9bbdSeschrock "---------------\n"); 351399653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 351444cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 351544cd46caSbillm "(replicated metadata)\n")); 351699653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 351799653d4eSeschrock "RAID-Z\n")); 3518d7306b64Sek110237 (void) printf(gettext(" 4 zpool history\n")); 3519c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 3520c9431fa1Sahl "algorithm\n")); 3521990b4856Slling (void) printf(gettext(" 6 bootfs pool property\n")); 35228654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 3523ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 3524a9799022Sck153898 (void) printf(gettext(" 9 refquota and refreservation " 3525a9799022Sck153898 "properties\n")); 3526fa94a07fSbrendan (void) printf(gettext(" 10 Cache devices\n")); 3527088f3894Sahrens (void) printf(gettext(" 11 Improved scrub performance\n")); 3528bb0ade09Sahrens (void) printf(gettext(" 12 Snapshot properties\n")); 352974e7dc98SMatthew Ahrens (void) printf(gettext(" 13 snapused property\n")); 3530d0f3f37eSMark Shellenbaum (void) printf(gettext(" 14 passthrough-x aclinherit " 3531d0f3f37eSMark Shellenbaum "support\n")); 35328654d025Sperrin (void) printf(gettext("For more information on a particular " 3533eaca9bbdSeschrock "version, including supported releases, see:\n\n")); 3534eaca9bbdSeschrock (void) printf("http://www.opensolaris.org/os/community/zfs/" 3535eaca9bbdSeschrock "version/N\n\n"); 3536eaca9bbdSeschrock (void) printf(gettext("Where 'N' is the version number.\n")); 3537eaca9bbdSeschrock } else if (argc == 0) { 3538eaca9bbdSeschrock int notfound; 3539eaca9bbdSeschrock 354099653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3541eaca9bbdSeschrock notfound = cb.cb_first; 3542eaca9bbdSeschrock 3543eaca9bbdSeschrock if (!cb.cb_all && ret == 0) { 3544eaca9bbdSeschrock if (!cb.cb_first) 3545eaca9bbdSeschrock (void) printf("\n"); 3546eaca9bbdSeschrock cb.cb_first = B_TRUE; 3547eaca9bbdSeschrock cb.cb_newer = B_TRUE; 354899653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3549eaca9bbdSeschrock if (!cb.cb_first) { 3550eaca9bbdSeschrock notfound = B_FALSE; 3551eaca9bbdSeschrock (void) printf("\n"); 3552eaca9bbdSeschrock } 3553eaca9bbdSeschrock } 3554eaca9bbdSeschrock 3555eaca9bbdSeschrock if (ret == 0) { 3556eaca9bbdSeschrock if (notfound) 3557eaca9bbdSeschrock (void) printf(gettext("All pools are formatted " 3558eaca9bbdSeschrock "using this version.\n")); 3559eaca9bbdSeschrock else if (!cb.cb_all) 3560eaca9bbdSeschrock (void) printf(gettext("Use 'zpool upgrade -v' " 3561eaca9bbdSeschrock "for a list of available versions and " 3562eaca9bbdSeschrock "their associated\nfeatures.\n")); 3563eaca9bbdSeschrock } 3564eaca9bbdSeschrock } else { 3565b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 3566b1b8ab34Slling upgrade_one, &cb); 356706eeb2adSek110237 } 356806eeb2adSek110237 356906eeb2adSek110237 return (ret); 357006eeb2adSek110237 } 357106eeb2adSek110237 3572ecd6cf80Smarks typedef struct hist_cbdata { 3573ecd6cf80Smarks boolean_t first; 3574ecd6cf80Smarks int longfmt; 3575ecd6cf80Smarks int internal; 3576ecd6cf80Smarks } hist_cbdata_t; 3577ecd6cf80Smarks 3578ecd6cf80Smarks char *hist_event_table[LOG_END] = { 3579ecd6cf80Smarks "invalid event", 3580ecd6cf80Smarks "pool create", 3581ecd6cf80Smarks "vdev add", 3582ecd6cf80Smarks "pool remove", 3583ecd6cf80Smarks "pool destroy", 3584ecd6cf80Smarks "pool export", 3585ecd6cf80Smarks "pool import", 3586ecd6cf80Smarks "vdev attach", 3587ecd6cf80Smarks "vdev replace", 3588ecd6cf80Smarks "vdev detach", 3589ecd6cf80Smarks "vdev online", 3590ecd6cf80Smarks "vdev offline", 3591ecd6cf80Smarks "vdev upgrade", 3592ecd6cf80Smarks "pool clear", 3593ecd6cf80Smarks "pool scrub", 3594ecd6cf80Smarks "pool property set", 3595ecd6cf80Smarks "create", 3596ecd6cf80Smarks "clone", 3597ecd6cf80Smarks "destroy", 3598ecd6cf80Smarks "destroy_begin_sync", 3599ecd6cf80Smarks "inherit", 3600ecd6cf80Smarks "property set", 3601ecd6cf80Smarks "quota set", 3602ecd6cf80Smarks "permission update", 3603ecd6cf80Smarks "permission remove", 3604ecd6cf80Smarks "permission who remove", 3605ecd6cf80Smarks "promote", 3606ecd6cf80Smarks "receive", 3607ecd6cf80Smarks "rename", 3608ecd6cf80Smarks "reservation set", 3609ecd6cf80Smarks "replay_inc_sync", 3610ecd6cf80Smarks "replay_full_sync", 3611ecd6cf80Smarks "rollback", 3612ecd6cf80Smarks "snapshot", 3613e7437265Sahrens "filesystem version upgrade", 3614a9799022Sck153898 "refquota set", 3615a9799022Sck153898 "refreservation set", 3616088f3894Sahrens "pool scrub done", 3617ecd6cf80Smarks }; 3618ecd6cf80Smarks 361906eeb2adSek110237 /* 362006eeb2adSek110237 * Print out the command history for a specific pool. 362106eeb2adSek110237 */ 362206eeb2adSek110237 static int 362306eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data) 362406eeb2adSek110237 { 362506eeb2adSek110237 nvlist_t *nvhis; 362606eeb2adSek110237 nvlist_t **records; 362706eeb2adSek110237 uint_t numrecords; 362806eeb2adSek110237 char *cmdstr; 3629ecd6cf80Smarks char *pathstr; 363006eeb2adSek110237 uint64_t dst_time; 363106eeb2adSek110237 time_t tsec; 363206eeb2adSek110237 struct tm t; 363306eeb2adSek110237 char tbuf[30]; 363406eeb2adSek110237 int ret, i; 3635ecd6cf80Smarks uint64_t who; 3636ecd6cf80Smarks struct passwd *pwd; 3637ecd6cf80Smarks char *hostname; 3638ecd6cf80Smarks char *zonename; 3639ecd6cf80Smarks char internalstr[MAXPATHLEN]; 3640ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 3641ecd6cf80Smarks uint64_t txg; 3642ecd6cf80Smarks uint64_t ievent; 364306eeb2adSek110237 3644ecd6cf80Smarks cb->first = B_FALSE; 364506eeb2adSek110237 364606eeb2adSek110237 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 364706eeb2adSek110237 364806eeb2adSek110237 if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 364906eeb2adSek110237 return (ret); 365006eeb2adSek110237 365106eeb2adSek110237 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 365206eeb2adSek110237 &records, &numrecords) == 0); 365306eeb2adSek110237 for (i = 0; i < numrecords; i++) { 365406eeb2adSek110237 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3655ecd6cf80Smarks &dst_time) != 0) 3656ecd6cf80Smarks continue; 3657ecd6cf80Smarks 3658ecd6cf80Smarks /* is it an internal event or a standard event? */ 3659ecd6cf80Smarks if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3660ecd6cf80Smarks &cmdstr) != 0) { 3661ecd6cf80Smarks if (cb->internal == 0) 3662ecd6cf80Smarks continue; 3663ecd6cf80Smarks 3664ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3665ecd6cf80Smarks ZPOOL_HIST_INT_EVENT, &ievent) != 0) 3666ecd6cf80Smarks continue; 3667ecd6cf80Smarks verify(nvlist_lookup_uint64(records[i], 3668ecd6cf80Smarks ZPOOL_HIST_TXG, &txg) == 0); 3669ecd6cf80Smarks verify(nvlist_lookup_string(records[i], 3670ecd6cf80Smarks ZPOOL_HIST_INT_STR, &pathstr) == 0); 3671088f3894Sahrens if (ievent >= LOG_END) 3672ecd6cf80Smarks continue; 3673ecd6cf80Smarks (void) snprintf(internalstr, 3674ecd6cf80Smarks sizeof (internalstr), 3675ecd6cf80Smarks "[internal %s txg:%lld] %s", 3676ecd6cf80Smarks hist_event_table[ievent], txg, 3677ecd6cf80Smarks pathstr); 3678ecd6cf80Smarks cmdstr = internalstr; 3679ecd6cf80Smarks } 368006eeb2adSek110237 tsec = dst_time; 368106eeb2adSek110237 (void) localtime_r(&tsec, &t); 368206eeb2adSek110237 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3683ecd6cf80Smarks (void) printf("%s %s", tbuf, cmdstr); 3684ecd6cf80Smarks 3685ecd6cf80Smarks if (!cb->longfmt) { 3686ecd6cf80Smarks (void) printf("\n"); 3687ecd6cf80Smarks continue; 368806eeb2adSek110237 } 3689ecd6cf80Smarks (void) printf(" ["); 3690ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3691ecd6cf80Smarks ZPOOL_HIST_WHO, &who) == 0) { 3692ecd6cf80Smarks pwd = getpwuid((uid_t)who); 3693ecd6cf80Smarks if (pwd) 3694ecd6cf80Smarks (void) printf("user %s on", 3695ecd6cf80Smarks pwd->pw_name); 3696ecd6cf80Smarks else 3697ecd6cf80Smarks (void) printf("user %d on", 3698ecd6cf80Smarks (int)who); 3699ecd6cf80Smarks } else { 3700ecd6cf80Smarks (void) printf(gettext("no info]\n")); 3701ecd6cf80Smarks continue; 3702ecd6cf80Smarks } 3703ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3704ecd6cf80Smarks ZPOOL_HIST_HOST, &hostname) == 0) { 3705ecd6cf80Smarks (void) printf(" %s", hostname); 3706ecd6cf80Smarks } 3707ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3708ecd6cf80Smarks ZPOOL_HIST_ZONE, &zonename) == 0) { 3709ecd6cf80Smarks (void) printf(":%s", zonename); 3710ecd6cf80Smarks } 3711ecd6cf80Smarks 3712ecd6cf80Smarks (void) printf("]"); 3713ecd6cf80Smarks (void) printf("\n"); 371406eeb2adSek110237 } 371506eeb2adSek110237 (void) printf("\n"); 371606eeb2adSek110237 nvlist_free(nvhis); 371706eeb2adSek110237 371806eeb2adSek110237 return (ret); 371906eeb2adSek110237 } 372006eeb2adSek110237 372106eeb2adSek110237 /* 372206eeb2adSek110237 * zpool history <pool> 372306eeb2adSek110237 * 372406eeb2adSek110237 * Displays the history of commands that modified pools. 372506eeb2adSek110237 */ 3726ecd6cf80Smarks 3727ecd6cf80Smarks 372806eeb2adSek110237 int 372906eeb2adSek110237 zpool_do_history(int argc, char **argv) 373006eeb2adSek110237 { 3731ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 373206eeb2adSek110237 int ret; 3733ecd6cf80Smarks int c; 373406eeb2adSek110237 3735ecd6cf80Smarks cbdata.first = B_TRUE; 3736ecd6cf80Smarks /* check options */ 3737ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 3738ecd6cf80Smarks switch (c) { 3739ecd6cf80Smarks case 'l': 3740ecd6cf80Smarks cbdata.longfmt = 1; 3741ecd6cf80Smarks break; 3742ecd6cf80Smarks case 'i': 3743ecd6cf80Smarks cbdata.internal = 1; 3744ecd6cf80Smarks break; 3745ecd6cf80Smarks case '?': 3746ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3747ecd6cf80Smarks optopt); 3748ecd6cf80Smarks usage(B_FALSE); 3749ecd6cf80Smarks } 3750ecd6cf80Smarks } 375106eeb2adSek110237 argc -= optind; 375206eeb2adSek110237 argv += optind; 375306eeb2adSek110237 3754b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3755ecd6cf80Smarks &cbdata); 375606eeb2adSek110237 3757ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 375806eeb2adSek110237 (void) printf(gettext("no pools available\n")); 375906eeb2adSek110237 return (0); 3760eaca9bbdSeschrock } 3761eaca9bbdSeschrock 3762eaca9bbdSeschrock return (ret); 3763eaca9bbdSeschrock } 3764eaca9bbdSeschrock 3765b1b8ab34Slling static int 3766b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 3767b1b8ab34Slling { 3768990b4856Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 3769b1b8ab34Slling char value[MAXNAMELEN]; 3770990b4856Slling zprop_source_t srctype; 3771990b4856Slling zprop_list_t *pl; 3772b1b8ab34Slling 3773b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3774b1b8ab34Slling 3775b1b8ab34Slling /* 3776990b4856Slling * Skip the special fake placeholder. This will also skip 3777990b4856Slling * over the name property when 'all' is specified. 3778b1b8ab34Slling */ 3779990b4856Slling if (pl->pl_prop == ZPOOL_PROP_NAME && 3780b1b8ab34Slling pl == cbp->cb_proplist) 3781b1b8ab34Slling continue; 3782b1b8ab34Slling 3783b1b8ab34Slling if (zpool_get_prop(zhp, pl->pl_prop, 3784b1b8ab34Slling value, sizeof (value), &srctype) != 0) 3785b1b8ab34Slling continue; 3786b1b8ab34Slling 3787990b4856Slling zprop_print_one_property(zpool_get_name(zhp), cbp, 3788b1b8ab34Slling zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3789b1b8ab34Slling } 3790b1b8ab34Slling return (0); 3791b1b8ab34Slling } 3792b1b8ab34Slling 3793b1b8ab34Slling int 3794b1b8ab34Slling zpool_do_get(int argc, char **argv) 3795b1b8ab34Slling { 3796990b4856Slling zprop_get_cbdata_t cb = { 0 }; 3797990b4856Slling zprop_list_t fake_name = { 0 }; 3798b1b8ab34Slling int ret; 3799b1b8ab34Slling 3800b1b8ab34Slling if (argc < 3) 3801b1b8ab34Slling usage(B_FALSE); 3802b1b8ab34Slling 3803b1b8ab34Slling cb.cb_first = B_TRUE; 3804990b4856Slling cb.cb_sources = ZPROP_SRC_ALL; 3805b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 3806b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 3807b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 3808b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 3809990b4856Slling cb.cb_type = ZFS_TYPE_POOL; 3810b1b8ab34Slling 3811990b4856Slling if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 3812990b4856Slling ZFS_TYPE_POOL) != 0) 3813b1b8ab34Slling usage(B_FALSE); 3814b1b8ab34Slling 3815b1b8ab34Slling if (cb.cb_proplist != NULL) { 3816990b4856Slling fake_name.pl_prop = ZPOOL_PROP_NAME; 3817b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 3818b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 3819b1b8ab34Slling cb.cb_proplist = &fake_name; 3820b1b8ab34Slling } 3821b1b8ab34Slling 3822b1b8ab34Slling ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3823b1b8ab34Slling get_callback, &cb); 3824b1b8ab34Slling 3825b1b8ab34Slling if (cb.cb_proplist == &fake_name) 3826990b4856Slling zprop_free_list(fake_name.pl_next); 3827b1b8ab34Slling else 3828990b4856Slling zprop_free_list(cb.cb_proplist); 3829b1b8ab34Slling 3830b1b8ab34Slling return (ret); 3831b1b8ab34Slling } 3832b1b8ab34Slling 3833b1b8ab34Slling typedef struct set_cbdata { 3834b1b8ab34Slling char *cb_propname; 3835b1b8ab34Slling char *cb_value; 3836b1b8ab34Slling boolean_t cb_any_successful; 3837b1b8ab34Slling } set_cbdata_t; 3838b1b8ab34Slling 3839b1b8ab34Slling int 3840b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 3841b1b8ab34Slling { 3842b1b8ab34Slling int error; 3843b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 3844b1b8ab34Slling 3845b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3846b1b8ab34Slling 3847b1b8ab34Slling if (!error) 3848b1b8ab34Slling cb->cb_any_successful = B_TRUE; 3849b1b8ab34Slling 3850b1b8ab34Slling return (error); 3851b1b8ab34Slling } 3852b1b8ab34Slling 3853b1b8ab34Slling int 3854b1b8ab34Slling zpool_do_set(int argc, char **argv) 3855b1b8ab34Slling { 3856b1b8ab34Slling set_cbdata_t cb = { 0 }; 3857b1b8ab34Slling int error; 3858b1b8ab34Slling 3859b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 3860b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3861b1b8ab34Slling argv[1][1]); 3862b1b8ab34Slling usage(B_FALSE); 3863b1b8ab34Slling } 3864b1b8ab34Slling 3865b1b8ab34Slling if (argc < 2) { 3866b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 3867b1b8ab34Slling "argument\n")); 3868b1b8ab34Slling usage(B_FALSE); 3869b1b8ab34Slling } 3870b1b8ab34Slling 3871b1b8ab34Slling if (argc < 3) { 3872b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 3873b1b8ab34Slling usage(B_FALSE); 3874b1b8ab34Slling } 3875b1b8ab34Slling 3876b1b8ab34Slling if (argc > 3) { 3877b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 3878b1b8ab34Slling usage(B_FALSE); 3879b1b8ab34Slling } 3880b1b8ab34Slling 3881b1b8ab34Slling cb.cb_propname = argv[1]; 3882b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 3883b1b8ab34Slling if (cb.cb_value == NULL) { 3884b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 3885b1b8ab34Slling "property=value argument\n")); 3886b1b8ab34Slling usage(B_FALSE); 3887b1b8ab34Slling } 3888b1b8ab34Slling 3889b1b8ab34Slling *(cb.cb_value) = '\0'; 3890b1b8ab34Slling cb.cb_value++; 3891b1b8ab34Slling 3892b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3893b1b8ab34Slling set_callback, &cb); 3894b1b8ab34Slling 3895b1b8ab34Slling return (error); 3896b1b8ab34Slling } 3897b1b8ab34Slling 3898b1b8ab34Slling static int 3899b1b8ab34Slling find_command_idx(char *command, int *idx) 3900b1b8ab34Slling { 3901b1b8ab34Slling int i; 3902b1b8ab34Slling 3903b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 3904b1b8ab34Slling if (command_table[i].name == NULL) 3905b1b8ab34Slling continue; 3906b1b8ab34Slling 3907b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 3908b1b8ab34Slling *idx = i; 3909b1b8ab34Slling return (0); 3910b1b8ab34Slling } 3911b1b8ab34Slling } 3912b1b8ab34Slling return (1); 3913b1b8ab34Slling } 3914b1b8ab34Slling 3915fa9e4066Sahrens int 3916fa9e4066Sahrens main(int argc, char **argv) 3917fa9e4066Sahrens { 3918fa9e4066Sahrens int ret; 3919fa9e4066Sahrens int i; 3920fa9e4066Sahrens char *cmdname; 3921fa9e4066Sahrens 3922fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 3923fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 3924fa9e4066Sahrens 392599653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 392699653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 3927203a47d8Snd150628 "initialize ZFS library\n")); 392899653d4eSeschrock return (1); 392999653d4eSeschrock } 393099653d4eSeschrock 393199653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 393299653d4eSeschrock 3933fa9e4066Sahrens opterr = 0; 3934fa9e4066Sahrens 3935fa9e4066Sahrens /* 3936fa9e4066Sahrens * Make sure the user has specified some command. 3937fa9e4066Sahrens */ 3938fa9e4066Sahrens if (argc < 2) { 3939fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 394099653d4eSeschrock usage(B_FALSE); 3941fa9e4066Sahrens } 3942fa9e4066Sahrens 3943fa9e4066Sahrens cmdname = argv[1]; 3944fa9e4066Sahrens 3945fa9e4066Sahrens /* 3946fa9e4066Sahrens * Special case '-?' 3947fa9e4066Sahrens */ 3948fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 394999653d4eSeschrock usage(B_TRUE); 3950fa9e4066Sahrens 39512a6b87f0Sek110237 zpool_set_history_str("zpool", argc, argv, history_str); 39522a6b87f0Sek110237 verify(zpool_stage_history(g_zfs, history_str) == 0); 39532a6b87f0Sek110237 3954fa9e4066Sahrens /* 3955fa9e4066Sahrens * Run the appropriate command. 3956fa9e4066Sahrens */ 3957b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 3958fa9e4066Sahrens current_command = &command_table[i]; 3959fa9e4066Sahrens ret = command_table[i].func(argc - 1, argv + 1); 396091ebeef5Sahrens } else if (strchr(cmdname, '=')) { 396191ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 396291ebeef5Sahrens current_command = &command_table[i]; 396391ebeef5Sahrens ret = command_table[i].func(argc, argv); 396491ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 3965fa9e4066Sahrens /* 396691ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 396791ebeef5Sahrens * it as such. 3968fa9e4066Sahrens */ 3969ea8dc4b6Seschrock char buf[16384]; 3970ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 3971fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 3972fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 397391ebeef5Sahrens } else { 3974fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 3975fa9e4066Sahrens "command '%s'\n"), cmdname); 397699653d4eSeschrock usage(B_FALSE); 3977fa9e4066Sahrens } 3978fa9e4066Sahrens 397999653d4eSeschrock libzfs_fini(g_zfs); 398099653d4eSeschrock 3981fa9e4066Sahrens /* 3982fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3983fa9e4066Sahrens * for the purposes of running ::findleaks. 3984fa9e4066Sahrens */ 3985fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 3986fa9e4066Sahrens (void) printf("dumping core by request\n"); 3987fa9e4066Sahrens abort(); 3988fa9e4066Sahrens } 3989fa9e4066Sahrens 3990fa9e4066Sahrens return (ret); 3991fa9e4066Sahrens } 3992