1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 2199653d4eSeschrock 22fa9e4066Sahrens /* 2318ce54dfSek110237 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29fa9e4066Sahrens #include <assert.h> 30fa9e4066Sahrens #include <ctype.h> 31fa9e4066Sahrens #include <dirent.h> 32fa9e4066Sahrens #include <errno.h> 33fa9e4066Sahrens #include <fcntl.h> 34fa9e4066Sahrens #include <libgen.h> 35fa9e4066Sahrens #include <libintl.h> 36fa9e4066Sahrens #include <libuutil.h> 37fa9e4066Sahrens #include <locale.h> 38fa9e4066Sahrens #include <stdio.h> 39fa9e4066Sahrens #include <stdlib.h> 40fa9e4066Sahrens #include <string.h> 41fa9e4066Sahrens #include <strings.h> 42fa9e4066Sahrens #include <unistd.h> 43fa9e4066Sahrens #include <priv.h> 44ecd6cf80Smarks #include <pwd.h> 45ecd6cf80Smarks #include <zone.h> 46b1b8ab34Slling #include <sys/fs/zfs.h> 47fa9e4066Sahrens 48fa9e4066Sahrens #include <sys/stat.h> 49fa9e4066Sahrens 50fa9e4066Sahrens #include <libzfs.h> 51fa9e4066Sahrens 52fa9e4066Sahrens #include "zpool_util.h" 53b7b97454Sperrin #include "zfs_comutil.h" 54fa9e4066Sahrens 55fa9e4066Sahrens static int zpool_do_create(int, char **); 56fa9e4066Sahrens static int zpool_do_destroy(int, char **); 57fa9e4066Sahrens 58fa9e4066Sahrens static int zpool_do_add(int, char **); 5999653d4eSeschrock static int zpool_do_remove(int, char **); 60fa9e4066Sahrens 61fa9e4066Sahrens static int zpool_do_list(int, char **); 62fa9e4066Sahrens static int zpool_do_iostat(int, char **); 63fa9e4066Sahrens static int zpool_do_status(int, char **); 64fa9e4066Sahrens 65fa9e4066Sahrens static int zpool_do_online(int, char **); 66fa9e4066Sahrens static int zpool_do_offline(int, char **); 67ea8dc4b6Seschrock static int zpool_do_clear(int, char **); 68fa9e4066Sahrens 69fa9e4066Sahrens static int zpool_do_attach(int, char **); 70fa9e4066Sahrens static int zpool_do_detach(int, char **); 71fa9e4066Sahrens static int zpool_do_replace(int, char **); 72fa9e4066Sahrens 73fa9e4066Sahrens static int zpool_do_scrub(int, char **); 74fa9e4066Sahrens 75fa9e4066Sahrens static int zpool_do_import(int, char **); 76fa9e4066Sahrens static int zpool_do_export(int, char **); 77fa9e4066Sahrens 78eaca9bbdSeschrock static int zpool_do_upgrade(int, char **); 79eaca9bbdSeschrock 8006eeb2adSek110237 static int zpool_do_history(int, char **); 8106eeb2adSek110237 82b1b8ab34Slling static int zpool_do_get(int, char **); 83b1b8ab34Slling static int zpool_do_set(int, char **); 84b1b8ab34Slling 85fa9e4066Sahrens /* 86fa9e4066Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 87fa9e4066Sahrens * debugging facilities. 88fa9e4066Sahrens */ 8929ab75c9Srm160521 9029ab75c9Srm160521 #ifdef DEBUG 91fa9e4066Sahrens const char * 9299653d4eSeschrock _umem_debug_init(void) 93fa9e4066Sahrens { 94fa9e4066Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 95fa9e4066Sahrens } 96fa9e4066Sahrens 97fa9e4066Sahrens const char * 98fa9e4066Sahrens _umem_logging_init(void) 99fa9e4066Sahrens { 100fa9e4066Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 101fa9e4066Sahrens } 10229ab75c9Srm160521 #endif 103fa9e4066Sahrens 10465cd9f28Seschrock typedef enum { 10565cd9f28Seschrock HELP_ADD, 10665cd9f28Seschrock HELP_ATTACH, 107ea8dc4b6Seschrock HELP_CLEAR, 10865cd9f28Seschrock HELP_CREATE, 10965cd9f28Seschrock HELP_DESTROY, 11065cd9f28Seschrock HELP_DETACH, 11165cd9f28Seschrock HELP_EXPORT, 11206eeb2adSek110237 HELP_HISTORY, 11365cd9f28Seschrock HELP_IMPORT, 11465cd9f28Seschrock HELP_IOSTAT, 11565cd9f28Seschrock HELP_LIST, 11665cd9f28Seschrock HELP_OFFLINE, 11765cd9f28Seschrock HELP_ONLINE, 11865cd9f28Seschrock HELP_REPLACE, 11999653d4eSeschrock HELP_REMOVE, 12065cd9f28Seschrock HELP_SCRUB, 121eaca9bbdSeschrock HELP_STATUS, 122b1b8ab34Slling HELP_UPGRADE, 123b1b8ab34Slling HELP_GET, 124b1b8ab34Slling HELP_SET 12565cd9f28Seschrock } zpool_help_t; 12665cd9f28Seschrock 12765cd9f28Seschrock 128fa9e4066Sahrens typedef struct zpool_command { 129fa9e4066Sahrens const char *name; 130fa9e4066Sahrens int (*func)(int, char **); 13165cd9f28Seschrock zpool_help_t usage; 132fa9e4066Sahrens } zpool_command_t; 133fa9e4066Sahrens 134fa9e4066Sahrens /* 135fa9e4066Sahrens * Master command table. Each ZFS command has a name, associated function, and 136ea8dc4b6Seschrock * usage message. The usage messages need to be internationalized, so we have 137ea8dc4b6Seschrock * to have a function to return the usage message based on a command index. 13865cd9f28Seschrock * 13965cd9f28Seschrock * These commands are organized according to how they are displayed in the usage 14065cd9f28Seschrock * message. An empty command (one with a NULL name) indicates an empty line in 14165cd9f28Seschrock * the generic usage message. 142fa9e4066Sahrens */ 143fa9e4066Sahrens static zpool_command_t command_table[] = { 14465cd9f28Seschrock { "create", zpool_do_create, HELP_CREATE }, 14565cd9f28Seschrock { "destroy", zpool_do_destroy, HELP_DESTROY }, 146fa9e4066Sahrens { NULL }, 14765cd9f28Seschrock { "add", zpool_do_add, HELP_ADD }, 14899653d4eSeschrock { "remove", zpool_do_remove, HELP_REMOVE }, 149fa9e4066Sahrens { NULL }, 15065cd9f28Seschrock { "list", zpool_do_list, HELP_LIST }, 15165cd9f28Seschrock { "iostat", zpool_do_iostat, HELP_IOSTAT }, 15265cd9f28Seschrock { "status", zpool_do_status, HELP_STATUS }, 153fa9e4066Sahrens { NULL }, 15465cd9f28Seschrock { "online", zpool_do_online, HELP_ONLINE }, 15565cd9f28Seschrock { "offline", zpool_do_offline, HELP_OFFLINE }, 156ea8dc4b6Seschrock { "clear", zpool_do_clear, HELP_CLEAR }, 157fa9e4066Sahrens { NULL }, 15865cd9f28Seschrock { "attach", zpool_do_attach, HELP_ATTACH }, 15965cd9f28Seschrock { "detach", zpool_do_detach, HELP_DETACH }, 16065cd9f28Seschrock { "replace", zpool_do_replace, HELP_REPLACE }, 161fa9e4066Sahrens { NULL }, 16265cd9f28Seschrock { "scrub", zpool_do_scrub, HELP_SCRUB }, 163fa9e4066Sahrens { NULL }, 16465cd9f28Seschrock { "import", zpool_do_import, HELP_IMPORT }, 16565cd9f28Seschrock { "export", zpool_do_export, HELP_EXPORT }, 16606eeb2adSek110237 { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 16706eeb2adSek110237 { NULL }, 168b1b8ab34Slling { "history", zpool_do_history, HELP_HISTORY }, 169b1b8ab34Slling { "get", zpool_do_get, HELP_GET }, 170b1b8ab34Slling { "set", zpool_do_set, HELP_SET }, 171fa9e4066Sahrens }; 172fa9e4066Sahrens 173fa9e4066Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 174fa9e4066Sahrens 175fa9e4066Sahrens zpool_command_t *current_command; 1762a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN]; 177fa9e4066Sahrens 17865cd9f28Seschrock static const char * 17965cd9f28Seschrock get_usage(zpool_help_t idx) { 18065cd9f28Seschrock switch (idx) { 18165cd9f28Seschrock case HELP_ADD: 18265cd9f28Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 18365cd9f28Seschrock case HELP_ATTACH: 18465cd9f28Seschrock return (gettext("\tattach [-f] <pool> <device> " 185e45ce728Sahrens "<new-device>\n")); 186ea8dc4b6Seschrock case HELP_CLEAR: 187ea8dc4b6Seschrock return (gettext("\tclear <pool> [device]\n")); 18865cd9f28Seschrock case HELP_CREATE: 189990b4856Slling return (gettext("\tcreate [-fn] [-o property=value] ... \n" 1900a48a24eStimh "\t [-O file-system-property=value] ... \n" 191990b4856Slling "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 19265cd9f28Seschrock case HELP_DESTROY: 19365cd9f28Seschrock return (gettext("\tdestroy [-f] <pool>\n")); 19465cd9f28Seschrock case HELP_DETACH: 19565cd9f28Seschrock return (gettext("\tdetach <pool> <device>\n")); 19665cd9f28Seschrock case HELP_EXPORT: 19765cd9f28Seschrock return (gettext("\texport [-f] <pool> ...\n")); 19806eeb2adSek110237 case HELP_HISTORY: 199ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 20065cd9f28Seschrock case HELP_IMPORT: 2014c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 2022f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 2032f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n" 2042f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 2052f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] " 2062f8aaab3Seschrock "<pool | id> [newpool]\n")); 20765cd9f28Seschrock case HELP_IOSTAT: 20865cd9f28Seschrock return (gettext("\tiostat [-v] [pool] ... [interval " 20965cd9f28Seschrock "[count]]\n")); 21065cd9f28Seschrock case HELP_LIST: 211990b4856Slling return (gettext("\tlist [-H] [-o property[,...]] " 212990b4856Slling "[pool] ...\n")); 21365cd9f28Seschrock case HELP_OFFLINE: 214441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 21565cd9f28Seschrock case HELP_ONLINE: 216441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 21765cd9f28Seschrock case HELP_REPLACE: 21865cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 219e45ce728Sahrens "[new-device]\n")); 22099653d4eSeschrock case HELP_REMOVE: 221fa94a07fSbrendan return (gettext("\tremove <pool> <device> ...\n")); 22265cd9f28Seschrock case HELP_SCRUB: 22365cd9f28Seschrock return (gettext("\tscrub [-s] <pool> ...\n")); 22465cd9f28Seschrock case HELP_STATUS: 22565cd9f28Seschrock return (gettext("\tstatus [-vx] [pool] ...\n")); 226eaca9bbdSeschrock case HELP_UPGRADE: 227eaca9bbdSeschrock return (gettext("\tupgrade\n" 228eaca9bbdSeschrock "\tupgrade -v\n" 229990b4856Slling "\tupgrade [-V version] <-a | pool ...>\n")); 230b1b8ab34Slling case HELP_GET: 231e45ce728Sahrens return (gettext("\tget <\"all\" | property[,...]> " 232b1b8ab34Slling "<pool> ...\n")); 233b1b8ab34Slling case HELP_SET: 234b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 23565cd9f28Seschrock } 23665cd9f28Seschrock 23765cd9f28Seschrock abort(); 23865cd9f28Seschrock /* NOTREACHED */ 23965cd9f28Seschrock } 24065cd9f28Seschrock 241fa9e4066Sahrens 242fa9e4066Sahrens /* 243b1b8ab34Slling * Callback routine that will print out a pool property value. 244b1b8ab34Slling */ 245990b4856Slling static int 246990b4856Slling print_prop_cb(int prop, void *cb) 247b1b8ab34Slling { 248b1b8ab34Slling FILE *fp = cb; 249b1b8ab34Slling 250b1b8ab34Slling (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 251b1b8ab34Slling 252990b4856Slling if (zpool_prop_readonly(prop)) 253990b4856Slling (void) fprintf(fp, " NO "); 254990b4856Slling else 255990b4856Slling (void) fprintf(fp, " YES "); 256990b4856Slling 257b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 258b1b8ab34Slling (void) fprintf(fp, "-\n"); 259b1b8ab34Slling else 260b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 261b1b8ab34Slling 262990b4856Slling return (ZPROP_CONT); 263b1b8ab34Slling } 264b1b8ab34Slling 265b1b8ab34Slling /* 266fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 267fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 268fa9e4066Sahrens * a complete usage message. 269fa9e4066Sahrens */ 270fa9e4066Sahrens void 27199653d4eSeschrock usage(boolean_t requested) 272fa9e4066Sahrens { 273fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 274fa9e4066Sahrens 275fa9e4066Sahrens if (current_command == NULL) { 276fa9e4066Sahrens int i; 277fa9e4066Sahrens 278fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 279fa9e4066Sahrens (void) fprintf(fp, 280fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 281fa9e4066Sahrens 282fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 283fa9e4066Sahrens if (command_table[i].name == NULL) 284fa9e4066Sahrens (void) fprintf(fp, "\n"); 285fa9e4066Sahrens else 286fa9e4066Sahrens (void) fprintf(fp, "%s", 28765cd9f28Seschrock get_usage(command_table[i].usage)); 288fa9e4066Sahrens } 289fa9e4066Sahrens } else { 290fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 29165cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 292fa9e4066Sahrens } 293fa9e4066Sahrens 294b1b8ab34Slling if (current_command != NULL && 295b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 296990b4856Slling (strcmp(current_command->name, "get") == 0) || 297990b4856Slling (strcmp(current_command->name, "list") == 0))) { 298b1b8ab34Slling 299b1b8ab34Slling (void) fprintf(fp, 300b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 301b1b8ab34Slling 302990b4856Slling (void) fprintf(fp, "\n\t%-13s %s %s\n\n", 303990b4856Slling "PROPERTY", "EDIT", "VALUES"); 304b1b8ab34Slling 305b1b8ab34Slling /* Iterate over all properties */ 306990b4856Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 307990b4856Slling ZFS_TYPE_POOL); 308b1b8ab34Slling } 309b1b8ab34Slling 310e9dbad6fSeschrock /* 311e9dbad6fSeschrock * See comments at end of main(). 312e9dbad6fSeschrock */ 313e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 314e9dbad6fSeschrock (void) printf("dumping core by request\n"); 315e9dbad6fSeschrock abort(); 316e9dbad6fSeschrock } 317e9dbad6fSeschrock 318fa9e4066Sahrens exit(requested ? 0 : 2); 319fa9e4066Sahrens } 320fa9e4066Sahrens 321fa9e4066Sahrens void 3228654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 3238654d025Sperrin boolean_t print_logs) 324fa9e4066Sahrens { 325fa9e4066Sahrens nvlist_t **child; 326fa9e4066Sahrens uint_t c, children; 327afefbcddSeschrock char *vname; 328fa9e4066Sahrens 329fa9e4066Sahrens if (name != NULL) 330fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 331fa9e4066Sahrens 332fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 333fa9e4066Sahrens &child, &children) != 0) 334fa9e4066Sahrens return; 335fa9e4066Sahrens 336afefbcddSeschrock for (c = 0; c < children; c++) { 3378654d025Sperrin uint64_t is_log = B_FALSE; 3388654d025Sperrin 3398654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3408654d025Sperrin &is_log); 3418654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 3428654d025Sperrin continue; 3438654d025Sperrin 34499653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 3458654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 3468654d025Sperrin B_FALSE); 347afefbcddSeschrock free(vname); 348afefbcddSeschrock } 349fa9e4066Sahrens } 350fa9e4066Sahrens 351fa9e4066Sahrens /* 352990b4856Slling * Add a property pair (name, string-value) into a property nvlist. 353990b4856Slling */ 354990b4856Slling static int 3550a48a24eStimh add_prop_list(const char *propname, char *propval, nvlist_t **props, 3560a48a24eStimh boolean_t poolprop) 357990b4856Slling { 3580a48a24eStimh zpool_prop_t prop = ZPROP_INVAL; 3590a48a24eStimh zfs_prop_t fprop; 360990b4856Slling nvlist_t *proplist; 3610a48a24eStimh const char *normnm; 3620a48a24eStimh char *strval; 363990b4856Slling 364990b4856Slling if (*props == NULL && 365990b4856Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 366990b4856Slling (void) fprintf(stderr, 367990b4856Slling gettext("internal error: out of memory\n")); 368990b4856Slling return (1); 369990b4856Slling } 370990b4856Slling 371990b4856Slling proplist = *props; 372990b4856Slling 3730a48a24eStimh if (poolprop) { 374990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 375990b4856Slling (void) fprintf(stderr, gettext("property '%s' is " 376990b4856Slling "not a valid pool property\n"), propname); 377990b4856Slling return (2); 378990b4856Slling } 3790a48a24eStimh normnm = zpool_prop_to_name(prop); 3800a48a24eStimh } else { 3810a48a24eStimh if ((fprop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 3820a48a24eStimh (void) fprintf(stderr, gettext("property '%s' is " 3830a48a24eStimh "not a valid file system property\n"), propname); 3840a48a24eStimh return (2); 3850a48a24eStimh } 3860a48a24eStimh normnm = zfs_prop_to_name(fprop); 3870a48a24eStimh } 388990b4856Slling 3890a48a24eStimh if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 3900a48a24eStimh prop != ZPOOL_PROP_CACHEFILE) { 391990b4856Slling (void) fprintf(stderr, gettext("property '%s' " 392990b4856Slling "specified multiple times\n"), propname); 393990b4856Slling return (2); 394990b4856Slling } 395990b4856Slling 3960a48a24eStimh if (nvlist_add_string(proplist, normnm, propval) != 0) { 397990b4856Slling (void) fprintf(stderr, gettext("internal " 398990b4856Slling "error: out of memory\n")); 399990b4856Slling return (1); 400990b4856Slling } 401990b4856Slling 402990b4856Slling return (0); 403990b4856Slling } 404990b4856Slling 405990b4856Slling /* 406fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 407fa9e4066Sahrens * 408fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 409fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 410fa9e4066Sahrens * they were to be added. 411fa9e4066Sahrens * 412fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 413fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 414fa9e4066Sahrens * libzfs. 415fa9e4066Sahrens */ 416fa9e4066Sahrens int 417fa9e4066Sahrens zpool_do_add(int argc, char **argv) 418fa9e4066Sahrens { 41999653d4eSeschrock boolean_t force = B_FALSE; 42099653d4eSeschrock boolean_t dryrun = B_FALSE; 421fa9e4066Sahrens int c; 422fa9e4066Sahrens nvlist_t *nvroot; 423fa9e4066Sahrens char *poolname; 424fa9e4066Sahrens int ret; 425fa9e4066Sahrens zpool_handle_t *zhp; 426fa9e4066Sahrens nvlist_t *config; 427fa9e4066Sahrens 428fa9e4066Sahrens /* check options */ 429fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 430fa9e4066Sahrens switch (c) { 431fa9e4066Sahrens case 'f': 43299653d4eSeschrock force = B_TRUE; 433fa9e4066Sahrens break; 434fa9e4066Sahrens case 'n': 43599653d4eSeschrock dryrun = B_TRUE; 436fa9e4066Sahrens break; 437fa9e4066Sahrens case '?': 438fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 439fa9e4066Sahrens optopt); 44099653d4eSeschrock usage(B_FALSE); 441fa9e4066Sahrens } 442fa9e4066Sahrens } 443fa9e4066Sahrens 444fa9e4066Sahrens argc -= optind; 445fa9e4066Sahrens argv += optind; 446fa9e4066Sahrens 447fa9e4066Sahrens /* get pool name and check number of arguments */ 448fa9e4066Sahrens if (argc < 1) { 449fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 45099653d4eSeschrock usage(B_FALSE); 451fa9e4066Sahrens } 452fa9e4066Sahrens if (argc < 2) { 453fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 45499653d4eSeschrock usage(B_FALSE); 455fa9e4066Sahrens } 456fa9e4066Sahrens 457fa9e4066Sahrens poolname = argv[0]; 458fa9e4066Sahrens 459fa9e4066Sahrens argc--; 460fa9e4066Sahrens argv++; 461fa9e4066Sahrens 46299653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 463fa9e4066Sahrens return (1); 464fa9e4066Sahrens 465088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 466fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 467fa9e4066Sahrens poolname); 468fa9e4066Sahrens zpool_close(zhp); 469fa9e4066Sahrens return (1); 470fa9e4066Sahrens } 471fa9e4066Sahrens 472fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 4738488aeb5Staylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv); 474fa9e4066Sahrens if (nvroot == NULL) { 475fa9e4066Sahrens zpool_close(zhp); 476fa9e4066Sahrens return (1); 477fa9e4066Sahrens } 478fa9e4066Sahrens 479fa9e4066Sahrens if (dryrun) { 480fa9e4066Sahrens nvlist_t *poolnvroot; 481fa9e4066Sahrens 482fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 483fa9e4066Sahrens &poolnvroot) == 0); 484fa9e4066Sahrens 485fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 486fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 487fa9e4066Sahrens 4888654d025Sperrin /* print original main pool and new tree */ 4898654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 4908654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 4918654d025Sperrin 4928654d025Sperrin /* Do the same for the logs */ 4938654d025Sperrin if (num_logs(poolnvroot) > 0) { 4948654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 4958654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 4968654d025Sperrin } else if (num_logs(nvroot) > 0) { 4978654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 4988654d025Sperrin } 499fa9e4066Sahrens 500fa9e4066Sahrens ret = 0; 501fa9e4066Sahrens } else { 502fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 503fa9e4066Sahrens } 504fa9e4066Sahrens 50599653d4eSeschrock nvlist_free(nvroot); 50699653d4eSeschrock zpool_close(zhp); 50799653d4eSeschrock 50899653d4eSeschrock return (ret); 50999653d4eSeschrock } 51099653d4eSeschrock 51199653d4eSeschrock /* 512fa94a07fSbrendan * zpool remove <pool> <vdev> ... 51399653d4eSeschrock * 51499653d4eSeschrock * Removes the given vdev from the pool. Currently, this only supports removing 515fa94a07fSbrendan * spares and cache devices from the pool. Eventually, we'll want to support 516fa94a07fSbrendan * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs. 51799653d4eSeschrock */ 51899653d4eSeschrock int 51999653d4eSeschrock zpool_do_remove(int argc, char **argv) 52099653d4eSeschrock { 52199653d4eSeschrock char *poolname; 522fa94a07fSbrendan int i, ret = 0; 52399653d4eSeschrock zpool_handle_t *zhp; 52499653d4eSeschrock 52599653d4eSeschrock argc--; 52699653d4eSeschrock argv++; 52799653d4eSeschrock 52899653d4eSeschrock /* get pool name and check number of arguments */ 52999653d4eSeschrock if (argc < 1) { 53099653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 53199653d4eSeschrock usage(B_FALSE); 53299653d4eSeschrock } 53399653d4eSeschrock if (argc < 2) { 53499653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 53599653d4eSeschrock usage(B_FALSE); 53699653d4eSeschrock } 53799653d4eSeschrock 53899653d4eSeschrock poolname = argv[0]; 53999653d4eSeschrock 54099653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 54199653d4eSeschrock return (1); 54299653d4eSeschrock 543fa94a07fSbrendan for (i = 1; i < argc; i++) { 544fa94a07fSbrendan if (zpool_vdev_remove(zhp, argv[i]) != 0) 545fa94a07fSbrendan ret = 1; 546fa94a07fSbrendan } 54799653d4eSeschrock 548fa9e4066Sahrens return (ret); 549fa9e4066Sahrens } 550fa9e4066Sahrens 551fa9e4066Sahrens /* 5520a48a24eStimh * zpool create [-fn] [-o property=value] ... 5530a48a24eStimh * [-O file-system-property=value] ... 5540a48a24eStimh * [-R root] [-m mountpoint] <pool> <dev> ... 555fa9e4066Sahrens * 556fa9e4066Sahrens * -f Force creation, even if devices appear in use 557fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 558fa9e4066Sahrens * were to be created. 559fa9e4066Sahrens * -R Create a pool under an alternate root 560fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 561fa9e4066Sahrens * '/<pool>' 562990b4856Slling * -o Set property=value. 5630a48a24eStimh * -O Set fsproperty=value in the pool's root file system 564fa9e4066Sahrens * 565b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 566fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 567fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 568fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 569fa9e4066Sahrens */ 570fa9e4066Sahrens int 571fa9e4066Sahrens zpool_do_create(int argc, char **argv) 572fa9e4066Sahrens { 57399653d4eSeschrock boolean_t force = B_FALSE; 57499653d4eSeschrock boolean_t dryrun = B_FALSE; 575fa9e4066Sahrens int c; 576990b4856Slling nvlist_t *nvroot = NULL; 577fa9e4066Sahrens char *poolname; 578990b4856Slling int ret = 1; 579fa9e4066Sahrens char *altroot = NULL; 580fa9e4066Sahrens char *mountpoint = NULL; 5810a48a24eStimh nvlist_t *fsprops = NULL; 582990b4856Slling nvlist_t *props = NULL; 5832f8aaab3Seschrock char *propval; 584fa9e4066Sahrens 585fa9e4066Sahrens /* check options */ 5860a48a24eStimh while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) { 587fa9e4066Sahrens switch (c) { 588fa9e4066Sahrens case 'f': 58999653d4eSeschrock force = B_TRUE; 590fa9e4066Sahrens break; 591fa9e4066Sahrens case 'n': 59299653d4eSeschrock dryrun = B_TRUE; 593fa9e4066Sahrens break; 594fa9e4066Sahrens case 'R': 595fa9e4066Sahrens altroot = optarg; 596990b4856Slling if (add_prop_list(zpool_prop_to_name( 5970a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 598990b4856Slling goto errout; 5992f8aaab3Seschrock if (nvlist_lookup_string(props, 6002f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 6012f8aaab3Seschrock &propval) == 0) 6022f8aaab3Seschrock break; 603990b4856Slling if (add_prop_list(zpool_prop_to_name( 6040a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 605990b4856Slling goto errout; 606fa9e4066Sahrens break; 607fa9e4066Sahrens case 'm': 608fa9e4066Sahrens mountpoint = optarg; 609fa9e4066Sahrens break; 610990b4856Slling case 'o': 611990b4856Slling if ((propval = strchr(optarg, '=')) == NULL) { 612990b4856Slling (void) fprintf(stderr, gettext("missing " 613990b4856Slling "'=' for -o option\n")); 614990b4856Slling goto errout; 615990b4856Slling } 616990b4856Slling *propval = '\0'; 617990b4856Slling propval++; 618990b4856Slling 6190a48a24eStimh if (add_prop_list(optarg, propval, &props, B_TRUE)) 6200a48a24eStimh goto errout; 6210a48a24eStimh break; 6220a48a24eStimh case 'O': 6230a48a24eStimh if ((propval = strchr(optarg, '=')) == NULL) { 6240a48a24eStimh (void) fprintf(stderr, gettext("missing " 6250a48a24eStimh "'=' for -O option\n")); 6260a48a24eStimh goto errout; 6270a48a24eStimh } 6280a48a24eStimh *propval = '\0'; 6290a48a24eStimh propval++; 6300a48a24eStimh 6310a48a24eStimh if (add_prop_list(optarg, propval, &fsprops, B_FALSE)) 632990b4856Slling goto errout; 633990b4856Slling break; 634fa9e4066Sahrens case ':': 635fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 636fa9e4066Sahrens "'%c' option\n"), optopt); 637990b4856Slling goto badusage; 638fa9e4066Sahrens case '?': 639fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 640fa9e4066Sahrens optopt); 641990b4856Slling goto badusage; 642fa9e4066Sahrens } 643fa9e4066Sahrens } 644fa9e4066Sahrens 645fa9e4066Sahrens argc -= optind; 646fa9e4066Sahrens argv += optind; 647fa9e4066Sahrens 648fa9e4066Sahrens /* get pool name and check number of arguments */ 649fa9e4066Sahrens if (argc < 1) { 650fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 651990b4856Slling goto badusage; 652fa9e4066Sahrens } 653fa9e4066Sahrens if (argc < 2) { 654fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 655990b4856Slling goto badusage; 656fa9e4066Sahrens } 657fa9e4066Sahrens 658fa9e4066Sahrens poolname = argv[0]; 659fa9e4066Sahrens 660fa9e4066Sahrens /* 661fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 662fa9e4066Sahrens * user to use 'zfs create' instead. 663fa9e4066Sahrens */ 664fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 665fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 666fa9e4066Sahrens "character '/' in pool name\n"), poolname); 667fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 668fa9e4066Sahrens "create a dataset\n")); 669990b4856Slling goto errout; 670fa9e4066Sahrens } 671fa9e4066Sahrens 672fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 67399653d4eSeschrock nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1, 67499653d4eSeschrock argv + 1); 675fa9e4066Sahrens if (nvroot == NULL) 6760a48a24eStimh goto errout; 677fa9e4066Sahrens 67899653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 679b7b97454Sperrin if (!zfs_allocatable_devs(nvroot)) { 68099653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 68199653d4eSeschrock "specification: at least one toplevel vdev must be " 68299653d4eSeschrock "specified\n")); 683990b4856Slling goto errout; 68499653d4eSeschrock } 68599653d4eSeschrock 68699653d4eSeschrock 687fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 688fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 689e9dbad6fSeschrock "must be an absolute path\n"), altroot); 690990b4856Slling goto errout; 691fa9e4066Sahrens } 692fa9e4066Sahrens 693fa9e4066Sahrens /* 694fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 695fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 696fa9e4066Sahrens */ 697fa9e4066Sahrens if (mountpoint == NULL || 698fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 699fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 700fa9e4066Sahrens char buf[MAXPATHLEN]; 70111022c7cStimh DIR *dirp; 702fa9e4066Sahrens 703fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 704fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 705fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 706fa9e4066Sahrens "'none'\n"), mountpoint); 707990b4856Slling goto errout; 708fa9e4066Sahrens } 709fa9e4066Sahrens 710fa9e4066Sahrens if (mountpoint == NULL) { 711fa9e4066Sahrens if (altroot != NULL) 712fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 713fa9e4066Sahrens altroot, poolname); 714fa9e4066Sahrens else 715fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 716fa9e4066Sahrens poolname); 717fa9e4066Sahrens } else { 718fa9e4066Sahrens if (altroot != NULL) 719fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 720fa9e4066Sahrens altroot, mountpoint); 721fa9e4066Sahrens else 722fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 723fa9e4066Sahrens mountpoint); 724fa9e4066Sahrens } 725fa9e4066Sahrens 72611022c7cStimh if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 72711022c7cStimh (void) fprintf(stderr, gettext("mountpoint '%s' : " 72811022c7cStimh "%s\n"), buf, strerror(errno)); 729fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 730fa9e4066Sahrens "option to provide a different default\n")); 731990b4856Slling goto errout; 73211022c7cStimh } else if (dirp) { 73311022c7cStimh int count = 0; 73411022c7cStimh 73511022c7cStimh while (count < 3 && readdir(dirp) != NULL) 73611022c7cStimh count++; 73711022c7cStimh (void) closedir(dirp); 73811022c7cStimh 73911022c7cStimh if (count > 2) { 74011022c7cStimh (void) fprintf(stderr, gettext("mountpoint " 74111022c7cStimh "'%s' exists and is not empty\n"), buf); 74211022c7cStimh (void) fprintf(stderr, gettext("use '-m' " 74311022c7cStimh "option to provide a " 74411022c7cStimh "different default\n")); 74511022c7cStimh goto errout; 74611022c7cStimh } 747fa9e4066Sahrens } 748fa9e4066Sahrens } 749fa9e4066Sahrens 750fa9e4066Sahrens if (dryrun) { 751fa9e4066Sahrens /* 752fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 753fa9e4066Sahrens * through all the vdevs in the list and print out in an 754fa9e4066Sahrens * appropriate hierarchy. 755fa9e4066Sahrens */ 756fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 757fa9e4066Sahrens "following layout:\n\n"), poolname); 758fa9e4066Sahrens 7598654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 7608654d025Sperrin if (num_logs(nvroot) > 0) 7618654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 762fa9e4066Sahrens 763fa9e4066Sahrens ret = 0; 764fa9e4066Sahrens } else { 765fa9e4066Sahrens /* 766fa9e4066Sahrens * Hand off to libzfs. 767fa9e4066Sahrens */ 7680a48a24eStimh if (zpool_create(g_zfs, poolname, 7690a48a24eStimh nvroot, props, fsprops) == 0) { 77099653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 771fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 772fa9e4066Sahrens if (pool != NULL) { 773fa9e4066Sahrens if (mountpoint != NULL) 774fa9e4066Sahrens verify(zfs_prop_set(pool, 775e9dbad6fSeschrock zfs_prop_to_name( 776e9dbad6fSeschrock ZFS_PROP_MOUNTPOINT), 777fa9e4066Sahrens mountpoint) == 0); 778fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 779da6c28aaSamw ret = zfs_shareall(pool); 780fa9e4066Sahrens zfs_close(pool); 781fa9e4066Sahrens } 78299653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 78399653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 78499653d4eSeschrock "been omitted\n")); 785fa9e4066Sahrens } 786fa9e4066Sahrens } 787fa9e4066Sahrens 788990b4856Slling errout: 789fa9e4066Sahrens nvlist_free(nvroot); 7900a48a24eStimh nvlist_free(fsprops); 791990b4856Slling nvlist_free(props); 792fa9e4066Sahrens return (ret); 793990b4856Slling badusage: 7940a48a24eStimh nvlist_free(fsprops); 795990b4856Slling nvlist_free(props); 796990b4856Slling usage(B_FALSE); 797990b4856Slling return (2); 798fa9e4066Sahrens } 799fa9e4066Sahrens 800fa9e4066Sahrens /* 801fa9e4066Sahrens * zpool destroy <pool> 802fa9e4066Sahrens * 803fa9e4066Sahrens * -f Forcefully unmount any datasets 804fa9e4066Sahrens * 805fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 806fa9e4066Sahrens */ 807fa9e4066Sahrens int 808fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 809fa9e4066Sahrens { 81099653d4eSeschrock boolean_t force = B_FALSE; 811fa9e4066Sahrens int c; 812fa9e4066Sahrens char *pool; 813fa9e4066Sahrens zpool_handle_t *zhp; 814fa9e4066Sahrens int ret; 815fa9e4066Sahrens 816fa9e4066Sahrens /* check options */ 817fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 818fa9e4066Sahrens switch (c) { 819fa9e4066Sahrens case 'f': 82099653d4eSeschrock force = B_TRUE; 821fa9e4066Sahrens break; 822fa9e4066Sahrens case '?': 823fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 824fa9e4066Sahrens optopt); 82599653d4eSeschrock usage(B_FALSE); 826fa9e4066Sahrens } 827fa9e4066Sahrens } 828fa9e4066Sahrens 829fa9e4066Sahrens argc -= optind; 830fa9e4066Sahrens argv += optind; 831fa9e4066Sahrens 832fa9e4066Sahrens /* check arguments */ 833fa9e4066Sahrens if (argc < 1) { 834fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 83599653d4eSeschrock usage(B_FALSE); 836fa9e4066Sahrens } 837fa9e4066Sahrens if (argc > 1) { 838fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 83999653d4eSeschrock usage(B_FALSE); 840fa9e4066Sahrens } 841fa9e4066Sahrens 842fa9e4066Sahrens pool = argv[0]; 843fa9e4066Sahrens 84499653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 845fa9e4066Sahrens /* 846fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 847fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 848fa9e4066Sahrens */ 849fa9e4066Sahrens if (strchr(pool, '/') != NULL) 850fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 851fa9e4066Sahrens "destroy a dataset\n")); 852fa9e4066Sahrens return (1); 853fa9e4066Sahrens } 854fa9e4066Sahrens 855f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 856fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 857fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 858fa9e4066Sahrens return (1); 859fa9e4066Sahrens } 860fa9e4066Sahrens 861fa9e4066Sahrens ret = (zpool_destroy(zhp) != 0); 862fa9e4066Sahrens 863fa9e4066Sahrens zpool_close(zhp); 864fa9e4066Sahrens 865fa9e4066Sahrens return (ret); 866fa9e4066Sahrens } 867fa9e4066Sahrens 868fa9e4066Sahrens /* 869fa9e4066Sahrens * zpool export [-f] <pool> ... 870fa9e4066Sahrens * 871fa9e4066Sahrens * -f Forcefully unmount datasets 872fa9e4066Sahrens * 873b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 874fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 875fa9e4066Sahrens * then the datasets will be forcefully unmounted. 876fa9e4066Sahrens */ 877fa9e4066Sahrens int 878fa9e4066Sahrens zpool_do_export(int argc, char **argv) 879fa9e4066Sahrens { 88099653d4eSeschrock boolean_t force = B_FALSE; 881fa9e4066Sahrens int c; 882fa9e4066Sahrens zpool_handle_t *zhp; 883fa9e4066Sahrens int ret; 884fa9e4066Sahrens int i; 885fa9e4066Sahrens 886fa9e4066Sahrens /* check options */ 887fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 888fa9e4066Sahrens switch (c) { 889fa9e4066Sahrens case 'f': 89099653d4eSeschrock force = B_TRUE; 891fa9e4066Sahrens break; 892fa9e4066Sahrens case '?': 893fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 894fa9e4066Sahrens optopt); 89599653d4eSeschrock usage(B_FALSE); 896fa9e4066Sahrens } 897fa9e4066Sahrens } 898fa9e4066Sahrens 899fa9e4066Sahrens argc -= optind; 900fa9e4066Sahrens argv += optind; 901fa9e4066Sahrens 902fa9e4066Sahrens /* check arguments */ 903fa9e4066Sahrens if (argc < 1) { 904fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 90599653d4eSeschrock usage(B_FALSE); 906fa9e4066Sahrens } 907fa9e4066Sahrens 908fa9e4066Sahrens ret = 0; 909fa9e4066Sahrens for (i = 0; i < argc; i++) { 91099653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 911fa9e4066Sahrens ret = 1; 912fa9e4066Sahrens continue; 913fa9e4066Sahrens } 914fa9e4066Sahrens 915f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 916fa9e4066Sahrens ret = 1; 917fa9e4066Sahrens zpool_close(zhp); 918fa9e4066Sahrens continue; 919fa9e4066Sahrens } 920fa9e4066Sahrens 92189a89ebfSlling if (zpool_export(zhp, force) != 0) 922fa9e4066Sahrens ret = 1; 923fa9e4066Sahrens 924fa9e4066Sahrens zpool_close(zhp); 925fa9e4066Sahrens } 926fa9e4066Sahrens 927fa9e4066Sahrens return (ret); 928fa9e4066Sahrens } 929fa9e4066Sahrens 930fa9e4066Sahrens /* 931fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 932fa9e4066Sahrens * name column. 933fa9e4066Sahrens */ 934fa9e4066Sahrens static int 935c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 936fa9e4066Sahrens { 93799653d4eSeschrock char *name = zpool_vdev_name(g_zfs, zhp, nv); 938fa9e4066Sahrens nvlist_t **child; 939fa9e4066Sahrens uint_t c, children; 940fa9e4066Sahrens int ret; 941fa9e4066Sahrens 942fa9e4066Sahrens if (strlen(name) + depth > max) 943fa9e4066Sahrens max = strlen(name) + depth; 944fa9e4066Sahrens 945afefbcddSeschrock free(name); 946afefbcddSeschrock 94799653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 94899653d4eSeschrock &child, &children) == 0) { 949fa9e4066Sahrens for (c = 0; c < children; c++) 95099653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 95199653d4eSeschrock max)) > max) 952fa9e4066Sahrens max = ret; 95399653d4eSeschrock } 95499653d4eSeschrock 955fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 956fa94a07fSbrendan &child, &children) == 0) { 957fa94a07fSbrendan for (c = 0; c < children; c++) 958fa94a07fSbrendan if ((ret = max_width(zhp, child[c], depth + 2, 959fa94a07fSbrendan max)) > max) 960fa94a07fSbrendan max = ret; 961fa94a07fSbrendan } 962fa94a07fSbrendan 96399653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 96499653d4eSeschrock &child, &children) == 0) { 96599653d4eSeschrock for (c = 0; c < children; c++) 96699653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 96799653d4eSeschrock max)) > max) 96899653d4eSeschrock max = ret; 96999653d4eSeschrock } 97099653d4eSeschrock 971fa9e4066Sahrens 972fa9e4066Sahrens return (max); 973fa9e4066Sahrens } 974fa9e4066Sahrens 975fa9e4066Sahrens 976fa9e4066Sahrens /* 977fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 978fa9e4066Sahrens * pool, printing out the name and status for each one. 979fa9e4066Sahrens */ 980fa9e4066Sahrens void 9818654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth, 9828654d025Sperrin boolean_t print_logs) 983fa9e4066Sahrens { 984fa9e4066Sahrens nvlist_t **child; 985fa9e4066Sahrens uint_t c, children; 986fa9e4066Sahrens vdev_stat_t *vs; 987afefbcddSeschrock char *type, *vname; 988fa9e4066Sahrens 989fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 990fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_MISSING) == 0) 991fa9e4066Sahrens return; 992fa9e4066Sahrens 993fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 994fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 995fa9e4066Sahrens 996fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 997990b4856Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 998fa9e4066Sahrens 999fa9e4066Sahrens if (vs->vs_aux != 0) { 10003d7072f8Seschrock (void) printf(" "); 1001fa9e4066Sahrens 1002fa9e4066Sahrens switch (vs->vs_aux) { 1003fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 1004fa9e4066Sahrens (void) printf(gettext("cannot open")); 1005fa9e4066Sahrens break; 1006fa9e4066Sahrens 1007fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 1008fa9e4066Sahrens (void) printf(gettext("missing device")); 1009fa9e4066Sahrens break; 1010fa9e4066Sahrens 1011fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 1012fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 1013fa9e4066Sahrens break; 1014fa9e4066Sahrens 1015eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 1016eaca9bbdSeschrock (void) printf(gettext("newer version")); 1017eaca9bbdSeschrock break; 1018eaca9bbdSeschrock 10193d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 10203d7072f8Seschrock (void) printf(gettext("too many errors")); 10213d7072f8Seschrock break; 10223d7072f8Seschrock 1023fa9e4066Sahrens default: 1024fa9e4066Sahrens (void) printf(gettext("corrupted data")); 1025fa9e4066Sahrens break; 1026fa9e4066Sahrens } 1027fa9e4066Sahrens } 1028fa9e4066Sahrens (void) printf("\n"); 1029fa9e4066Sahrens 1030fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1031fa9e4066Sahrens &child, &children) != 0) 1032fa9e4066Sahrens return; 1033fa9e4066Sahrens 1034afefbcddSeschrock for (c = 0; c < children; c++) { 10358654d025Sperrin uint64_t is_log = B_FALSE; 10368654d025Sperrin 10378654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 10388654d025Sperrin &is_log); 10398654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 10408654d025Sperrin continue; 10418654d025Sperrin 104299653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1043afefbcddSeschrock print_import_config(vname, child[c], 10448654d025Sperrin namewidth, depth + 2, B_FALSE); 1045afefbcddSeschrock free(vname); 1046afefbcddSeschrock } 104799653d4eSeschrock 1048fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1049fa94a07fSbrendan &child, &children) == 0) { 1050fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 1051fa94a07fSbrendan for (c = 0; c < children; c++) { 1052fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1053fa94a07fSbrendan (void) printf("\t %s\n", vname); 1054fa94a07fSbrendan free(vname); 1055fa94a07fSbrendan } 1056fa94a07fSbrendan } 105799653d4eSeschrock 1058fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1059fa94a07fSbrendan &child, &children) == 0) { 106099653d4eSeschrock (void) printf(gettext("\tspares\n")); 106199653d4eSeschrock for (c = 0; c < children; c++) { 106299653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 106399653d4eSeschrock (void) printf("\t %s\n", vname); 106499653d4eSeschrock free(vname); 106599653d4eSeschrock } 1066fa9e4066Sahrens } 1067fa94a07fSbrendan } 1068fa9e4066Sahrens 1069fa9e4066Sahrens /* 1070fa9e4066Sahrens * Display the status for the given pool. 1071fa9e4066Sahrens */ 1072fa9e4066Sahrens static void 1073fa9e4066Sahrens show_import(nvlist_t *config) 1074fa9e4066Sahrens { 1075fa9e4066Sahrens uint64_t pool_state; 1076fa9e4066Sahrens vdev_stat_t *vs; 1077fa9e4066Sahrens char *name; 1078fa9e4066Sahrens uint64_t guid; 1079fa9e4066Sahrens char *msgid; 1080fa9e4066Sahrens nvlist_t *nvroot; 1081fa9e4066Sahrens int reason; 108246657f8dSmmusante const char *health; 1083fa9e4066Sahrens uint_t vsc; 1084fa9e4066Sahrens int namewidth; 1085fa9e4066Sahrens 1086fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1087fa9e4066Sahrens &name) == 0); 1088fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1089fa9e4066Sahrens &guid) == 0); 1090fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1091fa9e4066Sahrens &pool_state) == 0); 1092fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1093fa9e4066Sahrens &nvroot) == 0); 1094fa9e4066Sahrens 1095fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1096fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 1097990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1098fa9e4066Sahrens 1099fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1100fa9e4066Sahrens 110146657f8dSmmusante (void) printf(gettext(" pool: %s\n"), name); 110246657f8dSmmusante (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 110346657f8dSmmusante (void) printf(gettext(" state: %s"), health); 11044c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 110546657f8dSmmusante (void) printf(gettext(" (DESTROYED)")); 11064c58d714Sdarrenm (void) printf("\n"); 1107fa9e4066Sahrens 1108fa9e4066Sahrens switch (reason) { 1109fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1110fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1111fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 1112fa9e4066Sahrens (void) printf(gettext("status: One or more devices are missing " 1113fa9e4066Sahrens "from the system.\n")); 1114fa9e4066Sahrens break; 1115fa9e4066Sahrens 1116fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1117fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1118fa9e4066Sahrens (void) printf(gettext("status: One or more devices contains " 1119fa9e4066Sahrens "corrupted data.\n")); 1120fa9e4066Sahrens break; 1121fa9e4066Sahrens 1122fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 1123fa9e4066Sahrens (void) printf(gettext("status: The pool data is corrupted.\n")); 1124fa9e4066Sahrens break; 1125fa9e4066Sahrens 1126441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 1127441d80aaSlling (void) printf(gettext("status: One or more devices " 1128441d80aaSlling "are offlined.\n")); 1129441d80aaSlling break; 1130441d80aaSlling 1131ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 1132ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is " 1133ea8dc4b6Seschrock "corrupted.\n")); 1134ea8dc4b6Seschrock break; 1135ea8dc4b6Seschrock 1136eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 1137eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1138eaca9bbdSeschrock "older on-disk version.\n")); 1139eaca9bbdSeschrock break; 1140eaca9bbdSeschrock 1141eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1142eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1143eaca9bbdSeschrock "incompatible version.\n")); 1144eaca9bbdSeschrock break; 1145*b87f3af3Sperrin 114695173954Sek110237 case ZPOOL_STATUS_HOSTID_MISMATCH: 114795173954Sek110237 (void) printf(gettext("status: The pool was last accessed by " 114895173954Sek110237 "another system.\n")); 114995173954Sek110237 break; 1150*b87f3af3Sperrin 11513d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 11523d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 11533d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 11543d7072f8Seschrock "faulted.\n")); 11553d7072f8Seschrock break; 11563d7072f8Seschrock 1157*b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 1158*b87f3af3Sperrin (void) printf(gettext("status: An intent log record cannot be " 1159*b87f3af3Sperrin "read.\n")); 1160*b87f3af3Sperrin break; 1161*b87f3af3Sperrin 1162fa9e4066Sahrens default: 1163fa9e4066Sahrens /* 1164fa9e4066Sahrens * No other status can be seen when importing pools. 1165fa9e4066Sahrens */ 1166fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1167fa9e4066Sahrens } 1168fa9e4066Sahrens 1169fa9e4066Sahrens /* 1170fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1171fa9e4066Sahrens */ 117246657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 1173eaca9bbdSeschrock if (reason == ZPOOL_STATUS_VERSION_OLDER) 1174eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1175eaca9bbdSeschrock "imported using its name or numeric identifier, " 1176eaca9bbdSeschrock "though\n\tsome features will not be available " 1177eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 117895173954Sek110237 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 117995173954Sek110237 (void) printf(gettext("action: The pool can be " 118095173954Sek110237 "imported using its name or numeric " 118195173954Sek110237 "identifier and\n\tthe '-f' flag.\n")); 1182fa9e4066Sahrens else 1183eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1184eaca9bbdSeschrock "imported using its name or numeric " 1185eaca9bbdSeschrock "identifier.\n")); 118646657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1187fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported " 1188fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1189eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1190fa9e4066Sahrens } else { 1191eaca9bbdSeschrock switch (reason) { 1192eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1193eaca9bbdSeschrock (void) printf(gettext("action: The pool cannot be " 1194eaca9bbdSeschrock "imported. Access the pool on a system running " 1195eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1196eaca9bbdSeschrock "backup.\n")); 1197eaca9bbdSeschrock break; 1198eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1199eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1200eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 1201fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1202fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1203fa9e4066Sahrens "again.\n")); 1204eaca9bbdSeschrock break; 1205eaca9bbdSeschrock default: 1206fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1207fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1208fa9e4066Sahrens } 1209eaca9bbdSeschrock } 1210eaca9bbdSeschrock 121146657f8dSmmusante /* 121246657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 121346657f8dSmmusante * is "corrupt data": 121446657f8dSmmusante */ 121546657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 121646657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 121746657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1218eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1219eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1220eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1221eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1222eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 122318ce54dfSek110237 "another system, but can be imported using\n\t" 1224eaca9bbdSeschrock "the '-f' flag.\n")); 1225eaca9bbdSeschrock } 1226fa9e4066Sahrens 1227fa9e4066Sahrens if (msgid != NULL) 1228fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1229fa9e4066Sahrens msgid); 1230fa9e4066Sahrens 1231fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 1232fa9e4066Sahrens 1233c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1234fa9e4066Sahrens if (namewidth < 10) 1235fa9e4066Sahrens namewidth = 10; 12368654d025Sperrin 12378654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_FALSE); 12388654d025Sperrin if (num_logs(nvroot) > 0) { 12398654d025Sperrin (void) printf(gettext("\tlogs\n")); 12408654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_TRUE); 12418654d025Sperrin } 1242fa9e4066Sahrens 1243fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 124446657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1245fa9e4066Sahrens "be part of this pool, though their\n\texact " 124646657f8dSmmusante "configuration cannot be determined.\n")); 1247fa9e4066Sahrens } 1248fa9e4066Sahrens } 1249fa9e4066Sahrens 1250fa9e4066Sahrens /* 1251fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1252990b4856Slling * lifting off to zpool_import_props(), and then mounts the datasets contained 1253990b4856Slling * within the pool. 1254fa9e4066Sahrens */ 1255fa9e4066Sahrens static int 1256fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 1257c5904d13Seschrock int force, nvlist_t *props, boolean_t allowfaulted) 1258fa9e4066Sahrens { 1259fa9e4066Sahrens zpool_handle_t *zhp; 1260fa9e4066Sahrens char *name; 1261fa9e4066Sahrens uint64_t state; 1262eaca9bbdSeschrock uint64_t version; 1263ecd6cf80Smarks int error = 0; 1264fa9e4066Sahrens 1265fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1266fa9e4066Sahrens &name) == 0); 1267fa9e4066Sahrens 1268fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1269fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1270eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1271eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1272e7437265Sahrens if (version > SPA_VERSION) { 1273eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1274eaca9bbdSeschrock "is formatted using a newer ZFS version\n"), name); 1275eaca9bbdSeschrock return (1); 1276eaca9bbdSeschrock } else if (state != POOL_STATE_EXPORTED && !force) { 127795173954Sek110237 uint64_t hostid; 127895173954Sek110237 127995173954Sek110237 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 128095173954Sek110237 &hostid) == 0) { 128195173954Sek110237 if ((unsigned long)hostid != gethostid()) { 128295173954Sek110237 char *hostname; 128395173954Sek110237 uint64_t timestamp; 128495173954Sek110237 time_t t; 128595173954Sek110237 128695173954Sek110237 verify(nvlist_lookup_string(config, 128795173954Sek110237 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 128895173954Sek110237 verify(nvlist_lookup_uint64(config, 128995173954Sek110237 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 129095173954Sek110237 t = timestamp; 129195173954Sek110237 (void) fprintf(stderr, gettext("cannot import " 129295173954Sek110237 "'%s': pool may be in use from other " 129395173954Sek110237 "system, it was last accessed by %s " 129495173954Sek110237 "(hostid: 0x%lx) on %s"), name, hostname, 129595173954Sek110237 (unsigned long)hostid, 129695173954Sek110237 asctime(localtime(&t))); 129795173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to " 129895173954Sek110237 "import anyway\n")); 1299fa9e4066Sahrens return (1); 1300fa9e4066Sahrens } 130195173954Sek110237 } else { 130295173954Sek110237 (void) fprintf(stderr, gettext("cannot import '%s': " 130395173954Sek110237 "pool may be in use from other system\n"), name); 130495173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to import " 130595173954Sek110237 "anyway\n")); 130695173954Sek110237 return (1); 130795173954Sek110237 } 130895173954Sek110237 } 1309fa9e4066Sahrens 1310c5904d13Seschrock if (zpool_import_props(g_zfs, config, newname, props, 1311c5904d13Seschrock allowfaulted) != 0) 1312fa9e4066Sahrens return (1); 1313fa9e4066Sahrens 1314fa9e4066Sahrens if (newname != NULL) 1315fa9e4066Sahrens name = (char *)newname; 1316fa9e4066Sahrens 1317c5904d13Seschrock verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL); 1318fa9e4066Sahrens 1319f3861e1aSahl if (zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1320fa9e4066Sahrens zpool_close(zhp); 1321fa9e4066Sahrens return (1); 1322fa9e4066Sahrens } 1323fa9e4066Sahrens 1324fa9e4066Sahrens zpool_close(zhp); 1325ecd6cf80Smarks return (error); 1326fa9e4066Sahrens } 1327fa9e4066Sahrens 1328fa9e4066Sahrens /* 13294c58d714Sdarrenm * zpool import [-d dir] [-D] 13302f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 13312f8aaab3Seschrock * [-d dir | -c cachefile] [-f] -a 13322f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 13332f8aaab3Seschrock * [-d dir | -c cachefile] [-f] <pool | id> [newpool] 13342f8aaab3Seschrock * 13352f8aaab3Seschrock * -c Read pool information from a cachefile instead of searching 13362f8aaab3Seschrock * devices. 1337fa9e4066Sahrens * 1338fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1339fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1340fa9e4066Sahrens * 13414c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 13424c58d714Sdarrenm * specified destroyed pools. 13434c58d714Sdarrenm * 1344fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1345fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1346fa9e4066Sahrens * is rebooted. 1347fa9e4066Sahrens * 1348fa9e4066Sahrens * -f Force import, even if it appears that the pool is active. 1349fa9e4066Sahrens * 1350c5904d13Seschrock * -F Import even in the presence of faulted vdevs. This is an 1351c5904d13Seschrock * intentionally undocumented option for testing purposes, and 1352c5904d13Seschrock * treats the pool configuration as complete, leaving any bad 1353c5904d13Seschrock * vdevs in the FAULTED state. 1354c5904d13Seschrock * 1355fa9e4066Sahrens * -a Import all pools found. 1356fa9e4066Sahrens * 1357990b4856Slling * -o Set property=value and/or temporary mount options (without '='). 1358ecd6cf80Smarks * 1359fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 1360fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 1361fa9e4066Sahrens */ 1362fa9e4066Sahrens int 1363fa9e4066Sahrens zpool_do_import(int argc, char **argv) 1364fa9e4066Sahrens { 1365fa9e4066Sahrens char **searchdirs = NULL; 1366fa9e4066Sahrens int nsearch = 0; 1367fa9e4066Sahrens int c; 1368fa9e4066Sahrens int err; 13692f8aaab3Seschrock nvlist_t *pools = NULL; 137099653d4eSeschrock boolean_t do_all = B_FALSE; 137199653d4eSeschrock boolean_t do_destroyed = B_FALSE; 1372fa9e4066Sahrens char *mntopts = NULL; 137399653d4eSeschrock boolean_t do_force = B_FALSE; 1374fa9e4066Sahrens nvpair_t *elem; 1375fa9e4066Sahrens nvlist_t *config; 137624e697d4Sck153898 uint64_t searchguid = 0; 137724e697d4Sck153898 char *searchname = NULL; 1378990b4856Slling char *propval; 1379fa9e4066Sahrens nvlist_t *found_config; 1380ecd6cf80Smarks nvlist_t *props = NULL; 138199653d4eSeschrock boolean_t first; 1382c5904d13Seschrock boolean_t allow_faulted = B_FALSE; 13834c58d714Sdarrenm uint64_t pool_state; 13842f8aaab3Seschrock char *cachefile = NULL; 1385fa9e4066Sahrens 1386fa9e4066Sahrens /* check options */ 1387c5904d13Seschrock while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) { 1388fa9e4066Sahrens switch (c) { 1389fa9e4066Sahrens case 'a': 139099653d4eSeschrock do_all = B_TRUE; 1391fa9e4066Sahrens break; 13922f8aaab3Seschrock case 'c': 13932f8aaab3Seschrock cachefile = optarg; 13942f8aaab3Seschrock break; 1395fa9e4066Sahrens case 'd': 1396fa9e4066Sahrens if (searchdirs == NULL) { 1397fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1398fa9e4066Sahrens } else { 1399fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 1400fa9e4066Sahrens sizeof (char *)); 1401fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 1402fa9e4066Sahrens sizeof (char *)); 1403fa9e4066Sahrens free(searchdirs); 1404fa9e4066Sahrens searchdirs = tmp; 1405fa9e4066Sahrens } 1406fa9e4066Sahrens searchdirs[nsearch++] = optarg; 1407fa9e4066Sahrens break; 14084c58d714Sdarrenm case 'D': 140999653d4eSeschrock do_destroyed = B_TRUE; 14104c58d714Sdarrenm break; 1411fa9e4066Sahrens case 'f': 141299653d4eSeschrock do_force = B_TRUE; 1413fa9e4066Sahrens break; 1414c5904d13Seschrock case 'F': 1415c5904d13Seschrock allow_faulted = B_TRUE; 1416c5904d13Seschrock break; 1417fa9e4066Sahrens case 'o': 1418990b4856Slling if ((propval = strchr(optarg, '=')) != NULL) { 1419990b4856Slling *propval = '\0'; 1420990b4856Slling propval++; 14210a48a24eStimh if (add_prop_list(optarg, propval, 14220a48a24eStimh &props, B_TRUE)) 1423990b4856Slling goto error; 1424990b4856Slling } else { 1425fa9e4066Sahrens mntopts = optarg; 1426990b4856Slling } 1427fa9e4066Sahrens break; 1428fa9e4066Sahrens case 'R': 1429990b4856Slling if (add_prop_list(zpool_prop_to_name( 14300a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 1431990b4856Slling goto error; 14322f8aaab3Seschrock if (nvlist_lookup_string(props, 14332f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 14342f8aaab3Seschrock &propval) == 0) 14352f8aaab3Seschrock break; 1436990b4856Slling if (add_prop_list(zpool_prop_to_name( 14370a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1438990b4856Slling goto error; 1439fa9e4066Sahrens break; 1440fa9e4066Sahrens case ':': 1441fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 1442fa9e4066Sahrens "'%c' option\n"), optopt); 144399653d4eSeschrock usage(B_FALSE); 1444fa9e4066Sahrens break; 1445fa9e4066Sahrens case '?': 1446fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1447fa9e4066Sahrens optopt); 144899653d4eSeschrock usage(B_FALSE); 1449fa9e4066Sahrens } 1450fa9e4066Sahrens } 1451fa9e4066Sahrens 1452fa9e4066Sahrens argc -= optind; 1453fa9e4066Sahrens argv += optind; 1454fa9e4066Sahrens 14552f8aaab3Seschrock if (cachefile && nsearch != 0) { 14562f8aaab3Seschrock (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 14572f8aaab3Seschrock usage(B_FALSE); 14582f8aaab3Seschrock } 14592f8aaab3Seschrock 1460fa9e4066Sahrens if (searchdirs == NULL) { 1461fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1462fa9e4066Sahrens searchdirs[0] = "/dev/dsk"; 1463fa9e4066Sahrens nsearch = 1; 1464fa9e4066Sahrens } 1465fa9e4066Sahrens 1466fa9e4066Sahrens /* check argument count */ 1467fa9e4066Sahrens if (do_all) { 1468fa9e4066Sahrens if (argc != 0) { 1469fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 147099653d4eSeschrock usage(B_FALSE); 1471fa9e4066Sahrens } 1472fa9e4066Sahrens } else { 1473fa9e4066Sahrens if (argc > 2) { 1474fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 147599653d4eSeschrock usage(B_FALSE); 1476fa9e4066Sahrens } 1477fa9e4066Sahrens 1478fa9e4066Sahrens /* 1479fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 1480fa9e4066Sahrens * here because otherwise any attempt to discover pools will 1481fa9e4066Sahrens * silently fail. 1482fa9e4066Sahrens */ 1483fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1484fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 1485fa9e4066Sahrens "discover pools: permission denied\n")); 148699653d4eSeschrock free(searchdirs); 1487fa9e4066Sahrens return (1); 1488fa9e4066Sahrens } 1489fa9e4066Sahrens } 1490fa9e4066Sahrens 1491fa9e4066Sahrens /* 1492fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 1493fa9e4066Sahrens * 1494fa9e4066Sahrens * <none> Iterate through all pools and display information about 1495fa9e4066Sahrens * each one. 1496fa9e4066Sahrens * 1497fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 1498fa9e4066Sahrens * 1499fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 1500fa9e4066Sahrens * name and import that one. 15014c58d714Sdarrenm * 15024c58d714Sdarrenm * -D Above options applies only to destroyed pools. 1503fa9e4066Sahrens */ 1504fa9e4066Sahrens if (argc != 0) { 1505fa9e4066Sahrens char *endptr; 1506fa9e4066Sahrens 1507fa9e4066Sahrens errno = 0; 1508fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 1509fa9e4066Sahrens if (errno != 0 || *endptr != '\0') 1510fa9e4066Sahrens searchname = argv[0]; 1511fa9e4066Sahrens found_config = NULL; 1512fa9e4066Sahrens } 1513fa9e4066Sahrens 151424e697d4Sck153898 if (cachefile) { 1515e829d913Sck153898 pools = zpool_find_import_cached(g_zfs, cachefile, searchname, 1516e829d913Sck153898 searchguid); 151724e697d4Sck153898 } else if (searchname != NULL) { 151824e697d4Sck153898 pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs, 151924e697d4Sck153898 searchname); 152024e697d4Sck153898 } else { 152124e697d4Sck153898 /* 152224e697d4Sck153898 * It's OK to search by guid even if searchguid is 0. 152324e697d4Sck153898 */ 152424e697d4Sck153898 pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs, 152524e697d4Sck153898 searchguid); 152624e697d4Sck153898 } 152724e697d4Sck153898 152824e697d4Sck153898 if (pools == NULL) { 152924e697d4Sck153898 if (argc != 0) { 153024e697d4Sck153898 (void) fprintf(stderr, gettext("cannot import '%s': " 153124e697d4Sck153898 "no such pool available\n"), argv[0]); 153224e697d4Sck153898 } 153324e697d4Sck153898 free(searchdirs); 153424e697d4Sck153898 return (1); 153524e697d4Sck153898 } 153624e697d4Sck153898 153724e697d4Sck153898 /* 153824e697d4Sck153898 * At this point we have a list of import candidate configs. Even if 153924e697d4Sck153898 * we were searching by pool name or guid, we still need to 154024e697d4Sck153898 * post-process the list to deal with pool state and possible 154124e697d4Sck153898 * duplicate names. 154224e697d4Sck153898 */ 1543fa9e4066Sahrens err = 0; 1544fa9e4066Sahrens elem = NULL; 154599653d4eSeschrock first = B_TRUE; 1546fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1547fa9e4066Sahrens 1548fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 1549fa9e4066Sahrens 15504c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 15514c58d714Sdarrenm &pool_state) == 0); 15524c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 15534c58d714Sdarrenm continue; 15544c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 15554c58d714Sdarrenm continue; 15564c58d714Sdarrenm 1557fa9e4066Sahrens if (argc == 0) { 1558fa9e4066Sahrens if (first) 155999653d4eSeschrock first = B_FALSE; 15603bb79becSeschrock else if (!do_all) 1561fa9e4066Sahrens (void) printf("\n"); 1562fa9e4066Sahrens 1563fa9e4066Sahrens if (do_all) 1564fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 1565c5904d13Seschrock do_force, props, allow_faulted); 1566fa9e4066Sahrens else 1567fa9e4066Sahrens show_import(config); 1568fa9e4066Sahrens } else if (searchname != NULL) { 1569fa9e4066Sahrens char *name; 1570fa9e4066Sahrens 1571fa9e4066Sahrens /* 1572fa9e4066Sahrens * We are searching for a pool based on name. 1573fa9e4066Sahrens */ 1574fa9e4066Sahrens verify(nvlist_lookup_string(config, 1575fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1576fa9e4066Sahrens 1577fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 1578fa9e4066Sahrens if (found_config != NULL) { 1579fa9e4066Sahrens (void) fprintf(stderr, gettext( 1580fa9e4066Sahrens "cannot import '%s': more than " 1581fa9e4066Sahrens "one matching pool\n"), searchname); 1582fa9e4066Sahrens (void) fprintf(stderr, gettext( 1583fa9e4066Sahrens "import by numeric ID instead\n")); 158499653d4eSeschrock err = B_TRUE; 1585fa9e4066Sahrens } 1586fa9e4066Sahrens found_config = config; 1587fa9e4066Sahrens } 1588fa9e4066Sahrens } else { 1589fa9e4066Sahrens uint64_t guid; 1590fa9e4066Sahrens 1591fa9e4066Sahrens /* 1592fa9e4066Sahrens * Search for a pool by guid. 1593fa9e4066Sahrens */ 1594fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1595fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1596fa9e4066Sahrens 1597fa9e4066Sahrens if (guid == searchguid) 1598fa9e4066Sahrens found_config = config; 1599fa9e4066Sahrens } 1600fa9e4066Sahrens } 1601fa9e4066Sahrens 1602fa9e4066Sahrens /* 1603fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 1604fa9e4066Sahrens * pool, and then do the import. 1605fa9e4066Sahrens */ 1606fa9e4066Sahrens if (argc != 0 && err == 0) { 1607fa9e4066Sahrens if (found_config == NULL) { 1608fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 1609fa9e4066Sahrens "no such pool available\n"), argv[0]); 161099653d4eSeschrock err = B_TRUE; 1611fa9e4066Sahrens } else { 1612fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 1613c5904d13Seschrock argv[1], mntopts, do_force, props, allow_faulted); 1614fa9e4066Sahrens } 1615fa9e4066Sahrens } 1616fa9e4066Sahrens 1617fa9e4066Sahrens /* 1618fa9e4066Sahrens * If we were just looking for pools, report an error if none were 1619fa9e4066Sahrens * found. 1620fa9e4066Sahrens */ 1621fa9e4066Sahrens if (argc == 0 && first) 1622fa9e4066Sahrens (void) fprintf(stderr, 1623fa9e4066Sahrens gettext("no pools available to import\n")); 1624fa9e4066Sahrens 1625ecd6cf80Smarks error: 1626ecd6cf80Smarks nvlist_free(props); 1627fa9e4066Sahrens nvlist_free(pools); 162899653d4eSeschrock free(searchdirs); 1629fa9e4066Sahrens 1630fa9e4066Sahrens return (err ? 1 : 0); 1631fa9e4066Sahrens } 1632fa9e4066Sahrens 1633fa9e4066Sahrens typedef struct iostat_cbdata { 1634fa9e4066Sahrens zpool_list_t *cb_list; 1635fa9e4066Sahrens int cb_verbose; 1636fa9e4066Sahrens int cb_iteration; 1637fa9e4066Sahrens int cb_namewidth; 1638fa9e4066Sahrens } iostat_cbdata_t; 1639fa9e4066Sahrens 1640fa9e4066Sahrens static void 1641fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 1642fa9e4066Sahrens { 1643fa9e4066Sahrens int i = 0; 1644fa9e4066Sahrens 1645fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 1646fa9e4066Sahrens (void) printf("-"); 1647fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1648fa9e4066Sahrens } 1649fa9e4066Sahrens 1650fa9e4066Sahrens static void 1651fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 1652fa9e4066Sahrens { 1653fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 1654fa9e4066Sahrens cb->cb_namewidth, ""); 1655fa9e4066Sahrens (void) printf("%-*s used avail read write read write\n", 1656fa9e4066Sahrens cb->cb_namewidth, "pool"); 1657fa9e4066Sahrens print_iostat_separator(cb); 1658fa9e4066Sahrens } 1659fa9e4066Sahrens 1660fa9e4066Sahrens /* 1661fa9e4066Sahrens * Display a single statistic. 1662fa9e4066Sahrens */ 1663990b4856Slling static void 1664fa9e4066Sahrens print_one_stat(uint64_t value) 1665fa9e4066Sahrens { 1666fa9e4066Sahrens char buf[64]; 1667fa9e4066Sahrens 1668fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 1669fa9e4066Sahrens (void) printf(" %5s", buf); 1670fa9e4066Sahrens } 1671fa9e4066Sahrens 1672fa9e4066Sahrens /* 1673fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 1674fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 1675fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 1676fa9e4066Sahrens */ 1677fa9e4066Sahrens void 1678c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1679c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1680fa9e4066Sahrens { 1681fa9e4066Sahrens nvlist_t **oldchild, **newchild; 1682fa9e4066Sahrens uint_t c, children; 1683fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 1684fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 1685fa9e4066Sahrens uint64_t tdelta; 1686fa9e4066Sahrens double scale; 1687afefbcddSeschrock char *vname; 1688fa9e4066Sahrens 1689fa9e4066Sahrens if (oldnv != NULL) { 1690fa9e4066Sahrens verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1691fa9e4066Sahrens (uint64_t **)&oldvs, &c) == 0); 1692fa9e4066Sahrens } else { 1693fa9e4066Sahrens oldvs = &zerovs; 1694fa9e4066Sahrens } 1695fa9e4066Sahrens 1696fa9e4066Sahrens verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1697fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 1698fa9e4066Sahrens 1699fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 1700fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 1701fa9e4066Sahrens else 1702fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 1703fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1704fa9e4066Sahrens 1705fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1706fa9e4066Sahrens 1707fa9e4066Sahrens if (tdelta == 0) 1708fa9e4066Sahrens scale = 1.0; 1709fa9e4066Sahrens else 1710fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 1711fa9e4066Sahrens 1712fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 1713fa9e4066Sahrens if (newvs->vs_space == 0) { 1714fa9e4066Sahrens (void) printf(" - -"); 1715fa9e4066Sahrens } else { 1716fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 1717fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 1718fa9e4066Sahrens } 1719fa9e4066Sahrens 1720fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1721fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 1722fa9e4066Sahrens 1723fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1724fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1725fa9e4066Sahrens 1726fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1727fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 1728fa9e4066Sahrens 1729fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1730fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1731fa9e4066Sahrens 1732fa9e4066Sahrens (void) printf("\n"); 1733fa9e4066Sahrens 1734fa9e4066Sahrens if (!cb->cb_verbose) 1735fa9e4066Sahrens return; 1736fa9e4066Sahrens 1737fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1738fa9e4066Sahrens &newchild, &children) != 0) 1739fa9e4066Sahrens return; 1740fa9e4066Sahrens 1741fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1742fa9e4066Sahrens &oldchild, &c) != 0) 1743fa9e4066Sahrens return; 1744fa9e4066Sahrens 1745afefbcddSeschrock for (c = 0; c < children; c++) { 174699653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1747c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1748afefbcddSeschrock newchild[c], cb, depth + 2); 1749afefbcddSeschrock free(vname); 1750afefbcddSeschrock } 1751fa94a07fSbrendan 1752fa94a07fSbrendan /* 1753fa94a07fSbrendan * Include level 2 ARC devices in iostat output 1754fa94a07fSbrendan */ 1755fa94a07fSbrendan if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 1756fa94a07fSbrendan &newchild, &children) != 0) 1757fa94a07fSbrendan return; 1758fa94a07fSbrendan 1759fa94a07fSbrendan if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 1760fa94a07fSbrendan &oldchild, &c) != 0) 1761fa94a07fSbrendan return; 1762fa94a07fSbrendan 1763fa94a07fSbrendan if (children > 0) { 1764fa94a07fSbrendan (void) printf("%-*s - - - - - " 1765fa94a07fSbrendan "-\n", cb->cb_namewidth, "cache"); 1766fa94a07fSbrendan for (c = 0; c < children; c++) { 1767fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1768fa94a07fSbrendan print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1769fa94a07fSbrendan newchild[c], cb, depth + 2); 1770fa94a07fSbrendan free(vname); 1771fa94a07fSbrendan } 1772fa94a07fSbrendan } 1773fa9e4066Sahrens } 1774fa9e4066Sahrens 1775088e9d47Seschrock static int 1776088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 1777088e9d47Seschrock { 1778088e9d47Seschrock iostat_cbdata_t *cb = data; 177994de1d4cSeschrock boolean_t missing; 1780088e9d47Seschrock 1781088e9d47Seschrock /* 1782088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 1783088e9d47Seschrock */ 178494de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 178594de1d4cSeschrock return (-1); 178694de1d4cSeschrock 178794de1d4cSeschrock if (missing) 1788088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 1789088e9d47Seschrock 1790088e9d47Seschrock return (0); 1791088e9d47Seschrock } 1792088e9d47Seschrock 1793fa9e4066Sahrens /* 1794fa9e4066Sahrens * Callback to print out the iostats for the given pool. 1795fa9e4066Sahrens */ 1796fa9e4066Sahrens int 1797fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 1798fa9e4066Sahrens { 1799fa9e4066Sahrens iostat_cbdata_t *cb = data; 1800fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 1801fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 1802fa9e4066Sahrens 1803088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 1804fa9e4066Sahrens 1805088e9d47Seschrock if (cb->cb_iteration == 1) 1806fa9e4066Sahrens oldconfig = NULL; 1807fa9e4066Sahrens 1808fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1809fa9e4066Sahrens &newnvroot) == 0); 1810fa9e4066Sahrens 1811088e9d47Seschrock if (oldconfig == NULL) 1812fa9e4066Sahrens oldnvroot = NULL; 1813088e9d47Seschrock else 1814088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 1815088e9d47Seschrock &oldnvroot) == 0); 1816fa9e4066Sahrens 1817fa9e4066Sahrens /* 1818fa9e4066Sahrens * Print out the statistics for the pool. 1819fa9e4066Sahrens */ 1820c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1821fa9e4066Sahrens 1822fa9e4066Sahrens if (cb->cb_verbose) 1823fa9e4066Sahrens print_iostat_separator(cb); 1824fa9e4066Sahrens 1825fa9e4066Sahrens return (0); 1826fa9e4066Sahrens } 1827fa9e4066Sahrens 1828fa9e4066Sahrens int 1829fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 1830fa9e4066Sahrens { 1831fa9e4066Sahrens iostat_cbdata_t *cb = data; 1832fa9e4066Sahrens nvlist_t *config, *nvroot; 1833fa9e4066Sahrens 1834088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 1835fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1836fa9e4066Sahrens &nvroot) == 0); 1837fa9e4066Sahrens if (!cb->cb_verbose) 1838fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1839fa9e4066Sahrens else 1840c67d9675Seschrock cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 1841fa9e4066Sahrens } 1842fa9e4066Sahrens 1843fa9e4066Sahrens /* 1844fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 1845fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 1846fa9e4066Sahrens */ 1847fa9e4066Sahrens if (cb->cb_namewidth < 10) 1848fa9e4066Sahrens cb->cb_namewidth = 10; 1849fa9e4066Sahrens if (cb->cb_namewidth > 38) 1850fa9e4066Sahrens cb->cb_namewidth = 38; 1851fa9e4066Sahrens 1852fa9e4066Sahrens return (0); 1853fa9e4066Sahrens } 1854fa9e4066Sahrens 1855fa9e4066Sahrens /* 1856fa9e4066Sahrens * zpool iostat [-v] [pool] ... [interval [count]] 1857fa9e4066Sahrens * 1858fa9e4066Sahrens * -v Display statistics for individual vdevs 1859fa9e4066Sahrens * 1860fa9e4066Sahrens * This command can be tricky because we want to be able to deal with pool 1861fa9e4066Sahrens * creation/destruction as well as vdev configuration changes. The bulk of this 1862fa9e4066Sahrens * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1863fa9e4066Sahrens * on pool_list_update() to detect the addition of new pools. Configuration 1864fa9e4066Sahrens * changes are all handled within libzfs. 1865fa9e4066Sahrens */ 1866fa9e4066Sahrens int 1867fa9e4066Sahrens zpool_do_iostat(int argc, char **argv) 1868fa9e4066Sahrens { 1869fa9e4066Sahrens int c; 1870fa9e4066Sahrens int ret; 1871fa9e4066Sahrens int npools; 1872fa9e4066Sahrens unsigned long interval = 0, count = 0; 1873fa9e4066Sahrens zpool_list_t *list; 187499653d4eSeschrock boolean_t verbose = B_FALSE; 1875fa9e4066Sahrens iostat_cbdata_t cb; 1876fa9e4066Sahrens 1877fa9e4066Sahrens /* check options */ 1878fa9e4066Sahrens while ((c = getopt(argc, argv, "v")) != -1) { 1879fa9e4066Sahrens switch (c) { 1880fa9e4066Sahrens case 'v': 188199653d4eSeschrock verbose = B_TRUE; 1882fa9e4066Sahrens break; 1883fa9e4066Sahrens case '?': 1884fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1885fa9e4066Sahrens optopt); 188699653d4eSeschrock usage(B_FALSE); 1887fa9e4066Sahrens } 1888fa9e4066Sahrens } 1889fa9e4066Sahrens 1890fa9e4066Sahrens argc -= optind; 1891fa9e4066Sahrens argv += optind; 1892fa9e4066Sahrens 1893fa9e4066Sahrens /* 1894fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 1895fa9e4066Sahrens */ 1896fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1897fa9e4066Sahrens char *end; 1898fa9e4066Sahrens 1899fa9e4066Sahrens errno = 0; 1900fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1901fa9e4066Sahrens 1902fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1903fa9e4066Sahrens if (interval == 0) { 1904fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1905fa9e4066Sahrens "cannot be zero\n")); 190699653d4eSeschrock usage(B_FALSE); 1907fa9e4066Sahrens } 1908fa9e4066Sahrens 1909fa9e4066Sahrens /* 1910fa9e4066Sahrens * Ignore the last parameter 1911fa9e4066Sahrens */ 1912fa9e4066Sahrens argc--; 1913fa9e4066Sahrens } else { 1914fa9e4066Sahrens /* 1915fa9e4066Sahrens * If this is not a valid number, just plow on. The 1916fa9e4066Sahrens * user will get a more informative error message later 1917fa9e4066Sahrens * on. 1918fa9e4066Sahrens */ 1919fa9e4066Sahrens interval = 0; 1920fa9e4066Sahrens } 1921fa9e4066Sahrens } 1922fa9e4066Sahrens 1923fa9e4066Sahrens /* 1924fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 1925fa9e4066Sahrens * and an integer. 1926fa9e4066Sahrens */ 1927fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1928fa9e4066Sahrens char *end; 1929fa9e4066Sahrens 1930fa9e4066Sahrens errno = 0; 1931fa9e4066Sahrens count = interval; 1932fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1933fa9e4066Sahrens 1934fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1935fa9e4066Sahrens if (interval == 0) { 1936fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1937fa9e4066Sahrens "cannot be zero\n")); 193899653d4eSeschrock usage(B_FALSE); 1939fa9e4066Sahrens } 1940fa9e4066Sahrens 1941fa9e4066Sahrens /* 1942fa9e4066Sahrens * Ignore the last parameter 1943fa9e4066Sahrens */ 1944fa9e4066Sahrens argc--; 1945fa9e4066Sahrens } else { 1946fa9e4066Sahrens interval = 0; 1947fa9e4066Sahrens } 1948fa9e4066Sahrens } 1949fa9e4066Sahrens 1950fa9e4066Sahrens /* 1951fa9e4066Sahrens * Construct the list of all interesting pools. 1952fa9e4066Sahrens */ 1953fa9e4066Sahrens ret = 0; 1954b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 1955fa9e4066Sahrens return (1); 1956fa9e4066Sahrens 195799653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 195899653d4eSeschrock pool_list_free(list); 1959fa9e4066Sahrens return (1); 196099653d4eSeschrock } 1961fa9e4066Sahrens 1962fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 196399653d4eSeschrock pool_list_free(list); 1964fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 1965fa9e4066Sahrens return (1); 1966fa9e4066Sahrens } 1967fa9e4066Sahrens 1968fa9e4066Sahrens /* 1969fa9e4066Sahrens * Enter the main iostat loop. 1970fa9e4066Sahrens */ 1971fa9e4066Sahrens cb.cb_list = list; 1972fa9e4066Sahrens cb.cb_verbose = verbose; 1973fa9e4066Sahrens cb.cb_iteration = 0; 1974fa9e4066Sahrens cb.cb_namewidth = 0; 1975fa9e4066Sahrens 1976fa9e4066Sahrens for (;;) { 1977fa9e4066Sahrens pool_list_update(list); 1978fa9e4066Sahrens 1979fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 1980fa9e4066Sahrens break; 1981fa9e4066Sahrens 1982fa9e4066Sahrens /* 1983088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 1984088e9d47Seschrock * before calculating the maximum name width, so that any 1985088e9d47Seschrock * configuration changes are properly accounted for. 1986088e9d47Seschrock */ 198799653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 1988088e9d47Seschrock 1989088e9d47Seschrock /* 1990fa9e4066Sahrens * Iterate over all pools to determine the maximum width 1991fa9e4066Sahrens * for the pool / device name column across all pools. 1992fa9e4066Sahrens */ 1993fa9e4066Sahrens cb.cb_namewidth = 0; 199499653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 1995fa9e4066Sahrens 1996fa9e4066Sahrens /* 1997fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 1998fa9e4066Sahrens */ 1999fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 2000fa9e4066Sahrens print_iostat_header(&cb); 2001fa9e4066Sahrens 200299653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2003fa9e4066Sahrens 2004fa9e4066Sahrens /* 2005fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 2006fa9e4066Sahrens * (which prints a separator for us), then print a separator. 2007fa9e4066Sahrens */ 2008fa9e4066Sahrens if (npools > 1 && !verbose) 2009fa9e4066Sahrens print_iostat_separator(&cb); 2010fa9e4066Sahrens 2011fa9e4066Sahrens if (verbose) 2012fa9e4066Sahrens (void) printf("\n"); 2013fa9e4066Sahrens 201439c23413Seschrock /* 201539c23413Seschrock * Flush the output so that redirection to a file isn't buffered 201639c23413Seschrock * indefinitely. 201739c23413Seschrock */ 201839c23413Seschrock (void) fflush(stdout); 201939c23413Seschrock 2020fa9e4066Sahrens if (interval == 0) 2021fa9e4066Sahrens break; 2022fa9e4066Sahrens 2023fa9e4066Sahrens if (count != 0 && --count == 0) 2024fa9e4066Sahrens break; 2025fa9e4066Sahrens 2026fa9e4066Sahrens (void) sleep(interval); 2027fa9e4066Sahrens } 2028fa9e4066Sahrens 2029fa9e4066Sahrens pool_list_free(list); 2030fa9e4066Sahrens 2031fa9e4066Sahrens return (ret); 2032fa9e4066Sahrens } 2033fa9e4066Sahrens 2034fa9e4066Sahrens typedef struct list_cbdata { 203599653d4eSeschrock boolean_t cb_scripted; 203699653d4eSeschrock boolean_t cb_first; 2037990b4856Slling zprop_list_t *cb_proplist; 2038fa9e4066Sahrens } list_cbdata_t; 2039fa9e4066Sahrens 2040fa9e4066Sahrens /* 2041fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 2042fa9e4066Sahrens */ 2043990b4856Slling static void 2044990b4856Slling print_header(zprop_list_t *pl) 2045fa9e4066Sahrens { 2046990b4856Slling const char *header; 2047990b4856Slling boolean_t first = B_TRUE; 2048990b4856Slling boolean_t right_justify; 2049fa9e4066Sahrens 2050990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 2051990b4856Slling if (pl->pl_prop == ZPROP_INVAL) 2052990b4856Slling continue; 2053990b4856Slling 2054990b4856Slling if (!first) 2055fa9e4066Sahrens (void) printf(" "); 2056fa9e4066Sahrens else 2057990b4856Slling first = B_FALSE; 2058fa9e4066Sahrens 2059990b4856Slling header = zpool_prop_column_name(pl->pl_prop); 2060990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2061990b4856Slling 2062990b4856Slling if (pl->pl_next == NULL && !right_justify) 2063990b4856Slling (void) printf("%s", header); 2064990b4856Slling else if (right_justify) 2065990b4856Slling (void) printf("%*s", pl->pl_width, header); 2066990b4856Slling else 2067990b4856Slling (void) printf("%-*s", pl->pl_width, header); 2068fa9e4066Sahrens } 2069fa9e4066Sahrens 2070fa9e4066Sahrens (void) printf("\n"); 2071fa9e4066Sahrens } 2072fa9e4066Sahrens 2073990b4856Slling /* 2074990b4856Slling * Given a pool and a list of properties, print out all the properties according 2075990b4856Slling * to the described layout. 2076990b4856Slling */ 2077990b4856Slling static void 2078990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 2079990b4856Slling { 2080990b4856Slling boolean_t first = B_TRUE; 2081990b4856Slling char property[ZPOOL_MAXPROPLEN]; 2082990b4856Slling char *propstr; 2083990b4856Slling boolean_t right_justify; 2084990b4856Slling int width; 2085990b4856Slling 2086990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 2087990b4856Slling if (!first) { 2088990b4856Slling if (scripted) 2089990b4856Slling (void) printf("\t"); 2090990b4856Slling else 2091990b4856Slling (void) printf(" "); 2092990b4856Slling } else { 2093990b4856Slling first = B_FALSE; 2094990b4856Slling } 2095990b4856Slling 2096990b4856Slling right_justify = B_FALSE; 2097990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 2098990b4856Slling if (zpool_get_prop(zhp, pl->pl_prop, property, 2099990b4856Slling sizeof (property), NULL) != 0) 2100990b4856Slling propstr = "-"; 2101990b4856Slling else 2102990b4856Slling propstr = property; 2103990b4856Slling 2104990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2105990b4856Slling } else { 2106990b4856Slling propstr = "-"; 2107990b4856Slling } 2108990b4856Slling 2109990b4856Slling width = pl->pl_width; 2110990b4856Slling 2111990b4856Slling /* 2112990b4856Slling * If this is being called in scripted mode, or if this is the 2113990b4856Slling * last column and it is left-justified, don't include a width 2114990b4856Slling * format specifier. 2115990b4856Slling */ 2116990b4856Slling if (scripted || (pl->pl_next == NULL && !right_justify)) 2117990b4856Slling (void) printf("%s", propstr); 2118990b4856Slling else if (right_justify) 2119990b4856Slling (void) printf("%*s", width, propstr); 2120990b4856Slling else 2121990b4856Slling (void) printf("%-*s", width, propstr); 2122990b4856Slling } 2123990b4856Slling 2124990b4856Slling (void) printf("\n"); 2125990b4856Slling } 2126990b4856Slling 2127990b4856Slling /* 2128990b4856Slling * Generic callback function to list a pool. 2129990b4856Slling */ 2130fa9e4066Sahrens int 2131fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data) 2132fa9e4066Sahrens { 2133fa9e4066Sahrens list_cbdata_t *cbp = data; 2134fa9e4066Sahrens 2135fa9e4066Sahrens if (cbp->cb_first) { 2136fa9e4066Sahrens if (!cbp->cb_scripted) 2137990b4856Slling print_header(cbp->cb_proplist); 213899653d4eSeschrock cbp->cb_first = B_FALSE; 2139fa9e4066Sahrens } 2140fa9e4066Sahrens 2141990b4856Slling print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2142fa9e4066Sahrens 2143fa9e4066Sahrens return (0); 2144fa9e4066Sahrens } 2145fa9e4066Sahrens 2146fa9e4066Sahrens /* 2147990b4856Slling * zpool list [-H] [-o prop[,prop]*] [pool] ... 2148fa9e4066Sahrens * 2149990b4856Slling * -H Scripted mode. Don't display headers, and separate properties 2150990b4856Slling * by a single tab. 2151990b4856Slling * -o List of properties to display. Defaults to 2152990b4856Slling * "name,size,used,available,capacity,health,altroot" 2153fa9e4066Sahrens * 2154fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 2155fa9e4066Sahrens * statistics for each one, as well as health status summary. 2156fa9e4066Sahrens */ 2157fa9e4066Sahrens int 2158fa9e4066Sahrens zpool_do_list(int argc, char **argv) 2159fa9e4066Sahrens { 2160fa9e4066Sahrens int c; 2161fa9e4066Sahrens int ret; 2162fa9e4066Sahrens list_cbdata_t cb = { 0 }; 2163990b4856Slling static char default_props[] = 2164990b4856Slling "name,size,used,available,capacity,health,altroot"; 2165990b4856Slling char *props = default_props; 2166fa9e4066Sahrens 2167fa9e4066Sahrens /* check options */ 2168fa9e4066Sahrens while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2169fa9e4066Sahrens switch (c) { 2170fa9e4066Sahrens case 'H': 217199653d4eSeschrock cb.cb_scripted = B_TRUE; 2172fa9e4066Sahrens break; 2173fa9e4066Sahrens case 'o': 2174990b4856Slling props = optarg; 2175fa9e4066Sahrens break; 2176fa9e4066Sahrens case ':': 2177fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2178fa9e4066Sahrens "'%c' option\n"), optopt); 217999653d4eSeschrock usage(B_FALSE); 2180fa9e4066Sahrens break; 2181fa9e4066Sahrens case '?': 2182fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2183fa9e4066Sahrens optopt); 218499653d4eSeschrock usage(B_FALSE); 2185fa9e4066Sahrens } 2186fa9e4066Sahrens } 2187fa9e4066Sahrens 2188fa9e4066Sahrens argc -= optind; 2189fa9e4066Sahrens argv += optind; 2190fa9e4066Sahrens 2191990b4856Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 219299653d4eSeschrock usage(B_FALSE); 2193fa9e4066Sahrens 219499653d4eSeschrock cb.cb_first = B_TRUE; 2195fa9e4066Sahrens 2196990b4856Slling ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2197990b4856Slling list_callback, &cb); 2198990b4856Slling 2199990b4856Slling zprop_free_list(cb.cb_proplist); 2200fa9e4066Sahrens 2201fce7d82bSmmusante if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2202fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 2203fa9e4066Sahrens return (0); 2204fa9e4066Sahrens } 2205fa9e4066Sahrens 2206fa9e4066Sahrens return (ret); 2207fa9e4066Sahrens } 2208fa9e4066Sahrens 2209fa9e4066Sahrens static nvlist_t * 2210fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name) 2211fa9e4066Sahrens { 2212fa9e4066Sahrens nvlist_t **child; 2213fa9e4066Sahrens uint_t c, children; 2214fa9e4066Sahrens nvlist_t *match; 2215fa9e4066Sahrens char *path; 2216fa9e4066Sahrens 2217fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2218fa9e4066Sahrens &child, &children) != 0) { 2219fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2220fa9e4066Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0) 2221fa9e4066Sahrens name += 9; 2222fa9e4066Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0) 2223fa9e4066Sahrens path += 9; 2224fa9e4066Sahrens if (strcmp(name, path) == 0) 2225fa9e4066Sahrens return (nv); 2226fa9e4066Sahrens return (NULL); 2227fa9e4066Sahrens } 2228fa9e4066Sahrens 2229fa9e4066Sahrens for (c = 0; c < children; c++) 2230fa9e4066Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2231fa9e4066Sahrens return (match); 2232fa9e4066Sahrens 2233fa9e4066Sahrens return (NULL); 2234fa9e4066Sahrens } 2235fa9e4066Sahrens 2236fa9e4066Sahrens static int 2237fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 2238fa9e4066Sahrens { 223999653d4eSeschrock boolean_t force = B_FALSE; 2240fa9e4066Sahrens int c; 2241fa9e4066Sahrens nvlist_t *nvroot; 2242fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 2243fa9e4066Sahrens zpool_handle_t *zhp; 224499653d4eSeschrock int ret; 2245fa9e4066Sahrens 2246fa9e4066Sahrens /* check options */ 2247fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2248fa9e4066Sahrens switch (c) { 2249fa9e4066Sahrens case 'f': 225099653d4eSeschrock force = B_TRUE; 2251fa9e4066Sahrens break; 2252fa9e4066Sahrens case '?': 2253fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2254fa9e4066Sahrens optopt); 225599653d4eSeschrock usage(B_FALSE); 2256fa9e4066Sahrens } 2257fa9e4066Sahrens } 2258fa9e4066Sahrens 2259fa9e4066Sahrens argc -= optind; 2260fa9e4066Sahrens argv += optind; 2261fa9e4066Sahrens 2262fa9e4066Sahrens /* get pool name and check number of arguments */ 2263fa9e4066Sahrens if (argc < 1) { 2264fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 226599653d4eSeschrock usage(B_FALSE); 2266fa9e4066Sahrens } 2267fa9e4066Sahrens 2268fa9e4066Sahrens poolname = argv[0]; 2269fa9e4066Sahrens 2270fa9e4066Sahrens if (argc < 2) { 2271fa9e4066Sahrens (void) fprintf(stderr, 2272fa9e4066Sahrens gettext("missing <device> specification\n")); 227399653d4eSeschrock usage(B_FALSE); 2274fa9e4066Sahrens } 2275fa9e4066Sahrens 2276fa9e4066Sahrens old_disk = argv[1]; 2277fa9e4066Sahrens 2278fa9e4066Sahrens if (argc < 3) { 2279fa9e4066Sahrens if (!replacing) { 2280fa9e4066Sahrens (void) fprintf(stderr, 2281fa9e4066Sahrens gettext("missing <new_device> specification\n")); 228299653d4eSeschrock usage(B_FALSE); 2283fa9e4066Sahrens } 2284fa9e4066Sahrens new_disk = old_disk; 2285fa9e4066Sahrens argc -= 1; 2286fa9e4066Sahrens argv += 1; 2287fa9e4066Sahrens } else { 2288fa9e4066Sahrens new_disk = argv[2]; 2289fa9e4066Sahrens argc -= 2; 2290fa9e4066Sahrens argv += 2; 2291fa9e4066Sahrens } 2292fa9e4066Sahrens 2293fa9e4066Sahrens if (argc > 1) { 2294fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 229599653d4eSeschrock usage(B_FALSE); 2296fa9e4066Sahrens } 2297fa9e4066Sahrens 229899653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2299fa9e4066Sahrens return (1); 2300fa9e4066Sahrens 23018488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 2302fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2303fa9e4066Sahrens poolname); 2304fa9e4066Sahrens zpool_close(zhp); 2305fa9e4066Sahrens return (1); 2306fa9e4066Sahrens } 2307fa9e4066Sahrens 23088488aeb5Staylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv); 2309fa9e4066Sahrens if (nvroot == NULL) { 2310fa9e4066Sahrens zpool_close(zhp); 2311fa9e4066Sahrens return (1); 2312fa9e4066Sahrens } 2313fa9e4066Sahrens 231499653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 231599653d4eSeschrock 231699653d4eSeschrock nvlist_free(nvroot); 231799653d4eSeschrock zpool_close(zhp); 231899653d4eSeschrock 231999653d4eSeschrock return (ret); 2320fa9e4066Sahrens } 2321fa9e4066Sahrens 2322fa9e4066Sahrens /* 2323fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 2324fa9e4066Sahrens * 2325fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2326fa9e4066Sahrens * 2327fa9e4066Sahrens * Replace <device> with <new_device>. 2328fa9e4066Sahrens */ 2329fa9e4066Sahrens /* ARGSUSED */ 2330fa9e4066Sahrens int 2331fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 2332fa9e4066Sahrens { 2333fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2334fa9e4066Sahrens } 2335fa9e4066Sahrens 2336fa9e4066Sahrens /* 2337fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 2338fa9e4066Sahrens * 2339fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2340fa9e4066Sahrens * 2341fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 2342fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 2343fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 2344fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 2345fa9e4066Sahrens */ 2346fa9e4066Sahrens int 2347fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 2348fa9e4066Sahrens { 2349fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2350fa9e4066Sahrens } 2351fa9e4066Sahrens 2352fa9e4066Sahrens /* 2353fa9e4066Sahrens * zpool detach [-f] <pool> <device> 2354fa9e4066Sahrens * 2355fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 2356fa9e4066Sahrens * (not supported yet) 2357fa9e4066Sahrens * 2358fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 2359fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 2360fa9e4066Sahrens * has the only valid copy of some data. 2361fa9e4066Sahrens */ 2362fa9e4066Sahrens /* ARGSUSED */ 2363fa9e4066Sahrens int 2364fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 2365fa9e4066Sahrens { 2366fa9e4066Sahrens int c; 2367fa9e4066Sahrens char *poolname, *path; 2368fa9e4066Sahrens zpool_handle_t *zhp; 236999653d4eSeschrock int ret; 2370fa9e4066Sahrens 2371fa9e4066Sahrens /* check options */ 2372fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2373fa9e4066Sahrens switch (c) { 2374fa9e4066Sahrens case 'f': 2375fa9e4066Sahrens case '?': 2376fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2377fa9e4066Sahrens optopt); 237899653d4eSeschrock usage(B_FALSE); 2379fa9e4066Sahrens } 2380fa9e4066Sahrens } 2381fa9e4066Sahrens 2382fa9e4066Sahrens argc -= optind; 2383fa9e4066Sahrens argv += optind; 2384fa9e4066Sahrens 2385fa9e4066Sahrens /* get pool name and check number of arguments */ 2386fa9e4066Sahrens if (argc < 1) { 2387fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 238899653d4eSeschrock usage(B_FALSE); 2389fa9e4066Sahrens } 2390fa9e4066Sahrens 2391fa9e4066Sahrens if (argc < 2) { 2392fa9e4066Sahrens (void) fprintf(stderr, 2393fa9e4066Sahrens gettext("missing <device> specification\n")); 239499653d4eSeschrock usage(B_FALSE); 2395fa9e4066Sahrens } 2396fa9e4066Sahrens 2397fa9e4066Sahrens poolname = argv[0]; 2398fa9e4066Sahrens path = argv[1]; 2399fa9e4066Sahrens 240099653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2401fa9e4066Sahrens return (1); 2402fa9e4066Sahrens 240399653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 240499653d4eSeschrock 240599653d4eSeschrock zpool_close(zhp); 240699653d4eSeschrock 240799653d4eSeschrock return (ret); 2408fa9e4066Sahrens } 2409fa9e4066Sahrens 2410fa9e4066Sahrens /* 2411441d80aaSlling * zpool online <pool> <device> ... 2412fa9e4066Sahrens */ 2413fa9e4066Sahrens int 2414fa9e4066Sahrens zpool_do_online(int argc, char **argv) 2415fa9e4066Sahrens { 2416fa9e4066Sahrens int c, i; 2417fa9e4066Sahrens char *poolname; 2418fa9e4066Sahrens zpool_handle_t *zhp; 2419fa9e4066Sahrens int ret = 0; 24203d7072f8Seschrock vdev_state_t newstate; 2421fa9e4066Sahrens 2422fa9e4066Sahrens /* check options */ 2423fa9e4066Sahrens while ((c = getopt(argc, argv, "t")) != -1) { 2424fa9e4066Sahrens switch (c) { 2425fa9e4066Sahrens case 't': 2426fa9e4066Sahrens case '?': 2427fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2428fa9e4066Sahrens optopt); 242999653d4eSeschrock usage(B_FALSE); 2430fa9e4066Sahrens } 2431fa9e4066Sahrens } 2432fa9e4066Sahrens 2433fa9e4066Sahrens argc -= optind; 2434fa9e4066Sahrens argv += optind; 2435fa9e4066Sahrens 2436fa9e4066Sahrens /* get pool name and check number of arguments */ 2437fa9e4066Sahrens if (argc < 1) { 2438fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 243999653d4eSeschrock usage(B_FALSE); 2440fa9e4066Sahrens } 2441fa9e4066Sahrens if (argc < 2) { 2442fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 244399653d4eSeschrock usage(B_FALSE); 2444fa9e4066Sahrens } 2445fa9e4066Sahrens 2446fa9e4066Sahrens poolname = argv[0]; 2447fa9e4066Sahrens 244899653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2449fa9e4066Sahrens return (1); 2450fa9e4066Sahrens 24513d7072f8Seschrock for (i = 1; i < argc; i++) { 24523d7072f8Seschrock if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) { 24533d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 24543d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 24553d7072f8Seschrock "onlined, but remains in faulted state\n"), 2456fa9e4066Sahrens argv[i]); 24573d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 24583d7072f8Seschrock (void) printf(gettext("use 'zpool " 24593d7072f8Seschrock "clear' to restore a faulted " 24603d7072f8Seschrock "device\n")); 2461fa9e4066Sahrens else 24623d7072f8Seschrock (void) printf(gettext("use 'zpool " 24633d7072f8Seschrock "replace' to replace devices " 24643d7072f8Seschrock "that are no longer present\n")); 24653d7072f8Seschrock } 24663d7072f8Seschrock } else { 2467fa9e4066Sahrens ret = 1; 24683d7072f8Seschrock } 24693d7072f8Seschrock } 2470fa9e4066Sahrens 247199653d4eSeschrock zpool_close(zhp); 247299653d4eSeschrock 2473fa9e4066Sahrens return (ret); 2474fa9e4066Sahrens } 2475fa9e4066Sahrens 2476fa9e4066Sahrens /* 2477441d80aaSlling * zpool offline [-ft] <pool> <device> ... 2478fa9e4066Sahrens * 2479fa9e4066Sahrens * -f Force the device into the offline state, even if doing 2480fa9e4066Sahrens * so would appear to compromise pool availability. 2481fa9e4066Sahrens * (not supported yet) 2482fa9e4066Sahrens * 2483fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 2484fa9e4066Sahrens * state will not be persistent across reboots. 2485fa9e4066Sahrens */ 2486fa9e4066Sahrens /* ARGSUSED */ 2487fa9e4066Sahrens int 2488fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 2489fa9e4066Sahrens { 2490fa9e4066Sahrens int c, i; 2491fa9e4066Sahrens char *poolname; 2492fa9e4066Sahrens zpool_handle_t *zhp; 249399653d4eSeschrock int ret = 0; 249499653d4eSeschrock boolean_t istmp = B_FALSE; 2495fa9e4066Sahrens 2496fa9e4066Sahrens /* check options */ 2497fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 2498fa9e4066Sahrens switch (c) { 2499fa9e4066Sahrens case 't': 250099653d4eSeschrock istmp = B_TRUE; 2501441d80aaSlling break; 2502441d80aaSlling case 'f': 2503fa9e4066Sahrens case '?': 2504fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2505fa9e4066Sahrens optopt); 250699653d4eSeschrock usage(B_FALSE); 2507fa9e4066Sahrens } 2508fa9e4066Sahrens } 2509fa9e4066Sahrens 2510fa9e4066Sahrens argc -= optind; 2511fa9e4066Sahrens argv += optind; 2512fa9e4066Sahrens 2513fa9e4066Sahrens /* get pool name and check number of arguments */ 2514fa9e4066Sahrens if (argc < 1) { 2515fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 251699653d4eSeschrock usage(B_FALSE); 2517fa9e4066Sahrens } 2518fa9e4066Sahrens if (argc < 2) { 2519fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 252099653d4eSeschrock usage(B_FALSE); 2521fa9e4066Sahrens } 2522fa9e4066Sahrens 2523fa9e4066Sahrens poolname = argv[0]; 2524fa9e4066Sahrens 252599653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2526fa9e4066Sahrens return (1); 2527fa9e4066Sahrens 25283d7072f8Seschrock for (i = 1; i < argc; i++) { 25293d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2530fa9e4066Sahrens ret = 1; 25313d7072f8Seschrock } 2532fa9e4066Sahrens 253399653d4eSeschrock zpool_close(zhp); 253499653d4eSeschrock 2535fa9e4066Sahrens return (ret); 2536fa9e4066Sahrens } 2537fa9e4066Sahrens 2538ea8dc4b6Seschrock /* 2539ea8dc4b6Seschrock * zpool clear <pool> [device] 2540ea8dc4b6Seschrock * 2541ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 2542ea8dc4b6Seschrock */ 2543ea8dc4b6Seschrock int 2544ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 2545ea8dc4b6Seschrock { 2546ea8dc4b6Seschrock int ret = 0; 2547ea8dc4b6Seschrock zpool_handle_t *zhp; 2548ea8dc4b6Seschrock char *pool, *device; 2549ea8dc4b6Seschrock 2550ea8dc4b6Seschrock if (argc < 2) { 2551ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 255299653d4eSeschrock usage(B_FALSE); 2553ea8dc4b6Seschrock } 2554ea8dc4b6Seschrock 2555ea8dc4b6Seschrock if (argc > 3) { 2556ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 255799653d4eSeschrock usage(B_FALSE); 2558ea8dc4b6Seschrock } 2559ea8dc4b6Seschrock 2560ea8dc4b6Seschrock pool = argv[1]; 2561ea8dc4b6Seschrock device = argc == 3 ? argv[2] : NULL; 2562ea8dc4b6Seschrock 2563*b87f3af3Sperrin if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 2564ea8dc4b6Seschrock return (1); 2565ea8dc4b6Seschrock 2566ea8dc4b6Seschrock if (zpool_clear(zhp, device) != 0) 2567ea8dc4b6Seschrock ret = 1; 2568ea8dc4b6Seschrock 2569ea8dc4b6Seschrock zpool_close(zhp); 2570ea8dc4b6Seschrock 2571ea8dc4b6Seschrock return (ret); 2572ea8dc4b6Seschrock } 2573ea8dc4b6Seschrock 2574fa9e4066Sahrens typedef struct scrub_cbdata { 2575fa9e4066Sahrens int cb_type; 257606eeb2adSek110237 int cb_argc; 257706eeb2adSek110237 char **cb_argv; 2578fa9e4066Sahrens } scrub_cbdata_t; 2579fa9e4066Sahrens 2580fa9e4066Sahrens int 2581fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 2582fa9e4066Sahrens { 2583fa9e4066Sahrens scrub_cbdata_t *cb = data; 258406eeb2adSek110237 int err; 2585fa9e4066Sahrens 2586ea8dc4b6Seschrock /* 2587ea8dc4b6Seschrock * Ignore faulted pools. 2588ea8dc4b6Seschrock */ 2589ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2590ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2591ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 2592ea8dc4b6Seschrock return (1); 2593ea8dc4b6Seschrock } 2594ea8dc4b6Seschrock 259506eeb2adSek110237 err = zpool_scrub(zhp, cb->cb_type); 259606eeb2adSek110237 259706eeb2adSek110237 return (err != 0); 2598fa9e4066Sahrens } 2599fa9e4066Sahrens 2600fa9e4066Sahrens /* 2601fa9e4066Sahrens * zpool scrub [-s] <pool> ... 2602fa9e4066Sahrens * 2603fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 2604fa9e4066Sahrens */ 2605fa9e4066Sahrens int 2606fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 2607fa9e4066Sahrens { 2608fa9e4066Sahrens int c; 2609fa9e4066Sahrens scrub_cbdata_t cb; 2610fa9e4066Sahrens 2611fa9e4066Sahrens cb.cb_type = POOL_SCRUB_EVERYTHING; 2612fa9e4066Sahrens 2613fa9e4066Sahrens /* check options */ 2614fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 2615fa9e4066Sahrens switch (c) { 2616fa9e4066Sahrens case 's': 2617fa9e4066Sahrens cb.cb_type = POOL_SCRUB_NONE; 2618fa9e4066Sahrens break; 2619fa9e4066Sahrens case '?': 2620fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2621fa9e4066Sahrens optopt); 262299653d4eSeschrock usage(B_FALSE); 2623fa9e4066Sahrens } 2624fa9e4066Sahrens } 2625fa9e4066Sahrens 262606eeb2adSek110237 cb.cb_argc = argc; 262706eeb2adSek110237 cb.cb_argv = argv; 2628fa9e4066Sahrens argc -= optind; 2629fa9e4066Sahrens argv += optind; 2630fa9e4066Sahrens 2631fa9e4066Sahrens if (argc < 1) { 2632fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 263399653d4eSeschrock usage(B_FALSE); 2634fa9e4066Sahrens } 2635fa9e4066Sahrens 2636b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2637fa9e4066Sahrens } 2638fa9e4066Sahrens 2639fa9e4066Sahrens typedef struct status_cbdata { 2640fa9e4066Sahrens int cb_count; 2641e9dbad6fSeschrock boolean_t cb_allpools; 264299653d4eSeschrock boolean_t cb_verbose; 264399653d4eSeschrock boolean_t cb_explain; 264499653d4eSeschrock boolean_t cb_first; 2645fa9e4066Sahrens } status_cbdata_t; 2646fa9e4066Sahrens 2647fa9e4066Sahrens /* 2648fa9e4066Sahrens * Print out detailed scrub status. 2649fa9e4066Sahrens */ 2650fa9e4066Sahrens void 2651fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot) 2652fa9e4066Sahrens { 2653fa9e4066Sahrens vdev_stat_t *vs; 2654fa9e4066Sahrens uint_t vsc; 2655fa9e4066Sahrens time_t start, end, now; 2656fa9e4066Sahrens double fraction_done; 265718ce54dfSek110237 uint64_t examined, total, minutes_left, minutes_taken; 2658fa9e4066Sahrens char *scrub_type; 2659fa9e4066Sahrens 2660fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2661fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 2662fa9e4066Sahrens 2663fa9e4066Sahrens /* 2664fa9e4066Sahrens * If there's never been a scrub, there's not much to say. 2665fa9e4066Sahrens */ 2666fa9e4066Sahrens if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2667fa9e4066Sahrens (void) printf(gettext("none requested\n")); 2668fa9e4066Sahrens return; 2669fa9e4066Sahrens } 2670fa9e4066Sahrens 2671fa9e4066Sahrens scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2672fa9e4066Sahrens "resilver" : "scrub"; 2673fa9e4066Sahrens 2674fa9e4066Sahrens start = vs->vs_scrub_start; 2675fa9e4066Sahrens end = vs->vs_scrub_end; 2676fa9e4066Sahrens now = time(NULL); 2677fa9e4066Sahrens examined = vs->vs_scrub_examined; 2678fa9e4066Sahrens total = vs->vs_alloc; 2679fa9e4066Sahrens 2680fa9e4066Sahrens if (end != 0) { 268118ce54dfSek110237 minutes_taken = (uint64_t)((end - start) / 60); 268218ce54dfSek110237 268318ce54dfSek110237 (void) printf(gettext("%s %s after %lluh%um with %llu errors " 268418ce54dfSek110237 "on %s"), 2685fa9e4066Sahrens scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 268618ce54dfSek110237 (u_longlong_t)(minutes_taken / 60), 268718ce54dfSek110237 (uint_t)(minutes_taken % 60), 2688fa9e4066Sahrens (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2689fa9e4066Sahrens return; 2690fa9e4066Sahrens } 2691fa9e4066Sahrens 2692fa9e4066Sahrens if (examined == 0) 2693fa9e4066Sahrens examined = 1; 2694fa9e4066Sahrens if (examined > total) 2695fa9e4066Sahrens total = examined; 2696fa9e4066Sahrens 2697fa9e4066Sahrens fraction_done = (double)examined / total; 2698fa9e4066Sahrens minutes_left = (uint64_t)((now - start) * 2699fa9e4066Sahrens (1 - fraction_done) / fraction_done / 60); 270018ce54dfSek110237 minutes_taken = (uint64_t)((now - start) / 60); 2701fa9e4066Sahrens 270218ce54dfSek110237 (void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, " 270318ce54dfSek110237 "%lluh%um to go\n"), 270418ce54dfSek110237 scrub_type, (u_longlong_t)(minutes_taken / 60), 270518ce54dfSek110237 (uint_t)(minutes_taken % 60), 100 * fraction_done, 2706fa9e4066Sahrens (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2707fa9e4066Sahrens } 2708fa9e4066Sahrens 270999653d4eSeschrock typedef struct spare_cbdata { 271099653d4eSeschrock uint64_t cb_guid; 271199653d4eSeschrock zpool_handle_t *cb_zhp; 271299653d4eSeschrock } spare_cbdata_t; 271399653d4eSeschrock 271499653d4eSeschrock static boolean_t 271599653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search) 271699653d4eSeschrock { 271799653d4eSeschrock uint64_t guid; 271899653d4eSeschrock nvlist_t **child; 271999653d4eSeschrock uint_t c, children; 272099653d4eSeschrock 272199653d4eSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 272299653d4eSeschrock search == guid) 272399653d4eSeschrock return (B_TRUE); 272499653d4eSeschrock 272599653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 272699653d4eSeschrock &child, &children) == 0) { 272799653d4eSeschrock for (c = 0; c < children; c++) 272899653d4eSeschrock if (find_vdev(child[c], search)) 272999653d4eSeschrock return (B_TRUE); 273099653d4eSeschrock } 273199653d4eSeschrock 273299653d4eSeschrock return (B_FALSE); 273399653d4eSeschrock } 273499653d4eSeschrock 273599653d4eSeschrock static int 273699653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data) 273799653d4eSeschrock { 273899653d4eSeschrock spare_cbdata_t *cbp = data; 273999653d4eSeschrock nvlist_t *config, *nvroot; 274099653d4eSeschrock 274199653d4eSeschrock config = zpool_get_config(zhp, NULL); 274299653d4eSeschrock verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 274399653d4eSeschrock &nvroot) == 0); 274499653d4eSeschrock 274599653d4eSeschrock if (find_vdev(nvroot, cbp->cb_guid)) { 274699653d4eSeschrock cbp->cb_zhp = zhp; 274799653d4eSeschrock return (1); 274899653d4eSeschrock } 274999653d4eSeschrock 275099653d4eSeschrock zpool_close(zhp); 275199653d4eSeschrock return (0); 275299653d4eSeschrock } 275399653d4eSeschrock 2754fa9e4066Sahrens /* 2755fa9e4066Sahrens * Print out configuration state as requested by status_callback. 2756fa9e4066Sahrens */ 2757fa9e4066Sahrens void 2758c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 27598654d025Sperrin int namewidth, int depth, boolean_t isspare, boolean_t print_logs) 2760fa9e4066Sahrens { 2761fa9e4066Sahrens nvlist_t **child; 2762fa9e4066Sahrens uint_t c, children; 2763fa9e4066Sahrens vdev_stat_t *vs; 2764ea8dc4b6Seschrock char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 2765afefbcddSeschrock char *vname; 2766ea8dc4b6Seschrock uint64_t notpresent; 276799653d4eSeschrock spare_cbdata_t cb; 2768990b4856Slling char *state; 2769fa9e4066Sahrens 2770fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2771fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 2772fa9e4066Sahrens 2773fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2774fa9e4066Sahrens &child, &children) != 0) 2775fa9e4066Sahrens children = 0; 2776fa9e4066Sahrens 2777990b4856Slling state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 277899653d4eSeschrock if (isspare) { 277999653d4eSeschrock /* 278099653d4eSeschrock * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 278199653d4eSeschrock * online drives. 278299653d4eSeschrock */ 278399653d4eSeschrock if (vs->vs_aux == VDEV_AUX_SPARED) 278499653d4eSeschrock state = "INUSE"; 278599653d4eSeschrock else if (vs->vs_state == VDEV_STATE_HEALTHY) 278699653d4eSeschrock state = "AVAIL"; 278799653d4eSeschrock } 2788fa9e4066Sahrens 278999653d4eSeschrock (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 279099653d4eSeschrock name, state); 279199653d4eSeschrock 279299653d4eSeschrock if (!isspare) { 2793fa9e4066Sahrens zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 2794fa9e4066Sahrens zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 2795fa9e4066Sahrens zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 2796fa9e4066Sahrens (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 279799653d4eSeschrock } 2798fa9e4066Sahrens 2799ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2800ea8dc4b6Seschrock ¬present) == 0) { 2801ea8dc4b6Seschrock char *path; 2802ea8dc4b6Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 28030917b783Seschrock (void) printf(" was %s", path); 2804ea8dc4b6Seschrock } else if (vs->vs_aux != 0) { 2805fa9e4066Sahrens (void) printf(" "); 2806fa9e4066Sahrens 2807fa9e4066Sahrens switch (vs->vs_aux) { 2808fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 2809fa9e4066Sahrens (void) printf(gettext("cannot open")); 2810fa9e4066Sahrens break; 2811fa9e4066Sahrens 2812fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 2813fa9e4066Sahrens (void) printf(gettext("missing device")); 2814fa9e4066Sahrens break; 2815fa9e4066Sahrens 2816fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 2817fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 2818fa9e4066Sahrens break; 2819fa9e4066Sahrens 2820eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 2821eaca9bbdSeschrock (void) printf(gettext("newer version")); 2822eaca9bbdSeschrock break; 2823eaca9bbdSeschrock 282499653d4eSeschrock case VDEV_AUX_SPARED: 282599653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 282699653d4eSeschrock &cb.cb_guid) == 0); 282799653d4eSeschrock if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 282899653d4eSeschrock if (strcmp(zpool_get_name(cb.cb_zhp), 282999653d4eSeschrock zpool_get_name(zhp)) == 0) 283099653d4eSeschrock (void) printf(gettext("currently in " 283199653d4eSeschrock "use")); 283299653d4eSeschrock else 283399653d4eSeschrock (void) printf(gettext("in use by " 283499653d4eSeschrock "pool '%s'"), 283599653d4eSeschrock zpool_get_name(cb.cb_zhp)); 283699653d4eSeschrock zpool_close(cb.cb_zhp); 283799653d4eSeschrock } else { 283899653d4eSeschrock (void) printf(gettext("currently in use")); 283999653d4eSeschrock } 284099653d4eSeschrock break; 284199653d4eSeschrock 28423d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 28433d7072f8Seschrock (void) printf(gettext("too many errors")); 28443d7072f8Seschrock break; 28453d7072f8Seschrock 284632b87932Sek110237 case VDEV_AUX_IO_FAILURE: 284732b87932Sek110237 (void) printf(gettext("experienced I/O failures")); 284832b87932Sek110237 break; 284932b87932Sek110237 2850*b87f3af3Sperrin case VDEV_AUX_BAD_LOG: 2851*b87f3af3Sperrin (void) printf(gettext("bad intent log")); 2852*b87f3af3Sperrin break; 2853*b87f3af3Sperrin 2854fa9e4066Sahrens default: 2855fa9e4066Sahrens (void) printf(gettext("corrupted data")); 2856fa9e4066Sahrens break; 2857fa9e4066Sahrens } 2858fa9e4066Sahrens } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2859fa9e4066Sahrens /* 2860fa9e4066Sahrens * Report bytes resilvered/repaired on leaf devices. 2861fa9e4066Sahrens */ 2862fa9e4066Sahrens zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2863fa9e4066Sahrens (void) printf(gettext(" %s %s"), repaired, 2864fa9e4066Sahrens (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2865fa9e4066Sahrens "resilvered" : "repaired"); 2866fa9e4066Sahrens } 2867fa9e4066Sahrens 2868fa9e4066Sahrens (void) printf("\n"); 2869fa9e4066Sahrens 2870afefbcddSeschrock for (c = 0; c < children; c++) { 28718654d025Sperrin uint64_t is_log = B_FALSE; 28728654d025Sperrin 28738654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 28748654d025Sperrin &is_log); 28758654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 28768654d025Sperrin continue; 287799653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 2878c67d9675Seschrock print_status_config(zhp, vname, child[c], 28798654d025Sperrin namewidth, depth + 2, isspare, B_FALSE); 2880afefbcddSeschrock free(vname); 2881afefbcddSeschrock } 2882fa9e4066Sahrens } 2883fa9e4066Sahrens 2884ea8dc4b6Seschrock static void 2885ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 2886ea8dc4b6Seschrock { 288775519f38Sek110237 nvlist_t *nverrlist = NULL; 288855434c77Sek110237 nvpair_t *elem; 288955434c77Sek110237 char *pathname; 289055434c77Sek110237 size_t len = MAXPATHLEN * 2; 2891ea8dc4b6Seschrock 289255434c77Sek110237 if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2893ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 2894ea8dc4b6Seschrock "(insufficient privileges)\n"); 2895ea8dc4b6Seschrock return; 2896ea8dc4b6Seschrock } 2897ea8dc4b6Seschrock 289855434c77Sek110237 (void) printf("errors: Permanent errors have been " 289955434c77Sek110237 "detected in the following files:\n\n"); 2900ea8dc4b6Seschrock 290155434c77Sek110237 pathname = safe_malloc(len); 290255434c77Sek110237 elem = NULL; 290355434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 290455434c77Sek110237 nvlist_t *nv; 290555434c77Sek110237 uint64_t dsobj, obj; 2906ea8dc4b6Seschrock 290755434c77Sek110237 verify(nvpair_value_nvlist(elem, &nv) == 0); 290855434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 290955434c77Sek110237 &dsobj) == 0); 291055434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 291155434c77Sek110237 &obj) == 0); 291255434c77Sek110237 zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 291355434c77Sek110237 (void) printf("%7s %s\n", "", pathname); 2914ea8dc4b6Seschrock } 291555434c77Sek110237 free(pathname); 291655434c77Sek110237 nvlist_free(nverrlist); 2917ea8dc4b6Seschrock } 2918ea8dc4b6Seschrock 291999653d4eSeschrock static void 292099653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 292199653d4eSeschrock int namewidth) 292299653d4eSeschrock { 292399653d4eSeschrock uint_t i; 292499653d4eSeschrock char *name; 292599653d4eSeschrock 292699653d4eSeschrock if (nspares == 0) 292799653d4eSeschrock return; 292899653d4eSeschrock 292999653d4eSeschrock (void) printf(gettext("\tspares\n")); 293099653d4eSeschrock 293199653d4eSeschrock for (i = 0; i < nspares; i++) { 293299653d4eSeschrock name = zpool_vdev_name(g_zfs, zhp, spares[i]); 293399653d4eSeschrock print_status_config(zhp, name, spares[i], 29348654d025Sperrin namewidth, 2, B_TRUE, B_FALSE); 293599653d4eSeschrock free(name); 293699653d4eSeschrock } 293799653d4eSeschrock } 293899653d4eSeschrock 2939fa94a07fSbrendan static void 2940fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 2941fa94a07fSbrendan int namewidth) 2942fa94a07fSbrendan { 2943fa94a07fSbrendan uint_t i; 2944fa94a07fSbrendan char *name; 2945fa94a07fSbrendan 2946fa94a07fSbrendan if (nl2cache == 0) 2947fa94a07fSbrendan return; 2948fa94a07fSbrendan 2949fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 2950fa94a07fSbrendan 2951fa94a07fSbrendan for (i = 0; i < nl2cache; i++) { 2952fa94a07fSbrendan name = zpool_vdev_name(g_zfs, zhp, l2cache[i]); 2953fa94a07fSbrendan print_status_config(zhp, name, l2cache[i], 2954fa94a07fSbrendan namewidth, 2, B_FALSE, B_FALSE); 2955fa94a07fSbrendan free(name); 2956fa94a07fSbrendan } 2957fa94a07fSbrendan } 2958fa94a07fSbrendan 2959fa9e4066Sahrens /* 2960fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 2961fa9e4066Sahrens * 2962fa9e4066Sahrens * pool: tank 2963fa9e4066Sahrens * status: DEGRADED 2964fa9e4066Sahrens * reason: One or more devices ... 2965fa9e4066Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01 2966fa9e4066Sahrens * config: 2967fa9e4066Sahrens * mirror DEGRADED 2968fa9e4066Sahrens * c1t0d0 OK 2969ea8dc4b6Seschrock * c2t0d0 UNAVAIL 2970fa9e4066Sahrens * 2971fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 2972fa9e4066Sahrens * option is specified, then we print out error rate information as well. 2973fa9e4066Sahrens */ 2974fa9e4066Sahrens int 2975fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 2976fa9e4066Sahrens { 2977fa9e4066Sahrens status_cbdata_t *cbp = data; 2978fa9e4066Sahrens nvlist_t *config, *nvroot; 2979fa9e4066Sahrens char *msgid; 2980fa9e4066Sahrens int reason; 298146657f8dSmmusante const char *health; 298246657f8dSmmusante uint_t c; 298346657f8dSmmusante vdev_stat_t *vs; 2984fa9e4066Sahrens 2985088e9d47Seschrock config = zpool_get_config(zhp, NULL); 2986fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 2987fa9e4066Sahrens 2988fa9e4066Sahrens cbp->cb_count++; 2989fa9e4066Sahrens 2990fa9e4066Sahrens /* 2991fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 2992fa9e4066Sahrens * problems. 2993fa9e4066Sahrens */ 2994e9dbad6fSeschrock if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 2995e9dbad6fSeschrock if (!cbp->cb_allpools) { 2996e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 2997e9dbad6fSeschrock zpool_get_name(zhp)); 2998e9dbad6fSeschrock if (cbp->cb_first) 2999e9dbad6fSeschrock cbp->cb_first = B_FALSE; 3000e9dbad6fSeschrock } 3001fa9e4066Sahrens return (0); 3002e9dbad6fSeschrock } 3003fa9e4066Sahrens 3004fa9e4066Sahrens if (cbp->cb_first) 300599653d4eSeschrock cbp->cb_first = B_FALSE; 3006fa9e4066Sahrens else 3007fa9e4066Sahrens (void) printf("\n"); 3008fa9e4066Sahrens 300946657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 301046657f8dSmmusante &nvroot) == 0); 301146657f8dSmmusante verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 301246657f8dSmmusante (uint64_t **)&vs, &c) == 0); 3013990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 3014fa9e4066Sahrens 3015fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 3016fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 3017fa9e4066Sahrens 3018fa9e4066Sahrens switch (reason) { 3019fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 3020fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3021fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 3022fa9e4066Sahrens "continue functioning in a degraded state.\n")); 3023fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 3024fa9e4066Sahrens "online it using 'zpool online'.\n")); 3025fa9e4066Sahrens break; 3026fa9e4066Sahrens 3027fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 3028fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3029fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 3030fa9e4066Sahrens "pool to continue functioning.\n")); 3031fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 3032fa9e4066Sahrens "online it using 'zpool online'.\n")); 3033fa9e4066Sahrens break; 3034fa9e4066Sahrens 3035fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 3036fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3037fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 3038fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 3039fa9e4066Sahrens "functioning in a degraded state.\n")); 3040fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 3041fa9e4066Sahrens "'zpool replace'.\n")); 3042fa9e4066Sahrens break; 3043fa9e4066Sahrens 3044fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 3045fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3046b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 3047fa9e4066Sahrens "There are insufficient replicas for the pool to " 3048fa9e4066Sahrens "continue\n\tfunctioning.\n")); 3049fa9e4066Sahrens (void) printf(gettext("action: Destroy and re-create the pool " 3050fa9e4066Sahrens "from a backup source.\n")); 3051fa9e4066Sahrens break; 3052fa9e4066Sahrens 3053fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 3054fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 3055fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 3056fa9e4066Sahrens "made to correct the error. Applications are " 3057fa9e4066Sahrens "unaffected.\n")); 3058fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 3059fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 3060ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 3061fa9e4066Sahrens "replace'.\n")); 3062fa9e4066Sahrens break; 3063fa9e4066Sahrens 3064fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 3065fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 3066d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 3067fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 3068fa9e4066Sahrens "a\n\tdegraded state.\n")); 3069fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 3070fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 3071fa9e4066Sahrens "replace'.\n")); 3072fa9e4066Sahrens break; 3073fa9e4066Sahrens 3074fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 3075fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 3076fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 3077fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 3078fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 3079fa9e4066Sahrens "complete.\n")); 3080fa9e4066Sahrens break; 3081fa9e4066Sahrens 3082ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 3083ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 3084ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 3085ea8dc4b6Seschrock "Applications may be affected.\n")); 3086ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 3087ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 3088ea8dc4b6Seschrock "backup.\n")); 3089ea8dc4b6Seschrock break; 3090ea8dc4b6Seschrock 3091ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 3092ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 3093ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 3094ea8dc4b6Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 3095ea8dc4b6Seschrock "from a backup source.\n")); 3096ea8dc4b6Seschrock break; 3097ea8dc4b6Seschrock 3098eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 3099eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 3100eaca9bbdSeschrock "older on-disk format. The pool can\n\tstill be used, but " 3101eaca9bbdSeschrock "some features are unavailable.\n")); 3102eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 3103eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 3104eaca9bbdSeschrock "be accessible on older software versions.\n")); 3105eaca9bbdSeschrock break; 3106eaca9bbdSeschrock 3107eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 3108eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 3109eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 3110eaca9bbdSeschrock "be accessed on this system.\n")); 3111eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 3112eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 3113eaca9bbdSeschrock "backup.\n")); 3114eaca9bbdSeschrock break; 3115eaca9bbdSeschrock 31163d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 31173d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 31183d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 31193d7072f8Seschrock "replicas exist for the pool to continue functioning " 31203d7072f8Seschrock "in a\n\tdegraded state.\n")); 31213d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 31223d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 31233d7072f8Seschrock break; 31243d7072f8Seschrock 31253d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 31263d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 31273d7072f8Seschrock "faulted in response to persistent errors. There are " 31283d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 31293d7072f8Seschrock "functioning.\n")); 31303d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 31313d7072f8Seschrock "from a backup source. Manually marking the device\n" 31323d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 31333d7072f8Seschrock "to be recovered.\n")); 31343d7072f8Seschrock break; 31353d7072f8Seschrock 313632b87932Sek110237 case ZPOOL_STATUS_IO_FAILURE_WAIT: 313732b87932Sek110237 case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 313832b87932Sek110237 (void) printf(gettext("status: One or more devices are " 31398a79c1b5Sek110237 "faulted in response to IO failures.\n")); 314032b87932Sek110237 (void) printf(gettext("action: Make sure the affected devices " 314132b87932Sek110237 "are connected, then run 'zpool clear'.\n")); 314232b87932Sek110237 break; 314332b87932Sek110237 3144*b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 3145*b87f3af3Sperrin (void) printf(gettext("status: An intent log record " 3146*b87f3af3Sperrin "could not be read.\n" 3147*b87f3af3Sperrin "\tWaiting for adminstrator intervention to fix the " 3148*b87f3af3Sperrin "faulted pool.\n")); 3149*b87f3af3Sperrin (void) printf(gettext("action: Either restore the affected " 3150*b87f3af3Sperrin "device(s) and run 'zpool online',\n" 3151*b87f3af3Sperrin "\tor ignore the intent log records by running " 3152*b87f3af3Sperrin "'zpool clear'.\n")); 3153*b87f3af3Sperrin break; 3154*b87f3af3Sperrin 3155fa9e4066Sahrens default: 3156fa9e4066Sahrens /* 3157fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 3158fa9e4066Sahrens */ 3159fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 3160fa9e4066Sahrens } 3161fa9e4066Sahrens 3162fa9e4066Sahrens if (msgid != NULL) 3163fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3164fa9e4066Sahrens msgid); 3165fa9e4066Sahrens 3166fa9e4066Sahrens if (config != NULL) { 3167fa9e4066Sahrens int namewidth; 3168ea8dc4b6Seschrock uint64_t nerr; 3169fa94a07fSbrendan nvlist_t **spares, **l2cache; 3170fa94a07fSbrendan uint_t nspares, nl2cache; 3171fa9e4066Sahrens 3172fa9e4066Sahrens 3173fa9e4066Sahrens (void) printf(gettext(" scrub: ")); 3174fa9e4066Sahrens print_scrub_status(nvroot); 3175fa9e4066Sahrens 3176c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 3177fa9e4066Sahrens if (namewidth < 10) 3178fa9e4066Sahrens namewidth = 10; 3179fa9e4066Sahrens 3180fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 3181fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3182fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3183c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 31848654d025Sperrin namewidth, 0, B_FALSE, B_FALSE); 31858654d025Sperrin if (num_logs(nvroot) > 0) 31868654d025Sperrin print_status_config(zhp, "logs", nvroot, namewidth, 0, 31878654d025Sperrin B_FALSE, B_TRUE); 318899653d4eSeschrock 3189fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 3190fa94a07fSbrendan &l2cache, &nl2cache) == 0) 3191fa94a07fSbrendan print_l2cache(zhp, l2cache, nl2cache, namewidth); 3192fa94a07fSbrendan 319399653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 319499653d4eSeschrock &spares, &nspares) == 0) 319599653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 3196ea8dc4b6Seschrock 3197ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3198ea8dc4b6Seschrock &nerr) == 0) { 319955434c77Sek110237 nvlist_t *nverrlist = NULL; 320055434c77Sek110237 3201ea8dc4b6Seschrock /* 3202ea8dc4b6Seschrock * If the approximate error count is small, get a 3203ea8dc4b6Seschrock * precise count by fetching the entire log and 3204ea8dc4b6Seschrock * uniquifying the results. 3205ea8dc4b6Seschrock */ 320675519f38Sek110237 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 320755434c77Sek110237 zpool_get_errlog(zhp, &nverrlist) == 0) { 320855434c77Sek110237 nvpair_t *elem; 320955434c77Sek110237 321055434c77Sek110237 elem = NULL; 321155434c77Sek110237 nerr = 0; 321255434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, 321355434c77Sek110237 elem)) != NULL) { 321455434c77Sek110237 nerr++; 321555434c77Sek110237 } 321655434c77Sek110237 } 321755434c77Sek110237 nvlist_free(nverrlist); 3218ea8dc4b6Seschrock 3219ea8dc4b6Seschrock (void) printf("\n"); 322099653d4eSeschrock 3221ea8dc4b6Seschrock if (nerr == 0) 3222ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 3223ea8dc4b6Seschrock "errors\n")); 3224ea8dc4b6Seschrock else if (!cbp->cb_verbose) 3225e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 32265ad82045Snd150628 "errors, use '-v' for a list\n"), 32275ad82045Snd150628 (u_longlong_t)nerr); 3228ea8dc4b6Seschrock else 3229ea8dc4b6Seschrock print_error_log(zhp); 3230ea8dc4b6Seschrock } 3231fa9e4066Sahrens } else { 3232fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 3233fa9e4066Sahrens "determined.\n")); 3234fa9e4066Sahrens } 3235fa9e4066Sahrens 3236fa9e4066Sahrens return (0); 3237fa9e4066Sahrens } 3238fa9e4066Sahrens 3239fa9e4066Sahrens /* 3240fa9e4066Sahrens * zpool status [-vx] [pool] ... 3241fa9e4066Sahrens * 3242fa9e4066Sahrens * -v Display complete error logs 3243fa9e4066Sahrens * -x Display only pools with potential problems 3244fa9e4066Sahrens * 3245fa9e4066Sahrens * Describes the health status of all pools or some subset. 3246fa9e4066Sahrens */ 3247fa9e4066Sahrens int 3248fa9e4066Sahrens zpool_do_status(int argc, char **argv) 3249fa9e4066Sahrens { 3250fa9e4066Sahrens int c; 3251fa9e4066Sahrens int ret; 3252fa9e4066Sahrens status_cbdata_t cb = { 0 }; 3253fa9e4066Sahrens 3254fa9e4066Sahrens /* check options */ 3255fa9e4066Sahrens while ((c = getopt(argc, argv, "vx")) != -1) { 3256fa9e4066Sahrens switch (c) { 3257fa9e4066Sahrens case 'v': 325899653d4eSeschrock cb.cb_verbose = B_TRUE; 3259fa9e4066Sahrens break; 3260fa9e4066Sahrens case 'x': 326199653d4eSeschrock cb.cb_explain = B_TRUE; 3262fa9e4066Sahrens break; 3263fa9e4066Sahrens case '?': 3264fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3265fa9e4066Sahrens optopt); 326699653d4eSeschrock usage(B_FALSE); 3267fa9e4066Sahrens } 3268fa9e4066Sahrens } 3269fa9e4066Sahrens 3270fa9e4066Sahrens argc -= optind; 3271fa9e4066Sahrens argv += optind; 3272fa9e4066Sahrens 327399653d4eSeschrock cb.cb_first = B_TRUE; 3274fa9e4066Sahrens 3275e9dbad6fSeschrock if (argc == 0) 3276e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 3277e9dbad6fSeschrock 3278b1b8ab34Slling ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3279fa9e4066Sahrens 3280fa9e4066Sahrens if (argc == 0 && cb.cb_count == 0) 3281fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 3282e9dbad6fSeschrock else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3283fa9e4066Sahrens (void) printf(gettext("all pools are healthy\n")); 3284fa9e4066Sahrens 3285fa9e4066Sahrens return (ret); 3286fa9e4066Sahrens } 3287fa9e4066Sahrens 3288eaca9bbdSeschrock typedef struct upgrade_cbdata { 3289eaca9bbdSeschrock int cb_all; 3290eaca9bbdSeschrock int cb_first; 3291eaca9bbdSeschrock int cb_newer; 329206eeb2adSek110237 int cb_argc; 3293990b4856Slling uint64_t cb_version; 329406eeb2adSek110237 char **cb_argv; 3295eaca9bbdSeschrock } upgrade_cbdata_t; 3296eaca9bbdSeschrock 3297eaca9bbdSeschrock static int 3298eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 3299eaca9bbdSeschrock { 3300eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 3301eaca9bbdSeschrock nvlist_t *config; 3302eaca9bbdSeschrock uint64_t version; 3303eaca9bbdSeschrock int ret = 0; 3304eaca9bbdSeschrock 3305eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 3306eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3307eaca9bbdSeschrock &version) == 0); 3308eaca9bbdSeschrock 3309e7437265Sahrens if (!cbp->cb_newer && version < SPA_VERSION) { 3310eaca9bbdSeschrock if (!cbp->cb_all) { 3311eaca9bbdSeschrock if (cbp->cb_first) { 3312eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3313eaca9bbdSeschrock "out of date, and can be upgraded. After " 3314eaca9bbdSeschrock "being\nupgraded, these pools will no " 3315eaca9bbdSeschrock "longer be accessible by older software " 3316eaca9bbdSeschrock "versions.\n\n")); 3317eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3318eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 331999653d4eSeschrock cbp->cb_first = B_FALSE; 3320eaca9bbdSeschrock } 3321eaca9bbdSeschrock 33225ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3323eaca9bbdSeschrock zpool_get_name(zhp)); 3324eaca9bbdSeschrock } else { 332599653d4eSeschrock cbp->cb_first = B_FALSE; 3326990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 332706eeb2adSek110237 if (!ret) { 3328eaca9bbdSeschrock (void) printf(gettext("Successfully upgraded " 3329990b4856Slling "'%s'\n\n"), zpool_get_name(zhp)); 3330eaca9bbdSeschrock } 333106eeb2adSek110237 } 3332e7437265Sahrens } else if (cbp->cb_newer && version > SPA_VERSION) { 3333eaca9bbdSeschrock assert(!cbp->cb_all); 3334eaca9bbdSeschrock 3335eaca9bbdSeschrock if (cbp->cb_first) { 3336eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3337eaca9bbdSeschrock "formatted using a newer software version and\n" 3338eaca9bbdSeschrock "cannot be accessed on the current system.\n\n")); 3339eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3340eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 334199653d4eSeschrock cbp->cb_first = B_FALSE; 3342eaca9bbdSeschrock } 3343eaca9bbdSeschrock 33445ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3345eaca9bbdSeschrock zpool_get_name(zhp)); 3346eaca9bbdSeschrock } 3347eaca9bbdSeschrock 3348eaca9bbdSeschrock zpool_close(zhp); 3349eaca9bbdSeschrock return (ret); 3350eaca9bbdSeschrock } 3351eaca9bbdSeschrock 3352eaca9bbdSeschrock /* ARGSUSED */ 3353eaca9bbdSeschrock static int 335406eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data) 3355eaca9bbdSeschrock { 3356990b4856Slling upgrade_cbdata_t *cbp = data; 3357990b4856Slling uint64_t cur_version; 3358eaca9bbdSeschrock int ret; 3359eaca9bbdSeschrock 33608654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 33618654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 33628654d025Sperrin "Pool 'log' must be renamed using export and import" 33638654d025Sperrin " to upgrade.\n")); 33648654d025Sperrin return (1); 33658654d025Sperrin } 3366990b4856Slling 3367990b4856Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 3368e6c728e1Sbrendan if (cur_version > cbp->cb_version) { 3369eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 3370e6c728e1Sbrendan "using more current version '%llu'.\n"), 3371e6c728e1Sbrendan zpool_get_name(zhp), cur_version); 3372e6c728e1Sbrendan return (0); 3373e6c728e1Sbrendan } 3374e6c728e1Sbrendan if (cur_version == cbp->cb_version) { 3375e6c728e1Sbrendan (void) printf(gettext("Pool '%s' is already formatted " 3376e6c728e1Sbrendan "using the current version.\n"), zpool_get_name(zhp)); 3377eaca9bbdSeschrock return (0); 3378eaca9bbdSeschrock } 3379eaca9bbdSeschrock 3380990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 338106eeb2adSek110237 338206eeb2adSek110237 if (!ret) { 338344cd46caSbillm (void) printf(gettext("Successfully upgraded '%s' " 3384990b4856Slling "from version %llu to version %llu\n\n"), 3385990b4856Slling zpool_get_name(zhp), (u_longlong_t)cur_version, 3386990b4856Slling (u_longlong_t)cbp->cb_version); 338706eeb2adSek110237 } 3388eaca9bbdSeschrock 3389eaca9bbdSeschrock return (ret != 0); 3390eaca9bbdSeschrock } 3391eaca9bbdSeschrock 3392eaca9bbdSeschrock /* 3393eaca9bbdSeschrock * zpool upgrade 3394eaca9bbdSeschrock * zpool upgrade -v 3395990b4856Slling * zpool upgrade [-V version] <-a | pool ...> 3396eaca9bbdSeschrock * 3397eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 3398eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 3399eaca9bbdSeschrock * upgrade all pools. 3400eaca9bbdSeschrock */ 3401eaca9bbdSeschrock int 3402eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 3403eaca9bbdSeschrock { 3404eaca9bbdSeschrock int c; 3405eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 3406eaca9bbdSeschrock int ret = 0; 3407eaca9bbdSeschrock boolean_t showversions = B_FALSE; 3408990b4856Slling char *end; 3409990b4856Slling 3410eaca9bbdSeschrock 3411eaca9bbdSeschrock /* check options */ 3412990b4856Slling while ((c = getopt(argc, argv, "avV:")) != -1) { 3413eaca9bbdSeschrock switch (c) { 3414eaca9bbdSeschrock case 'a': 341599653d4eSeschrock cb.cb_all = B_TRUE; 3416eaca9bbdSeschrock break; 3417eaca9bbdSeschrock case 'v': 3418eaca9bbdSeschrock showversions = B_TRUE; 3419eaca9bbdSeschrock break; 3420990b4856Slling case 'V': 3421990b4856Slling cb.cb_version = strtoll(optarg, &end, 10); 3422351420b3Slling if (*end != '\0' || cb.cb_version > SPA_VERSION || 3423351420b3Slling cb.cb_version < SPA_VERSION_1) { 3424990b4856Slling (void) fprintf(stderr, 3425990b4856Slling gettext("invalid version '%s'\n"), optarg); 3426990b4856Slling usage(B_FALSE); 3427990b4856Slling } 3428990b4856Slling break; 3429eaca9bbdSeschrock case '?': 3430eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3431eaca9bbdSeschrock optopt); 343299653d4eSeschrock usage(B_FALSE); 3433eaca9bbdSeschrock } 3434eaca9bbdSeschrock } 3435eaca9bbdSeschrock 343606eeb2adSek110237 cb.cb_argc = argc; 343706eeb2adSek110237 cb.cb_argv = argv; 3438eaca9bbdSeschrock argc -= optind; 3439eaca9bbdSeschrock argv += optind; 3440eaca9bbdSeschrock 3441351420b3Slling if (cb.cb_version == 0) { 3442351420b3Slling cb.cb_version = SPA_VERSION; 3443351420b3Slling } else if (!cb.cb_all && argc == 0) { 3444351420b3Slling (void) fprintf(stderr, gettext("-V option is " 3445351420b3Slling "incompatible with other arguments\n")); 3446351420b3Slling usage(B_FALSE); 3447351420b3Slling } 3448351420b3Slling 3449eaca9bbdSeschrock if (showversions) { 3450eaca9bbdSeschrock if (cb.cb_all || argc != 0) { 3451eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 3452eaca9bbdSeschrock "incompatible with other arguments\n")); 345399653d4eSeschrock usage(B_FALSE); 3454eaca9bbdSeschrock } 3455eaca9bbdSeschrock } else if (cb.cb_all) { 3456eaca9bbdSeschrock if (argc != 0) { 3457351420b3Slling (void) fprintf(stderr, gettext("-a option should not " 3458351420b3Slling "be used along with a pool name\n")); 345999653d4eSeschrock usage(B_FALSE); 3460eaca9bbdSeschrock } 3461eaca9bbdSeschrock } 3462eaca9bbdSeschrock 3463e7437265Sahrens (void) printf(gettext("This system is currently running " 3464e7437265Sahrens "ZFS pool version %llu.\n\n"), SPA_VERSION); 346599653d4eSeschrock cb.cb_first = B_TRUE; 3466eaca9bbdSeschrock if (showversions) { 3467eaca9bbdSeschrock (void) printf(gettext("The following versions are " 3468d7d4af51Smmusante "supported:\n\n")); 3469eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 3470eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 3471eaca9bbdSeschrock "---------------\n"); 347299653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 347344cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 347444cd46caSbillm "(replicated metadata)\n")); 347599653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 347699653d4eSeschrock "RAID-Z\n")); 3477d7306b64Sek110237 (void) printf(gettext(" 4 zpool history\n")); 3478c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 3479c9431fa1Sahl "algorithm\n")); 3480990b4856Slling (void) printf(gettext(" 6 bootfs pool property\n")); 34818654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 3482ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 3483a9799022Sck153898 (void) printf(gettext(" 9 refquota and refreservation " 3484a9799022Sck153898 "properties\n")); 3485fa94a07fSbrendan (void) printf(gettext(" 10 Cache devices\n")); 3486088f3894Sahrens (void) printf(gettext(" 11 Improved scrub performance\n")); 3487bb0ade09Sahrens (void) printf(gettext(" 12 Snapshot properties\n")); 34888654d025Sperrin (void) printf(gettext("For more information on a particular " 3489eaca9bbdSeschrock "version, including supported releases, see:\n\n")); 3490eaca9bbdSeschrock (void) printf("http://www.opensolaris.org/os/community/zfs/" 3491eaca9bbdSeschrock "version/N\n\n"); 3492eaca9bbdSeschrock (void) printf(gettext("Where 'N' is the version number.\n")); 3493eaca9bbdSeschrock } else if (argc == 0) { 3494eaca9bbdSeschrock int notfound; 3495eaca9bbdSeschrock 349699653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3497eaca9bbdSeschrock notfound = cb.cb_first; 3498eaca9bbdSeschrock 3499eaca9bbdSeschrock if (!cb.cb_all && ret == 0) { 3500eaca9bbdSeschrock if (!cb.cb_first) 3501eaca9bbdSeschrock (void) printf("\n"); 3502eaca9bbdSeschrock cb.cb_first = B_TRUE; 3503eaca9bbdSeschrock cb.cb_newer = B_TRUE; 350499653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3505eaca9bbdSeschrock if (!cb.cb_first) { 3506eaca9bbdSeschrock notfound = B_FALSE; 3507eaca9bbdSeschrock (void) printf("\n"); 3508eaca9bbdSeschrock } 3509eaca9bbdSeschrock } 3510eaca9bbdSeschrock 3511eaca9bbdSeschrock if (ret == 0) { 3512eaca9bbdSeschrock if (notfound) 3513eaca9bbdSeschrock (void) printf(gettext("All pools are formatted " 3514eaca9bbdSeschrock "using this version.\n")); 3515eaca9bbdSeschrock else if (!cb.cb_all) 3516eaca9bbdSeschrock (void) printf(gettext("Use 'zpool upgrade -v' " 3517eaca9bbdSeschrock "for a list of available versions and " 3518eaca9bbdSeschrock "their associated\nfeatures.\n")); 3519eaca9bbdSeschrock } 3520eaca9bbdSeschrock } else { 3521b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 3522b1b8ab34Slling upgrade_one, &cb); 352306eeb2adSek110237 } 352406eeb2adSek110237 352506eeb2adSek110237 return (ret); 352606eeb2adSek110237 } 352706eeb2adSek110237 3528ecd6cf80Smarks typedef struct hist_cbdata { 3529ecd6cf80Smarks boolean_t first; 3530ecd6cf80Smarks int longfmt; 3531ecd6cf80Smarks int internal; 3532ecd6cf80Smarks } hist_cbdata_t; 3533ecd6cf80Smarks 3534ecd6cf80Smarks char *hist_event_table[LOG_END] = { 3535ecd6cf80Smarks "invalid event", 3536ecd6cf80Smarks "pool create", 3537ecd6cf80Smarks "vdev add", 3538ecd6cf80Smarks "pool remove", 3539ecd6cf80Smarks "pool destroy", 3540ecd6cf80Smarks "pool export", 3541ecd6cf80Smarks "pool import", 3542ecd6cf80Smarks "vdev attach", 3543ecd6cf80Smarks "vdev replace", 3544ecd6cf80Smarks "vdev detach", 3545ecd6cf80Smarks "vdev online", 3546ecd6cf80Smarks "vdev offline", 3547ecd6cf80Smarks "vdev upgrade", 3548ecd6cf80Smarks "pool clear", 3549ecd6cf80Smarks "pool scrub", 3550ecd6cf80Smarks "pool property set", 3551ecd6cf80Smarks "create", 3552ecd6cf80Smarks "clone", 3553ecd6cf80Smarks "destroy", 3554ecd6cf80Smarks "destroy_begin_sync", 3555ecd6cf80Smarks "inherit", 3556ecd6cf80Smarks "property set", 3557ecd6cf80Smarks "quota set", 3558ecd6cf80Smarks "permission update", 3559ecd6cf80Smarks "permission remove", 3560ecd6cf80Smarks "permission who remove", 3561ecd6cf80Smarks "promote", 3562ecd6cf80Smarks "receive", 3563ecd6cf80Smarks "rename", 3564ecd6cf80Smarks "reservation set", 3565ecd6cf80Smarks "replay_inc_sync", 3566ecd6cf80Smarks "replay_full_sync", 3567ecd6cf80Smarks "rollback", 3568ecd6cf80Smarks "snapshot", 3569e7437265Sahrens "filesystem version upgrade", 3570a9799022Sck153898 "refquota set", 3571a9799022Sck153898 "refreservation set", 3572088f3894Sahrens "pool scrub done", 3573ecd6cf80Smarks }; 3574ecd6cf80Smarks 357506eeb2adSek110237 /* 357606eeb2adSek110237 * Print out the command history for a specific pool. 357706eeb2adSek110237 */ 357806eeb2adSek110237 static int 357906eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data) 358006eeb2adSek110237 { 358106eeb2adSek110237 nvlist_t *nvhis; 358206eeb2adSek110237 nvlist_t **records; 358306eeb2adSek110237 uint_t numrecords; 358406eeb2adSek110237 char *cmdstr; 3585ecd6cf80Smarks char *pathstr; 358606eeb2adSek110237 uint64_t dst_time; 358706eeb2adSek110237 time_t tsec; 358806eeb2adSek110237 struct tm t; 358906eeb2adSek110237 char tbuf[30]; 359006eeb2adSek110237 int ret, i; 3591ecd6cf80Smarks uint64_t who; 3592ecd6cf80Smarks struct passwd *pwd; 3593ecd6cf80Smarks char *hostname; 3594ecd6cf80Smarks char *zonename; 3595ecd6cf80Smarks char internalstr[MAXPATHLEN]; 3596ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 3597ecd6cf80Smarks uint64_t txg; 3598ecd6cf80Smarks uint64_t ievent; 359906eeb2adSek110237 3600ecd6cf80Smarks cb->first = B_FALSE; 360106eeb2adSek110237 360206eeb2adSek110237 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 360306eeb2adSek110237 360406eeb2adSek110237 if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 360506eeb2adSek110237 return (ret); 360606eeb2adSek110237 360706eeb2adSek110237 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 360806eeb2adSek110237 &records, &numrecords) == 0); 360906eeb2adSek110237 for (i = 0; i < numrecords; i++) { 361006eeb2adSek110237 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3611ecd6cf80Smarks &dst_time) != 0) 3612ecd6cf80Smarks continue; 3613ecd6cf80Smarks 3614ecd6cf80Smarks /* is it an internal event or a standard event? */ 3615ecd6cf80Smarks if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3616ecd6cf80Smarks &cmdstr) != 0) { 3617ecd6cf80Smarks if (cb->internal == 0) 3618ecd6cf80Smarks continue; 3619ecd6cf80Smarks 3620ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3621ecd6cf80Smarks ZPOOL_HIST_INT_EVENT, &ievent) != 0) 3622ecd6cf80Smarks continue; 3623ecd6cf80Smarks verify(nvlist_lookup_uint64(records[i], 3624ecd6cf80Smarks ZPOOL_HIST_TXG, &txg) == 0); 3625ecd6cf80Smarks verify(nvlist_lookup_string(records[i], 3626ecd6cf80Smarks ZPOOL_HIST_INT_STR, &pathstr) == 0); 3627088f3894Sahrens if (ievent >= LOG_END) 3628ecd6cf80Smarks continue; 3629ecd6cf80Smarks (void) snprintf(internalstr, 3630ecd6cf80Smarks sizeof (internalstr), 3631ecd6cf80Smarks "[internal %s txg:%lld] %s", 3632ecd6cf80Smarks hist_event_table[ievent], txg, 3633ecd6cf80Smarks pathstr); 3634ecd6cf80Smarks cmdstr = internalstr; 3635ecd6cf80Smarks } 363606eeb2adSek110237 tsec = dst_time; 363706eeb2adSek110237 (void) localtime_r(&tsec, &t); 363806eeb2adSek110237 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3639ecd6cf80Smarks (void) printf("%s %s", tbuf, cmdstr); 3640ecd6cf80Smarks 3641ecd6cf80Smarks if (!cb->longfmt) { 3642ecd6cf80Smarks (void) printf("\n"); 3643ecd6cf80Smarks continue; 364406eeb2adSek110237 } 3645ecd6cf80Smarks (void) printf(" ["); 3646ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3647ecd6cf80Smarks ZPOOL_HIST_WHO, &who) == 0) { 3648ecd6cf80Smarks pwd = getpwuid((uid_t)who); 3649ecd6cf80Smarks if (pwd) 3650ecd6cf80Smarks (void) printf("user %s on", 3651ecd6cf80Smarks pwd->pw_name); 3652ecd6cf80Smarks else 3653ecd6cf80Smarks (void) printf("user %d on", 3654ecd6cf80Smarks (int)who); 3655ecd6cf80Smarks } else { 3656ecd6cf80Smarks (void) printf(gettext("no info]\n")); 3657ecd6cf80Smarks continue; 3658ecd6cf80Smarks } 3659ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3660ecd6cf80Smarks ZPOOL_HIST_HOST, &hostname) == 0) { 3661ecd6cf80Smarks (void) printf(" %s", hostname); 3662ecd6cf80Smarks } 3663ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3664ecd6cf80Smarks ZPOOL_HIST_ZONE, &zonename) == 0) { 3665ecd6cf80Smarks (void) printf(":%s", zonename); 3666ecd6cf80Smarks } 3667ecd6cf80Smarks 3668ecd6cf80Smarks (void) printf("]"); 3669ecd6cf80Smarks (void) printf("\n"); 367006eeb2adSek110237 } 367106eeb2adSek110237 (void) printf("\n"); 367206eeb2adSek110237 nvlist_free(nvhis); 367306eeb2adSek110237 367406eeb2adSek110237 return (ret); 367506eeb2adSek110237 } 367606eeb2adSek110237 367706eeb2adSek110237 /* 367806eeb2adSek110237 * zpool history <pool> 367906eeb2adSek110237 * 368006eeb2adSek110237 * Displays the history of commands that modified pools. 368106eeb2adSek110237 */ 3682ecd6cf80Smarks 3683ecd6cf80Smarks 368406eeb2adSek110237 int 368506eeb2adSek110237 zpool_do_history(int argc, char **argv) 368606eeb2adSek110237 { 3687ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 368806eeb2adSek110237 int ret; 3689ecd6cf80Smarks int c; 369006eeb2adSek110237 3691ecd6cf80Smarks cbdata.first = B_TRUE; 3692ecd6cf80Smarks /* check options */ 3693ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 3694ecd6cf80Smarks switch (c) { 3695ecd6cf80Smarks case 'l': 3696ecd6cf80Smarks cbdata.longfmt = 1; 3697ecd6cf80Smarks break; 3698ecd6cf80Smarks case 'i': 3699ecd6cf80Smarks cbdata.internal = 1; 3700ecd6cf80Smarks break; 3701ecd6cf80Smarks case '?': 3702ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3703ecd6cf80Smarks optopt); 3704ecd6cf80Smarks usage(B_FALSE); 3705ecd6cf80Smarks } 3706ecd6cf80Smarks } 370706eeb2adSek110237 argc -= optind; 370806eeb2adSek110237 argv += optind; 370906eeb2adSek110237 3710b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3711ecd6cf80Smarks &cbdata); 371206eeb2adSek110237 3713ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 371406eeb2adSek110237 (void) printf(gettext("no pools available\n")); 371506eeb2adSek110237 return (0); 3716eaca9bbdSeschrock } 3717eaca9bbdSeschrock 3718eaca9bbdSeschrock return (ret); 3719eaca9bbdSeschrock } 3720eaca9bbdSeschrock 3721b1b8ab34Slling static int 3722b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 3723b1b8ab34Slling { 3724990b4856Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 3725b1b8ab34Slling char value[MAXNAMELEN]; 3726990b4856Slling zprop_source_t srctype; 3727990b4856Slling zprop_list_t *pl; 3728b1b8ab34Slling 3729b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3730b1b8ab34Slling 3731b1b8ab34Slling /* 3732990b4856Slling * Skip the special fake placeholder. This will also skip 3733990b4856Slling * over the name property when 'all' is specified. 3734b1b8ab34Slling */ 3735990b4856Slling if (pl->pl_prop == ZPOOL_PROP_NAME && 3736b1b8ab34Slling pl == cbp->cb_proplist) 3737b1b8ab34Slling continue; 3738b1b8ab34Slling 3739b1b8ab34Slling if (zpool_get_prop(zhp, pl->pl_prop, 3740b1b8ab34Slling value, sizeof (value), &srctype) != 0) 3741b1b8ab34Slling continue; 3742b1b8ab34Slling 3743990b4856Slling zprop_print_one_property(zpool_get_name(zhp), cbp, 3744b1b8ab34Slling zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3745b1b8ab34Slling } 3746b1b8ab34Slling return (0); 3747b1b8ab34Slling } 3748b1b8ab34Slling 3749b1b8ab34Slling int 3750b1b8ab34Slling zpool_do_get(int argc, char **argv) 3751b1b8ab34Slling { 3752990b4856Slling zprop_get_cbdata_t cb = { 0 }; 3753990b4856Slling zprop_list_t fake_name = { 0 }; 3754b1b8ab34Slling int ret; 3755b1b8ab34Slling 3756b1b8ab34Slling if (argc < 3) 3757b1b8ab34Slling usage(B_FALSE); 3758b1b8ab34Slling 3759b1b8ab34Slling cb.cb_first = B_TRUE; 3760990b4856Slling cb.cb_sources = ZPROP_SRC_ALL; 3761b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 3762b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 3763b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 3764b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 3765990b4856Slling cb.cb_type = ZFS_TYPE_POOL; 3766b1b8ab34Slling 3767990b4856Slling if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 3768990b4856Slling ZFS_TYPE_POOL) != 0) 3769b1b8ab34Slling usage(B_FALSE); 3770b1b8ab34Slling 3771b1b8ab34Slling if (cb.cb_proplist != NULL) { 3772990b4856Slling fake_name.pl_prop = ZPOOL_PROP_NAME; 3773b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 3774b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 3775b1b8ab34Slling cb.cb_proplist = &fake_name; 3776b1b8ab34Slling } 3777b1b8ab34Slling 3778b1b8ab34Slling ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3779b1b8ab34Slling get_callback, &cb); 3780b1b8ab34Slling 3781b1b8ab34Slling if (cb.cb_proplist == &fake_name) 3782990b4856Slling zprop_free_list(fake_name.pl_next); 3783b1b8ab34Slling else 3784990b4856Slling zprop_free_list(cb.cb_proplist); 3785b1b8ab34Slling 3786b1b8ab34Slling return (ret); 3787b1b8ab34Slling } 3788b1b8ab34Slling 3789b1b8ab34Slling typedef struct set_cbdata { 3790b1b8ab34Slling char *cb_propname; 3791b1b8ab34Slling char *cb_value; 3792b1b8ab34Slling boolean_t cb_any_successful; 3793b1b8ab34Slling } set_cbdata_t; 3794b1b8ab34Slling 3795b1b8ab34Slling int 3796b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 3797b1b8ab34Slling { 3798b1b8ab34Slling int error; 3799b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 3800b1b8ab34Slling 3801b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3802b1b8ab34Slling 3803b1b8ab34Slling if (!error) 3804b1b8ab34Slling cb->cb_any_successful = B_TRUE; 3805b1b8ab34Slling 3806b1b8ab34Slling return (error); 3807b1b8ab34Slling } 3808b1b8ab34Slling 3809b1b8ab34Slling int 3810b1b8ab34Slling zpool_do_set(int argc, char **argv) 3811b1b8ab34Slling { 3812b1b8ab34Slling set_cbdata_t cb = { 0 }; 3813b1b8ab34Slling int error; 3814b1b8ab34Slling 3815b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 3816b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3817b1b8ab34Slling argv[1][1]); 3818b1b8ab34Slling usage(B_FALSE); 3819b1b8ab34Slling } 3820b1b8ab34Slling 3821b1b8ab34Slling if (argc < 2) { 3822b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 3823b1b8ab34Slling "argument\n")); 3824b1b8ab34Slling usage(B_FALSE); 3825b1b8ab34Slling } 3826b1b8ab34Slling 3827b1b8ab34Slling if (argc < 3) { 3828b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 3829b1b8ab34Slling usage(B_FALSE); 3830b1b8ab34Slling } 3831b1b8ab34Slling 3832b1b8ab34Slling if (argc > 3) { 3833b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 3834b1b8ab34Slling usage(B_FALSE); 3835b1b8ab34Slling } 3836b1b8ab34Slling 3837b1b8ab34Slling cb.cb_propname = argv[1]; 3838b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 3839b1b8ab34Slling if (cb.cb_value == NULL) { 3840b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 3841b1b8ab34Slling "property=value argument\n")); 3842b1b8ab34Slling usage(B_FALSE); 3843b1b8ab34Slling } 3844b1b8ab34Slling 3845b1b8ab34Slling *(cb.cb_value) = '\0'; 3846b1b8ab34Slling cb.cb_value++; 3847b1b8ab34Slling 3848b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3849b1b8ab34Slling set_callback, &cb); 3850b1b8ab34Slling 3851b1b8ab34Slling return (error); 3852b1b8ab34Slling } 3853b1b8ab34Slling 3854b1b8ab34Slling static int 3855b1b8ab34Slling find_command_idx(char *command, int *idx) 3856b1b8ab34Slling { 3857b1b8ab34Slling int i; 3858b1b8ab34Slling 3859b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 3860b1b8ab34Slling if (command_table[i].name == NULL) 3861b1b8ab34Slling continue; 3862b1b8ab34Slling 3863b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 3864b1b8ab34Slling *idx = i; 3865b1b8ab34Slling return (0); 3866b1b8ab34Slling } 3867b1b8ab34Slling } 3868b1b8ab34Slling return (1); 3869b1b8ab34Slling } 3870b1b8ab34Slling 3871fa9e4066Sahrens int 3872fa9e4066Sahrens main(int argc, char **argv) 3873fa9e4066Sahrens { 3874fa9e4066Sahrens int ret; 3875fa9e4066Sahrens int i; 3876fa9e4066Sahrens char *cmdname; 3877fa9e4066Sahrens 3878fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 3879fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 3880fa9e4066Sahrens 388199653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 388299653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 3883203a47d8Snd150628 "initialize ZFS library\n")); 388499653d4eSeschrock return (1); 388599653d4eSeschrock } 388699653d4eSeschrock 388799653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 388899653d4eSeschrock 3889fa9e4066Sahrens opterr = 0; 3890fa9e4066Sahrens 3891fa9e4066Sahrens /* 3892fa9e4066Sahrens * Make sure the user has specified some command. 3893fa9e4066Sahrens */ 3894fa9e4066Sahrens if (argc < 2) { 3895fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 389699653d4eSeschrock usage(B_FALSE); 3897fa9e4066Sahrens } 3898fa9e4066Sahrens 3899fa9e4066Sahrens cmdname = argv[1]; 3900fa9e4066Sahrens 3901fa9e4066Sahrens /* 3902fa9e4066Sahrens * Special case '-?' 3903fa9e4066Sahrens */ 3904fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 390599653d4eSeschrock usage(B_TRUE); 3906fa9e4066Sahrens 39072a6b87f0Sek110237 zpool_set_history_str("zpool", argc, argv, history_str); 39082a6b87f0Sek110237 verify(zpool_stage_history(g_zfs, history_str) == 0); 39092a6b87f0Sek110237 3910fa9e4066Sahrens /* 3911fa9e4066Sahrens * Run the appropriate command. 3912fa9e4066Sahrens */ 3913b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 3914fa9e4066Sahrens current_command = &command_table[i]; 3915fa9e4066Sahrens ret = command_table[i].func(argc - 1, argv + 1); 391691ebeef5Sahrens } else if (strchr(cmdname, '=')) { 391791ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 391891ebeef5Sahrens current_command = &command_table[i]; 391991ebeef5Sahrens ret = command_table[i].func(argc, argv); 392091ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 3921fa9e4066Sahrens /* 392291ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 392391ebeef5Sahrens * it as such. 3924fa9e4066Sahrens */ 3925ea8dc4b6Seschrock char buf[16384]; 3926ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 3927fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 3928fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 392991ebeef5Sahrens } else { 3930fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 3931fa9e4066Sahrens "command '%s'\n"), cmdname); 393299653d4eSeschrock usage(B_FALSE); 3933fa9e4066Sahrens } 3934fa9e4066Sahrens 393599653d4eSeschrock libzfs_fini(g_zfs); 393699653d4eSeschrock 3937fa9e4066Sahrens /* 3938fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3939fa9e4066Sahrens * for the purposes of running ::findleaks. 3940fa9e4066Sahrens */ 3941fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 3942fa9e4066Sahrens (void) printf("dumping core by request\n"); 3943fa9e4066Sahrens abort(); 3944fa9e4066Sahrens } 3945fa9e4066Sahrens 3946fa9e4066Sahrens return (ret); 3947fa9e4066Sahrens } 3948