1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 2199653d4eSeschrock 22fa9e4066Sahrens /* 23379c004dSEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #include <assert.h> 28fa9e4066Sahrens #include <ctype.h> 29fa9e4066Sahrens #include <dirent.h> 30fa9e4066Sahrens #include <errno.h> 31fa9e4066Sahrens #include <fcntl.h> 32fa9e4066Sahrens #include <libgen.h> 33fa9e4066Sahrens #include <libintl.h> 34fa9e4066Sahrens #include <libuutil.h> 35fa9e4066Sahrens #include <locale.h> 36fa9e4066Sahrens #include <stdio.h> 37fa9e4066Sahrens #include <stdlib.h> 38fa9e4066Sahrens #include <string.h> 39fa9e4066Sahrens #include <strings.h> 40fa9e4066Sahrens #include <unistd.h> 41fa9e4066Sahrens #include <priv.h> 42ecd6cf80Smarks #include <pwd.h> 43ecd6cf80Smarks #include <zone.h> 44b1b8ab34Slling #include <sys/fs/zfs.h> 45fa9e4066Sahrens 46fa9e4066Sahrens #include <sys/stat.h> 47fa9e4066Sahrens 48fa9e4066Sahrens #include <libzfs.h> 49fa9e4066Sahrens 50fa9e4066Sahrens #include "zpool_util.h" 51b7b97454Sperrin #include "zfs_comutil.h" 52fa9e4066Sahrens 53*26fd7700SKrishnendu Sadhukhan - Sun Microsystems #include "statcommon.h" 54*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 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 178*26fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE; 179*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 18065cd9f28Seschrock static const char * 18165cd9f28Seschrock get_usage(zpool_help_t idx) { 18265cd9f28Seschrock switch (idx) { 18365cd9f28Seschrock case HELP_ADD: 18465cd9f28Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 18565cd9f28Seschrock case HELP_ATTACH: 18665cd9f28Seschrock return (gettext("\tattach [-f] <pool> <device> " 187e45ce728Sahrens "<new-device>\n")); 188ea8dc4b6Seschrock case HELP_CLEAR: 189ea8dc4b6Seschrock return (gettext("\tclear <pool> [device]\n")); 19065cd9f28Seschrock case HELP_CREATE: 191990b4856Slling return (gettext("\tcreate [-fn] [-o property=value] ... \n" 1920a48a24eStimh "\t [-O file-system-property=value] ... \n" 193990b4856Slling "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 19465cd9f28Seschrock case HELP_DESTROY: 19565cd9f28Seschrock return (gettext("\tdestroy [-f] <pool>\n")); 19665cd9f28Seschrock case HELP_DETACH: 19765cd9f28Seschrock return (gettext("\tdetach <pool> <device>\n")); 19865cd9f28Seschrock case HELP_EXPORT: 19965cd9f28Seschrock return (gettext("\texport [-f] <pool> ...\n")); 20006eeb2adSek110237 case HELP_HISTORY: 201ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 20265cd9f28Seschrock case HELP_IMPORT: 2034c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 2042f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 2052f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n" 2062f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 2072f8aaab3Seschrock "\t [-d dir | -c cachefile] [-D] [-f] [-R root] " 2082f8aaab3Seschrock "<pool | id> [newpool]\n")); 20965cd9f28Seschrock case HELP_IOSTAT: 210*26fd7700SKrishnendu Sadhukhan - Sun Microsystems return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 21165cd9f28Seschrock "[count]]\n")); 21265cd9f28Seschrock case HELP_LIST: 213990b4856Slling return (gettext("\tlist [-H] [-o property[,...]] " 214990b4856Slling "[pool] ...\n")); 21565cd9f28Seschrock case HELP_OFFLINE: 216441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 21765cd9f28Seschrock case HELP_ONLINE: 218441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 21965cd9f28Seschrock case HELP_REPLACE: 22065cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 221e45ce728Sahrens "[new-device]\n")); 22299653d4eSeschrock case HELP_REMOVE: 223fa94a07fSbrendan return (gettext("\tremove <pool> <device> ...\n")); 22465cd9f28Seschrock case HELP_SCRUB: 22565cd9f28Seschrock return (gettext("\tscrub [-s] <pool> ...\n")); 22665cd9f28Seschrock case HELP_STATUS: 22765cd9f28Seschrock return (gettext("\tstatus [-vx] [pool] ...\n")); 228eaca9bbdSeschrock case HELP_UPGRADE: 229eaca9bbdSeschrock return (gettext("\tupgrade\n" 230eaca9bbdSeschrock "\tupgrade -v\n" 231990b4856Slling "\tupgrade [-V version] <-a | pool ...>\n")); 232b1b8ab34Slling case HELP_GET: 233e45ce728Sahrens return (gettext("\tget <\"all\" | property[,...]> " 234b1b8ab34Slling "<pool> ...\n")); 235b1b8ab34Slling case HELP_SET: 236b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 23765cd9f28Seschrock } 23865cd9f28Seschrock 23965cd9f28Seschrock abort(); 24065cd9f28Seschrock /* NOTREACHED */ 24165cd9f28Seschrock } 24265cd9f28Seschrock 243fa9e4066Sahrens 244fa9e4066Sahrens /* 245b1b8ab34Slling * Callback routine that will print out a pool property value. 246b1b8ab34Slling */ 247990b4856Slling static int 248990b4856Slling print_prop_cb(int prop, void *cb) 249b1b8ab34Slling { 250b1b8ab34Slling FILE *fp = cb; 251b1b8ab34Slling 252b1b8ab34Slling (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 253b1b8ab34Slling 254990b4856Slling if (zpool_prop_readonly(prop)) 255990b4856Slling (void) fprintf(fp, " NO "); 256990b4856Slling else 257990b4856Slling (void) fprintf(fp, " YES "); 258990b4856Slling 259b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 260b1b8ab34Slling (void) fprintf(fp, "-\n"); 261b1b8ab34Slling else 262b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 263b1b8ab34Slling 264990b4856Slling return (ZPROP_CONT); 265b1b8ab34Slling } 266b1b8ab34Slling 267b1b8ab34Slling /* 268fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 269fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 270fa9e4066Sahrens * a complete usage message. 271fa9e4066Sahrens */ 272fa9e4066Sahrens void 27399653d4eSeschrock usage(boolean_t requested) 274fa9e4066Sahrens { 275fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 276fa9e4066Sahrens 277fa9e4066Sahrens if (current_command == NULL) { 278fa9e4066Sahrens int i; 279fa9e4066Sahrens 280fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 281fa9e4066Sahrens (void) fprintf(fp, 282fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 283fa9e4066Sahrens 284fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 285fa9e4066Sahrens if (command_table[i].name == NULL) 286fa9e4066Sahrens (void) fprintf(fp, "\n"); 287fa9e4066Sahrens else 288fa9e4066Sahrens (void) fprintf(fp, "%s", 28965cd9f28Seschrock get_usage(command_table[i].usage)); 290fa9e4066Sahrens } 291fa9e4066Sahrens } else { 292fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 29365cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 294fa9e4066Sahrens } 295fa9e4066Sahrens 296b1b8ab34Slling if (current_command != NULL && 297b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 298990b4856Slling (strcmp(current_command->name, "get") == 0) || 299990b4856Slling (strcmp(current_command->name, "list") == 0))) { 300b1b8ab34Slling 301b1b8ab34Slling (void) fprintf(fp, 302b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 303b1b8ab34Slling 304990b4856Slling (void) fprintf(fp, "\n\t%-13s %s %s\n\n", 305990b4856Slling "PROPERTY", "EDIT", "VALUES"); 306b1b8ab34Slling 307b1b8ab34Slling /* Iterate over all properties */ 308990b4856Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 309990b4856Slling ZFS_TYPE_POOL); 310b1b8ab34Slling } 311b1b8ab34Slling 312e9dbad6fSeschrock /* 313e9dbad6fSeschrock * See comments at end of main(). 314e9dbad6fSeschrock */ 315e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 316e9dbad6fSeschrock (void) printf("dumping core by request\n"); 317e9dbad6fSeschrock abort(); 318e9dbad6fSeschrock } 319e9dbad6fSeschrock 320fa9e4066Sahrens exit(requested ? 0 : 2); 321fa9e4066Sahrens } 322fa9e4066Sahrens 323fa9e4066Sahrens void 3248654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 3258654d025Sperrin boolean_t print_logs) 326fa9e4066Sahrens { 327fa9e4066Sahrens nvlist_t **child; 328fa9e4066Sahrens uint_t c, children; 329afefbcddSeschrock char *vname; 330fa9e4066Sahrens 331fa9e4066Sahrens if (name != NULL) 332fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 333fa9e4066Sahrens 334fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 335fa9e4066Sahrens &child, &children) != 0) 336fa9e4066Sahrens return; 337fa9e4066Sahrens 338afefbcddSeschrock for (c = 0; c < children; c++) { 3398654d025Sperrin uint64_t is_log = B_FALSE; 3408654d025Sperrin 3418654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3428654d025Sperrin &is_log); 3438654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 3448654d025Sperrin continue; 3458654d025Sperrin 34699653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 3478654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 3488654d025Sperrin B_FALSE); 349afefbcddSeschrock free(vname); 350afefbcddSeschrock } 351fa9e4066Sahrens } 352fa9e4066Sahrens 353fa9e4066Sahrens /* 354990b4856Slling * Add a property pair (name, string-value) into a property nvlist. 355990b4856Slling */ 356990b4856Slling static int 3570a48a24eStimh add_prop_list(const char *propname, char *propval, nvlist_t **props, 3580a48a24eStimh boolean_t poolprop) 359990b4856Slling { 3600a48a24eStimh zpool_prop_t prop = ZPROP_INVAL; 3610a48a24eStimh zfs_prop_t fprop; 362990b4856Slling nvlist_t *proplist; 3630a48a24eStimh const char *normnm; 3640a48a24eStimh char *strval; 365990b4856Slling 366990b4856Slling if (*props == NULL && 367990b4856Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 368990b4856Slling (void) fprintf(stderr, 369990b4856Slling gettext("internal error: out of memory\n")); 370990b4856Slling return (1); 371990b4856Slling } 372990b4856Slling 373990b4856Slling proplist = *props; 374990b4856Slling 3750a48a24eStimh if (poolprop) { 376990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 377990b4856Slling (void) fprintf(stderr, gettext("property '%s' is " 378990b4856Slling "not a valid pool property\n"), propname); 379990b4856Slling return (2); 380990b4856Slling } 3810a48a24eStimh normnm = zpool_prop_to_name(prop); 3820a48a24eStimh } else { 38314843421SMatthew Ahrens if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 3840a48a24eStimh normnm = zfs_prop_to_name(fprop); 38514843421SMatthew Ahrens } else { 38614843421SMatthew Ahrens normnm = propname; 38714843421SMatthew Ahrens } 3880a48a24eStimh } 389990b4856Slling 3900a48a24eStimh if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 3910a48a24eStimh prop != ZPOOL_PROP_CACHEFILE) { 392990b4856Slling (void) fprintf(stderr, gettext("property '%s' " 393990b4856Slling "specified multiple times\n"), propname); 394990b4856Slling return (2); 395990b4856Slling } 396990b4856Slling 3970a48a24eStimh if (nvlist_add_string(proplist, normnm, propval) != 0) { 398990b4856Slling (void) fprintf(stderr, gettext("internal " 399990b4856Slling "error: out of memory\n")); 400990b4856Slling return (1); 401990b4856Slling } 402990b4856Slling 403990b4856Slling return (0); 404990b4856Slling } 405990b4856Slling 406990b4856Slling /* 407fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 408fa9e4066Sahrens * 409fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 410fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 411fa9e4066Sahrens * they were to be added. 412fa9e4066Sahrens * 413fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 414fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 415fa9e4066Sahrens * libzfs. 416fa9e4066Sahrens */ 417fa9e4066Sahrens int 418fa9e4066Sahrens zpool_do_add(int argc, char **argv) 419fa9e4066Sahrens { 42099653d4eSeschrock boolean_t force = B_FALSE; 42199653d4eSeschrock boolean_t dryrun = B_FALSE; 422fa9e4066Sahrens int c; 423fa9e4066Sahrens nvlist_t *nvroot; 424fa9e4066Sahrens char *poolname; 425fa9e4066Sahrens int ret; 426fa9e4066Sahrens zpool_handle_t *zhp; 427fa9e4066Sahrens nvlist_t *config; 428fa9e4066Sahrens 429fa9e4066Sahrens /* check options */ 430fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 431fa9e4066Sahrens switch (c) { 432fa9e4066Sahrens case 'f': 43399653d4eSeschrock force = B_TRUE; 434fa9e4066Sahrens break; 435fa9e4066Sahrens case 'n': 43699653d4eSeschrock dryrun = B_TRUE; 437fa9e4066Sahrens break; 438fa9e4066Sahrens case '?': 439fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 440fa9e4066Sahrens optopt); 44199653d4eSeschrock usage(B_FALSE); 442fa9e4066Sahrens } 443fa9e4066Sahrens } 444fa9e4066Sahrens 445fa9e4066Sahrens argc -= optind; 446fa9e4066Sahrens argv += optind; 447fa9e4066Sahrens 448fa9e4066Sahrens /* get pool name and check number of arguments */ 449fa9e4066Sahrens if (argc < 1) { 450fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 45199653d4eSeschrock usage(B_FALSE); 452fa9e4066Sahrens } 453fa9e4066Sahrens if (argc < 2) { 454fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 45599653d4eSeschrock usage(B_FALSE); 456fa9e4066Sahrens } 457fa9e4066Sahrens 458fa9e4066Sahrens poolname = argv[0]; 459fa9e4066Sahrens 460fa9e4066Sahrens argc--; 461fa9e4066Sahrens argv++; 462fa9e4066Sahrens 46399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 464fa9e4066Sahrens return (1); 465fa9e4066Sahrens 466088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 467fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 468fa9e4066Sahrens poolname); 469fa9e4066Sahrens zpool_close(zhp); 470fa9e4066Sahrens return (1); 471fa9e4066Sahrens } 472fa9e4066Sahrens 473fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 474705040edSEric Taylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 475705040edSEric Taylor argc, argv); 476fa9e4066Sahrens if (nvroot == NULL) { 477fa9e4066Sahrens zpool_close(zhp); 478fa9e4066Sahrens return (1); 479fa9e4066Sahrens } 480fa9e4066Sahrens 481fa9e4066Sahrens if (dryrun) { 482fa9e4066Sahrens nvlist_t *poolnvroot; 483fa9e4066Sahrens 484fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 485fa9e4066Sahrens &poolnvroot) == 0); 486fa9e4066Sahrens 487fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 488fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 489fa9e4066Sahrens 4908654d025Sperrin /* print original main pool and new tree */ 4918654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 4928654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 4938654d025Sperrin 4948654d025Sperrin /* Do the same for the logs */ 4958654d025Sperrin if (num_logs(poolnvroot) > 0) { 4968654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 4978654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 4988654d025Sperrin } else if (num_logs(nvroot) > 0) { 4998654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 5008654d025Sperrin } 501fa9e4066Sahrens 502fa9e4066Sahrens ret = 0; 503fa9e4066Sahrens } else { 504fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 505fa9e4066Sahrens } 506fa9e4066Sahrens 50799653d4eSeschrock nvlist_free(nvroot); 50899653d4eSeschrock zpool_close(zhp); 50999653d4eSeschrock 51099653d4eSeschrock return (ret); 51199653d4eSeschrock } 51299653d4eSeschrock 51399653d4eSeschrock /* 514fa94a07fSbrendan * zpool remove <pool> <vdev> ... 51599653d4eSeschrock * 51699653d4eSeschrock * Removes the given vdev from the pool. Currently, this only supports removing 517fa94a07fSbrendan * spares and cache devices from the pool. Eventually, we'll want to support 518fa94a07fSbrendan * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs. 51999653d4eSeschrock */ 52099653d4eSeschrock int 52199653d4eSeschrock zpool_do_remove(int argc, char **argv) 52299653d4eSeschrock { 52399653d4eSeschrock char *poolname; 524fa94a07fSbrendan int i, ret = 0; 52599653d4eSeschrock zpool_handle_t *zhp; 52699653d4eSeschrock 52799653d4eSeschrock argc--; 52899653d4eSeschrock argv++; 52999653d4eSeschrock 53099653d4eSeschrock /* get pool name and check number of arguments */ 53199653d4eSeschrock if (argc < 1) { 53299653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 53399653d4eSeschrock usage(B_FALSE); 53499653d4eSeschrock } 53599653d4eSeschrock if (argc < 2) { 53699653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 53799653d4eSeschrock usage(B_FALSE); 53899653d4eSeschrock } 53999653d4eSeschrock 54099653d4eSeschrock poolname = argv[0]; 54199653d4eSeschrock 54299653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 54399653d4eSeschrock return (1); 54499653d4eSeschrock 545fa94a07fSbrendan for (i = 1; i < argc; i++) { 546fa94a07fSbrendan if (zpool_vdev_remove(zhp, argv[i]) != 0) 547fa94a07fSbrendan ret = 1; 548fa94a07fSbrendan } 54999653d4eSeschrock 550fa9e4066Sahrens return (ret); 551fa9e4066Sahrens } 552fa9e4066Sahrens 553fa9e4066Sahrens /* 5540a48a24eStimh * zpool create [-fn] [-o property=value] ... 5550a48a24eStimh * [-O file-system-property=value] ... 5560a48a24eStimh * [-R root] [-m mountpoint] <pool> <dev> ... 557fa9e4066Sahrens * 558fa9e4066Sahrens * -f Force creation, even if devices appear in use 559fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 560fa9e4066Sahrens * were to be created. 561fa9e4066Sahrens * -R Create a pool under an alternate root 562fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 563fa9e4066Sahrens * '/<pool>' 564990b4856Slling * -o Set property=value. 5650a48a24eStimh * -O Set fsproperty=value in the pool's root file system 566fa9e4066Sahrens * 567b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 568fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 569fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 570fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 571fa9e4066Sahrens */ 572fa9e4066Sahrens int 573fa9e4066Sahrens zpool_do_create(int argc, char **argv) 574fa9e4066Sahrens { 57599653d4eSeschrock boolean_t force = B_FALSE; 57699653d4eSeschrock boolean_t dryrun = B_FALSE; 577fa9e4066Sahrens int c; 578990b4856Slling nvlist_t *nvroot = NULL; 579fa9e4066Sahrens char *poolname; 580990b4856Slling int ret = 1; 581fa9e4066Sahrens char *altroot = NULL; 582fa9e4066Sahrens char *mountpoint = NULL; 5830a48a24eStimh nvlist_t *fsprops = NULL; 584990b4856Slling nvlist_t *props = NULL; 5852f8aaab3Seschrock char *propval; 586fa9e4066Sahrens 587fa9e4066Sahrens /* check options */ 5880a48a24eStimh while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) { 589fa9e4066Sahrens switch (c) { 590fa9e4066Sahrens case 'f': 59199653d4eSeschrock force = B_TRUE; 592fa9e4066Sahrens break; 593fa9e4066Sahrens case 'n': 59499653d4eSeschrock dryrun = B_TRUE; 595fa9e4066Sahrens break; 596fa9e4066Sahrens case 'R': 597fa9e4066Sahrens altroot = optarg; 598990b4856Slling if (add_prop_list(zpool_prop_to_name( 5990a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 600990b4856Slling goto errout; 6012f8aaab3Seschrock if (nvlist_lookup_string(props, 6022f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 6032f8aaab3Seschrock &propval) == 0) 6042f8aaab3Seschrock break; 605990b4856Slling if (add_prop_list(zpool_prop_to_name( 6060a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 607990b4856Slling goto errout; 608fa9e4066Sahrens break; 609fa9e4066Sahrens case 'm': 610fa9e4066Sahrens mountpoint = optarg; 611fa9e4066Sahrens break; 612990b4856Slling case 'o': 613990b4856Slling if ((propval = strchr(optarg, '=')) == NULL) { 614990b4856Slling (void) fprintf(stderr, gettext("missing " 615990b4856Slling "'=' for -o option\n")); 616990b4856Slling goto errout; 617990b4856Slling } 618990b4856Slling *propval = '\0'; 619990b4856Slling propval++; 620990b4856Slling 6210a48a24eStimh if (add_prop_list(optarg, propval, &props, B_TRUE)) 6220a48a24eStimh goto errout; 6230a48a24eStimh break; 6240a48a24eStimh case 'O': 6250a48a24eStimh if ((propval = strchr(optarg, '=')) == NULL) { 6260a48a24eStimh (void) fprintf(stderr, gettext("missing " 6270a48a24eStimh "'=' for -O option\n")); 6280a48a24eStimh goto errout; 6290a48a24eStimh } 6300a48a24eStimh *propval = '\0'; 6310a48a24eStimh propval++; 6320a48a24eStimh 6330a48a24eStimh if (add_prop_list(optarg, propval, &fsprops, B_FALSE)) 634990b4856Slling goto errout; 635990b4856Slling break; 636fa9e4066Sahrens case ':': 637fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 638fa9e4066Sahrens "'%c' option\n"), optopt); 639990b4856Slling goto badusage; 640fa9e4066Sahrens case '?': 641fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 642fa9e4066Sahrens optopt); 643990b4856Slling goto badusage; 644fa9e4066Sahrens } 645fa9e4066Sahrens } 646fa9e4066Sahrens 647fa9e4066Sahrens argc -= optind; 648fa9e4066Sahrens argv += optind; 649fa9e4066Sahrens 650fa9e4066Sahrens /* get pool name and check number of arguments */ 651fa9e4066Sahrens if (argc < 1) { 652fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 653990b4856Slling goto badusage; 654fa9e4066Sahrens } 655fa9e4066Sahrens if (argc < 2) { 656fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 657990b4856Slling goto badusage; 658fa9e4066Sahrens } 659fa9e4066Sahrens 660fa9e4066Sahrens poolname = argv[0]; 661fa9e4066Sahrens 662fa9e4066Sahrens /* 663fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 664fa9e4066Sahrens * user to use 'zfs create' instead. 665fa9e4066Sahrens */ 666fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 667fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 668fa9e4066Sahrens "character '/' in pool name\n"), poolname); 669fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 670fa9e4066Sahrens "create a dataset\n")); 671990b4856Slling goto errout; 672fa9e4066Sahrens } 673fa9e4066Sahrens 674fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 675705040edSEric Taylor nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 676705040edSEric Taylor argc - 1, argv + 1); 677fa9e4066Sahrens if (nvroot == NULL) 6780a48a24eStimh goto errout; 679fa9e4066Sahrens 68099653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 681b7b97454Sperrin if (!zfs_allocatable_devs(nvroot)) { 68299653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 68399653d4eSeschrock "specification: at least one toplevel vdev must be " 68499653d4eSeschrock "specified\n")); 685990b4856Slling goto errout; 68699653d4eSeschrock } 68799653d4eSeschrock 68899653d4eSeschrock 689fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 690fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 691e9dbad6fSeschrock "must be an absolute path\n"), altroot); 692990b4856Slling goto errout; 693fa9e4066Sahrens } 694fa9e4066Sahrens 695fa9e4066Sahrens /* 696fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 697fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 698fa9e4066Sahrens */ 699fa9e4066Sahrens if (mountpoint == NULL || 700fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 701fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 702fa9e4066Sahrens char buf[MAXPATHLEN]; 70311022c7cStimh DIR *dirp; 704fa9e4066Sahrens 705fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 706fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 707fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 708fa9e4066Sahrens "'none'\n"), mountpoint); 709990b4856Slling goto errout; 710fa9e4066Sahrens } 711fa9e4066Sahrens 712fa9e4066Sahrens if (mountpoint == NULL) { 713fa9e4066Sahrens if (altroot != NULL) 714fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 715fa9e4066Sahrens altroot, poolname); 716fa9e4066Sahrens else 717fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 718fa9e4066Sahrens poolname); 719fa9e4066Sahrens } else { 720fa9e4066Sahrens if (altroot != NULL) 721fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 722fa9e4066Sahrens altroot, mountpoint); 723fa9e4066Sahrens else 724fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 725fa9e4066Sahrens mountpoint); 726fa9e4066Sahrens } 727fa9e4066Sahrens 72811022c7cStimh if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 72911022c7cStimh (void) fprintf(stderr, gettext("mountpoint '%s' : " 73011022c7cStimh "%s\n"), buf, strerror(errno)); 731fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 732fa9e4066Sahrens "option to provide a different default\n")); 733990b4856Slling goto errout; 73411022c7cStimh } else if (dirp) { 73511022c7cStimh int count = 0; 73611022c7cStimh 73711022c7cStimh while (count < 3 && readdir(dirp) != NULL) 73811022c7cStimh count++; 73911022c7cStimh (void) closedir(dirp); 74011022c7cStimh 74111022c7cStimh if (count > 2) { 74211022c7cStimh (void) fprintf(stderr, gettext("mountpoint " 74311022c7cStimh "'%s' exists and is not empty\n"), buf); 74411022c7cStimh (void) fprintf(stderr, gettext("use '-m' " 74511022c7cStimh "option to provide a " 74611022c7cStimh "different default\n")); 74711022c7cStimh goto errout; 74811022c7cStimh } 749fa9e4066Sahrens } 750fa9e4066Sahrens } 751fa9e4066Sahrens 752fa9e4066Sahrens if (dryrun) { 753fa9e4066Sahrens /* 754fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 755fa9e4066Sahrens * through all the vdevs in the list and print out in an 756fa9e4066Sahrens * appropriate hierarchy. 757fa9e4066Sahrens */ 758fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 759fa9e4066Sahrens "following layout:\n\n"), poolname); 760fa9e4066Sahrens 7618654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 7628654d025Sperrin if (num_logs(nvroot) > 0) 7638654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 764fa9e4066Sahrens 765fa9e4066Sahrens ret = 0; 766fa9e4066Sahrens } else { 767fa9e4066Sahrens /* 768fa9e4066Sahrens * Hand off to libzfs. 769fa9e4066Sahrens */ 7700a48a24eStimh if (zpool_create(g_zfs, poolname, 7710a48a24eStimh nvroot, props, fsprops) == 0) { 77299653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 773fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 774fa9e4066Sahrens if (pool != NULL) { 775fa9e4066Sahrens if (mountpoint != NULL) 776fa9e4066Sahrens verify(zfs_prop_set(pool, 777e9dbad6fSeschrock zfs_prop_to_name( 778e9dbad6fSeschrock ZFS_PROP_MOUNTPOINT), 779fa9e4066Sahrens mountpoint) == 0); 780fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 781da6c28aaSamw ret = zfs_shareall(pool); 782fa9e4066Sahrens zfs_close(pool); 783fa9e4066Sahrens } 78499653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 78599653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 78699653d4eSeschrock "been omitted\n")); 787fa9e4066Sahrens } 788fa9e4066Sahrens } 789fa9e4066Sahrens 790990b4856Slling errout: 791fa9e4066Sahrens nvlist_free(nvroot); 7920a48a24eStimh nvlist_free(fsprops); 793990b4856Slling nvlist_free(props); 794fa9e4066Sahrens return (ret); 795990b4856Slling badusage: 7960a48a24eStimh nvlist_free(fsprops); 797990b4856Slling nvlist_free(props); 798990b4856Slling usage(B_FALSE); 799990b4856Slling return (2); 800fa9e4066Sahrens } 801fa9e4066Sahrens 802fa9e4066Sahrens /* 803fa9e4066Sahrens * zpool destroy <pool> 804fa9e4066Sahrens * 805fa9e4066Sahrens * -f Forcefully unmount any datasets 806fa9e4066Sahrens * 807fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 808fa9e4066Sahrens */ 809fa9e4066Sahrens int 810fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 811fa9e4066Sahrens { 81299653d4eSeschrock boolean_t force = B_FALSE; 813fa9e4066Sahrens int c; 814fa9e4066Sahrens char *pool; 815fa9e4066Sahrens zpool_handle_t *zhp; 816fa9e4066Sahrens int ret; 817fa9e4066Sahrens 818fa9e4066Sahrens /* check options */ 819fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 820fa9e4066Sahrens switch (c) { 821fa9e4066Sahrens case 'f': 82299653d4eSeschrock force = B_TRUE; 823fa9e4066Sahrens break; 824fa9e4066Sahrens case '?': 825fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 826fa9e4066Sahrens optopt); 82799653d4eSeschrock usage(B_FALSE); 828fa9e4066Sahrens } 829fa9e4066Sahrens } 830fa9e4066Sahrens 831fa9e4066Sahrens argc -= optind; 832fa9e4066Sahrens argv += optind; 833fa9e4066Sahrens 834fa9e4066Sahrens /* check arguments */ 835fa9e4066Sahrens if (argc < 1) { 836fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 83799653d4eSeschrock usage(B_FALSE); 838fa9e4066Sahrens } 839fa9e4066Sahrens if (argc > 1) { 840fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 84199653d4eSeschrock usage(B_FALSE); 842fa9e4066Sahrens } 843fa9e4066Sahrens 844fa9e4066Sahrens pool = argv[0]; 845fa9e4066Sahrens 84699653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 847fa9e4066Sahrens /* 848fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 849fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 850fa9e4066Sahrens */ 851fa9e4066Sahrens if (strchr(pool, '/') != NULL) 852fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 853fa9e4066Sahrens "destroy a dataset\n")); 854fa9e4066Sahrens return (1); 855fa9e4066Sahrens } 856fa9e4066Sahrens 857f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 858fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 859fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 860fa9e4066Sahrens return (1); 861fa9e4066Sahrens } 862fa9e4066Sahrens 863fa9e4066Sahrens ret = (zpool_destroy(zhp) != 0); 864fa9e4066Sahrens 865fa9e4066Sahrens zpool_close(zhp); 866fa9e4066Sahrens 867fa9e4066Sahrens return (ret); 868fa9e4066Sahrens } 869fa9e4066Sahrens 870fa9e4066Sahrens /* 871fa9e4066Sahrens * zpool export [-f] <pool> ... 872fa9e4066Sahrens * 873fa9e4066Sahrens * -f Forcefully unmount datasets 874fa9e4066Sahrens * 875b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 876fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 877fa9e4066Sahrens * then the datasets will be forcefully unmounted. 878fa9e4066Sahrens */ 879fa9e4066Sahrens int 880fa9e4066Sahrens zpool_do_export(int argc, char **argv) 881fa9e4066Sahrens { 88299653d4eSeschrock boolean_t force = B_FALSE; 883394ab0cbSGeorge Wilson boolean_t hardforce = B_FALSE; 884fa9e4066Sahrens int c; 885fa9e4066Sahrens zpool_handle_t *zhp; 886fa9e4066Sahrens int ret; 887fa9e4066Sahrens int i; 888fa9e4066Sahrens 889fa9e4066Sahrens /* check options */ 890394ab0cbSGeorge Wilson while ((c = getopt(argc, argv, "fF")) != -1) { 891fa9e4066Sahrens switch (c) { 892fa9e4066Sahrens case 'f': 89399653d4eSeschrock force = B_TRUE; 894fa9e4066Sahrens break; 895394ab0cbSGeorge Wilson case 'F': 896394ab0cbSGeorge Wilson hardforce = B_TRUE; 897394ab0cbSGeorge Wilson break; 898fa9e4066Sahrens case '?': 899fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 900fa9e4066Sahrens optopt); 90199653d4eSeschrock usage(B_FALSE); 902fa9e4066Sahrens } 903fa9e4066Sahrens } 904fa9e4066Sahrens 905fa9e4066Sahrens argc -= optind; 906fa9e4066Sahrens argv += optind; 907fa9e4066Sahrens 908fa9e4066Sahrens /* check arguments */ 909fa9e4066Sahrens if (argc < 1) { 910fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 91199653d4eSeschrock usage(B_FALSE); 912fa9e4066Sahrens } 913fa9e4066Sahrens 914fa9e4066Sahrens ret = 0; 915fa9e4066Sahrens for (i = 0; i < argc; i++) { 91699653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 917fa9e4066Sahrens ret = 1; 918fa9e4066Sahrens continue; 919fa9e4066Sahrens } 920fa9e4066Sahrens 921f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 922fa9e4066Sahrens ret = 1; 923fa9e4066Sahrens zpool_close(zhp); 924fa9e4066Sahrens continue; 925fa9e4066Sahrens } 926fa9e4066Sahrens 927394ab0cbSGeorge Wilson if (hardforce) { 928394ab0cbSGeorge Wilson if (zpool_export_force(zhp) != 0) 929fa9e4066Sahrens ret = 1; 930394ab0cbSGeorge Wilson } else if (zpool_export(zhp, force) != 0) { 931394ab0cbSGeorge Wilson ret = 1; 932394ab0cbSGeorge Wilson } 933fa9e4066Sahrens 934fa9e4066Sahrens zpool_close(zhp); 935fa9e4066Sahrens } 936fa9e4066Sahrens 937fa9e4066Sahrens return (ret); 938fa9e4066Sahrens } 939fa9e4066Sahrens 940fa9e4066Sahrens /* 941fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 942fa9e4066Sahrens * name column. 943fa9e4066Sahrens */ 944fa9e4066Sahrens static int 945c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 946fa9e4066Sahrens { 94799653d4eSeschrock char *name = zpool_vdev_name(g_zfs, zhp, nv); 948fa9e4066Sahrens nvlist_t **child; 949fa9e4066Sahrens uint_t c, children; 950fa9e4066Sahrens int ret; 951fa9e4066Sahrens 952fa9e4066Sahrens if (strlen(name) + depth > max) 953fa9e4066Sahrens max = strlen(name) + depth; 954fa9e4066Sahrens 955afefbcddSeschrock free(name); 956afefbcddSeschrock 95799653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 95899653d4eSeschrock &child, &children) == 0) { 959fa9e4066Sahrens for (c = 0; c < children; c++) 96099653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 96199653d4eSeschrock max)) > max) 962fa9e4066Sahrens max = ret; 96399653d4eSeschrock } 96499653d4eSeschrock 965fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 966fa94a07fSbrendan &child, &children) == 0) { 967fa94a07fSbrendan for (c = 0; c < children; c++) 968fa94a07fSbrendan if ((ret = max_width(zhp, child[c], depth + 2, 969fa94a07fSbrendan max)) > max) 970fa94a07fSbrendan max = ret; 971fa94a07fSbrendan } 972fa94a07fSbrendan 97399653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 97499653d4eSeschrock &child, &children) == 0) { 97599653d4eSeschrock for (c = 0; c < children; c++) 97699653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 97799653d4eSeschrock max)) > max) 97899653d4eSeschrock max = ret; 97999653d4eSeschrock } 98099653d4eSeschrock 981fa9e4066Sahrens 982fa9e4066Sahrens return (max); 983fa9e4066Sahrens } 984fa9e4066Sahrens 985e6ca193dSGeorge Wilson typedef struct spare_cbdata { 986e6ca193dSGeorge Wilson uint64_t cb_guid; 987e6ca193dSGeorge Wilson zpool_handle_t *cb_zhp; 988e6ca193dSGeorge Wilson } spare_cbdata_t; 989e6ca193dSGeorge Wilson 990e6ca193dSGeorge Wilson static boolean_t 991e6ca193dSGeorge Wilson find_vdev(nvlist_t *nv, uint64_t search) 992e6ca193dSGeorge Wilson { 993e6ca193dSGeorge Wilson uint64_t guid; 994e6ca193dSGeorge Wilson nvlist_t **child; 995e6ca193dSGeorge Wilson uint_t c, children; 996e6ca193dSGeorge Wilson 997e6ca193dSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 998e6ca193dSGeorge Wilson search == guid) 999e6ca193dSGeorge Wilson return (B_TRUE); 1000e6ca193dSGeorge Wilson 1001e6ca193dSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1002e6ca193dSGeorge Wilson &child, &children) == 0) { 1003e6ca193dSGeorge Wilson for (c = 0; c < children; c++) 1004e6ca193dSGeorge Wilson if (find_vdev(child[c], search)) 1005e6ca193dSGeorge Wilson return (B_TRUE); 1006e6ca193dSGeorge Wilson } 1007e6ca193dSGeorge Wilson 1008e6ca193dSGeorge Wilson return (B_FALSE); 1009e6ca193dSGeorge Wilson } 1010e6ca193dSGeorge Wilson 1011e6ca193dSGeorge Wilson static int 1012e6ca193dSGeorge Wilson find_spare(zpool_handle_t *zhp, void *data) 1013e6ca193dSGeorge Wilson { 1014e6ca193dSGeorge Wilson spare_cbdata_t *cbp = data; 1015e6ca193dSGeorge Wilson nvlist_t *config, *nvroot; 1016e6ca193dSGeorge Wilson 1017e6ca193dSGeorge Wilson config = zpool_get_config(zhp, NULL); 1018e6ca193dSGeorge Wilson verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1019e6ca193dSGeorge Wilson &nvroot) == 0); 1020e6ca193dSGeorge Wilson 1021e6ca193dSGeorge Wilson if (find_vdev(nvroot, cbp->cb_guid)) { 1022e6ca193dSGeorge Wilson cbp->cb_zhp = zhp; 1023e6ca193dSGeorge Wilson return (1); 1024e6ca193dSGeorge Wilson } 1025e6ca193dSGeorge Wilson 1026e6ca193dSGeorge Wilson zpool_close(zhp); 1027e6ca193dSGeorge Wilson return (0); 1028e6ca193dSGeorge Wilson } 1029e6ca193dSGeorge Wilson 1030e6ca193dSGeorge Wilson /* 1031e6ca193dSGeorge Wilson * Print out configuration state as requested by status_callback. 1032e6ca193dSGeorge Wilson */ 1033e6ca193dSGeorge Wilson void 1034e6ca193dSGeorge Wilson print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1035e6ca193dSGeorge Wilson int namewidth, int depth, boolean_t isspare) 1036e6ca193dSGeorge Wilson { 1037e6ca193dSGeorge Wilson nvlist_t **child; 1038e6ca193dSGeorge Wilson uint_t c, children; 1039e6ca193dSGeorge Wilson vdev_stat_t *vs; 1040e6ca193dSGeorge Wilson char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 1041e6ca193dSGeorge Wilson char *vname; 1042e6ca193dSGeorge Wilson uint64_t notpresent; 1043e6ca193dSGeorge Wilson spare_cbdata_t cb; 1044e6ca193dSGeorge Wilson char *state; 1045e6ca193dSGeorge Wilson 1046e6ca193dSGeorge Wilson verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 1047e6ca193dSGeorge Wilson (uint64_t **)&vs, &c) == 0); 1048e6ca193dSGeorge Wilson 1049e6ca193dSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1050e6ca193dSGeorge Wilson &child, &children) != 0) 1051e6ca193dSGeorge Wilson children = 0; 1052e6ca193dSGeorge Wilson 1053e6ca193dSGeorge Wilson state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1054e6ca193dSGeorge Wilson if (isspare) { 1055e6ca193dSGeorge Wilson /* 1056e6ca193dSGeorge Wilson * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1057e6ca193dSGeorge Wilson * online drives. 1058e6ca193dSGeorge Wilson */ 1059e6ca193dSGeorge Wilson if (vs->vs_aux == VDEV_AUX_SPARED) 1060e6ca193dSGeorge Wilson state = "INUSE"; 1061e6ca193dSGeorge Wilson else if (vs->vs_state == VDEV_STATE_HEALTHY) 1062e6ca193dSGeorge Wilson state = "AVAIL"; 1063e6ca193dSGeorge Wilson } 1064e6ca193dSGeorge Wilson 1065e6ca193dSGeorge Wilson (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1066e6ca193dSGeorge Wilson name, state); 1067e6ca193dSGeorge Wilson 1068e6ca193dSGeorge Wilson if (!isspare) { 1069e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1070e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1071e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1072e6ca193dSGeorge Wilson (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1073e6ca193dSGeorge Wilson } 1074e6ca193dSGeorge Wilson 1075e6ca193dSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1076e6ca193dSGeorge Wilson ¬present) == 0) { 1077e6ca193dSGeorge Wilson char *path; 1078e6ca193dSGeorge Wilson verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 1079e6ca193dSGeorge Wilson (void) printf(" was %s", path); 1080e6ca193dSGeorge Wilson } else if (vs->vs_aux != 0) { 1081e6ca193dSGeorge Wilson (void) printf(" "); 1082e6ca193dSGeorge Wilson 1083e6ca193dSGeorge Wilson switch (vs->vs_aux) { 1084e6ca193dSGeorge Wilson case VDEV_AUX_OPEN_FAILED: 1085e6ca193dSGeorge Wilson (void) printf(gettext("cannot open")); 1086e6ca193dSGeorge Wilson break; 1087e6ca193dSGeorge Wilson 1088e6ca193dSGeorge Wilson case VDEV_AUX_BAD_GUID_SUM: 1089e6ca193dSGeorge Wilson (void) printf(gettext("missing device")); 1090e6ca193dSGeorge Wilson break; 1091e6ca193dSGeorge Wilson 1092e6ca193dSGeorge Wilson case VDEV_AUX_NO_REPLICAS: 1093e6ca193dSGeorge Wilson (void) printf(gettext("insufficient replicas")); 1094e6ca193dSGeorge Wilson break; 1095e6ca193dSGeorge Wilson 1096e6ca193dSGeorge Wilson case VDEV_AUX_VERSION_NEWER: 1097e6ca193dSGeorge Wilson (void) printf(gettext("newer version")); 1098e6ca193dSGeorge Wilson break; 1099e6ca193dSGeorge Wilson 1100e6ca193dSGeorge Wilson case VDEV_AUX_SPARED: 1101e6ca193dSGeorge Wilson verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1102e6ca193dSGeorge Wilson &cb.cb_guid) == 0); 1103e6ca193dSGeorge Wilson if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1104e6ca193dSGeorge Wilson if (strcmp(zpool_get_name(cb.cb_zhp), 1105e6ca193dSGeorge Wilson zpool_get_name(zhp)) == 0) 1106e6ca193dSGeorge Wilson (void) printf(gettext("currently in " 1107e6ca193dSGeorge Wilson "use")); 1108e6ca193dSGeorge Wilson else 1109e6ca193dSGeorge Wilson (void) printf(gettext("in use by " 1110e6ca193dSGeorge Wilson "pool '%s'"), 1111e6ca193dSGeorge Wilson zpool_get_name(cb.cb_zhp)); 1112e6ca193dSGeorge Wilson zpool_close(cb.cb_zhp); 1113e6ca193dSGeorge Wilson } else { 1114e6ca193dSGeorge Wilson (void) printf(gettext("currently in use")); 1115e6ca193dSGeorge Wilson } 1116e6ca193dSGeorge Wilson break; 1117e6ca193dSGeorge Wilson 1118e6ca193dSGeorge Wilson case VDEV_AUX_ERR_EXCEEDED: 1119e6ca193dSGeorge Wilson (void) printf(gettext("too many errors")); 1120e6ca193dSGeorge Wilson break; 1121e6ca193dSGeorge Wilson 1122e6ca193dSGeorge Wilson case VDEV_AUX_IO_FAILURE: 1123e6ca193dSGeorge Wilson (void) printf(gettext("experienced I/O failures")); 1124e6ca193dSGeorge Wilson break; 1125e6ca193dSGeorge Wilson 1126e6ca193dSGeorge Wilson case VDEV_AUX_BAD_LOG: 1127e6ca193dSGeorge Wilson (void) printf(gettext("bad intent log")); 1128e6ca193dSGeorge Wilson break; 1129e6ca193dSGeorge Wilson 1130e6ca193dSGeorge Wilson default: 1131e6ca193dSGeorge Wilson (void) printf(gettext("corrupted data")); 1132e6ca193dSGeorge Wilson break; 1133e6ca193dSGeorge Wilson } 1134e6ca193dSGeorge Wilson } else if (vs->vs_scrub_repaired != 0 && children == 0) { 1135e6ca193dSGeorge Wilson /* 1136e6ca193dSGeorge Wilson * Report bytes resilvered/repaired on leaf devices. 1137e6ca193dSGeorge Wilson */ 1138e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 1139e6ca193dSGeorge Wilson (void) printf(gettext(" %s %s"), repaired, 1140e6ca193dSGeorge Wilson (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 1141e6ca193dSGeorge Wilson "resilvered" : "repaired"); 1142e6ca193dSGeorge Wilson } 1143e6ca193dSGeorge Wilson 1144e6ca193dSGeorge Wilson (void) printf("\n"); 1145e6ca193dSGeorge Wilson 1146e6ca193dSGeorge Wilson for (c = 0; c < children; c++) { 1147e6ca193dSGeorge Wilson uint64_t is_log = B_FALSE; 1148e6ca193dSGeorge Wilson 1149e6ca193dSGeorge Wilson /* Don't print logs here */ 1150e6ca193dSGeorge Wilson (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1151e6ca193dSGeorge Wilson &is_log); 1152e6ca193dSGeorge Wilson if (is_log) 1153e6ca193dSGeorge Wilson continue; 1154e6ca193dSGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, child[c]); 1155e6ca193dSGeorge Wilson print_status_config(zhp, vname, child[c], 1156e6ca193dSGeorge Wilson namewidth, depth + 2, isspare); 1157e6ca193dSGeorge Wilson free(vname); 1158e6ca193dSGeorge Wilson } 1159e6ca193dSGeorge Wilson } 1160e6ca193dSGeorge Wilson 1161fa9e4066Sahrens 1162fa9e4066Sahrens /* 1163fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 1164fa9e4066Sahrens * pool, printing out the name and status for each one. 1165fa9e4066Sahrens */ 1166fa9e4066Sahrens void 1167e6ca193dSGeorge Wilson print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1168fa9e4066Sahrens { 1169fa9e4066Sahrens nvlist_t **child; 1170fa9e4066Sahrens uint_t c, children; 1171fa9e4066Sahrens vdev_stat_t *vs; 1172afefbcddSeschrock char *type, *vname; 1173fa9e4066Sahrens 1174fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1175fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_MISSING) == 0) 1176fa9e4066Sahrens return; 1177fa9e4066Sahrens 1178fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 1179fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 1180fa9e4066Sahrens 1181fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1182990b4856Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1183fa9e4066Sahrens 1184fa9e4066Sahrens if (vs->vs_aux != 0) { 11853d7072f8Seschrock (void) printf(" "); 1186fa9e4066Sahrens 1187fa9e4066Sahrens switch (vs->vs_aux) { 1188fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 1189fa9e4066Sahrens (void) printf(gettext("cannot open")); 1190fa9e4066Sahrens break; 1191fa9e4066Sahrens 1192fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 1193fa9e4066Sahrens (void) printf(gettext("missing device")); 1194fa9e4066Sahrens break; 1195fa9e4066Sahrens 1196fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 1197fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 1198fa9e4066Sahrens break; 1199fa9e4066Sahrens 1200eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 1201eaca9bbdSeschrock (void) printf(gettext("newer version")); 1202eaca9bbdSeschrock break; 1203eaca9bbdSeschrock 12043d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 12053d7072f8Seschrock (void) printf(gettext("too many errors")); 12063d7072f8Seschrock break; 12073d7072f8Seschrock 1208fa9e4066Sahrens default: 1209fa9e4066Sahrens (void) printf(gettext("corrupted data")); 1210fa9e4066Sahrens break; 1211fa9e4066Sahrens } 1212fa9e4066Sahrens } 1213fa9e4066Sahrens (void) printf("\n"); 1214fa9e4066Sahrens 1215fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1216fa9e4066Sahrens &child, &children) != 0) 1217fa9e4066Sahrens return; 1218fa9e4066Sahrens 1219afefbcddSeschrock for (c = 0; c < children; c++) { 12208654d025Sperrin uint64_t is_log = B_FALSE; 12218654d025Sperrin 12228654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 12238654d025Sperrin &is_log); 1224e6ca193dSGeorge Wilson if (is_log) 12258654d025Sperrin continue; 12268654d025Sperrin 122799653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1228e6ca193dSGeorge Wilson print_import_config(vname, child[c], namewidth, depth + 2); 1229afefbcddSeschrock free(vname); 1230afefbcddSeschrock } 123199653d4eSeschrock 1232fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1233fa94a07fSbrendan &child, &children) == 0) { 1234fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 1235fa94a07fSbrendan for (c = 0; c < children; c++) { 1236fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1237fa94a07fSbrendan (void) printf("\t %s\n", vname); 1238fa94a07fSbrendan free(vname); 1239fa94a07fSbrendan } 1240fa94a07fSbrendan } 124199653d4eSeschrock 1242fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1243fa94a07fSbrendan &child, &children) == 0) { 124499653d4eSeschrock (void) printf(gettext("\tspares\n")); 124599653d4eSeschrock for (c = 0; c < children; c++) { 124699653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 124799653d4eSeschrock (void) printf("\t %s\n", vname); 124899653d4eSeschrock free(vname); 124999653d4eSeschrock } 1250fa9e4066Sahrens } 1251fa94a07fSbrendan } 1252fa9e4066Sahrens 1253fa9e4066Sahrens /* 1254e6ca193dSGeorge Wilson * Print log vdevs. 1255e6ca193dSGeorge Wilson * Logs are recorded as top level vdevs in the main pool child array 1256e6ca193dSGeorge Wilson * but with "is_log" set to 1. We use either print_status_config() or 1257e6ca193dSGeorge Wilson * print_import_config() to print the top level logs then any log 1258e6ca193dSGeorge Wilson * children (eg mirrored slogs) are printed recursively - which 1259e6ca193dSGeorge Wilson * works because only the top level vdev is marked "is_log" 1260e6ca193dSGeorge Wilson */ 1261e6ca193dSGeorge Wilson static void 1262e6ca193dSGeorge Wilson print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1263e6ca193dSGeorge Wilson { 1264e6ca193dSGeorge Wilson uint_t c, children; 1265e6ca193dSGeorge Wilson nvlist_t **child; 1266e6ca193dSGeorge Wilson 1267e6ca193dSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1268e6ca193dSGeorge Wilson &children) != 0) 1269e6ca193dSGeorge Wilson return; 1270e6ca193dSGeorge Wilson 1271e6ca193dSGeorge Wilson (void) printf(gettext("\tlogs\n")); 1272e6ca193dSGeorge Wilson 1273e6ca193dSGeorge Wilson for (c = 0; c < children; c++) { 1274e6ca193dSGeorge Wilson uint64_t is_log = B_FALSE; 1275e6ca193dSGeorge Wilson char *name; 1276e6ca193dSGeorge Wilson 1277e6ca193dSGeorge Wilson (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1278e6ca193dSGeorge Wilson &is_log); 1279e6ca193dSGeorge Wilson if (!is_log) 1280e6ca193dSGeorge Wilson continue; 1281e6ca193dSGeorge Wilson name = zpool_vdev_name(g_zfs, zhp, child[c]); 1282e6ca193dSGeorge Wilson if (verbose) 1283e6ca193dSGeorge Wilson print_status_config(zhp, name, child[c], namewidth, 1284e6ca193dSGeorge Wilson 2, B_FALSE); 1285e6ca193dSGeorge Wilson else 1286e6ca193dSGeorge Wilson print_import_config(name, child[c], namewidth, 2); 1287e6ca193dSGeorge Wilson free(name); 1288e6ca193dSGeorge Wilson } 1289e6ca193dSGeorge Wilson } 1290e6ca193dSGeorge Wilson /* 1291fa9e4066Sahrens * Display the status for the given pool. 1292fa9e4066Sahrens */ 1293fa9e4066Sahrens static void 1294fa9e4066Sahrens show_import(nvlist_t *config) 1295fa9e4066Sahrens { 1296fa9e4066Sahrens uint64_t pool_state; 1297fa9e4066Sahrens vdev_stat_t *vs; 1298fa9e4066Sahrens char *name; 1299fa9e4066Sahrens uint64_t guid; 1300fa9e4066Sahrens char *msgid; 1301fa9e4066Sahrens nvlist_t *nvroot; 1302fa9e4066Sahrens int reason; 130346657f8dSmmusante const char *health; 1304fa9e4066Sahrens uint_t vsc; 1305fa9e4066Sahrens int namewidth; 1306fa9e4066Sahrens 1307fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1308fa9e4066Sahrens &name) == 0); 1309fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1310fa9e4066Sahrens &guid) == 0); 1311fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1312fa9e4066Sahrens &pool_state) == 0); 1313fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1314fa9e4066Sahrens &nvroot) == 0); 1315fa9e4066Sahrens 1316fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1317fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 1318990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1319fa9e4066Sahrens 1320fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1321fa9e4066Sahrens 132246657f8dSmmusante (void) printf(gettext(" pool: %s\n"), name); 132346657f8dSmmusante (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 132446657f8dSmmusante (void) printf(gettext(" state: %s"), health); 13254c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 132646657f8dSmmusante (void) printf(gettext(" (DESTROYED)")); 13274c58d714Sdarrenm (void) printf("\n"); 1328fa9e4066Sahrens 1329fa9e4066Sahrens switch (reason) { 1330fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1331fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1332fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 1333fa9e4066Sahrens (void) printf(gettext("status: One or more devices are missing " 1334fa9e4066Sahrens "from the system.\n")); 1335fa9e4066Sahrens break; 1336fa9e4066Sahrens 1337fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1338fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1339fa9e4066Sahrens (void) printf(gettext("status: One or more devices contains " 1340fa9e4066Sahrens "corrupted data.\n")); 1341fa9e4066Sahrens break; 1342fa9e4066Sahrens 1343fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 1344fa9e4066Sahrens (void) printf(gettext("status: The pool data is corrupted.\n")); 1345fa9e4066Sahrens break; 1346fa9e4066Sahrens 1347441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 1348441d80aaSlling (void) printf(gettext("status: One or more devices " 1349441d80aaSlling "are offlined.\n")); 1350441d80aaSlling break; 1351441d80aaSlling 1352ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 1353ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is " 1354ea8dc4b6Seschrock "corrupted.\n")); 1355ea8dc4b6Seschrock break; 1356ea8dc4b6Seschrock 1357eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 1358eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1359eaca9bbdSeschrock "older on-disk version.\n")); 1360eaca9bbdSeschrock break; 1361eaca9bbdSeschrock 1362eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1363eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1364eaca9bbdSeschrock "incompatible version.\n")); 1365eaca9bbdSeschrock break; 1366b87f3af3Sperrin 136795173954Sek110237 case ZPOOL_STATUS_HOSTID_MISMATCH: 136895173954Sek110237 (void) printf(gettext("status: The pool was last accessed by " 136995173954Sek110237 "another system.\n")); 137095173954Sek110237 break; 1371b87f3af3Sperrin 13723d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 13733d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 13743d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 13753d7072f8Seschrock "faulted.\n")); 13763d7072f8Seschrock break; 13773d7072f8Seschrock 1378b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 1379b87f3af3Sperrin (void) printf(gettext("status: An intent log record cannot be " 1380b87f3af3Sperrin "read.\n")); 1381b87f3af3Sperrin break; 1382b87f3af3Sperrin 1383fa9e4066Sahrens default: 1384fa9e4066Sahrens /* 1385fa9e4066Sahrens * No other status can be seen when importing pools. 1386fa9e4066Sahrens */ 1387fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1388fa9e4066Sahrens } 1389fa9e4066Sahrens 1390fa9e4066Sahrens /* 1391fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1392fa9e4066Sahrens */ 139346657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 1394eaca9bbdSeschrock if (reason == ZPOOL_STATUS_VERSION_OLDER) 1395eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1396eaca9bbdSeschrock "imported using its name or numeric identifier, " 1397eaca9bbdSeschrock "though\n\tsome features will not be available " 1398eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 139995173954Sek110237 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 140095173954Sek110237 (void) printf(gettext("action: The pool can be " 140195173954Sek110237 "imported using its name or numeric " 140295173954Sek110237 "identifier and\n\tthe '-f' flag.\n")); 1403fa9e4066Sahrens else 1404eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1405eaca9bbdSeschrock "imported using its name or numeric " 1406eaca9bbdSeschrock "identifier.\n")); 140746657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1408fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported " 1409fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1410eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1411fa9e4066Sahrens } else { 1412eaca9bbdSeschrock switch (reason) { 1413eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1414eaca9bbdSeschrock (void) printf(gettext("action: The pool cannot be " 1415eaca9bbdSeschrock "imported. Access the pool on a system running " 1416eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1417eaca9bbdSeschrock "backup.\n")); 1418eaca9bbdSeschrock break; 1419eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1420eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1421eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 1422fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1423fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1424fa9e4066Sahrens "again.\n")); 1425eaca9bbdSeschrock break; 1426eaca9bbdSeschrock default: 1427fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1428fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1429fa9e4066Sahrens } 1430eaca9bbdSeschrock } 1431eaca9bbdSeschrock 143246657f8dSmmusante /* 143346657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 143446657f8dSmmusante * is "corrupt data": 143546657f8dSmmusante */ 143646657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 143746657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 143846657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1439eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1440eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1441eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1442eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1443eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 144418ce54dfSek110237 "another system, but can be imported using\n\t" 1445eaca9bbdSeschrock "the '-f' flag.\n")); 1446eaca9bbdSeschrock } 1447fa9e4066Sahrens 1448fa9e4066Sahrens if (msgid != NULL) 1449fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1450fa9e4066Sahrens msgid); 1451fa9e4066Sahrens 1452fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 1453fa9e4066Sahrens 1454c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1455fa9e4066Sahrens if (namewidth < 10) 1456fa9e4066Sahrens namewidth = 10; 14578654d025Sperrin 1458e6ca193dSGeorge Wilson print_import_config(name, nvroot, namewidth, 0); 1459e6ca193dSGeorge Wilson if (num_logs(nvroot) > 0) 1460e6ca193dSGeorge Wilson print_logs(NULL, nvroot, namewidth, B_FALSE); 1461fa9e4066Sahrens 1462fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 146346657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1464fa9e4066Sahrens "be part of this pool, though their\n\texact " 146546657f8dSmmusante "configuration cannot be determined.\n")); 1466fa9e4066Sahrens } 1467fa9e4066Sahrens } 1468fa9e4066Sahrens 1469fa9e4066Sahrens /* 1470fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1471990b4856Slling * lifting off to zpool_import_props(), and then mounts the datasets contained 1472990b4856Slling * within the pool. 1473fa9e4066Sahrens */ 1474fa9e4066Sahrens static int 1475fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 14764f0f5e5bSVictor Latushkin int force, nvlist_t *props, boolean_t do_verbatim) 1477fa9e4066Sahrens { 1478fa9e4066Sahrens zpool_handle_t *zhp; 1479fa9e4066Sahrens char *name; 1480fa9e4066Sahrens uint64_t state; 1481eaca9bbdSeschrock uint64_t version; 1482ecd6cf80Smarks int error = 0; 1483fa9e4066Sahrens 1484fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1485fa9e4066Sahrens &name) == 0); 1486fa9e4066Sahrens 1487fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1488fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1489eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1490eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1491e7437265Sahrens if (version > SPA_VERSION) { 1492eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1493eaca9bbdSeschrock "is formatted using a newer ZFS version\n"), name); 1494eaca9bbdSeschrock return (1); 1495eaca9bbdSeschrock } else if (state != POOL_STATE_EXPORTED && !force) { 149695173954Sek110237 uint64_t hostid; 149795173954Sek110237 149895173954Sek110237 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 149995173954Sek110237 &hostid) == 0) { 150095173954Sek110237 if ((unsigned long)hostid != gethostid()) { 150195173954Sek110237 char *hostname; 150295173954Sek110237 uint64_t timestamp; 150395173954Sek110237 time_t t; 150495173954Sek110237 150595173954Sek110237 verify(nvlist_lookup_string(config, 150695173954Sek110237 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 150795173954Sek110237 verify(nvlist_lookup_uint64(config, 150895173954Sek110237 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 150995173954Sek110237 t = timestamp; 151095173954Sek110237 (void) fprintf(stderr, gettext("cannot import " 151195173954Sek110237 "'%s': pool may be in use from other " 151295173954Sek110237 "system, it was last accessed by %s " 151395173954Sek110237 "(hostid: 0x%lx) on %s"), name, hostname, 151495173954Sek110237 (unsigned long)hostid, 151595173954Sek110237 asctime(localtime(&t))); 151695173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to " 151795173954Sek110237 "import anyway\n")); 1518fa9e4066Sahrens return (1); 1519fa9e4066Sahrens } 152095173954Sek110237 } else { 152195173954Sek110237 (void) fprintf(stderr, gettext("cannot import '%s': " 152295173954Sek110237 "pool may be in use from other system\n"), name); 152395173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to import " 152495173954Sek110237 "anyway\n")); 152595173954Sek110237 return (1); 152695173954Sek110237 } 152795173954Sek110237 } 1528fa9e4066Sahrens 15294f0f5e5bSVictor Latushkin if (zpool_import_props(g_zfs, config, newname, props, do_verbatim) != 0) 1530fa9e4066Sahrens return (1); 1531fa9e4066Sahrens 1532fa9e4066Sahrens if (newname != NULL) 1533fa9e4066Sahrens name = (char *)newname; 1534fa9e4066Sahrens 15354f0f5e5bSVictor Latushkin if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 15364f0f5e5bSVictor Latushkin return (1); 1537fa9e4066Sahrens 1538379c004dSEric Schrock if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1539379c004dSEric Schrock zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1540fa9e4066Sahrens zpool_close(zhp); 1541fa9e4066Sahrens return (1); 1542fa9e4066Sahrens } 1543fa9e4066Sahrens 1544fa9e4066Sahrens zpool_close(zhp); 1545ecd6cf80Smarks return (error); 1546fa9e4066Sahrens } 1547fa9e4066Sahrens 1548fa9e4066Sahrens /* 15494c58d714Sdarrenm * zpool import [-d dir] [-D] 15502f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 15512f8aaab3Seschrock * [-d dir | -c cachefile] [-f] -a 15522f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 15532f8aaab3Seschrock * [-d dir | -c cachefile] [-f] <pool | id> [newpool] 15542f8aaab3Seschrock * 15552f8aaab3Seschrock * -c Read pool information from a cachefile instead of searching 15562f8aaab3Seschrock * devices. 1557fa9e4066Sahrens * 1558fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1559fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1560fa9e4066Sahrens * 15614c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 15624c58d714Sdarrenm * specified destroyed pools. 15634c58d714Sdarrenm * 1564fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1565fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1566fa9e4066Sahrens * is rebooted. 1567fa9e4066Sahrens * 1568fa9e4066Sahrens * -f Force import, even if it appears that the pool is active. 1569fa9e4066Sahrens * 1570c5904d13Seschrock * -F Import even in the presence of faulted vdevs. This is an 1571c5904d13Seschrock * intentionally undocumented option for testing purposes, and 1572c5904d13Seschrock * treats the pool configuration as complete, leaving any bad 15734f0f5e5bSVictor Latushkin * vdevs in the FAULTED state. In other words, it does verbatim 15744f0f5e5bSVictor Latushkin * import. 1575c5904d13Seschrock * 1576fa9e4066Sahrens * -a Import all pools found. 1577fa9e4066Sahrens * 1578990b4856Slling * -o Set property=value and/or temporary mount options (without '='). 1579ecd6cf80Smarks * 1580fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 1581fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 1582fa9e4066Sahrens */ 1583fa9e4066Sahrens int 1584fa9e4066Sahrens zpool_do_import(int argc, char **argv) 1585fa9e4066Sahrens { 1586fa9e4066Sahrens char **searchdirs = NULL; 1587fa9e4066Sahrens int nsearch = 0; 1588fa9e4066Sahrens int c; 1589fa9e4066Sahrens int err; 15902f8aaab3Seschrock nvlist_t *pools = NULL; 159199653d4eSeschrock boolean_t do_all = B_FALSE; 159299653d4eSeschrock boolean_t do_destroyed = B_FALSE; 1593fa9e4066Sahrens char *mntopts = NULL; 159499653d4eSeschrock boolean_t do_force = B_FALSE; 1595fa9e4066Sahrens nvpair_t *elem; 1596fa9e4066Sahrens nvlist_t *config; 159724e697d4Sck153898 uint64_t searchguid = 0; 159824e697d4Sck153898 char *searchname = NULL; 1599990b4856Slling char *propval; 1600fa9e4066Sahrens nvlist_t *found_config; 1601ecd6cf80Smarks nvlist_t *props = NULL; 160299653d4eSeschrock boolean_t first; 16034f0f5e5bSVictor Latushkin boolean_t do_verbatim = B_FALSE; 16044c58d714Sdarrenm uint64_t pool_state; 16052f8aaab3Seschrock char *cachefile = NULL; 1606fa9e4066Sahrens 1607fa9e4066Sahrens /* check options */ 1608c5904d13Seschrock while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) { 1609fa9e4066Sahrens switch (c) { 1610fa9e4066Sahrens case 'a': 161199653d4eSeschrock do_all = B_TRUE; 1612fa9e4066Sahrens break; 16132f8aaab3Seschrock case 'c': 16142f8aaab3Seschrock cachefile = optarg; 16152f8aaab3Seschrock break; 1616fa9e4066Sahrens case 'd': 1617fa9e4066Sahrens if (searchdirs == NULL) { 1618fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1619fa9e4066Sahrens } else { 1620fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 1621fa9e4066Sahrens sizeof (char *)); 1622fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 1623fa9e4066Sahrens sizeof (char *)); 1624fa9e4066Sahrens free(searchdirs); 1625fa9e4066Sahrens searchdirs = tmp; 1626fa9e4066Sahrens } 1627fa9e4066Sahrens searchdirs[nsearch++] = optarg; 1628fa9e4066Sahrens break; 16294c58d714Sdarrenm case 'D': 163099653d4eSeschrock do_destroyed = B_TRUE; 16314c58d714Sdarrenm break; 1632fa9e4066Sahrens case 'f': 163399653d4eSeschrock do_force = B_TRUE; 1634fa9e4066Sahrens break; 1635c5904d13Seschrock case 'F': 16364f0f5e5bSVictor Latushkin do_verbatim = B_TRUE; 1637c5904d13Seschrock break; 1638fa9e4066Sahrens case 'o': 1639990b4856Slling if ((propval = strchr(optarg, '=')) != NULL) { 1640990b4856Slling *propval = '\0'; 1641990b4856Slling propval++; 16420a48a24eStimh if (add_prop_list(optarg, propval, 16430a48a24eStimh &props, B_TRUE)) 1644990b4856Slling goto error; 1645990b4856Slling } else { 1646fa9e4066Sahrens mntopts = optarg; 1647990b4856Slling } 1648fa9e4066Sahrens break; 1649fa9e4066Sahrens case 'R': 1650990b4856Slling if (add_prop_list(zpool_prop_to_name( 16510a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 1652990b4856Slling goto error; 16532f8aaab3Seschrock if (nvlist_lookup_string(props, 16542f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 16552f8aaab3Seschrock &propval) == 0) 16562f8aaab3Seschrock break; 1657990b4856Slling if (add_prop_list(zpool_prop_to_name( 16580a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1659990b4856Slling goto error; 1660fa9e4066Sahrens break; 1661fa9e4066Sahrens case ':': 1662fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 1663fa9e4066Sahrens "'%c' option\n"), optopt); 166499653d4eSeschrock usage(B_FALSE); 1665fa9e4066Sahrens break; 1666fa9e4066Sahrens case '?': 1667fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1668fa9e4066Sahrens optopt); 166999653d4eSeschrock usage(B_FALSE); 1670fa9e4066Sahrens } 1671fa9e4066Sahrens } 1672fa9e4066Sahrens 1673fa9e4066Sahrens argc -= optind; 1674fa9e4066Sahrens argv += optind; 1675fa9e4066Sahrens 16762f8aaab3Seschrock if (cachefile && nsearch != 0) { 16772f8aaab3Seschrock (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 16782f8aaab3Seschrock usage(B_FALSE); 16792f8aaab3Seschrock } 16802f8aaab3Seschrock 1681fa9e4066Sahrens if (searchdirs == NULL) { 1682fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1683fa9e4066Sahrens searchdirs[0] = "/dev/dsk"; 1684fa9e4066Sahrens nsearch = 1; 1685fa9e4066Sahrens } 1686fa9e4066Sahrens 1687fa9e4066Sahrens /* check argument count */ 1688fa9e4066Sahrens if (do_all) { 1689fa9e4066Sahrens if (argc != 0) { 1690fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 169199653d4eSeschrock usage(B_FALSE); 1692fa9e4066Sahrens } 1693fa9e4066Sahrens } else { 1694fa9e4066Sahrens if (argc > 2) { 1695fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 169699653d4eSeschrock usage(B_FALSE); 1697fa9e4066Sahrens } 1698fa9e4066Sahrens 1699fa9e4066Sahrens /* 1700fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 1701fa9e4066Sahrens * here because otherwise any attempt to discover pools will 1702fa9e4066Sahrens * silently fail. 1703fa9e4066Sahrens */ 1704fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1705fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 1706fa9e4066Sahrens "discover pools: permission denied\n")); 170799653d4eSeschrock free(searchdirs); 1708fa9e4066Sahrens return (1); 1709fa9e4066Sahrens } 1710fa9e4066Sahrens } 1711fa9e4066Sahrens 1712fa9e4066Sahrens /* 1713fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 1714fa9e4066Sahrens * 1715fa9e4066Sahrens * <none> Iterate through all pools and display information about 1716fa9e4066Sahrens * each one. 1717fa9e4066Sahrens * 1718fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 1719fa9e4066Sahrens * 1720fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 1721fa9e4066Sahrens * name and import that one. 17224c58d714Sdarrenm * 17234c58d714Sdarrenm * -D Above options applies only to destroyed pools. 1724fa9e4066Sahrens */ 1725fa9e4066Sahrens if (argc != 0) { 1726fa9e4066Sahrens char *endptr; 1727fa9e4066Sahrens 1728fa9e4066Sahrens errno = 0; 1729fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 1730fa9e4066Sahrens if (errno != 0 || *endptr != '\0') 1731fa9e4066Sahrens searchname = argv[0]; 1732fa9e4066Sahrens found_config = NULL; 1733fa9e4066Sahrens } 1734fa9e4066Sahrens 173524e697d4Sck153898 if (cachefile) { 1736e829d913Sck153898 pools = zpool_find_import_cached(g_zfs, cachefile, searchname, 1737e829d913Sck153898 searchguid); 173824e697d4Sck153898 } else if (searchname != NULL) { 173924e697d4Sck153898 pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs, 174024e697d4Sck153898 searchname); 174124e697d4Sck153898 } else { 174224e697d4Sck153898 /* 174324e697d4Sck153898 * It's OK to search by guid even if searchguid is 0. 174424e697d4Sck153898 */ 174524e697d4Sck153898 pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs, 174624e697d4Sck153898 searchguid); 174724e697d4Sck153898 } 174824e697d4Sck153898 174924e697d4Sck153898 if (pools == NULL) { 175024e697d4Sck153898 if (argc != 0) { 175124e697d4Sck153898 (void) fprintf(stderr, gettext("cannot import '%s': " 175224e697d4Sck153898 "no such pool available\n"), argv[0]); 175324e697d4Sck153898 } 175424e697d4Sck153898 free(searchdirs); 175524e697d4Sck153898 return (1); 175624e697d4Sck153898 } 175724e697d4Sck153898 175824e697d4Sck153898 /* 175924e697d4Sck153898 * At this point we have a list of import candidate configs. Even if 176024e697d4Sck153898 * we were searching by pool name or guid, we still need to 176124e697d4Sck153898 * post-process the list to deal with pool state and possible 176224e697d4Sck153898 * duplicate names. 176324e697d4Sck153898 */ 1764fa9e4066Sahrens err = 0; 1765fa9e4066Sahrens elem = NULL; 176699653d4eSeschrock first = B_TRUE; 1767fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1768fa9e4066Sahrens 1769fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 1770fa9e4066Sahrens 17714c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 17724c58d714Sdarrenm &pool_state) == 0); 17734c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 17744c58d714Sdarrenm continue; 17754c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 17764c58d714Sdarrenm continue; 17774c58d714Sdarrenm 1778fa9e4066Sahrens if (argc == 0) { 1779fa9e4066Sahrens if (first) 178099653d4eSeschrock first = B_FALSE; 17813bb79becSeschrock else if (!do_all) 1782fa9e4066Sahrens (void) printf("\n"); 1783fa9e4066Sahrens 1784fa9e4066Sahrens if (do_all) 1785fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 17864f0f5e5bSVictor Latushkin do_force, props, do_verbatim); 1787fa9e4066Sahrens else 1788fa9e4066Sahrens show_import(config); 1789fa9e4066Sahrens } else if (searchname != NULL) { 1790fa9e4066Sahrens char *name; 1791fa9e4066Sahrens 1792fa9e4066Sahrens /* 1793fa9e4066Sahrens * We are searching for a pool based on name. 1794fa9e4066Sahrens */ 1795fa9e4066Sahrens verify(nvlist_lookup_string(config, 1796fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1797fa9e4066Sahrens 1798fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 1799fa9e4066Sahrens if (found_config != NULL) { 1800fa9e4066Sahrens (void) fprintf(stderr, gettext( 1801fa9e4066Sahrens "cannot import '%s': more than " 1802fa9e4066Sahrens "one matching pool\n"), searchname); 1803fa9e4066Sahrens (void) fprintf(stderr, gettext( 1804fa9e4066Sahrens "import by numeric ID instead\n")); 180599653d4eSeschrock err = B_TRUE; 1806fa9e4066Sahrens } 1807fa9e4066Sahrens found_config = config; 1808fa9e4066Sahrens } 1809fa9e4066Sahrens } else { 1810fa9e4066Sahrens uint64_t guid; 1811fa9e4066Sahrens 1812fa9e4066Sahrens /* 1813fa9e4066Sahrens * Search for a pool by guid. 1814fa9e4066Sahrens */ 1815fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1816fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1817fa9e4066Sahrens 1818fa9e4066Sahrens if (guid == searchguid) 1819fa9e4066Sahrens found_config = config; 1820fa9e4066Sahrens } 1821fa9e4066Sahrens } 1822fa9e4066Sahrens 1823fa9e4066Sahrens /* 1824fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 1825fa9e4066Sahrens * pool, and then do the import. 1826fa9e4066Sahrens */ 1827fa9e4066Sahrens if (argc != 0 && err == 0) { 1828fa9e4066Sahrens if (found_config == NULL) { 1829fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 1830fa9e4066Sahrens "no such pool available\n"), argv[0]); 183199653d4eSeschrock err = B_TRUE; 1832fa9e4066Sahrens } else { 1833fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 18344f0f5e5bSVictor Latushkin argv[1], mntopts, do_force, props, do_verbatim); 1835fa9e4066Sahrens } 1836fa9e4066Sahrens } 1837fa9e4066Sahrens 1838fa9e4066Sahrens /* 1839fa9e4066Sahrens * If we were just looking for pools, report an error if none were 1840fa9e4066Sahrens * found. 1841fa9e4066Sahrens */ 1842fa9e4066Sahrens if (argc == 0 && first) 1843fa9e4066Sahrens (void) fprintf(stderr, 1844fa9e4066Sahrens gettext("no pools available to import\n")); 1845fa9e4066Sahrens 1846ecd6cf80Smarks error: 1847ecd6cf80Smarks nvlist_free(props); 1848fa9e4066Sahrens nvlist_free(pools); 184999653d4eSeschrock free(searchdirs); 1850fa9e4066Sahrens 1851fa9e4066Sahrens return (err ? 1 : 0); 1852fa9e4066Sahrens } 1853fa9e4066Sahrens 1854fa9e4066Sahrens typedef struct iostat_cbdata { 1855fa9e4066Sahrens zpool_list_t *cb_list; 1856fa9e4066Sahrens int cb_verbose; 1857fa9e4066Sahrens int cb_iteration; 1858fa9e4066Sahrens int cb_namewidth; 1859fa9e4066Sahrens } iostat_cbdata_t; 1860fa9e4066Sahrens 1861fa9e4066Sahrens static void 1862fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 1863fa9e4066Sahrens { 1864fa9e4066Sahrens int i = 0; 1865fa9e4066Sahrens 1866fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 1867fa9e4066Sahrens (void) printf("-"); 1868fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1869fa9e4066Sahrens } 1870fa9e4066Sahrens 1871fa9e4066Sahrens static void 1872fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 1873fa9e4066Sahrens { 1874fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 1875fa9e4066Sahrens cb->cb_namewidth, ""); 1876fa9e4066Sahrens (void) printf("%-*s used avail read write read write\n", 1877fa9e4066Sahrens cb->cb_namewidth, "pool"); 1878fa9e4066Sahrens print_iostat_separator(cb); 1879fa9e4066Sahrens } 1880fa9e4066Sahrens 1881fa9e4066Sahrens /* 1882fa9e4066Sahrens * Display a single statistic. 1883fa9e4066Sahrens */ 1884990b4856Slling static void 1885fa9e4066Sahrens print_one_stat(uint64_t value) 1886fa9e4066Sahrens { 1887fa9e4066Sahrens char buf[64]; 1888fa9e4066Sahrens 1889fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 1890fa9e4066Sahrens (void) printf(" %5s", buf); 1891fa9e4066Sahrens } 1892fa9e4066Sahrens 1893fa9e4066Sahrens /* 1894fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 1895fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 1896fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 1897fa9e4066Sahrens */ 1898fa9e4066Sahrens void 1899c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1900c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1901fa9e4066Sahrens { 1902fa9e4066Sahrens nvlist_t **oldchild, **newchild; 1903fa9e4066Sahrens uint_t c, children; 1904fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 1905fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 1906fa9e4066Sahrens uint64_t tdelta; 1907fa9e4066Sahrens double scale; 1908afefbcddSeschrock char *vname; 1909fa9e4066Sahrens 1910fa9e4066Sahrens if (oldnv != NULL) { 1911fa9e4066Sahrens verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1912fa9e4066Sahrens (uint64_t **)&oldvs, &c) == 0); 1913fa9e4066Sahrens } else { 1914fa9e4066Sahrens oldvs = &zerovs; 1915fa9e4066Sahrens } 1916fa9e4066Sahrens 1917fa9e4066Sahrens verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1918fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 1919fa9e4066Sahrens 1920fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 1921fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 1922fa9e4066Sahrens else 1923fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 1924fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1925fa9e4066Sahrens 1926fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1927fa9e4066Sahrens 1928fa9e4066Sahrens if (tdelta == 0) 1929fa9e4066Sahrens scale = 1.0; 1930fa9e4066Sahrens else 1931fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 1932fa9e4066Sahrens 1933fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 1934fa9e4066Sahrens if (newvs->vs_space == 0) { 1935fa9e4066Sahrens (void) printf(" - -"); 1936fa9e4066Sahrens } else { 1937fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 1938fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 1939fa9e4066Sahrens } 1940fa9e4066Sahrens 1941fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1942fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 1943fa9e4066Sahrens 1944fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1945fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1946fa9e4066Sahrens 1947fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1948fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 1949fa9e4066Sahrens 1950fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1951fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1952fa9e4066Sahrens 1953fa9e4066Sahrens (void) printf("\n"); 1954fa9e4066Sahrens 1955fa9e4066Sahrens if (!cb->cb_verbose) 1956fa9e4066Sahrens return; 1957fa9e4066Sahrens 1958fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1959fa9e4066Sahrens &newchild, &children) != 0) 1960fa9e4066Sahrens return; 1961fa9e4066Sahrens 1962fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1963fa9e4066Sahrens &oldchild, &c) != 0) 1964fa9e4066Sahrens return; 1965fa9e4066Sahrens 1966afefbcddSeschrock for (c = 0; c < children; c++) { 196799653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1968c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1969afefbcddSeschrock newchild[c], cb, depth + 2); 1970afefbcddSeschrock free(vname); 1971afefbcddSeschrock } 1972fa94a07fSbrendan 1973fa94a07fSbrendan /* 1974fa94a07fSbrendan * Include level 2 ARC devices in iostat output 1975fa94a07fSbrendan */ 1976fa94a07fSbrendan if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 1977fa94a07fSbrendan &newchild, &children) != 0) 1978fa94a07fSbrendan return; 1979fa94a07fSbrendan 1980fa94a07fSbrendan if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 1981fa94a07fSbrendan &oldchild, &c) != 0) 1982fa94a07fSbrendan return; 1983fa94a07fSbrendan 1984fa94a07fSbrendan if (children > 0) { 1985fa94a07fSbrendan (void) printf("%-*s - - - - - " 1986fa94a07fSbrendan "-\n", cb->cb_namewidth, "cache"); 1987fa94a07fSbrendan for (c = 0; c < children; c++) { 1988fa94a07fSbrendan vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1989fa94a07fSbrendan print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1990fa94a07fSbrendan newchild[c], cb, depth + 2); 1991fa94a07fSbrendan free(vname); 1992fa94a07fSbrendan } 1993fa94a07fSbrendan } 1994fa9e4066Sahrens } 1995fa9e4066Sahrens 1996088e9d47Seschrock static int 1997088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 1998088e9d47Seschrock { 1999088e9d47Seschrock iostat_cbdata_t *cb = data; 200094de1d4cSeschrock boolean_t missing; 2001088e9d47Seschrock 2002088e9d47Seschrock /* 2003088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 2004088e9d47Seschrock */ 200594de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 200694de1d4cSeschrock return (-1); 200794de1d4cSeschrock 200894de1d4cSeschrock if (missing) 2009088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 2010088e9d47Seschrock 2011088e9d47Seschrock return (0); 2012088e9d47Seschrock } 2013088e9d47Seschrock 2014fa9e4066Sahrens /* 2015fa9e4066Sahrens * Callback to print out the iostats for the given pool. 2016fa9e4066Sahrens */ 2017fa9e4066Sahrens int 2018fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 2019fa9e4066Sahrens { 2020fa9e4066Sahrens iostat_cbdata_t *cb = data; 2021fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 2022fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 2023fa9e4066Sahrens 2024088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 2025fa9e4066Sahrens 2026088e9d47Seschrock if (cb->cb_iteration == 1) 2027fa9e4066Sahrens oldconfig = NULL; 2028fa9e4066Sahrens 2029fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2030fa9e4066Sahrens &newnvroot) == 0); 2031fa9e4066Sahrens 2032088e9d47Seschrock if (oldconfig == NULL) 2033fa9e4066Sahrens oldnvroot = NULL; 2034088e9d47Seschrock else 2035088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2036088e9d47Seschrock &oldnvroot) == 0); 2037fa9e4066Sahrens 2038fa9e4066Sahrens /* 2039fa9e4066Sahrens * Print out the statistics for the pool. 2040fa9e4066Sahrens */ 2041c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2042fa9e4066Sahrens 2043fa9e4066Sahrens if (cb->cb_verbose) 2044fa9e4066Sahrens print_iostat_separator(cb); 2045fa9e4066Sahrens 2046fa9e4066Sahrens return (0); 2047fa9e4066Sahrens } 2048fa9e4066Sahrens 2049fa9e4066Sahrens int 2050fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 2051fa9e4066Sahrens { 2052fa9e4066Sahrens iostat_cbdata_t *cb = data; 2053fa9e4066Sahrens nvlist_t *config, *nvroot; 2054fa9e4066Sahrens 2055088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2056fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2057fa9e4066Sahrens &nvroot) == 0); 2058fa9e4066Sahrens if (!cb->cb_verbose) 2059fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2060fa9e4066Sahrens else 2061c67d9675Seschrock cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 2062fa9e4066Sahrens } 2063fa9e4066Sahrens 2064fa9e4066Sahrens /* 2065fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 2066fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 2067fa9e4066Sahrens */ 2068fa9e4066Sahrens if (cb->cb_namewidth < 10) 2069fa9e4066Sahrens cb->cb_namewidth = 10; 2070fa9e4066Sahrens if (cb->cb_namewidth > 38) 2071fa9e4066Sahrens cb->cb_namewidth = 38; 2072fa9e4066Sahrens 2073fa9e4066Sahrens return (0); 2074fa9e4066Sahrens } 2075fa9e4066Sahrens 2076fa9e4066Sahrens /* 2077*26fd7700SKrishnendu Sadhukhan - Sun Microsystems * zpool iostat [-T d|u] [-v] [pool] ... [interval [count]] 2078fa9e4066Sahrens * 2079*26fd7700SKrishnendu Sadhukhan - Sun Microsystems * -T Display a timestamp in date(1) or Unix format 2080fa9e4066Sahrens * -v Display statistics for individual vdevs 2081fa9e4066Sahrens * 2082fa9e4066Sahrens * This command can be tricky because we want to be able to deal with pool 2083fa9e4066Sahrens * creation/destruction as well as vdev configuration changes. The bulk of this 2084fa9e4066Sahrens * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2085fa9e4066Sahrens * on pool_list_update() to detect the addition of new pools. Configuration 2086fa9e4066Sahrens * changes are all handled within libzfs. 2087fa9e4066Sahrens */ 2088fa9e4066Sahrens int 2089fa9e4066Sahrens zpool_do_iostat(int argc, char **argv) 2090fa9e4066Sahrens { 2091fa9e4066Sahrens int c; 2092fa9e4066Sahrens int ret; 2093fa9e4066Sahrens int npools; 2094fa9e4066Sahrens unsigned long interval = 0, count = 0; 2095fa9e4066Sahrens zpool_list_t *list; 209699653d4eSeschrock boolean_t verbose = B_FALSE; 2097fa9e4066Sahrens iostat_cbdata_t cb; 2098fa9e4066Sahrens 2099fa9e4066Sahrens /* check options */ 2100*26fd7700SKrishnendu Sadhukhan - Sun Microsystems while ((c = getopt(argc, argv, "T:v")) != -1) { 2101fa9e4066Sahrens switch (c) { 2102*26fd7700SKrishnendu Sadhukhan - Sun Microsystems case 'T': 2103*26fd7700SKrishnendu Sadhukhan - Sun Microsystems if (optarg) { 2104*26fd7700SKrishnendu Sadhukhan - Sun Microsystems if (*optarg == 'u') 2105*26fd7700SKrishnendu Sadhukhan - Sun Microsystems timestamp_fmt = UDATE; 2106*26fd7700SKrishnendu Sadhukhan - Sun Microsystems else if (*optarg == 'd') 2107*26fd7700SKrishnendu Sadhukhan - Sun Microsystems timestamp_fmt = DDATE; 2108*26fd7700SKrishnendu Sadhukhan - Sun Microsystems else 2109*26fd7700SKrishnendu Sadhukhan - Sun Microsystems usage(B_FALSE); 2110*26fd7700SKrishnendu Sadhukhan - Sun Microsystems } else { 2111*26fd7700SKrishnendu Sadhukhan - Sun Microsystems usage(B_FALSE); 2112*26fd7700SKrishnendu Sadhukhan - Sun Microsystems } 2113*26fd7700SKrishnendu Sadhukhan - Sun Microsystems break; 2114fa9e4066Sahrens case 'v': 211599653d4eSeschrock verbose = B_TRUE; 2116fa9e4066Sahrens break; 2117fa9e4066Sahrens case '?': 2118fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2119fa9e4066Sahrens optopt); 212099653d4eSeschrock usage(B_FALSE); 2121fa9e4066Sahrens } 2122fa9e4066Sahrens } 2123fa9e4066Sahrens 2124fa9e4066Sahrens argc -= optind; 2125fa9e4066Sahrens argv += optind; 2126fa9e4066Sahrens 2127fa9e4066Sahrens /* 2128fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 2129fa9e4066Sahrens */ 2130fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 2131fa9e4066Sahrens char *end; 2132fa9e4066Sahrens 2133fa9e4066Sahrens errno = 0; 2134fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 2135fa9e4066Sahrens 2136fa9e4066Sahrens if (*end == '\0' && errno == 0) { 2137fa9e4066Sahrens if (interval == 0) { 2138fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 2139fa9e4066Sahrens "cannot be zero\n")); 214099653d4eSeschrock usage(B_FALSE); 2141fa9e4066Sahrens } 2142fa9e4066Sahrens 2143fa9e4066Sahrens /* 2144fa9e4066Sahrens * Ignore the last parameter 2145fa9e4066Sahrens */ 2146fa9e4066Sahrens argc--; 2147fa9e4066Sahrens } else { 2148fa9e4066Sahrens /* 2149fa9e4066Sahrens * If this is not a valid number, just plow on. The 2150fa9e4066Sahrens * user will get a more informative error message later 2151fa9e4066Sahrens * on. 2152fa9e4066Sahrens */ 2153fa9e4066Sahrens interval = 0; 2154fa9e4066Sahrens } 2155fa9e4066Sahrens } 2156fa9e4066Sahrens 2157fa9e4066Sahrens /* 2158fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 2159fa9e4066Sahrens * and an integer. 2160fa9e4066Sahrens */ 2161fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 2162fa9e4066Sahrens char *end; 2163fa9e4066Sahrens 2164fa9e4066Sahrens errno = 0; 2165fa9e4066Sahrens count = interval; 2166fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 2167fa9e4066Sahrens 2168fa9e4066Sahrens if (*end == '\0' && errno == 0) { 2169fa9e4066Sahrens if (interval == 0) { 2170fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 2171fa9e4066Sahrens "cannot be zero\n")); 217299653d4eSeschrock usage(B_FALSE); 2173fa9e4066Sahrens } 2174fa9e4066Sahrens 2175fa9e4066Sahrens /* 2176fa9e4066Sahrens * Ignore the last parameter 2177fa9e4066Sahrens */ 2178fa9e4066Sahrens argc--; 2179fa9e4066Sahrens } else { 2180fa9e4066Sahrens interval = 0; 2181fa9e4066Sahrens } 2182fa9e4066Sahrens } 2183fa9e4066Sahrens 2184fa9e4066Sahrens /* 2185fa9e4066Sahrens * Construct the list of all interesting pools. 2186fa9e4066Sahrens */ 2187fa9e4066Sahrens ret = 0; 2188b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2189fa9e4066Sahrens return (1); 2190fa9e4066Sahrens 219199653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 219299653d4eSeschrock pool_list_free(list); 2193fa9e4066Sahrens return (1); 219499653d4eSeschrock } 2195fa9e4066Sahrens 2196fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 219799653d4eSeschrock pool_list_free(list); 2198fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 2199fa9e4066Sahrens return (1); 2200fa9e4066Sahrens } 2201fa9e4066Sahrens 2202fa9e4066Sahrens /* 2203fa9e4066Sahrens * Enter the main iostat loop. 2204fa9e4066Sahrens */ 2205fa9e4066Sahrens cb.cb_list = list; 2206fa9e4066Sahrens cb.cb_verbose = verbose; 2207fa9e4066Sahrens cb.cb_iteration = 0; 2208fa9e4066Sahrens cb.cb_namewidth = 0; 2209fa9e4066Sahrens 2210fa9e4066Sahrens for (;;) { 2211fa9e4066Sahrens pool_list_update(list); 2212fa9e4066Sahrens 2213fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 2214fa9e4066Sahrens break; 2215fa9e4066Sahrens 2216fa9e4066Sahrens /* 2217088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 2218088e9d47Seschrock * before calculating the maximum name width, so that any 2219088e9d47Seschrock * configuration changes are properly accounted for. 2220088e9d47Seschrock */ 222199653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2222088e9d47Seschrock 2223088e9d47Seschrock /* 2224fa9e4066Sahrens * Iterate over all pools to determine the maximum width 2225fa9e4066Sahrens * for the pool / device name column across all pools. 2226fa9e4066Sahrens */ 2227fa9e4066Sahrens cb.cb_namewidth = 0; 222899653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2229fa9e4066Sahrens 2230*26fd7700SKrishnendu Sadhukhan - Sun Microsystems if (timestamp_fmt != NODATE) 2231*26fd7700SKrishnendu Sadhukhan - Sun Microsystems print_timestamp(timestamp_fmt); 2232*26fd7700SKrishnendu Sadhukhan - Sun Microsystems 2233fa9e4066Sahrens /* 2234fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 2235fa9e4066Sahrens */ 2236fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 2237fa9e4066Sahrens print_iostat_header(&cb); 2238fa9e4066Sahrens 223999653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2240fa9e4066Sahrens 2241fa9e4066Sahrens /* 2242fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 2243fa9e4066Sahrens * (which prints a separator for us), then print a separator. 2244fa9e4066Sahrens */ 2245fa9e4066Sahrens if (npools > 1 && !verbose) 2246fa9e4066Sahrens print_iostat_separator(&cb); 2247fa9e4066Sahrens 2248fa9e4066Sahrens if (verbose) 2249fa9e4066Sahrens (void) printf("\n"); 2250fa9e4066Sahrens 225139c23413Seschrock /* 225239c23413Seschrock * Flush the output so that redirection to a file isn't buffered 225339c23413Seschrock * indefinitely. 225439c23413Seschrock */ 225539c23413Seschrock (void) fflush(stdout); 225639c23413Seschrock 2257fa9e4066Sahrens if (interval == 0) 2258fa9e4066Sahrens break; 2259fa9e4066Sahrens 2260fa9e4066Sahrens if (count != 0 && --count == 0) 2261fa9e4066Sahrens break; 2262fa9e4066Sahrens 2263fa9e4066Sahrens (void) sleep(interval); 2264fa9e4066Sahrens } 2265fa9e4066Sahrens 2266fa9e4066Sahrens pool_list_free(list); 2267fa9e4066Sahrens 2268fa9e4066Sahrens return (ret); 2269fa9e4066Sahrens } 2270fa9e4066Sahrens 2271fa9e4066Sahrens typedef struct list_cbdata { 227299653d4eSeschrock boolean_t cb_scripted; 227399653d4eSeschrock boolean_t cb_first; 2274990b4856Slling zprop_list_t *cb_proplist; 2275fa9e4066Sahrens } list_cbdata_t; 2276fa9e4066Sahrens 2277fa9e4066Sahrens /* 2278fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 2279fa9e4066Sahrens */ 2280990b4856Slling static void 2281990b4856Slling print_header(zprop_list_t *pl) 2282fa9e4066Sahrens { 2283990b4856Slling const char *header; 2284990b4856Slling boolean_t first = B_TRUE; 2285990b4856Slling boolean_t right_justify; 2286fa9e4066Sahrens 2287990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 2288990b4856Slling if (pl->pl_prop == ZPROP_INVAL) 2289990b4856Slling continue; 2290990b4856Slling 2291990b4856Slling if (!first) 2292fa9e4066Sahrens (void) printf(" "); 2293fa9e4066Sahrens else 2294990b4856Slling first = B_FALSE; 2295fa9e4066Sahrens 2296990b4856Slling header = zpool_prop_column_name(pl->pl_prop); 2297990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2298990b4856Slling 2299990b4856Slling if (pl->pl_next == NULL && !right_justify) 2300990b4856Slling (void) printf("%s", header); 2301990b4856Slling else if (right_justify) 2302990b4856Slling (void) printf("%*s", pl->pl_width, header); 2303990b4856Slling else 2304990b4856Slling (void) printf("%-*s", pl->pl_width, header); 2305fa9e4066Sahrens } 2306fa9e4066Sahrens 2307fa9e4066Sahrens (void) printf("\n"); 2308fa9e4066Sahrens } 2309fa9e4066Sahrens 2310990b4856Slling /* 2311990b4856Slling * Given a pool and a list of properties, print out all the properties according 2312990b4856Slling * to the described layout. 2313990b4856Slling */ 2314990b4856Slling static void 2315990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 2316990b4856Slling { 2317990b4856Slling boolean_t first = B_TRUE; 2318990b4856Slling char property[ZPOOL_MAXPROPLEN]; 2319990b4856Slling char *propstr; 2320990b4856Slling boolean_t right_justify; 2321990b4856Slling int width; 2322990b4856Slling 2323990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 2324990b4856Slling if (!first) { 2325990b4856Slling if (scripted) 2326990b4856Slling (void) printf("\t"); 2327990b4856Slling else 2328990b4856Slling (void) printf(" "); 2329990b4856Slling } else { 2330990b4856Slling first = B_FALSE; 2331990b4856Slling } 2332990b4856Slling 2333990b4856Slling right_justify = B_FALSE; 2334990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 2335990b4856Slling if (zpool_get_prop(zhp, pl->pl_prop, property, 2336990b4856Slling sizeof (property), NULL) != 0) 2337990b4856Slling propstr = "-"; 2338990b4856Slling else 2339990b4856Slling propstr = property; 2340990b4856Slling 2341990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2342990b4856Slling } else { 2343990b4856Slling propstr = "-"; 2344990b4856Slling } 2345990b4856Slling 2346990b4856Slling width = pl->pl_width; 2347990b4856Slling 2348990b4856Slling /* 2349990b4856Slling * If this is being called in scripted mode, or if this is the 2350990b4856Slling * last column and it is left-justified, don't include a width 2351990b4856Slling * format specifier. 2352990b4856Slling */ 2353990b4856Slling if (scripted || (pl->pl_next == NULL && !right_justify)) 2354990b4856Slling (void) printf("%s", propstr); 2355990b4856Slling else if (right_justify) 2356990b4856Slling (void) printf("%*s", width, propstr); 2357990b4856Slling else 2358990b4856Slling (void) printf("%-*s", width, propstr); 2359990b4856Slling } 2360990b4856Slling 2361990b4856Slling (void) printf("\n"); 2362990b4856Slling } 2363990b4856Slling 2364990b4856Slling /* 2365990b4856Slling * Generic callback function to list a pool. 2366990b4856Slling */ 2367fa9e4066Sahrens int 2368fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data) 2369fa9e4066Sahrens { 2370fa9e4066Sahrens list_cbdata_t *cbp = data; 2371fa9e4066Sahrens 2372fa9e4066Sahrens if (cbp->cb_first) { 2373fa9e4066Sahrens if (!cbp->cb_scripted) 2374990b4856Slling print_header(cbp->cb_proplist); 237599653d4eSeschrock cbp->cb_first = B_FALSE; 2376fa9e4066Sahrens } 2377fa9e4066Sahrens 2378990b4856Slling print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2379fa9e4066Sahrens 2380fa9e4066Sahrens return (0); 2381fa9e4066Sahrens } 2382fa9e4066Sahrens 2383fa9e4066Sahrens /* 2384990b4856Slling * zpool list [-H] [-o prop[,prop]*] [pool] ... 2385fa9e4066Sahrens * 2386990b4856Slling * -H Scripted mode. Don't display headers, and separate properties 2387990b4856Slling * by a single tab. 2388990b4856Slling * -o List of properties to display. Defaults to 2389990b4856Slling * "name,size,used,available,capacity,health,altroot" 2390fa9e4066Sahrens * 2391fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 2392fa9e4066Sahrens * statistics for each one, as well as health status summary. 2393fa9e4066Sahrens */ 2394fa9e4066Sahrens int 2395fa9e4066Sahrens zpool_do_list(int argc, char **argv) 2396fa9e4066Sahrens { 2397fa9e4066Sahrens int c; 2398fa9e4066Sahrens int ret; 2399fa9e4066Sahrens list_cbdata_t cb = { 0 }; 2400990b4856Slling static char default_props[] = 2401990b4856Slling "name,size,used,available,capacity,health,altroot"; 2402990b4856Slling char *props = default_props; 2403fa9e4066Sahrens 2404fa9e4066Sahrens /* check options */ 2405fa9e4066Sahrens while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2406fa9e4066Sahrens switch (c) { 2407fa9e4066Sahrens case 'H': 240899653d4eSeschrock cb.cb_scripted = B_TRUE; 2409fa9e4066Sahrens break; 2410fa9e4066Sahrens case 'o': 2411990b4856Slling props = optarg; 2412fa9e4066Sahrens break; 2413fa9e4066Sahrens case ':': 2414fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2415fa9e4066Sahrens "'%c' option\n"), optopt); 241699653d4eSeschrock usage(B_FALSE); 2417fa9e4066Sahrens break; 2418fa9e4066Sahrens case '?': 2419fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2420fa9e4066Sahrens optopt); 242199653d4eSeschrock usage(B_FALSE); 2422fa9e4066Sahrens } 2423fa9e4066Sahrens } 2424fa9e4066Sahrens 2425fa9e4066Sahrens argc -= optind; 2426fa9e4066Sahrens argv += optind; 2427fa9e4066Sahrens 2428990b4856Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 242999653d4eSeschrock usage(B_FALSE); 2430fa9e4066Sahrens 243199653d4eSeschrock cb.cb_first = B_TRUE; 2432fa9e4066Sahrens 2433990b4856Slling ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2434990b4856Slling list_callback, &cb); 2435990b4856Slling 2436990b4856Slling zprop_free_list(cb.cb_proplist); 2437fa9e4066Sahrens 2438fce7d82bSmmusante if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2439fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 2440fa9e4066Sahrens return (0); 2441fa9e4066Sahrens } 2442fa9e4066Sahrens 2443fa9e4066Sahrens return (ret); 2444fa9e4066Sahrens } 2445fa9e4066Sahrens 2446fa9e4066Sahrens static nvlist_t * 2447fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name) 2448fa9e4066Sahrens { 2449fa9e4066Sahrens nvlist_t **child; 2450fa9e4066Sahrens uint_t c, children; 2451fa9e4066Sahrens nvlist_t *match; 2452fa9e4066Sahrens char *path; 2453fa9e4066Sahrens 2454fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2455fa9e4066Sahrens &child, &children) != 0) { 2456fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2457fa9e4066Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0) 2458fa9e4066Sahrens name += 9; 2459fa9e4066Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0) 2460fa9e4066Sahrens path += 9; 2461fa9e4066Sahrens if (strcmp(name, path) == 0) 2462fa9e4066Sahrens return (nv); 2463fa9e4066Sahrens return (NULL); 2464fa9e4066Sahrens } 2465fa9e4066Sahrens 2466fa9e4066Sahrens for (c = 0; c < children; c++) 2467fa9e4066Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2468fa9e4066Sahrens return (match); 2469fa9e4066Sahrens 2470fa9e4066Sahrens return (NULL); 2471fa9e4066Sahrens } 2472fa9e4066Sahrens 2473fa9e4066Sahrens static int 2474fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 2475fa9e4066Sahrens { 247699653d4eSeschrock boolean_t force = B_FALSE; 2477fa9e4066Sahrens int c; 2478fa9e4066Sahrens nvlist_t *nvroot; 2479fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 2480fa9e4066Sahrens zpool_handle_t *zhp; 248199653d4eSeschrock int ret; 2482fa9e4066Sahrens 2483fa9e4066Sahrens /* check options */ 2484fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2485fa9e4066Sahrens switch (c) { 2486fa9e4066Sahrens case 'f': 248799653d4eSeschrock force = B_TRUE; 2488fa9e4066Sahrens break; 2489fa9e4066Sahrens case '?': 2490fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2491fa9e4066Sahrens optopt); 249299653d4eSeschrock usage(B_FALSE); 2493fa9e4066Sahrens } 2494fa9e4066Sahrens } 2495fa9e4066Sahrens 2496fa9e4066Sahrens argc -= optind; 2497fa9e4066Sahrens argv += optind; 2498fa9e4066Sahrens 2499fa9e4066Sahrens /* get pool name and check number of arguments */ 2500fa9e4066Sahrens if (argc < 1) { 2501fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 250299653d4eSeschrock usage(B_FALSE); 2503fa9e4066Sahrens } 2504fa9e4066Sahrens 2505fa9e4066Sahrens poolname = argv[0]; 2506fa9e4066Sahrens 2507fa9e4066Sahrens if (argc < 2) { 2508fa9e4066Sahrens (void) fprintf(stderr, 2509fa9e4066Sahrens gettext("missing <device> specification\n")); 251099653d4eSeschrock usage(B_FALSE); 2511fa9e4066Sahrens } 2512fa9e4066Sahrens 2513fa9e4066Sahrens old_disk = argv[1]; 2514fa9e4066Sahrens 2515fa9e4066Sahrens if (argc < 3) { 2516fa9e4066Sahrens if (!replacing) { 2517fa9e4066Sahrens (void) fprintf(stderr, 2518fa9e4066Sahrens gettext("missing <new_device> specification\n")); 251999653d4eSeschrock usage(B_FALSE); 2520fa9e4066Sahrens } 2521fa9e4066Sahrens new_disk = old_disk; 2522fa9e4066Sahrens argc -= 1; 2523fa9e4066Sahrens argv += 1; 2524fa9e4066Sahrens } else { 2525fa9e4066Sahrens new_disk = argv[2]; 2526fa9e4066Sahrens argc -= 2; 2527fa9e4066Sahrens argv += 2; 2528fa9e4066Sahrens } 2529fa9e4066Sahrens 2530fa9e4066Sahrens if (argc > 1) { 2531fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 253299653d4eSeschrock usage(B_FALSE); 2533fa9e4066Sahrens } 2534fa9e4066Sahrens 253599653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2536fa9e4066Sahrens return (1); 2537fa9e4066Sahrens 25388488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 2539fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2540fa9e4066Sahrens poolname); 2541fa9e4066Sahrens zpool_close(zhp); 2542fa9e4066Sahrens return (1); 2543fa9e4066Sahrens } 2544fa9e4066Sahrens 2545705040edSEric Taylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 2546705040edSEric Taylor argc, argv); 2547fa9e4066Sahrens if (nvroot == NULL) { 2548fa9e4066Sahrens zpool_close(zhp); 2549fa9e4066Sahrens return (1); 2550fa9e4066Sahrens } 2551fa9e4066Sahrens 255299653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 255399653d4eSeschrock 255499653d4eSeschrock nvlist_free(nvroot); 255599653d4eSeschrock zpool_close(zhp); 255699653d4eSeschrock 255799653d4eSeschrock return (ret); 2558fa9e4066Sahrens } 2559fa9e4066Sahrens 2560fa9e4066Sahrens /* 2561fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 2562fa9e4066Sahrens * 2563fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2564fa9e4066Sahrens * 2565fa9e4066Sahrens * Replace <device> with <new_device>. 2566fa9e4066Sahrens */ 2567fa9e4066Sahrens /* ARGSUSED */ 2568fa9e4066Sahrens int 2569fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 2570fa9e4066Sahrens { 2571fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2572fa9e4066Sahrens } 2573fa9e4066Sahrens 2574fa9e4066Sahrens /* 2575fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 2576fa9e4066Sahrens * 2577fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2578fa9e4066Sahrens * 2579fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 2580fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 2581fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 2582fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 2583fa9e4066Sahrens */ 2584fa9e4066Sahrens int 2585fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 2586fa9e4066Sahrens { 2587fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2588fa9e4066Sahrens } 2589fa9e4066Sahrens 2590fa9e4066Sahrens /* 2591fa9e4066Sahrens * zpool detach [-f] <pool> <device> 2592fa9e4066Sahrens * 2593fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 2594fa9e4066Sahrens * (not supported yet) 2595fa9e4066Sahrens * 2596fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 2597fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 2598fa9e4066Sahrens * has the only valid copy of some data. 2599fa9e4066Sahrens */ 2600fa9e4066Sahrens /* ARGSUSED */ 2601fa9e4066Sahrens int 2602fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 2603fa9e4066Sahrens { 2604fa9e4066Sahrens int c; 2605fa9e4066Sahrens char *poolname, *path; 2606fa9e4066Sahrens zpool_handle_t *zhp; 260799653d4eSeschrock int ret; 2608fa9e4066Sahrens 2609fa9e4066Sahrens /* check options */ 2610fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2611fa9e4066Sahrens switch (c) { 2612fa9e4066Sahrens case 'f': 2613fa9e4066Sahrens case '?': 2614fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2615fa9e4066Sahrens optopt); 261699653d4eSeschrock usage(B_FALSE); 2617fa9e4066Sahrens } 2618fa9e4066Sahrens } 2619fa9e4066Sahrens 2620fa9e4066Sahrens argc -= optind; 2621fa9e4066Sahrens argv += optind; 2622fa9e4066Sahrens 2623fa9e4066Sahrens /* get pool name and check number of arguments */ 2624fa9e4066Sahrens if (argc < 1) { 2625fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 262699653d4eSeschrock usage(B_FALSE); 2627fa9e4066Sahrens } 2628fa9e4066Sahrens 2629fa9e4066Sahrens if (argc < 2) { 2630fa9e4066Sahrens (void) fprintf(stderr, 2631fa9e4066Sahrens gettext("missing <device> specification\n")); 263299653d4eSeschrock usage(B_FALSE); 2633fa9e4066Sahrens } 2634fa9e4066Sahrens 2635fa9e4066Sahrens poolname = argv[0]; 2636fa9e4066Sahrens path = argv[1]; 2637fa9e4066Sahrens 263899653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2639fa9e4066Sahrens return (1); 2640fa9e4066Sahrens 264199653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 264299653d4eSeschrock 264399653d4eSeschrock zpool_close(zhp); 264499653d4eSeschrock 264599653d4eSeschrock return (ret); 2646fa9e4066Sahrens } 2647fa9e4066Sahrens 2648fa9e4066Sahrens /* 2649441d80aaSlling * zpool online <pool> <device> ... 2650fa9e4066Sahrens */ 2651fa9e4066Sahrens int 2652fa9e4066Sahrens zpool_do_online(int argc, char **argv) 2653fa9e4066Sahrens { 2654fa9e4066Sahrens int c, i; 2655fa9e4066Sahrens char *poolname; 2656fa9e4066Sahrens zpool_handle_t *zhp; 2657fa9e4066Sahrens int ret = 0; 26583d7072f8Seschrock vdev_state_t newstate; 2659573ca77eSGeorge Wilson int flags = 0; 2660fa9e4066Sahrens 2661fa9e4066Sahrens /* check options */ 2662573ca77eSGeorge Wilson while ((c = getopt(argc, argv, "et")) != -1) { 2663fa9e4066Sahrens switch (c) { 2664573ca77eSGeorge Wilson case 'e': 2665573ca77eSGeorge Wilson flags |= ZFS_ONLINE_EXPAND; 2666573ca77eSGeorge Wilson break; 2667fa9e4066Sahrens case 't': 2668fa9e4066Sahrens case '?': 2669fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2670fa9e4066Sahrens optopt); 267199653d4eSeschrock usage(B_FALSE); 2672fa9e4066Sahrens } 2673fa9e4066Sahrens } 2674fa9e4066Sahrens 2675fa9e4066Sahrens argc -= optind; 2676fa9e4066Sahrens argv += optind; 2677fa9e4066Sahrens 2678fa9e4066Sahrens /* get pool name and check number of arguments */ 2679fa9e4066Sahrens if (argc < 1) { 2680fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 268199653d4eSeschrock usage(B_FALSE); 2682fa9e4066Sahrens } 2683fa9e4066Sahrens if (argc < 2) { 2684fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 268599653d4eSeschrock usage(B_FALSE); 2686fa9e4066Sahrens } 2687fa9e4066Sahrens 2688fa9e4066Sahrens poolname = argv[0]; 2689fa9e4066Sahrens 269099653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2691fa9e4066Sahrens return (1); 2692fa9e4066Sahrens 26933d7072f8Seschrock for (i = 1; i < argc; i++) { 2694573ca77eSGeorge Wilson if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 26953d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 26963d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 26973d7072f8Seschrock "onlined, but remains in faulted state\n"), 2698fa9e4066Sahrens argv[i]); 26993d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 27003d7072f8Seschrock (void) printf(gettext("use 'zpool " 27013d7072f8Seschrock "clear' to restore a faulted " 27023d7072f8Seschrock "device\n")); 2703fa9e4066Sahrens else 27043d7072f8Seschrock (void) printf(gettext("use 'zpool " 27053d7072f8Seschrock "replace' to replace devices " 27063d7072f8Seschrock "that are no longer present\n")); 27073d7072f8Seschrock } 27083d7072f8Seschrock } else { 2709fa9e4066Sahrens ret = 1; 27103d7072f8Seschrock } 27113d7072f8Seschrock } 2712fa9e4066Sahrens 271399653d4eSeschrock zpool_close(zhp); 271499653d4eSeschrock 2715fa9e4066Sahrens return (ret); 2716fa9e4066Sahrens } 2717fa9e4066Sahrens 2718fa9e4066Sahrens /* 2719441d80aaSlling * zpool offline [-ft] <pool> <device> ... 2720fa9e4066Sahrens * 2721fa9e4066Sahrens * -f Force the device into the offline state, even if doing 2722fa9e4066Sahrens * so would appear to compromise pool availability. 2723fa9e4066Sahrens * (not supported yet) 2724fa9e4066Sahrens * 2725fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 2726fa9e4066Sahrens * state will not be persistent across reboots. 2727fa9e4066Sahrens */ 2728fa9e4066Sahrens /* ARGSUSED */ 2729fa9e4066Sahrens int 2730fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 2731fa9e4066Sahrens { 2732fa9e4066Sahrens int c, i; 2733fa9e4066Sahrens char *poolname; 2734fa9e4066Sahrens zpool_handle_t *zhp; 273599653d4eSeschrock int ret = 0; 273699653d4eSeschrock boolean_t istmp = B_FALSE; 2737fa9e4066Sahrens 2738fa9e4066Sahrens /* check options */ 2739fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 2740fa9e4066Sahrens switch (c) { 2741fa9e4066Sahrens case 't': 274299653d4eSeschrock istmp = B_TRUE; 2743441d80aaSlling break; 2744441d80aaSlling case 'f': 2745fa9e4066Sahrens case '?': 2746fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2747fa9e4066Sahrens optopt); 274899653d4eSeschrock usage(B_FALSE); 2749fa9e4066Sahrens } 2750fa9e4066Sahrens } 2751fa9e4066Sahrens 2752fa9e4066Sahrens argc -= optind; 2753fa9e4066Sahrens argv += optind; 2754fa9e4066Sahrens 2755fa9e4066Sahrens /* get pool name and check number of arguments */ 2756fa9e4066Sahrens if (argc < 1) { 2757fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 275899653d4eSeschrock usage(B_FALSE); 2759fa9e4066Sahrens } 2760fa9e4066Sahrens if (argc < 2) { 2761fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 276299653d4eSeschrock usage(B_FALSE); 2763fa9e4066Sahrens } 2764fa9e4066Sahrens 2765fa9e4066Sahrens poolname = argv[0]; 2766fa9e4066Sahrens 276799653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2768fa9e4066Sahrens return (1); 2769fa9e4066Sahrens 27703d7072f8Seschrock for (i = 1; i < argc; i++) { 27713d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2772fa9e4066Sahrens ret = 1; 27733d7072f8Seschrock } 2774fa9e4066Sahrens 277599653d4eSeschrock zpool_close(zhp); 277699653d4eSeschrock 2777fa9e4066Sahrens return (ret); 2778fa9e4066Sahrens } 2779fa9e4066Sahrens 2780ea8dc4b6Seschrock /* 2781ea8dc4b6Seschrock * zpool clear <pool> [device] 2782ea8dc4b6Seschrock * 2783ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 2784ea8dc4b6Seschrock */ 2785ea8dc4b6Seschrock int 2786ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 2787ea8dc4b6Seschrock { 2788ea8dc4b6Seschrock int ret = 0; 2789ea8dc4b6Seschrock zpool_handle_t *zhp; 2790ea8dc4b6Seschrock char *pool, *device; 2791ea8dc4b6Seschrock 2792ea8dc4b6Seschrock if (argc < 2) { 2793ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 279499653d4eSeschrock usage(B_FALSE); 2795ea8dc4b6Seschrock } 2796ea8dc4b6Seschrock 2797ea8dc4b6Seschrock if (argc > 3) { 2798ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 279999653d4eSeschrock usage(B_FALSE); 2800ea8dc4b6Seschrock } 2801ea8dc4b6Seschrock 2802ea8dc4b6Seschrock pool = argv[1]; 2803ea8dc4b6Seschrock device = argc == 3 ? argv[2] : NULL; 2804ea8dc4b6Seschrock 2805b87f3af3Sperrin if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 2806ea8dc4b6Seschrock return (1); 2807ea8dc4b6Seschrock 2808ea8dc4b6Seschrock if (zpool_clear(zhp, device) != 0) 2809ea8dc4b6Seschrock ret = 1; 2810ea8dc4b6Seschrock 2811ea8dc4b6Seschrock zpool_close(zhp); 2812ea8dc4b6Seschrock 2813ea8dc4b6Seschrock return (ret); 2814ea8dc4b6Seschrock } 2815ea8dc4b6Seschrock 2816fa9e4066Sahrens typedef struct scrub_cbdata { 2817fa9e4066Sahrens int cb_type; 281806eeb2adSek110237 int cb_argc; 281906eeb2adSek110237 char **cb_argv; 2820fa9e4066Sahrens } scrub_cbdata_t; 2821fa9e4066Sahrens 2822fa9e4066Sahrens int 2823fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 2824fa9e4066Sahrens { 2825fa9e4066Sahrens scrub_cbdata_t *cb = data; 282606eeb2adSek110237 int err; 2827fa9e4066Sahrens 2828ea8dc4b6Seschrock /* 2829ea8dc4b6Seschrock * Ignore faulted pools. 2830ea8dc4b6Seschrock */ 2831ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2832ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2833ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 2834ea8dc4b6Seschrock return (1); 2835ea8dc4b6Seschrock } 2836ea8dc4b6Seschrock 283706eeb2adSek110237 err = zpool_scrub(zhp, cb->cb_type); 283806eeb2adSek110237 283906eeb2adSek110237 return (err != 0); 2840fa9e4066Sahrens } 2841fa9e4066Sahrens 2842fa9e4066Sahrens /* 2843fa9e4066Sahrens * zpool scrub [-s] <pool> ... 2844fa9e4066Sahrens * 2845fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 2846fa9e4066Sahrens */ 2847fa9e4066Sahrens int 2848fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 2849fa9e4066Sahrens { 2850fa9e4066Sahrens int c; 2851fa9e4066Sahrens scrub_cbdata_t cb; 2852fa9e4066Sahrens 2853fa9e4066Sahrens cb.cb_type = POOL_SCRUB_EVERYTHING; 2854fa9e4066Sahrens 2855fa9e4066Sahrens /* check options */ 2856fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 2857fa9e4066Sahrens switch (c) { 2858fa9e4066Sahrens case 's': 2859fa9e4066Sahrens cb.cb_type = POOL_SCRUB_NONE; 2860fa9e4066Sahrens break; 2861fa9e4066Sahrens case '?': 2862fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2863fa9e4066Sahrens optopt); 286499653d4eSeschrock usage(B_FALSE); 2865fa9e4066Sahrens } 2866fa9e4066Sahrens } 2867fa9e4066Sahrens 286806eeb2adSek110237 cb.cb_argc = argc; 286906eeb2adSek110237 cb.cb_argv = argv; 2870fa9e4066Sahrens argc -= optind; 2871fa9e4066Sahrens argv += optind; 2872fa9e4066Sahrens 2873fa9e4066Sahrens if (argc < 1) { 2874fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 287599653d4eSeschrock usage(B_FALSE); 2876fa9e4066Sahrens } 2877fa9e4066Sahrens 2878b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2879fa9e4066Sahrens } 2880fa9e4066Sahrens 2881fa9e4066Sahrens typedef struct status_cbdata { 2882fa9e4066Sahrens int cb_count; 2883e9dbad6fSeschrock boolean_t cb_allpools; 288499653d4eSeschrock boolean_t cb_verbose; 288599653d4eSeschrock boolean_t cb_explain; 288699653d4eSeschrock boolean_t cb_first; 2887fa9e4066Sahrens } status_cbdata_t; 2888fa9e4066Sahrens 2889fa9e4066Sahrens /* 2890fa9e4066Sahrens * Print out detailed scrub status. 2891fa9e4066Sahrens */ 2892fa9e4066Sahrens void 2893fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot) 2894fa9e4066Sahrens { 2895fa9e4066Sahrens vdev_stat_t *vs; 2896fa9e4066Sahrens uint_t vsc; 2897fa9e4066Sahrens time_t start, end, now; 2898fa9e4066Sahrens double fraction_done; 289918ce54dfSek110237 uint64_t examined, total, minutes_left, minutes_taken; 2900fa9e4066Sahrens char *scrub_type; 2901fa9e4066Sahrens 2902fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2903fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 2904fa9e4066Sahrens 2905fa9e4066Sahrens /* 2906fa9e4066Sahrens * If there's never been a scrub, there's not much to say. 2907fa9e4066Sahrens */ 2908fa9e4066Sahrens if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2909fa9e4066Sahrens (void) printf(gettext("none requested\n")); 2910fa9e4066Sahrens return; 2911fa9e4066Sahrens } 2912fa9e4066Sahrens 2913fa9e4066Sahrens scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2914fa9e4066Sahrens "resilver" : "scrub"; 2915fa9e4066Sahrens 2916fa9e4066Sahrens start = vs->vs_scrub_start; 2917fa9e4066Sahrens end = vs->vs_scrub_end; 2918fa9e4066Sahrens now = time(NULL); 2919fa9e4066Sahrens examined = vs->vs_scrub_examined; 2920fa9e4066Sahrens total = vs->vs_alloc; 2921fa9e4066Sahrens 2922fa9e4066Sahrens if (end != 0) { 292318ce54dfSek110237 minutes_taken = (uint64_t)((end - start) / 60); 292418ce54dfSek110237 292518ce54dfSek110237 (void) printf(gettext("%s %s after %lluh%um with %llu errors " 292618ce54dfSek110237 "on %s"), 2927fa9e4066Sahrens scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 292818ce54dfSek110237 (u_longlong_t)(minutes_taken / 60), 292918ce54dfSek110237 (uint_t)(minutes_taken % 60), 2930fa9e4066Sahrens (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2931fa9e4066Sahrens return; 2932fa9e4066Sahrens } 2933fa9e4066Sahrens 2934fa9e4066Sahrens if (examined == 0) 2935fa9e4066Sahrens examined = 1; 2936fa9e4066Sahrens if (examined > total) 2937fa9e4066Sahrens total = examined; 2938fa9e4066Sahrens 2939fa9e4066Sahrens fraction_done = (double)examined / total; 2940fa9e4066Sahrens minutes_left = (uint64_t)((now - start) * 2941fa9e4066Sahrens (1 - fraction_done) / fraction_done / 60); 294218ce54dfSek110237 minutes_taken = (uint64_t)((now - start) / 60); 2943fa9e4066Sahrens 294418ce54dfSek110237 (void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, " 294518ce54dfSek110237 "%lluh%um to go\n"), 294618ce54dfSek110237 scrub_type, (u_longlong_t)(minutes_taken / 60), 294718ce54dfSek110237 (uint_t)(minutes_taken % 60), 100 * fraction_done, 2948fa9e4066Sahrens (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2949fa9e4066Sahrens } 2950fa9e4066Sahrens 2951ea8dc4b6Seschrock static void 2952ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 2953ea8dc4b6Seschrock { 295475519f38Sek110237 nvlist_t *nverrlist = NULL; 295555434c77Sek110237 nvpair_t *elem; 295655434c77Sek110237 char *pathname; 295755434c77Sek110237 size_t len = MAXPATHLEN * 2; 2958ea8dc4b6Seschrock 295955434c77Sek110237 if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2960ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 2961ea8dc4b6Seschrock "(insufficient privileges)\n"); 2962ea8dc4b6Seschrock return; 2963ea8dc4b6Seschrock } 2964ea8dc4b6Seschrock 296555434c77Sek110237 (void) printf("errors: Permanent errors have been " 296655434c77Sek110237 "detected in the following files:\n\n"); 2967ea8dc4b6Seschrock 296855434c77Sek110237 pathname = safe_malloc(len); 296955434c77Sek110237 elem = NULL; 297055434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 297155434c77Sek110237 nvlist_t *nv; 297255434c77Sek110237 uint64_t dsobj, obj; 2973ea8dc4b6Seschrock 297455434c77Sek110237 verify(nvpair_value_nvlist(elem, &nv) == 0); 297555434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 297655434c77Sek110237 &dsobj) == 0); 297755434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 297855434c77Sek110237 &obj) == 0); 297955434c77Sek110237 zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 298055434c77Sek110237 (void) printf("%7s %s\n", "", pathname); 2981ea8dc4b6Seschrock } 298255434c77Sek110237 free(pathname); 298355434c77Sek110237 nvlist_free(nverrlist); 2984ea8dc4b6Seschrock } 2985ea8dc4b6Seschrock 298699653d4eSeschrock static void 298799653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 298899653d4eSeschrock int namewidth) 298999653d4eSeschrock { 299099653d4eSeschrock uint_t i; 299199653d4eSeschrock char *name; 299299653d4eSeschrock 299399653d4eSeschrock if (nspares == 0) 299499653d4eSeschrock return; 299599653d4eSeschrock 299699653d4eSeschrock (void) printf(gettext("\tspares\n")); 299799653d4eSeschrock 299899653d4eSeschrock for (i = 0; i < nspares; i++) { 299999653d4eSeschrock name = zpool_vdev_name(g_zfs, zhp, spares[i]); 300099653d4eSeschrock print_status_config(zhp, name, spares[i], 3001aa8cf21aSNeil Perrin namewidth, 2, B_TRUE); 300299653d4eSeschrock free(name); 300399653d4eSeschrock } 300499653d4eSeschrock } 300599653d4eSeschrock 3006fa94a07fSbrendan static void 3007fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 3008fa94a07fSbrendan int namewidth) 3009fa94a07fSbrendan { 3010fa94a07fSbrendan uint_t i; 3011fa94a07fSbrendan char *name; 3012fa94a07fSbrendan 3013fa94a07fSbrendan if (nl2cache == 0) 3014fa94a07fSbrendan return; 3015fa94a07fSbrendan 3016fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 3017fa94a07fSbrendan 3018fa94a07fSbrendan for (i = 0; i < nl2cache; i++) { 3019fa94a07fSbrendan name = zpool_vdev_name(g_zfs, zhp, l2cache[i]); 3020fa94a07fSbrendan print_status_config(zhp, name, l2cache[i], 3021aa8cf21aSNeil Perrin namewidth, 2, B_FALSE); 3022aa8cf21aSNeil Perrin free(name); 3023aa8cf21aSNeil Perrin } 3024aa8cf21aSNeil Perrin } 3025aa8cf21aSNeil Perrin 3026aa8cf21aSNeil Perrin /* 3027fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 3028fa9e4066Sahrens * 3029fa9e4066Sahrens * pool: tank 3030fa9e4066Sahrens * status: DEGRADED 3031fa9e4066Sahrens * reason: One or more devices ... 3032fa9e4066Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01 3033fa9e4066Sahrens * config: 3034fa9e4066Sahrens * mirror DEGRADED 3035fa9e4066Sahrens * c1t0d0 OK 3036ea8dc4b6Seschrock * c2t0d0 UNAVAIL 3037fa9e4066Sahrens * 3038fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 3039fa9e4066Sahrens * option is specified, then we print out error rate information as well. 3040fa9e4066Sahrens */ 3041fa9e4066Sahrens int 3042fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 3043fa9e4066Sahrens { 3044fa9e4066Sahrens status_cbdata_t *cbp = data; 3045fa9e4066Sahrens nvlist_t *config, *nvroot; 3046fa9e4066Sahrens char *msgid; 3047fa9e4066Sahrens int reason; 304846657f8dSmmusante const char *health; 304946657f8dSmmusante uint_t c; 305046657f8dSmmusante vdev_stat_t *vs; 3051fa9e4066Sahrens 3052088e9d47Seschrock config = zpool_get_config(zhp, NULL); 3053fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 3054fa9e4066Sahrens 3055fa9e4066Sahrens cbp->cb_count++; 3056fa9e4066Sahrens 3057fa9e4066Sahrens /* 3058fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 3059fa9e4066Sahrens * problems. 3060fa9e4066Sahrens */ 3061e9dbad6fSeschrock if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 3062e9dbad6fSeschrock if (!cbp->cb_allpools) { 3063e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 3064e9dbad6fSeschrock zpool_get_name(zhp)); 3065e9dbad6fSeschrock if (cbp->cb_first) 3066e9dbad6fSeschrock cbp->cb_first = B_FALSE; 3067e9dbad6fSeschrock } 3068fa9e4066Sahrens return (0); 3069e9dbad6fSeschrock } 3070fa9e4066Sahrens 3071fa9e4066Sahrens if (cbp->cb_first) 307299653d4eSeschrock cbp->cb_first = B_FALSE; 3073fa9e4066Sahrens else 3074fa9e4066Sahrens (void) printf("\n"); 3075fa9e4066Sahrens 307646657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 307746657f8dSmmusante &nvroot) == 0); 307846657f8dSmmusante verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 307946657f8dSmmusante (uint64_t **)&vs, &c) == 0); 3080990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 3081fa9e4066Sahrens 3082fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 3083fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 3084fa9e4066Sahrens 3085fa9e4066Sahrens switch (reason) { 3086fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 3087fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3088fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 3089fa9e4066Sahrens "continue functioning in a degraded state.\n")); 3090fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 3091fa9e4066Sahrens "online it using 'zpool online'.\n")); 3092fa9e4066Sahrens break; 3093fa9e4066Sahrens 3094fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 3095fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3096fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 3097fa9e4066Sahrens "pool to continue functioning.\n")); 3098fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 3099fa9e4066Sahrens "online it using 'zpool online'.\n")); 3100fa9e4066Sahrens break; 3101fa9e4066Sahrens 3102fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 3103fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3104fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 3105fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 3106fa9e4066Sahrens "functioning in a degraded state.\n")); 3107fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 3108fa9e4066Sahrens "'zpool replace'.\n")); 3109fa9e4066Sahrens break; 3110fa9e4066Sahrens 3111fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 3112fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 3113b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 3114fa9e4066Sahrens "There are insufficient replicas for the pool to " 3115fa9e4066Sahrens "continue\n\tfunctioning.\n")); 3116fa9e4066Sahrens (void) printf(gettext("action: Destroy and re-create the pool " 3117fa9e4066Sahrens "from a backup source.\n")); 3118fa9e4066Sahrens break; 3119fa9e4066Sahrens 3120fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 3121fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 3122fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 3123fa9e4066Sahrens "made to correct the error. Applications are " 3124fa9e4066Sahrens "unaffected.\n")); 3125fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 3126fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 3127ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 3128fa9e4066Sahrens "replace'.\n")); 3129fa9e4066Sahrens break; 3130fa9e4066Sahrens 3131fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 3132fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 3133d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 3134fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 3135fa9e4066Sahrens "a\n\tdegraded state.\n")); 3136fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 3137fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 3138fa9e4066Sahrens "replace'.\n")); 3139fa9e4066Sahrens break; 3140fa9e4066Sahrens 3141c25309d4SGeorge Wilson case ZPOOL_STATUS_REMOVED_DEV: 3142c25309d4SGeorge Wilson (void) printf(gettext("status: One or more devices has " 3143c25309d4SGeorge Wilson "been removed by the administrator.\n\tSufficient " 3144c25309d4SGeorge Wilson "replicas exist for the pool to continue functioning in " 3145c25309d4SGeorge Wilson "a\n\tdegraded state.\n")); 3146c25309d4SGeorge Wilson (void) printf(gettext("action: Online the device using " 3147c25309d4SGeorge Wilson "'zpool online' or replace the device with\n\t'zpool " 3148c25309d4SGeorge Wilson "replace'.\n")); 3149c25309d4SGeorge Wilson break; 3150c25309d4SGeorge Wilson 3151c25309d4SGeorge Wilson 3152fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 3153fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 3154fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 3155fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 3156fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 3157fa9e4066Sahrens "complete.\n")); 3158fa9e4066Sahrens break; 3159fa9e4066Sahrens 3160ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 3161ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 3162ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 3163ea8dc4b6Seschrock "Applications may be affected.\n")); 3164ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 3165ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 3166ea8dc4b6Seschrock "backup.\n")); 3167ea8dc4b6Seschrock break; 3168ea8dc4b6Seschrock 3169ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 3170ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 3171ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 3172ea8dc4b6Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 3173ea8dc4b6Seschrock "from a backup source.\n")); 3174ea8dc4b6Seschrock break; 3175ea8dc4b6Seschrock 3176eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 3177eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 3178eaca9bbdSeschrock "older on-disk format. The pool can\n\tstill be used, but " 3179eaca9bbdSeschrock "some features are unavailable.\n")); 3180eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 3181eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 3182eaca9bbdSeschrock "be accessible on older software versions.\n")); 3183eaca9bbdSeschrock break; 3184eaca9bbdSeschrock 3185eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 3186eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 3187eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 3188eaca9bbdSeschrock "be accessed on this system.\n")); 3189eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 3190eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 3191eaca9bbdSeschrock "backup.\n")); 3192eaca9bbdSeschrock break; 3193eaca9bbdSeschrock 31943d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 31953d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 31963d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 31973d7072f8Seschrock "replicas exist for the pool to continue functioning " 31983d7072f8Seschrock "in a\n\tdegraded state.\n")); 31993d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 32003d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 32013d7072f8Seschrock break; 32023d7072f8Seschrock 32033d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 32043d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 32053d7072f8Seschrock "faulted in response to persistent errors. There are " 32063d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 32073d7072f8Seschrock "functioning.\n")); 32083d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 32093d7072f8Seschrock "from a backup source. Manually marking the device\n" 32103d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 32113d7072f8Seschrock "to be recovered.\n")); 32123d7072f8Seschrock break; 32133d7072f8Seschrock 321432b87932Sek110237 case ZPOOL_STATUS_IO_FAILURE_WAIT: 321532b87932Sek110237 case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 321632b87932Sek110237 (void) printf(gettext("status: One or more devices are " 32178a79c1b5Sek110237 "faulted in response to IO failures.\n")); 321832b87932Sek110237 (void) printf(gettext("action: Make sure the affected devices " 321932b87932Sek110237 "are connected, then run 'zpool clear'.\n")); 322032b87932Sek110237 break; 322132b87932Sek110237 3222b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 3223b87f3af3Sperrin (void) printf(gettext("status: An intent log record " 3224b87f3af3Sperrin "could not be read.\n" 3225b87f3af3Sperrin "\tWaiting for adminstrator intervention to fix the " 3226b87f3af3Sperrin "faulted pool.\n")); 3227b87f3af3Sperrin (void) printf(gettext("action: Either restore the affected " 3228b87f3af3Sperrin "device(s) and run 'zpool online',\n" 3229b87f3af3Sperrin "\tor ignore the intent log records by running " 3230b87f3af3Sperrin "'zpool clear'.\n")); 3231b87f3af3Sperrin break; 3232b87f3af3Sperrin 3233fa9e4066Sahrens default: 3234fa9e4066Sahrens /* 3235fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 3236fa9e4066Sahrens */ 3237fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 3238fa9e4066Sahrens } 3239fa9e4066Sahrens 3240fa9e4066Sahrens if (msgid != NULL) 3241fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3242fa9e4066Sahrens msgid); 3243fa9e4066Sahrens 3244fa9e4066Sahrens if (config != NULL) { 3245fa9e4066Sahrens int namewidth; 3246ea8dc4b6Seschrock uint64_t nerr; 3247fa94a07fSbrendan nvlist_t **spares, **l2cache; 3248fa94a07fSbrendan uint_t nspares, nl2cache; 3249fa9e4066Sahrens 3250fa9e4066Sahrens 3251fa9e4066Sahrens (void) printf(gettext(" scrub: ")); 3252fa9e4066Sahrens print_scrub_status(nvroot); 3253fa9e4066Sahrens 3254c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 3255fa9e4066Sahrens if (namewidth < 10) 3256fa9e4066Sahrens namewidth = 10; 3257fa9e4066Sahrens 3258fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 3259fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3260fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3261c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 3262aa8cf21aSNeil Perrin namewidth, 0, B_FALSE); 326399653d4eSeschrock 32644dea40f0SNeil Perrin if (num_logs(nvroot) > 0) 3265e6ca193dSGeorge Wilson print_logs(zhp, nvroot, namewidth, B_TRUE); 3266fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 3267fa94a07fSbrendan &l2cache, &nl2cache) == 0) 3268fa94a07fSbrendan print_l2cache(zhp, l2cache, nl2cache, namewidth); 3269fa94a07fSbrendan 327099653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 327199653d4eSeschrock &spares, &nspares) == 0) 327299653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 3273ea8dc4b6Seschrock 3274ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3275ea8dc4b6Seschrock &nerr) == 0) { 327655434c77Sek110237 nvlist_t *nverrlist = NULL; 327755434c77Sek110237 3278ea8dc4b6Seschrock /* 3279ea8dc4b6Seschrock * If the approximate error count is small, get a 3280ea8dc4b6Seschrock * precise count by fetching the entire log and 3281ea8dc4b6Seschrock * uniquifying the results. 3282ea8dc4b6Seschrock */ 328375519f38Sek110237 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 328455434c77Sek110237 zpool_get_errlog(zhp, &nverrlist) == 0) { 328555434c77Sek110237 nvpair_t *elem; 328655434c77Sek110237 328755434c77Sek110237 elem = NULL; 328855434c77Sek110237 nerr = 0; 328955434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, 329055434c77Sek110237 elem)) != NULL) { 329155434c77Sek110237 nerr++; 329255434c77Sek110237 } 329355434c77Sek110237 } 329455434c77Sek110237 nvlist_free(nverrlist); 3295ea8dc4b6Seschrock 3296ea8dc4b6Seschrock (void) printf("\n"); 329799653d4eSeschrock 3298ea8dc4b6Seschrock if (nerr == 0) 3299ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 3300ea8dc4b6Seschrock "errors\n")); 3301ea8dc4b6Seschrock else if (!cbp->cb_verbose) 3302e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 33035ad82045Snd150628 "errors, use '-v' for a list\n"), 33045ad82045Snd150628 (u_longlong_t)nerr); 3305ea8dc4b6Seschrock else 3306ea8dc4b6Seschrock print_error_log(zhp); 3307ea8dc4b6Seschrock } 3308fa9e4066Sahrens } else { 3309fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 3310fa9e4066Sahrens "determined.\n")); 3311fa9e4066Sahrens } 3312fa9e4066Sahrens 3313fa9e4066Sahrens return (0); 3314fa9e4066Sahrens } 3315fa9e4066Sahrens 3316fa9e4066Sahrens /* 3317fa9e4066Sahrens * zpool status [-vx] [pool] ... 3318fa9e4066Sahrens * 3319fa9e4066Sahrens * -v Display complete error logs 3320fa9e4066Sahrens * -x Display only pools with potential problems 3321fa9e4066Sahrens * 3322fa9e4066Sahrens * Describes the health status of all pools or some subset. 3323fa9e4066Sahrens */ 3324fa9e4066Sahrens int 3325fa9e4066Sahrens zpool_do_status(int argc, char **argv) 3326fa9e4066Sahrens { 3327fa9e4066Sahrens int c; 3328fa9e4066Sahrens int ret; 3329fa9e4066Sahrens status_cbdata_t cb = { 0 }; 3330fa9e4066Sahrens 3331fa9e4066Sahrens /* check options */ 3332fa9e4066Sahrens while ((c = getopt(argc, argv, "vx")) != -1) { 3333fa9e4066Sahrens switch (c) { 3334fa9e4066Sahrens case 'v': 333599653d4eSeschrock cb.cb_verbose = B_TRUE; 3336fa9e4066Sahrens break; 3337fa9e4066Sahrens case 'x': 333899653d4eSeschrock cb.cb_explain = B_TRUE; 3339fa9e4066Sahrens break; 3340fa9e4066Sahrens case '?': 3341fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3342fa9e4066Sahrens optopt); 334399653d4eSeschrock usage(B_FALSE); 3344fa9e4066Sahrens } 3345fa9e4066Sahrens } 3346fa9e4066Sahrens 3347fa9e4066Sahrens argc -= optind; 3348fa9e4066Sahrens argv += optind; 3349fa9e4066Sahrens 335099653d4eSeschrock cb.cb_first = B_TRUE; 3351fa9e4066Sahrens 3352e9dbad6fSeschrock if (argc == 0) 3353e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 3354e9dbad6fSeschrock 3355b1b8ab34Slling ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3356fa9e4066Sahrens 3357fa9e4066Sahrens if (argc == 0 && cb.cb_count == 0) 3358fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 3359e9dbad6fSeschrock else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3360fa9e4066Sahrens (void) printf(gettext("all pools are healthy\n")); 3361fa9e4066Sahrens 3362fa9e4066Sahrens return (ret); 3363fa9e4066Sahrens } 3364fa9e4066Sahrens 3365eaca9bbdSeschrock typedef struct upgrade_cbdata { 3366eaca9bbdSeschrock int cb_all; 3367eaca9bbdSeschrock int cb_first; 3368eaca9bbdSeschrock int cb_newer; 336906eeb2adSek110237 int cb_argc; 3370990b4856Slling uint64_t cb_version; 337106eeb2adSek110237 char **cb_argv; 3372eaca9bbdSeschrock } upgrade_cbdata_t; 3373eaca9bbdSeschrock 3374eaca9bbdSeschrock static int 3375eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 3376eaca9bbdSeschrock { 3377eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 3378eaca9bbdSeschrock nvlist_t *config; 3379eaca9bbdSeschrock uint64_t version; 3380eaca9bbdSeschrock int ret = 0; 3381eaca9bbdSeschrock 3382eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 3383eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3384eaca9bbdSeschrock &version) == 0); 3385eaca9bbdSeschrock 3386e7437265Sahrens if (!cbp->cb_newer && version < SPA_VERSION) { 3387eaca9bbdSeschrock if (!cbp->cb_all) { 3388eaca9bbdSeschrock if (cbp->cb_first) { 3389eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3390eaca9bbdSeschrock "out of date, and can be upgraded. After " 3391eaca9bbdSeschrock "being\nupgraded, these pools will no " 3392eaca9bbdSeschrock "longer be accessible by older software " 3393eaca9bbdSeschrock "versions.\n\n")); 3394eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3395eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 339699653d4eSeschrock cbp->cb_first = B_FALSE; 3397eaca9bbdSeschrock } 3398eaca9bbdSeschrock 33995ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3400eaca9bbdSeschrock zpool_get_name(zhp)); 3401eaca9bbdSeschrock } else { 340299653d4eSeschrock cbp->cb_first = B_FALSE; 3403990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 340406eeb2adSek110237 if (!ret) { 3405eaca9bbdSeschrock (void) printf(gettext("Successfully upgraded " 3406990b4856Slling "'%s'\n\n"), zpool_get_name(zhp)); 3407eaca9bbdSeschrock } 340806eeb2adSek110237 } 3409e7437265Sahrens } else if (cbp->cb_newer && version > SPA_VERSION) { 3410eaca9bbdSeschrock assert(!cbp->cb_all); 3411eaca9bbdSeschrock 3412eaca9bbdSeschrock if (cbp->cb_first) { 3413eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3414eaca9bbdSeschrock "formatted using a newer software version and\n" 3415eaca9bbdSeschrock "cannot be accessed on the current system.\n\n")); 3416eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3417eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 341899653d4eSeschrock cbp->cb_first = B_FALSE; 3419eaca9bbdSeschrock } 3420eaca9bbdSeschrock 34215ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3422eaca9bbdSeschrock zpool_get_name(zhp)); 3423eaca9bbdSeschrock } 3424eaca9bbdSeschrock 3425eaca9bbdSeschrock zpool_close(zhp); 3426eaca9bbdSeschrock return (ret); 3427eaca9bbdSeschrock } 3428eaca9bbdSeschrock 3429eaca9bbdSeschrock /* ARGSUSED */ 3430eaca9bbdSeschrock static int 343106eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data) 3432eaca9bbdSeschrock { 3433990b4856Slling upgrade_cbdata_t *cbp = data; 3434990b4856Slling uint64_t cur_version; 3435eaca9bbdSeschrock int ret; 3436eaca9bbdSeschrock 34378654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 34388654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 34398654d025Sperrin "Pool 'log' must be renamed using export and import" 34408654d025Sperrin " to upgrade.\n")); 34418654d025Sperrin return (1); 34428654d025Sperrin } 3443990b4856Slling 3444990b4856Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 3445e6c728e1Sbrendan if (cur_version > cbp->cb_version) { 3446eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 3447e6c728e1Sbrendan "using more current version '%llu'.\n"), 3448e6c728e1Sbrendan zpool_get_name(zhp), cur_version); 3449e6c728e1Sbrendan return (0); 3450e6c728e1Sbrendan } 3451e6c728e1Sbrendan if (cur_version == cbp->cb_version) { 3452e6c728e1Sbrendan (void) printf(gettext("Pool '%s' is already formatted " 3453e6c728e1Sbrendan "using the current version.\n"), zpool_get_name(zhp)); 3454eaca9bbdSeschrock return (0); 3455eaca9bbdSeschrock } 3456eaca9bbdSeschrock 3457990b4856Slling ret = zpool_upgrade(zhp, cbp->cb_version); 345806eeb2adSek110237 345906eeb2adSek110237 if (!ret) { 346044cd46caSbillm (void) printf(gettext("Successfully upgraded '%s' " 3461990b4856Slling "from version %llu to version %llu\n\n"), 3462990b4856Slling zpool_get_name(zhp), (u_longlong_t)cur_version, 3463990b4856Slling (u_longlong_t)cbp->cb_version); 346406eeb2adSek110237 } 3465eaca9bbdSeschrock 3466eaca9bbdSeschrock return (ret != 0); 3467eaca9bbdSeschrock } 3468eaca9bbdSeschrock 3469eaca9bbdSeschrock /* 3470eaca9bbdSeschrock * zpool upgrade 3471eaca9bbdSeschrock * zpool upgrade -v 3472990b4856Slling * zpool upgrade [-V version] <-a | pool ...> 3473eaca9bbdSeschrock * 3474eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 3475eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 3476eaca9bbdSeschrock * upgrade all pools. 3477eaca9bbdSeschrock */ 3478eaca9bbdSeschrock int 3479eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 3480eaca9bbdSeschrock { 3481eaca9bbdSeschrock int c; 3482eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 3483eaca9bbdSeschrock int ret = 0; 3484eaca9bbdSeschrock boolean_t showversions = B_FALSE; 3485990b4856Slling char *end; 3486990b4856Slling 3487eaca9bbdSeschrock 3488eaca9bbdSeschrock /* check options */ 3489478ed9adSEric Taylor while ((c = getopt(argc, argv, ":avV:")) != -1) { 3490eaca9bbdSeschrock switch (c) { 3491eaca9bbdSeschrock case 'a': 349299653d4eSeschrock cb.cb_all = B_TRUE; 3493eaca9bbdSeschrock break; 3494eaca9bbdSeschrock case 'v': 3495eaca9bbdSeschrock showversions = B_TRUE; 3496eaca9bbdSeschrock break; 3497990b4856Slling case 'V': 3498990b4856Slling cb.cb_version = strtoll(optarg, &end, 10); 3499351420b3Slling if (*end != '\0' || cb.cb_version > SPA_VERSION || 3500351420b3Slling cb.cb_version < SPA_VERSION_1) { 3501990b4856Slling (void) fprintf(stderr, 3502990b4856Slling gettext("invalid version '%s'\n"), optarg); 3503990b4856Slling usage(B_FALSE); 3504990b4856Slling } 3505990b4856Slling break; 3506478ed9adSEric Taylor case ':': 3507478ed9adSEric Taylor (void) fprintf(stderr, gettext("missing argument for " 3508478ed9adSEric Taylor "'%c' option\n"), optopt); 3509478ed9adSEric Taylor usage(B_FALSE); 3510478ed9adSEric Taylor break; 3511eaca9bbdSeschrock case '?': 3512eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3513eaca9bbdSeschrock optopt); 351499653d4eSeschrock usage(B_FALSE); 3515eaca9bbdSeschrock } 3516eaca9bbdSeschrock } 3517eaca9bbdSeschrock 351806eeb2adSek110237 cb.cb_argc = argc; 351906eeb2adSek110237 cb.cb_argv = argv; 3520eaca9bbdSeschrock argc -= optind; 3521eaca9bbdSeschrock argv += optind; 3522eaca9bbdSeschrock 3523351420b3Slling if (cb.cb_version == 0) { 3524351420b3Slling cb.cb_version = SPA_VERSION; 3525351420b3Slling } else if (!cb.cb_all && argc == 0) { 3526351420b3Slling (void) fprintf(stderr, gettext("-V option is " 3527351420b3Slling "incompatible with other arguments\n")); 3528351420b3Slling usage(B_FALSE); 3529351420b3Slling } 3530351420b3Slling 3531eaca9bbdSeschrock if (showversions) { 3532eaca9bbdSeschrock if (cb.cb_all || argc != 0) { 3533eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 3534eaca9bbdSeschrock "incompatible with other arguments\n")); 353599653d4eSeschrock usage(B_FALSE); 3536eaca9bbdSeschrock } 3537eaca9bbdSeschrock } else if (cb.cb_all) { 3538eaca9bbdSeschrock if (argc != 0) { 3539351420b3Slling (void) fprintf(stderr, gettext("-a option should not " 3540351420b3Slling "be used along with a pool name\n")); 354199653d4eSeschrock usage(B_FALSE); 3542eaca9bbdSeschrock } 3543eaca9bbdSeschrock } 3544eaca9bbdSeschrock 3545e7437265Sahrens (void) printf(gettext("This system is currently running " 3546e7437265Sahrens "ZFS pool version %llu.\n\n"), SPA_VERSION); 354799653d4eSeschrock cb.cb_first = B_TRUE; 3548eaca9bbdSeschrock if (showversions) { 3549eaca9bbdSeschrock (void) printf(gettext("The following versions are " 3550d7d4af51Smmusante "supported:\n\n")); 3551eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 3552eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 3553eaca9bbdSeschrock "---------------\n"); 355499653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 355544cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 355644cd46caSbillm "(replicated metadata)\n")); 355799653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 355899653d4eSeschrock "RAID-Z\n")); 3559d7306b64Sek110237 (void) printf(gettext(" 4 zpool history\n")); 3560c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 3561c9431fa1Sahl "algorithm\n")); 3562990b4856Slling (void) printf(gettext(" 6 bootfs pool property\n")); 35638654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 3564ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 3565a9799022Sck153898 (void) printf(gettext(" 9 refquota and refreservation " 3566a9799022Sck153898 "properties\n")); 3567fa94a07fSbrendan (void) printf(gettext(" 10 Cache devices\n")); 3568088f3894Sahrens (void) printf(gettext(" 11 Improved scrub performance\n")); 3569bb0ade09Sahrens (void) printf(gettext(" 12 Snapshot properties\n")); 357074e7dc98SMatthew Ahrens (void) printf(gettext(" 13 snapused property\n")); 357114843421SMatthew Ahrens (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 357214843421SMatthew Ahrens (void) printf(gettext(" 15 user/group space accounting\n")); 3573478ed9adSEric Taylor (void) printf(gettext(" 16 stmf property support\n")); 35747aeab329SAdam Leventhal (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 3575842727c2SChris Kirby (void) printf(gettext(" 18 snapshot user holds\n")); 35768654d025Sperrin (void) printf(gettext("For more information on a particular " 3577eaca9bbdSeschrock "version, including supported releases, see:\n\n")); 3578eaca9bbdSeschrock (void) printf("http://www.opensolaris.org/os/community/zfs/" 3579eaca9bbdSeschrock "version/N\n\n"); 3580eaca9bbdSeschrock (void) printf(gettext("Where 'N' is the version number.\n")); 3581eaca9bbdSeschrock } else if (argc == 0) { 3582eaca9bbdSeschrock int notfound; 3583eaca9bbdSeschrock 358499653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3585eaca9bbdSeschrock notfound = cb.cb_first; 3586eaca9bbdSeschrock 3587eaca9bbdSeschrock if (!cb.cb_all && ret == 0) { 3588eaca9bbdSeschrock if (!cb.cb_first) 3589eaca9bbdSeschrock (void) printf("\n"); 3590eaca9bbdSeschrock cb.cb_first = B_TRUE; 3591eaca9bbdSeschrock cb.cb_newer = B_TRUE; 359299653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3593eaca9bbdSeschrock if (!cb.cb_first) { 3594eaca9bbdSeschrock notfound = B_FALSE; 3595eaca9bbdSeschrock (void) printf("\n"); 3596eaca9bbdSeschrock } 3597eaca9bbdSeschrock } 3598eaca9bbdSeschrock 3599eaca9bbdSeschrock if (ret == 0) { 3600eaca9bbdSeschrock if (notfound) 3601eaca9bbdSeschrock (void) printf(gettext("All pools are formatted " 3602eaca9bbdSeschrock "using this version.\n")); 3603eaca9bbdSeschrock else if (!cb.cb_all) 3604eaca9bbdSeschrock (void) printf(gettext("Use 'zpool upgrade -v' " 3605eaca9bbdSeschrock "for a list of available versions and " 3606eaca9bbdSeschrock "their associated\nfeatures.\n")); 3607eaca9bbdSeschrock } 3608eaca9bbdSeschrock } else { 3609b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 3610b1b8ab34Slling upgrade_one, &cb); 361106eeb2adSek110237 } 361206eeb2adSek110237 361306eeb2adSek110237 return (ret); 361406eeb2adSek110237 } 361506eeb2adSek110237 3616ecd6cf80Smarks typedef struct hist_cbdata { 3617ecd6cf80Smarks boolean_t first; 3618ecd6cf80Smarks int longfmt; 3619ecd6cf80Smarks int internal; 3620ecd6cf80Smarks } hist_cbdata_t; 3621ecd6cf80Smarks 3622ecd6cf80Smarks char *hist_event_table[LOG_END] = { 3623ecd6cf80Smarks "invalid event", 3624ecd6cf80Smarks "pool create", 3625ecd6cf80Smarks "vdev add", 3626ecd6cf80Smarks "pool remove", 3627ecd6cf80Smarks "pool destroy", 3628ecd6cf80Smarks "pool export", 3629ecd6cf80Smarks "pool import", 3630ecd6cf80Smarks "vdev attach", 3631ecd6cf80Smarks "vdev replace", 3632ecd6cf80Smarks "vdev detach", 3633ecd6cf80Smarks "vdev online", 3634ecd6cf80Smarks "vdev offline", 3635ecd6cf80Smarks "vdev upgrade", 3636ecd6cf80Smarks "pool clear", 3637ecd6cf80Smarks "pool scrub", 3638ecd6cf80Smarks "pool property set", 3639ecd6cf80Smarks "create", 3640ecd6cf80Smarks "clone", 3641ecd6cf80Smarks "destroy", 3642ecd6cf80Smarks "destroy_begin_sync", 3643ecd6cf80Smarks "inherit", 3644ecd6cf80Smarks "property set", 3645ecd6cf80Smarks "quota set", 3646ecd6cf80Smarks "permission update", 3647ecd6cf80Smarks "permission remove", 3648ecd6cf80Smarks "permission who remove", 3649ecd6cf80Smarks "promote", 3650ecd6cf80Smarks "receive", 3651ecd6cf80Smarks "rename", 3652ecd6cf80Smarks "reservation set", 3653ecd6cf80Smarks "replay_inc_sync", 3654ecd6cf80Smarks "replay_full_sync", 3655ecd6cf80Smarks "rollback", 3656ecd6cf80Smarks "snapshot", 3657e7437265Sahrens "filesystem version upgrade", 3658a9799022Sck153898 "refquota set", 3659a9799022Sck153898 "refreservation set", 3660088f3894Sahrens "pool scrub done", 3661842727c2SChris Kirby "user hold", 3662842727c2SChris Kirby "user release", 3663ecd6cf80Smarks }; 3664ecd6cf80Smarks 366506eeb2adSek110237 /* 366606eeb2adSek110237 * Print out the command history for a specific pool. 366706eeb2adSek110237 */ 366806eeb2adSek110237 static int 366906eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data) 367006eeb2adSek110237 { 367106eeb2adSek110237 nvlist_t *nvhis; 367206eeb2adSek110237 nvlist_t **records; 367306eeb2adSek110237 uint_t numrecords; 367406eeb2adSek110237 char *cmdstr; 3675ecd6cf80Smarks char *pathstr; 367606eeb2adSek110237 uint64_t dst_time; 367706eeb2adSek110237 time_t tsec; 367806eeb2adSek110237 struct tm t; 367906eeb2adSek110237 char tbuf[30]; 368006eeb2adSek110237 int ret, i; 3681ecd6cf80Smarks uint64_t who; 3682ecd6cf80Smarks struct passwd *pwd; 3683ecd6cf80Smarks char *hostname; 3684ecd6cf80Smarks char *zonename; 3685ecd6cf80Smarks char internalstr[MAXPATHLEN]; 3686ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 3687ecd6cf80Smarks uint64_t txg; 3688ecd6cf80Smarks uint64_t ievent; 368906eeb2adSek110237 3690ecd6cf80Smarks cb->first = B_FALSE; 369106eeb2adSek110237 369206eeb2adSek110237 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 369306eeb2adSek110237 369406eeb2adSek110237 if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 369506eeb2adSek110237 return (ret); 369606eeb2adSek110237 369706eeb2adSek110237 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 369806eeb2adSek110237 &records, &numrecords) == 0); 369906eeb2adSek110237 for (i = 0; i < numrecords; i++) { 370006eeb2adSek110237 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3701ecd6cf80Smarks &dst_time) != 0) 3702ecd6cf80Smarks continue; 3703ecd6cf80Smarks 3704ecd6cf80Smarks /* is it an internal event or a standard event? */ 3705ecd6cf80Smarks if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3706ecd6cf80Smarks &cmdstr) != 0) { 3707ecd6cf80Smarks if (cb->internal == 0) 3708ecd6cf80Smarks continue; 3709ecd6cf80Smarks 3710ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3711ecd6cf80Smarks ZPOOL_HIST_INT_EVENT, &ievent) != 0) 3712ecd6cf80Smarks continue; 3713ecd6cf80Smarks verify(nvlist_lookup_uint64(records[i], 3714ecd6cf80Smarks ZPOOL_HIST_TXG, &txg) == 0); 3715ecd6cf80Smarks verify(nvlist_lookup_string(records[i], 3716ecd6cf80Smarks ZPOOL_HIST_INT_STR, &pathstr) == 0); 3717088f3894Sahrens if (ievent >= LOG_END) 3718ecd6cf80Smarks continue; 3719ecd6cf80Smarks (void) snprintf(internalstr, 3720ecd6cf80Smarks sizeof (internalstr), 3721ecd6cf80Smarks "[internal %s txg:%lld] %s", 3722ecd6cf80Smarks hist_event_table[ievent], txg, 3723ecd6cf80Smarks pathstr); 3724ecd6cf80Smarks cmdstr = internalstr; 3725ecd6cf80Smarks } 372606eeb2adSek110237 tsec = dst_time; 372706eeb2adSek110237 (void) localtime_r(&tsec, &t); 372806eeb2adSek110237 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3729ecd6cf80Smarks (void) printf("%s %s", tbuf, cmdstr); 3730ecd6cf80Smarks 3731ecd6cf80Smarks if (!cb->longfmt) { 3732ecd6cf80Smarks (void) printf("\n"); 3733ecd6cf80Smarks continue; 373406eeb2adSek110237 } 3735ecd6cf80Smarks (void) printf(" ["); 3736ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3737ecd6cf80Smarks ZPOOL_HIST_WHO, &who) == 0) { 3738ecd6cf80Smarks pwd = getpwuid((uid_t)who); 3739ecd6cf80Smarks if (pwd) 3740ecd6cf80Smarks (void) printf("user %s on", 3741ecd6cf80Smarks pwd->pw_name); 3742ecd6cf80Smarks else 3743ecd6cf80Smarks (void) printf("user %d on", 3744ecd6cf80Smarks (int)who); 3745ecd6cf80Smarks } else { 3746ecd6cf80Smarks (void) printf(gettext("no info]\n")); 3747ecd6cf80Smarks continue; 3748ecd6cf80Smarks } 3749ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3750ecd6cf80Smarks ZPOOL_HIST_HOST, &hostname) == 0) { 3751ecd6cf80Smarks (void) printf(" %s", hostname); 3752ecd6cf80Smarks } 3753ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3754ecd6cf80Smarks ZPOOL_HIST_ZONE, &zonename) == 0) { 3755ecd6cf80Smarks (void) printf(":%s", zonename); 3756ecd6cf80Smarks } 3757ecd6cf80Smarks 3758ecd6cf80Smarks (void) printf("]"); 3759ecd6cf80Smarks (void) printf("\n"); 376006eeb2adSek110237 } 376106eeb2adSek110237 (void) printf("\n"); 376206eeb2adSek110237 nvlist_free(nvhis); 376306eeb2adSek110237 376406eeb2adSek110237 return (ret); 376506eeb2adSek110237 } 376606eeb2adSek110237 376706eeb2adSek110237 /* 376806eeb2adSek110237 * zpool history <pool> 376906eeb2adSek110237 * 377006eeb2adSek110237 * Displays the history of commands that modified pools. 377106eeb2adSek110237 */ 3772ecd6cf80Smarks 3773ecd6cf80Smarks 377406eeb2adSek110237 int 377506eeb2adSek110237 zpool_do_history(int argc, char **argv) 377606eeb2adSek110237 { 3777ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 377806eeb2adSek110237 int ret; 3779ecd6cf80Smarks int c; 378006eeb2adSek110237 3781ecd6cf80Smarks cbdata.first = B_TRUE; 3782ecd6cf80Smarks /* check options */ 3783ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 3784ecd6cf80Smarks switch (c) { 3785ecd6cf80Smarks case 'l': 3786ecd6cf80Smarks cbdata.longfmt = 1; 3787ecd6cf80Smarks break; 3788ecd6cf80Smarks case 'i': 3789ecd6cf80Smarks cbdata.internal = 1; 3790ecd6cf80Smarks break; 3791ecd6cf80Smarks case '?': 3792ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3793ecd6cf80Smarks optopt); 3794ecd6cf80Smarks usage(B_FALSE); 3795ecd6cf80Smarks } 3796ecd6cf80Smarks } 379706eeb2adSek110237 argc -= optind; 379806eeb2adSek110237 argv += optind; 379906eeb2adSek110237 3800b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3801ecd6cf80Smarks &cbdata); 380206eeb2adSek110237 3803ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 380406eeb2adSek110237 (void) printf(gettext("no pools available\n")); 380506eeb2adSek110237 return (0); 3806eaca9bbdSeschrock } 3807eaca9bbdSeschrock 3808eaca9bbdSeschrock return (ret); 3809eaca9bbdSeschrock } 3810eaca9bbdSeschrock 3811b1b8ab34Slling static int 3812b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 3813b1b8ab34Slling { 3814990b4856Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 3815b1b8ab34Slling char value[MAXNAMELEN]; 3816990b4856Slling zprop_source_t srctype; 3817990b4856Slling zprop_list_t *pl; 3818b1b8ab34Slling 3819b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3820b1b8ab34Slling 3821b1b8ab34Slling /* 3822990b4856Slling * Skip the special fake placeholder. This will also skip 3823990b4856Slling * over the name property when 'all' is specified. 3824b1b8ab34Slling */ 3825990b4856Slling if (pl->pl_prop == ZPOOL_PROP_NAME && 3826b1b8ab34Slling pl == cbp->cb_proplist) 3827b1b8ab34Slling continue; 3828b1b8ab34Slling 3829b1b8ab34Slling if (zpool_get_prop(zhp, pl->pl_prop, 3830b1b8ab34Slling value, sizeof (value), &srctype) != 0) 3831b1b8ab34Slling continue; 3832b1b8ab34Slling 3833990b4856Slling zprop_print_one_property(zpool_get_name(zhp), cbp, 3834b1b8ab34Slling zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3835b1b8ab34Slling } 3836b1b8ab34Slling return (0); 3837b1b8ab34Slling } 3838b1b8ab34Slling 3839b1b8ab34Slling int 3840b1b8ab34Slling zpool_do_get(int argc, char **argv) 3841b1b8ab34Slling { 3842990b4856Slling zprop_get_cbdata_t cb = { 0 }; 3843990b4856Slling zprop_list_t fake_name = { 0 }; 3844b1b8ab34Slling int ret; 3845b1b8ab34Slling 3846b1b8ab34Slling if (argc < 3) 3847b1b8ab34Slling usage(B_FALSE); 3848b1b8ab34Slling 3849b1b8ab34Slling cb.cb_first = B_TRUE; 3850990b4856Slling cb.cb_sources = ZPROP_SRC_ALL; 3851b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 3852b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 3853b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 3854b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 3855990b4856Slling cb.cb_type = ZFS_TYPE_POOL; 3856b1b8ab34Slling 3857990b4856Slling if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 3858990b4856Slling ZFS_TYPE_POOL) != 0) 3859b1b8ab34Slling usage(B_FALSE); 3860b1b8ab34Slling 3861b1b8ab34Slling if (cb.cb_proplist != NULL) { 3862990b4856Slling fake_name.pl_prop = ZPOOL_PROP_NAME; 3863b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 3864b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 3865b1b8ab34Slling cb.cb_proplist = &fake_name; 3866b1b8ab34Slling } 3867b1b8ab34Slling 3868b1b8ab34Slling ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3869b1b8ab34Slling get_callback, &cb); 3870b1b8ab34Slling 3871b1b8ab34Slling if (cb.cb_proplist == &fake_name) 3872990b4856Slling zprop_free_list(fake_name.pl_next); 3873b1b8ab34Slling else 3874990b4856Slling zprop_free_list(cb.cb_proplist); 3875b1b8ab34Slling 3876b1b8ab34Slling return (ret); 3877b1b8ab34Slling } 3878b1b8ab34Slling 3879b1b8ab34Slling typedef struct set_cbdata { 3880b1b8ab34Slling char *cb_propname; 3881b1b8ab34Slling char *cb_value; 3882b1b8ab34Slling boolean_t cb_any_successful; 3883b1b8ab34Slling } set_cbdata_t; 3884b1b8ab34Slling 3885b1b8ab34Slling int 3886b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 3887b1b8ab34Slling { 3888b1b8ab34Slling int error; 3889b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 3890b1b8ab34Slling 3891b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3892b1b8ab34Slling 3893b1b8ab34Slling if (!error) 3894b1b8ab34Slling cb->cb_any_successful = B_TRUE; 3895b1b8ab34Slling 3896b1b8ab34Slling return (error); 3897b1b8ab34Slling } 3898b1b8ab34Slling 3899b1b8ab34Slling int 3900b1b8ab34Slling zpool_do_set(int argc, char **argv) 3901b1b8ab34Slling { 3902b1b8ab34Slling set_cbdata_t cb = { 0 }; 3903b1b8ab34Slling int error; 3904b1b8ab34Slling 3905b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 3906b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3907b1b8ab34Slling argv[1][1]); 3908b1b8ab34Slling usage(B_FALSE); 3909b1b8ab34Slling } 3910b1b8ab34Slling 3911b1b8ab34Slling if (argc < 2) { 3912b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 3913b1b8ab34Slling "argument\n")); 3914b1b8ab34Slling usage(B_FALSE); 3915b1b8ab34Slling } 3916b1b8ab34Slling 3917b1b8ab34Slling if (argc < 3) { 3918b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 3919b1b8ab34Slling usage(B_FALSE); 3920b1b8ab34Slling } 3921b1b8ab34Slling 3922b1b8ab34Slling if (argc > 3) { 3923b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 3924b1b8ab34Slling usage(B_FALSE); 3925b1b8ab34Slling } 3926b1b8ab34Slling 3927b1b8ab34Slling cb.cb_propname = argv[1]; 3928b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 3929b1b8ab34Slling if (cb.cb_value == NULL) { 3930b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 3931b1b8ab34Slling "property=value argument\n")); 3932b1b8ab34Slling usage(B_FALSE); 3933b1b8ab34Slling } 3934b1b8ab34Slling 3935b1b8ab34Slling *(cb.cb_value) = '\0'; 3936b1b8ab34Slling cb.cb_value++; 3937b1b8ab34Slling 3938b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3939b1b8ab34Slling set_callback, &cb); 3940b1b8ab34Slling 3941b1b8ab34Slling return (error); 3942b1b8ab34Slling } 3943b1b8ab34Slling 3944b1b8ab34Slling static int 3945b1b8ab34Slling find_command_idx(char *command, int *idx) 3946b1b8ab34Slling { 3947b1b8ab34Slling int i; 3948b1b8ab34Slling 3949b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 3950b1b8ab34Slling if (command_table[i].name == NULL) 3951b1b8ab34Slling continue; 3952b1b8ab34Slling 3953b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 3954b1b8ab34Slling *idx = i; 3955b1b8ab34Slling return (0); 3956b1b8ab34Slling } 3957b1b8ab34Slling } 3958b1b8ab34Slling return (1); 3959b1b8ab34Slling } 3960b1b8ab34Slling 3961fa9e4066Sahrens int 3962fa9e4066Sahrens main(int argc, char **argv) 3963fa9e4066Sahrens { 3964fa9e4066Sahrens int ret; 3965fa9e4066Sahrens int i; 3966fa9e4066Sahrens char *cmdname; 3967fa9e4066Sahrens 3968fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 3969fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 3970fa9e4066Sahrens 397199653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 397299653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 3973203a47d8Snd150628 "initialize ZFS library\n")); 397499653d4eSeschrock return (1); 397599653d4eSeschrock } 397699653d4eSeschrock 397799653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 397899653d4eSeschrock 3979fa9e4066Sahrens opterr = 0; 3980fa9e4066Sahrens 3981fa9e4066Sahrens /* 3982fa9e4066Sahrens * Make sure the user has specified some command. 3983fa9e4066Sahrens */ 3984fa9e4066Sahrens if (argc < 2) { 3985fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 398699653d4eSeschrock usage(B_FALSE); 3987fa9e4066Sahrens } 3988fa9e4066Sahrens 3989fa9e4066Sahrens cmdname = argv[1]; 3990fa9e4066Sahrens 3991fa9e4066Sahrens /* 3992fa9e4066Sahrens * Special case '-?' 3993fa9e4066Sahrens */ 3994fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 399599653d4eSeschrock usage(B_TRUE); 3996fa9e4066Sahrens 39972a6b87f0Sek110237 zpool_set_history_str("zpool", argc, argv, history_str); 39982a6b87f0Sek110237 verify(zpool_stage_history(g_zfs, history_str) == 0); 39992a6b87f0Sek110237 4000fa9e4066Sahrens /* 4001fa9e4066Sahrens * Run the appropriate command. 4002fa9e4066Sahrens */ 4003b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 4004fa9e4066Sahrens current_command = &command_table[i]; 4005fa9e4066Sahrens ret = command_table[i].func(argc - 1, argv + 1); 400691ebeef5Sahrens } else if (strchr(cmdname, '=')) { 400791ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 400891ebeef5Sahrens current_command = &command_table[i]; 400991ebeef5Sahrens ret = command_table[i].func(argc, argv); 401091ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 4011fa9e4066Sahrens /* 401291ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 401391ebeef5Sahrens * it as such. 4014fa9e4066Sahrens */ 4015ea8dc4b6Seschrock char buf[16384]; 4016ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 4017fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 4018fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 401991ebeef5Sahrens } else { 4020fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 4021fa9e4066Sahrens "command '%s'\n"), cmdname); 402299653d4eSeschrock usage(B_FALSE); 4023fa9e4066Sahrens } 4024fa9e4066Sahrens 402599653d4eSeschrock libzfs_fini(g_zfs); 402699653d4eSeschrock 4027fa9e4066Sahrens /* 4028fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 4029fa9e4066Sahrens * for the purposes of running ::findleaks. 4030fa9e4066Sahrens */ 4031fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 4032fa9e4066Sahrens (void) printf("dumping core by request\n"); 4033fa9e4066Sahrens abort(); 4034fa9e4066Sahrens } 4035fa9e4066Sahrens 4036fa9e4066Sahrens return (ret); 4037fa9e4066Sahrens } 4038