1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 2199653d4eSeschrock 22fa9e4066Sahrens /* 2339c23413Seschrock * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29fa9e4066Sahrens #include <assert.h> 30fa9e4066Sahrens #include <ctype.h> 31fa9e4066Sahrens #include <dirent.h> 32fa9e4066Sahrens #include <errno.h> 33fa9e4066Sahrens #include <fcntl.h> 34fa9e4066Sahrens #include <libgen.h> 35fa9e4066Sahrens #include <libintl.h> 36fa9e4066Sahrens #include <libuutil.h> 37fa9e4066Sahrens #include <locale.h> 38fa9e4066Sahrens #include <stdio.h> 39fa9e4066Sahrens #include <stdlib.h> 40fa9e4066Sahrens #include <string.h> 41fa9e4066Sahrens #include <strings.h> 42fa9e4066Sahrens #include <unistd.h> 43fa9e4066Sahrens #include <priv.h> 44ecd6cf80Smarks #include <pwd.h> 45ecd6cf80Smarks #include <zone.h> 46b1b8ab34Slling #include <sys/fs/zfs.h> 47fa9e4066Sahrens 48fa9e4066Sahrens #include <sys/stat.h> 49fa9e4066Sahrens 50fa9e4066Sahrens #include <libzfs.h> 51fa9e4066Sahrens 52fa9e4066Sahrens #include "zpool_util.h" 53fa9e4066Sahrens 54fa9e4066Sahrens static int zpool_do_create(int, char **); 55fa9e4066Sahrens static int zpool_do_destroy(int, char **); 56fa9e4066Sahrens 57fa9e4066Sahrens static int zpool_do_add(int, char **); 5899653d4eSeschrock static int zpool_do_remove(int, char **); 59fa9e4066Sahrens 60fa9e4066Sahrens static int zpool_do_list(int, char **); 61fa9e4066Sahrens static int zpool_do_iostat(int, char **); 62fa9e4066Sahrens static int zpool_do_status(int, char **); 63fa9e4066Sahrens 64fa9e4066Sahrens static int zpool_do_online(int, char **); 65fa9e4066Sahrens static int zpool_do_offline(int, char **); 66ea8dc4b6Seschrock static int zpool_do_clear(int, char **); 67fa9e4066Sahrens 68fa9e4066Sahrens static int zpool_do_attach(int, char **); 69fa9e4066Sahrens static int zpool_do_detach(int, char **); 70fa9e4066Sahrens static int zpool_do_replace(int, char **); 71fa9e4066Sahrens 72fa9e4066Sahrens static int zpool_do_scrub(int, char **); 73fa9e4066Sahrens 74fa9e4066Sahrens static int zpool_do_import(int, char **); 75fa9e4066Sahrens static int zpool_do_export(int, char **); 76fa9e4066Sahrens 77eaca9bbdSeschrock static int zpool_do_upgrade(int, char **); 78eaca9bbdSeschrock 7906eeb2adSek110237 static int zpool_do_history(int, char **); 8006eeb2adSek110237 81b1b8ab34Slling static int zpool_do_get(int, char **); 82b1b8ab34Slling static int zpool_do_set(int, char **); 83b1b8ab34Slling 84fa9e4066Sahrens /* 85fa9e4066Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 86fa9e4066Sahrens * debugging facilities. 87fa9e4066Sahrens */ 88fa9e4066Sahrens const char * 8999653d4eSeschrock _umem_debug_init(void) 90fa9e4066Sahrens { 91fa9e4066Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 92fa9e4066Sahrens } 93fa9e4066Sahrens 94fa9e4066Sahrens const char * 95fa9e4066Sahrens _umem_logging_init(void) 96fa9e4066Sahrens { 97fa9e4066Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 98fa9e4066Sahrens } 99fa9e4066Sahrens 10065cd9f28Seschrock typedef enum { 10165cd9f28Seschrock HELP_ADD, 10265cd9f28Seschrock HELP_ATTACH, 103ea8dc4b6Seschrock HELP_CLEAR, 10465cd9f28Seschrock HELP_CREATE, 10565cd9f28Seschrock HELP_DESTROY, 10665cd9f28Seschrock HELP_DETACH, 10765cd9f28Seschrock HELP_EXPORT, 10806eeb2adSek110237 HELP_HISTORY, 10965cd9f28Seschrock HELP_IMPORT, 11065cd9f28Seschrock HELP_IOSTAT, 11165cd9f28Seschrock HELP_LIST, 11265cd9f28Seschrock HELP_OFFLINE, 11365cd9f28Seschrock HELP_ONLINE, 11465cd9f28Seschrock HELP_REPLACE, 11599653d4eSeschrock HELP_REMOVE, 11665cd9f28Seschrock HELP_SCRUB, 117eaca9bbdSeschrock HELP_STATUS, 118b1b8ab34Slling HELP_UPGRADE, 119b1b8ab34Slling HELP_GET, 120b1b8ab34Slling HELP_SET 12165cd9f28Seschrock } zpool_help_t; 12265cd9f28Seschrock 12365cd9f28Seschrock 124fa9e4066Sahrens typedef struct zpool_command { 125fa9e4066Sahrens const char *name; 126fa9e4066Sahrens int (*func)(int, char **); 12765cd9f28Seschrock zpool_help_t usage; 128fa9e4066Sahrens } zpool_command_t; 129fa9e4066Sahrens 130fa9e4066Sahrens /* 131fa9e4066Sahrens * Master command table. Each ZFS command has a name, associated function, and 132ea8dc4b6Seschrock * usage message. The usage messages need to be internationalized, so we have 133ea8dc4b6Seschrock * to have a function to return the usage message based on a command index. 13465cd9f28Seschrock * 13565cd9f28Seschrock * These commands are organized according to how they are displayed in the usage 13665cd9f28Seschrock * message. An empty command (one with a NULL name) indicates an empty line in 13765cd9f28Seschrock * the generic usage message. 138fa9e4066Sahrens */ 139fa9e4066Sahrens static zpool_command_t command_table[] = { 14065cd9f28Seschrock { "create", zpool_do_create, HELP_CREATE }, 14165cd9f28Seschrock { "destroy", zpool_do_destroy, HELP_DESTROY }, 142fa9e4066Sahrens { NULL }, 14365cd9f28Seschrock { "add", zpool_do_add, HELP_ADD }, 14499653d4eSeschrock { "remove", zpool_do_remove, HELP_REMOVE }, 145fa9e4066Sahrens { NULL }, 14665cd9f28Seschrock { "list", zpool_do_list, HELP_LIST }, 14765cd9f28Seschrock { "iostat", zpool_do_iostat, HELP_IOSTAT }, 14865cd9f28Seschrock { "status", zpool_do_status, HELP_STATUS }, 149fa9e4066Sahrens { NULL }, 15065cd9f28Seschrock { "online", zpool_do_online, HELP_ONLINE }, 15165cd9f28Seschrock { "offline", zpool_do_offline, HELP_OFFLINE }, 152ea8dc4b6Seschrock { "clear", zpool_do_clear, HELP_CLEAR }, 153fa9e4066Sahrens { NULL }, 15465cd9f28Seschrock { "attach", zpool_do_attach, HELP_ATTACH }, 15565cd9f28Seschrock { "detach", zpool_do_detach, HELP_DETACH }, 15665cd9f28Seschrock { "replace", zpool_do_replace, HELP_REPLACE }, 157fa9e4066Sahrens { NULL }, 15865cd9f28Seschrock { "scrub", zpool_do_scrub, HELP_SCRUB }, 159fa9e4066Sahrens { NULL }, 16065cd9f28Seschrock { "import", zpool_do_import, HELP_IMPORT }, 16165cd9f28Seschrock { "export", zpool_do_export, HELP_EXPORT }, 16206eeb2adSek110237 { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 16306eeb2adSek110237 { NULL }, 164b1b8ab34Slling { "history", zpool_do_history, HELP_HISTORY }, 165b1b8ab34Slling { "get", zpool_do_get, HELP_GET }, 166b1b8ab34Slling { "set", zpool_do_set, HELP_SET }, 167fa9e4066Sahrens }; 168fa9e4066Sahrens 169fa9e4066Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 170fa9e4066Sahrens 171fa9e4066Sahrens zpool_command_t *current_command; 172fa9e4066Sahrens 17365cd9f28Seschrock static const char * 17465cd9f28Seschrock get_usage(zpool_help_t idx) { 17565cd9f28Seschrock switch (idx) { 17665cd9f28Seschrock case HELP_ADD: 17765cd9f28Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 17865cd9f28Seschrock case HELP_ATTACH: 17965cd9f28Seschrock return (gettext("\tattach [-f] <pool> <device> " 180*e45ce728Sahrens "<new-device>\n")); 181ea8dc4b6Seschrock case HELP_CLEAR: 182ea8dc4b6Seschrock return (gettext("\tclear <pool> [device]\n")); 18365cd9f28Seschrock case HELP_CREATE: 18465cd9f28Seschrock return (gettext("\tcreate [-fn] [-R root] [-m mountpoint] " 18565cd9f28Seschrock "<pool> <vdev> ...\n")); 18665cd9f28Seschrock case HELP_DESTROY: 18765cd9f28Seschrock return (gettext("\tdestroy [-f] <pool>\n")); 18865cd9f28Seschrock case HELP_DETACH: 18965cd9f28Seschrock return (gettext("\tdetach <pool> <device>\n")); 19065cd9f28Seschrock case HELP_EXPORT: 19165cd9f28Seschrock return (gettext("\texport [-f] <pool> ...\n")); 19206eeb2adSek110237 case HELP_HISTORY: 193ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 19465cd9f28Seschrock case HELP_IMPORT: 1954c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 196ecd6cf80Smarks "\timport [-p property=value] [-d dir] [-D] [-f] " 197ecd6cf80Smarks "[-o opts] [-R root] -a\n" 198ecd6cf80Smarks "\timport [-p property=value] [-d dir] [-D] [-f] \n" 199ecd6cf80Smarks "\t [-o opts] [-R root ] <pool | id> [newpool]\n")); 20065cd9f28Seschrock case HELP_IOSTAT: 20165cd9f28Seschrock return (gettext("\tiostat [-v] [pool] ... [interval " 20265cd9f28Seschrock "[count]]\n")); 20365cd9f28Seschrock case HELP_LIST: 204*e45ce728Sahrens return (gettext("\tlist [-H] [-o field[,...]] [pool] ...\n")); 20565cd9f28Seschrock case HELP_OFFLINE: 206441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 20765cd9f28Seschrock case HELP_ONLINE: 208441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 20965cd9f28Seschrock case HELP_REPLACE: 21065cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 211*e45ce728Sahrens "[new-device]\n")); 21299653d4eSeschrock case HELP_REMOVE: 21399653d4eSeschrock return (gettext("\tremove <pool> <device>\n")); 21465cd9f28Seschrock case HELP_SCRUB: 21565cd9f28Seschrock return (gettext("\tscrub [-s] <pool> ...\n")); 21665cd9f28Seschrock case HELP_STATUS: 21765cd9f28Seschrock return (gettext("\tstatus [-vx] [pool] ...\n")); 218eaca9bbdSeschrock case HELP_UPGRADE: 219eaca9bbdSeschrock return (gettext("\tupgrade\n" 220eaca9bbdSeschrock "\tupgrade -v\n" 221eaca9bbdSeschrock "\tupgrade <-a | pool>\n")); 222b1b8ab34Slling case HELP_GET: 223*e45ce728Sahrens return (gettext("\tget <\"all\" | property[,...]> " 224b1b8ab34Slling "<pool> ...\n")); 225b1b8ab34Slling case HELP_SET: 226b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 22765cd9f28Seschrock } 22865cd9f28Seschrock 22965cd9f28Seschrock abort(); 23065cd9f28Seschrock /* NOTREACHED */ 23165cd9f28Seschrock } 23265cd9f28Seschrock 233fa9e4066Sahrens /* 234fa9e4066Sahrens * Fields available for 'zpool list'. 235fa9e4066Sahrens */ 236fa9e4066Sahrens typedef enum { 237fa9e4066Sahrens ZPOOL_FIELD_NAME, 238fa9e4066Sahrens ZPOOL_FIELD_SIZE, 239fa9e4066Sahrens ZPOOL_FIELD_USED, 240fa9e4066Sahrens ZPOOL_FIELD_AVAILABLE, 241fa9e4066Sahrens ZPOOL_FIELD_CAPACITY, 242fa9e4066Sahrens ZPOOL_FIELD_HEALTH, 243fa9e4066Sahrens ZPOOL_FIELD_ROOT 244fa9e4066Sahrens } zpool_field_t; 245fa9e4066Sahrens 246fa9e4066Sahrens #define MAX_FIELDS 10 247fa9e4066Sahrens 248fa9e4066Sahrens typedef struct column_def { 249fa9e4066Sahrens const char *cd_title; 250fa9e4066Sahrens size_t cd_width; 251fa9e4066Sahrens enum { 252fa9e4066Sahrens left_justify, 253fa9e4066Sahrens right_justify 254fa9e4066Sahrens } cd_justify; 255fa9e4066Sahrens } column_def_t; 256fa9e4066Sahrens 257fa9e4066Sahrens static column_def_t column_table[] = { 258fa9e4066Sahrens { "NAME", 20, left_justify }, 259fa9e4066Sahrens { "SIZE", 6, right_justify }, 260fa9e4066Sahrens { "USED", 6, right_justify }, 261fa9e4066Sahrens { "AVAIL", 6, right_justify }, 262fa9e4066Sahrens { "CAP", 5, right_justify }, 263fa9e4066Sahrens { "HEALTH", 9, left_justify }, 264fa9e4066Sahrens { "ALTROOT", 15, left_justify } 265fa9e4066Sahrens }; 266fa9e4066Sahrens 267fa9e4066Sahrens static char *column_subopts[] = { 268fa9e4066Sahrens "name", 269fa9e4066Sahrens "size", 270fa9e4066Sahrens "used", 271fa9e4066Sahrens "available", 272fa9e4066Sahrens "capacity", 273fa9e4066Sahrens "health", 274fa9e4066Sahrens "root", 275fa9e4066Sahrens NULL 276fa9e4066Sahrens }; 277fa9e4066Sahrens 278fa9e4066Sahrens /* 279b1b8ab34Slling * Callback routine that will print out a pool property value. 280b1b8ab34Slling */ 281b1b8ab34Slling static zpool_prop_t 282b1b8ab34Slling print_prop_cb(zpool_prop_t prop, void *cb) 283b1b8ab34Slling { 284b1b8ab34Slling FILE *fp = cb; 285b1b8ab34Slling 286b1b8ab34Slling (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 287b1b8ab34Slling 288b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 289b1b8ab34Slling (void) fprintf(fp, "-\n"); 290b1b8ab34Slling else 291b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 292b1b8ab34Slling 293b1b8ab34Slling return (ZFS_PROP_CONT); 294b1b8ab34Slling } 295b1b8ab34Slling 296b1b8ab34Slling /* 297fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 298fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 299fa9e4066Sahrens * a complete usage message. 300fa9e4066Sahrens */ 301fa9e4066Sahrens void 30299653d4eSeschrock usage(boolean_t requested) 303fa9e4066Sahrens { 304fa9e4066Sahrens int i; 305fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 306fa9e4066Sahrens 307fa9e4066Sahrens if (current_command == NULL) { 308fa9e4066Sahrens int i; 309fa9e4066Sahrens 310fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 311fa9e4066Sahrens (void) fprintf(fp, 312fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 313fa9e4066Sahrens 314fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 315fa9e4066Sahrens if (command_table[i].name == NULL) 316fa9e4066Sahrens (void) fprintf(fp, "\n"); 317fa9e4066Sahrens else 318fa9e4066Sahrens (void) fprintf(fp, "%s", 31965cd9f28Seschrock get_usage(command_table[i].usage)); 320fa9e4066Sahrens } 321fa9e4066Sahrens } else { 322fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 32365cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 324fa9e4066Sahrens 325fa9e4066Sahrens if (strcmp(current_command->name, "list") == 0) { 326fa9e4066Sahrens (void) fprintf(fp, gettext("\nwhere 'field' is one " 327fa9e4066Sahrens "of the following:\n\n")); 328fa9e4066Sahrens 329fa9e4066Sahrens for (i = 0; column_subopts[i] != NULL; i++) 330fa9e4066Sahrens (void) fprintf(fp, "\t%s\n", column_subopts[i]); 331fa9e4066Sahrens } 332fa9e4066Sahrens } 333fa9e4066Sahrens 334b1b8ab34Slling if (current_command != NULL && 335b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 336b1b8ab34Slling (strcmp(current_command->name, "get") == 0))) { 337b1b8ab34Slling 338b1b8ab34Slling (void) fprintf(fp, 339b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 340b1b8ab34Slling 341b1b8ab34Slling (void) fprintf(fp, "\n\t%-13s %s\n\n", 342b1b8ab34Slling "PROPERTY", "VALUES"); 343b1b8ab34Slling 344b1b8ab34Slling /* Iterate over all properties */ 34591ebeef5Sahrens (void) zpool_prop_iter(print_prop_cb, fp); 346b1b8ab34Slling } 347b1b8ab34Slling 348e9dbad6fSeschrock /* 349e9dbad6fSeschrock * See comments at end of main(). 350e9dbad6fSeschrock */ 351e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 352e9dbad6fSeschrock (void) printf("dumping core by request\n"); 353e9dbad6fSeschrock abort(); 354e9dbad6fSeschrock } 355e9dbad6fSeschrock 356fa9e4066Sahrens exit(requested ? 0 : 2); 357fa9e4066Sahrens } 358fa9e4066Sahrens 359fa9e4066Sahrens const char * 36046657f8dSmmusante state_to_health(int vs_state) 36146657f8dSmmusante { 36246657f8dSmmusante switch (vs_state) { 36346657f8dSmmusante case VDEV_STATE_CLOSED: 36446657f8dSmmusante case VDEV_STATE_CANT_OPEN: 36546657f8dSmmusante case VDEV_STATE_OFFLINE: 36646657f8dSmmusante return (dgettext(TEXT_DOMAIN, "FAULTED")); 36746657f8dSmmusante case VDEV_STATE_DEGRADED: 36846657f8dSmmusante return (dgettext(TEXT_DOMAIN, "DEGRADED")); 36946657f8dSmmusante case VDEV_STATE_HEALTHY: 37046657f8dSmmusante return (dgettext(TEXT_DOMAIN, "ONLINE")); 37146657f8dSmmusante } 37246657f8dSmmusante 37346657f8dSmmusante return (dgettext(TEXT_DOMAIN, "UNKNOWN")); 37446657f8dSmmusante } 37546657f8dSmmusante 37646657f8dSmmusante const char * 377ea8dc4b6Seschrock state_to_name(vdev_stat_t *vs) 378fa9e4066Sahrens { 379ea8dc4b6Seschrock switch (vs->vs_state) { 380fa9e4066Sahrens case VDEV_STATE_CLOSED: 381fa9e4066Sahrens case VDEV_STATE_CANT_OPEN: 382ea8dc4b6Seschrock if (vs->vs_aux == VDEV_AUX_CORRUPT_DATA) 383fa9e4066Sahrens return (gettext("FAULTED")); 384ea8dc4b6Seschrock else 385ea8dc4b6Seschrock return (gettext("UNAVAIL")); 386fa9e4066Sahrens case VDEV_STATE_OFFLINE: 387fa9e4066Sahrens return (gettext("OFFLINE")); 3883d7072f8Seschrock case VDEV_STATE_REMOVED: 3893d7072f8Seschrock return (gettext("REMOVED")); 3903d7072f8Seschrock case VDEV_STATE_FAULTED: 3913d7072f8Seschrock return (gettext("FAULTED")); 392fa9e4066Sahrens case VDEV_STATE_DEGRADED: 393fa9e4066Sahrens return (gettext("DEGRADED")); 394fa9e4066Sahrens case VDEV_STATE_HEALTHY: 395fa9e4066Sahrens return (gettext("ONLINE")); 396fa9e4066Sahrens } 397fa9e4066Sahrens 398fa9e4066Sahrens return (gettext("UNKNOWN")); 399fa9e4066Sahrens } 400fa9e4066Sahrens 401fa9e4066Sahrens void 4028654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 4038654d025Sperrin boolean_t print_logs) 404fa9e4066Sahrens { 405fa9e4066Sahrens nvlist_t **child; 406fa9e4066Sahrens uint_t c, children; 407afefbcddSeschrock char *vname; 408fa9e4066Sahrens 409fa9e4066Sahrens if (name != NULL) 410fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 411fa9e4066Sahrens 412fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 413fa9e4066Sahrens &child, &children) != 0) 414fa9e4066Sahrens return; 415fa9e4066Sahrens 416afefbcddSeschrock for (c = 0; c < children; c++) { 4178654d025Sperrin uint64_t is_log = B_FALSE; 4188654d025Sperrin 4198654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 4208654d025Sperrin &is_log); 4218654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 4228654d025Sperrin continue; 4238654d025Sperrin 42499653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 4258654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 4268654d025Sperrin B_FALSE); 427afefbcddSeschrock free(vname); 428afefbcddSeschrock } 429fa9e4066Sahrens } 430fa9e4066Sahrens 431fa9e4066Sahrens /* 432fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 433fa9e4066Sahrens * 434fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 435fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 436fa9e4066Sahrens * they were to be added. 437fa9e4066Sahrens * 438fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 439fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 440fa9e4066Sahrens * libzfs. 441fa9e4066Sahrens */ 442fa9e4066Sahrens int 443fa9e4066Sahrens zpool_do_add(int argc, char **argv) 444fa9e4066Sahrens { 44599653d4eSeschrock boolean_t force = B_FALSE; 44699653d4eSeschrock boolean_t dryrun = B_FALSE; 447fa9e4066Sahrens int c; 448fa9e4066Sahrens nvlist_t *nvroot; 449fa9e4066Sahrens char *poolname; 450fa9e4066Sahrens int ret; 451fa9e4066Sahrens zpool_handle_t *zhp; 452fa9e4066Sahrens nvlist_t *config; 453fa9e4066Sahrens 454fa9e4066Sahrens /* check options */ 455fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 456fa9e4066Sahrens switch (c) { 457fa9e4066Sahrens case 'f': 45899653d4eSeschrock force = B_TRUE; 459fa9e4066Sahrens break; 460fa9e4066Sahrens case 'n': 46199653d4eSeschrock dryrun = B_TRUE; 462fa9e4066Sahrens break; 463fa9e4066Sahrens case '?': 464fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 465fa9e4066Sahrens optopt); 46699653d4eSeschrock usage(B_FALSE); 467fa9e4066Sahrens } 468fa9e4066Sahrens } 469fa9e4066Sahrens 470fa9e4066Sahrens argc -= optind; 471fa9e4066Sahrens argv += optind; 472fa9e4066Sahrens 473fa9e4066Sahrens /* get pool name and check number of arguments */ 474fa9e4066Sahrens if (argc < 1) { 475fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 47699653d4eSeschrock usage(B_FALSE); 477fa9e4066Sahrens } 478fa9e4066Sahrens if (argc < 2) { 479fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 48099653d4eSeschrock usage(B_FALSE); 481fa9e4066Sahrens } 482fa9e4066Sahrens 483fa9e4066Sahrens poolname = argv[0]; 484fa9e4066Sahrens 485fa9e4066Sahrens argc--; 486fa9e4066Sahrens argv++; 487fa9e4066Sahrens 48899653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 489fa9e4066Sahrens return (1); 490fa9e4066Sahrens 491088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 492fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 493fa9e4066Sahrens poolname); 494fa9e4066Sahrens zpool_close(zhp); 495fa9e4066Sahrens return (1); 496fa9e4066Sahrens } 497fa9e4066Sahrens 498fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 4998488aeb5Staylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv); 500fa9e4066Sahrens if (nvroot == NULL) { 501fa9e4066Sahrens zpool_close(zhp); 502fa9e4066Sahrens return (1); 503fa9e4066Sahrens } 504fa9e4066Sahrens 505fa9e4066Sahrens if (dryrun) { 506fa9e4066Sahrens nvlist_t *poolnvroot; 507fa9e4066Sahrens 508fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 509fa9e4066Sahrens &poolnvroot) == 0); 510fa9e4066Sahrens 511fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 512fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 513fa9e4066Sahrens 5148654d025Sperrin /* print original main pool and new tree */ 5158654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 5168654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 5178654d025Sperrin 5188654d025Sperrin /* Do the same for the logs */ 5198654d025Sperrin if (num_logs(poolnvroot) > 0) { 5208654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 5218654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 5228654d025Sperrin } else if (num_logs(nvroot) > 0) { 5238654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 5248654d025Sperrin } 525fa9e4066Sahrens 526fa9e4066Sahrens ret = 0; 527fa9e4066Sahrens } else { 528fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 529fa9e4066Sahrens } 530fa9e4066Sahrens 53199653d4eSeschrock nvlist_free(nvroot); 53299653d4eSeschrock zpool_close(zhp); 53399653d4eSeschrock 53499653d4eSeschrock return (ret); 53599653d4eSeschrock } 53699653d4eSeschrock 53799653d4eSeschrock /* 53899653d4eSeschrock * zpool remove <pool> <vdev> 53999653d4eSeschrock * 54099653d4eSeschrock * Removes the given vdev from the pool. Currently, this only supports removing 54199653d4eSeschrock * spares from the pool. Eventually, we'll want to support removing leaf vdevs 54299653d4eSeschrock * (as an alias for 'detach') as well as toplevel vdevs. 54399653d4eSeschrock */ 54499653d4eSeschrock int 54599653d4eSeschrock zpool_do_remove(int argc, char **argv) 54699653d4eSeschrock { 54799653d4eSeschrock char *poolname; 54899653d4eSeschrock int ret; 54999653d4eSeschrock zpool_handle_t *zhp; 55099653d4eSeschrock 55199653d4eSeschrock argc--; 55299653d4eSeschrock argv++; 55399653d4eSeschrock 55499653d4eSeschrock /* get pool name and check number of arguments */ 55599653d4eSeschrock if (argc < 1) { 55699653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 55799653d4eSeschrock usage(B_FALSE); 55899653d4eSeschrock } 55999653d4eSeschrock if (argc < 2) { 56099653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 56199653d4eSeschrock usage(B_FALSE); 56299653d4eSeschrock } 56399653d4eSeschrock 56499653d4eSeschrock poolname = argv[0]; 56599653d4eSeschrock 56699653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 56799653d4eSeschrock return (1); 56899653d4eSeschrock 56999653d4eSeschrock ret = (zpool_vdev_remove(zhp, argv[1]) != 0); 57099653d4eSeschrock 571fa9e4066Sahrens return (ret); 572fa9e4066Sahrens } 573fa9e4066Sahrens 574fa9e4066Sahrens /* 575fa9e4066Sahrens * zpool create [-fn] [-R root] [-m mountpoint] <pool> <dev> ... 576fa9e4066Sahrens * 577fa9e4066Sahrens * -f Force creation, even if devices appear in use 578fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 579fa9e4066Sahrens * were to be created. 580fa9e4066Sahrens * -R Create a pool under an alternate root 581fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 582fa9e4066Sahrens * '/<pool>' 583fa9e4066Sahrens * 584b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 585fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 586fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 587fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 588fa9e4066Sahrens */ 589fa9e4066Sahrens int 590fa9e4066Sahrens zpool_do_create(int argc, char **argv) 591fa9e4066Sahrens { 59299653d4eSeschrock boolean_t force = B_FALSE; 59399653d4eSeschrock boolean_t dryrun = B_FALSE; 594fa9e4066Sahrens int c; 595fa9e4066Sahrens nvlist_t *nvroot; 596fa9e4066Sahrens char *poolname; 597fa9e4066Sahrens int ret; 598fa9e4066Sahrens char *altroot = NULL; 599fa9e4066Sahrens char *mountpoint = NULL; 60099653d4eSeschrock nvlist_t **child; 60199653d4eSeschrock uint_t children; 602fa9e4066Sahrens 603fa9e4066Sahrens /* check options */ 604fa9e4066Sahrens while ((c = getopt(argc, argv, ":fnR:m:")) != -1) { 605fa9e4066Sahrens switch (c) { 606fa9e4066Sahrens case 'f': 60799653d4eSeschrock force = B_TRUE; 608fa9e4066Sahrens break; 609fa9e4066Sahrens case 'n': 61099653d4eSeschrock dryrun = B_TRUE; 611fa9e4066Sahrens break; 612fa9e4066Sahrens case 'R': 613fa9e4066Sahrens altroot = optarg; 614fa9e4066Sahrens break; 615fa9e4066Sahrens case 'm': 616fa9e4066Sahrens mountpoint = optarg; 617fa9e4066Sahrens break; 618fa9e4066Sahrens case ':': 619fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 620fa9e4066Sahrens "'%c' option\n"), optopt); 62199653d4eSeschrock usage(B_FALSE); 622fa9e4066Sahrens break; 623fa9e4066Sahrens case '?': 624fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 625fa9e4066Sahrens optopt); 62699653d4eSeschrock usage(B_FALSE); 627fa9e4066Sahrens } 628fa9e4066Sahrens } 629fa9e4066Sahrens 630fa9e4066Sahrens argc -= optind; 631fa9e4066Sahrens argv += optind; 632fa9e4066Sahrens 633fa9e4066Sahrens /* get pool name and check number of arguments */ 634fa9e4066Sahrens if (argc < 1) { 635fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 63699653d4eSeschrock usage(B_FALSE); 637fa9e4066Sahrens } 638fa9e4066Sahrens if (argc < 2) { 639fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 64099653d4eSeschrock usage(B_FALSE); 641fa9e4066Sahrens } 642fa9e4066Sahrens 643fa9e4066Sahrens poolname = argv[0]; 644fa9e4066Sahrens 645fa9e4066Sahrens /* 646fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 647fa9e4066Sahrens * user to use 'zfs create' instead. 648fa9e4066Sahrens */ 649fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 650fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 651fa9e4066Sahrens "character '/' in pool name\n"), poolname); 652fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 653fa9e4066Sahrens "create a dataset\n")); 654fa9e4066Sahrens return (1); 655fa9e4066Sahrens } 656fa9e4066Sahrens 657fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 65899653d4eSeschrock nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1, 65999653d4eSeschrock argv + 1); 660fa9e4066Sahrens if (nvroot == NULL) 661fa9e4066Sahrens return (1); 662fa9e4066Sahrens 66399653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 66499653d4eSeschrock verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 66599653d4eSeschrock &child, &children) == 0); 66699653d4eSeschrock if (children == 0) { 66799653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 66899653d4eSeschrock "specification: at least one toplevel vdev must be " 66999653d4eSeschrock "specified\n")); 67099653d4eSeschrock return (1); 67199653d4eSeschrock } 67299653d4eSeschrock 67399653d4eSeschrock 674fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 675fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 676e9dbad6fSeschrock "must be an absolute path\n"), altroot); 67799653d4eSeschrock nvlist_free(nvroot); 678fa9e4066Sahrens return (1); 679fa9e4066Sahrens } 680fa9e4066Sahrens 681fa9e4066Sahrens /* 682fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 683fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 684fa9e4066Sahrens */ 685fa9e4066Sahrens if (mountpoint == NULL || 686fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 687fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 688fa9e4066Sahrens char buf[MAXPATHLEN]; 689fa9e4066Sahrens struct stat64 statbuf; 690fa9e4066Sahrens 691fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 692fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 693fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 694fa9e4066Sahrens "'none'\n"), mountpoint); 69599653d4eSeschrock nvlist_free(nvroot); 696fa9e4066Sahrens return (1); 697fa9e4066Sahrens } 698fa9e4066Sahrens 699fa9e4066Sahrens if (mountpoint == NULL) { 700fa9e4066Sahrens if (altroot != NULL) 701fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 702fa9e4066Sahrens altroot, poolname); 703fa9e4066Sahrens else 704fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 705fa9e4066Sahrens poolname); 706fa9e4066Sahrens } else { 707fa9e4066Sahrens if (altroot != NULL) 708fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 709fa9e4066Sahrens altroot, mountpoint); 710fa9e4066Sahrens else 711fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 712fa9e4066Sahrens mountpoint); 713fa9e4066Sahrens } 714fa9e4066Sahrens 715fa9e4066Sahrens if (stat64(buf, &statbuf) == 0 && 716fa9e4066Sahrens statbuf.st_nlink != 2) { 717fa9e4066Sahrens if (mountpoint == NULL) 718fa9e4066Sahrens (void) fprintf(stderr, gettext("default " 719fa9e4066Sahrens "mountpoint '%s' exists and is not " 720fa9e4066Sahrens "empty\n"), buf); 721fa9e4066Sahrens else 722fa9e4066Sahrens (void) fprintf(stderr, gettext("mountpoint " 723fa9e4066Sahrens "'%s' exists and is not empty\n"), buf); 724fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 725fa9e4066Sahrens "option to provide a different default\n")); 72699653d4eSeschrock nvlist_free(nvroot); 727fa9e4066Sahrens return (1); 728fa9e4066Sahrens } 729fa9e4066Sahrens } 730fa9e4066Sahrens 731fa9e4066Sahrens 732fa9e4066Sahrens if (dryrun) { 733fa9e4066Sahrens /* 734fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 735fa9e4066Sahrens * through all the vdevs in the list and print out in an 736fa9e4066Sahrens * appropriate hierarchy. 737fa9e4066Sahrens */ 738fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 739fa9e4066Sahrens "following layout:\n\n"), poolname); 740fa9e4066Sahrens 7418654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 7428654d025Sperrin if (num_logs(nvroot) > 0) 7438654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 744fa9e4066Sahrens 745fa9e4066Sahrens ret = 0; 746fa9e4066Sahrens } else { 747fa9e4066Sahrens ret = 1; 748fa9e4066Sahrens /* 749fa9e4066Sahrens * Hand off to libzfs. 750fa9e4066Sahrens */ 75199653d4eSeschrock if (zpool_create(g_zfs, poolname, nvroot, altroot) == 0) { 75299653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 753fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 754fa9e4066Sahrens if (pool != NULL) { 755fa9e4066Sahrens if (mountpoint != NULL) 756fa9e4066Sahrens verify(zfs_prop_set(pool, 757e9dbad6fSeschrock zfs_prop_to_name( 758e9dbad6fSeschrock ZFS_PROP_MOUNTPOINT), 759fa9e4066Sahrens mountpoint) == 0); 760fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 761f3861e1aSahl ret = zfs_share_nfs(pool); 762fa9e4066Sahrens zfs_close(pool); 763fa9e4066Sahrens } 76499653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 76599653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 76699653d4eSeschrock "been omitted\n")); 767fa9e4066Sahrens } 768fa9e4066Sahrens } 769fa9e4066Sahrens 770fa9e4066Sahrens nvlist_free(nvroot); 771fa9e4066Sahrens 772fa9e4066Sahrens return (ret); 773fa9e4066Sahrens } 774fa9e4066Sahrens 775fa9e4066Sahrens /* 776fa9e4066Sahrens * zpool destroy <pool> 777fa9e4066Sahrens * 778fa9e4066Sahrens * -f Forcefully unmount any datasets 779fa9e4066Sahrens * 780fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 781fa9e4066Sahrens */ 782fa9e4066Sahrens int 783fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 784fa9e4066Sahrens { 78599653d4eSeschrock boolean_t force = B_FALSE; 786fa9e4066Sahrens int c; 787fa9e4066Sahrens char *pool; 788fa9e4066Sahrens zpool_handle_t *zhp; 789fa9e4066Sahrens int ret; 790fa9e4066Sahrens 791fa9e4066Sahrens /* check options */ 792fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 793fa9e4066Sahrens switch (c) { 794fa9e4066Sahrens case 'f': 79599653d4eSeschrock force = B_TRUE; 796fa9e4066Sahrens break; 797fa9e4066Sahrens case '?': 798fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 799fa9e4066Sahrens optopt); 80099653d4eSeschrock usage(B_FALSE); 801fa9e4066Sahrens } 802fa9e4066Sahrens } 803fa9e4066Sahrens 804fa9e4066Sahrens argc -= optind; 805fa9e4066Sahrens argv += optind; 806fa9e4066Sahrens 807fa9e4066Sahrens /* check arguments */ 808fa9e4066Sahrens if (argc < 1) { 809fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 81099653d4eSeschrock usage(B_FALSE); 811fa9e4066Sahrens } 812fa9e4066Sahrens if (argc > 1) { 813fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 81499653d4eSeschrock usage(B_FALSE); 815fa9e4066Sahrens } 816fa9e4066Sahrens 817fa9e4066Sahrens pool = argv[0]; 818fa9e4066Sahrens 81999653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 820fa9e4066Sahrens /* 821fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 822fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 823fa9e4066Sahrens */ 824fa9e4066Sahrens if (strchr(pool, '/') != NULL) 825fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 826fa9e4066Sahrens "destroy a dataset\n")); 827fa9e4066Sahrens return (1); 828fa9e4066Sahrens } 829fa9e4066Sahrens 830f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 831fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 832fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 833fa9e4066Sahrens return (1); 834fa9e4066Sahrens } 835fa9e4066Sahrens 836fa9e4066Sahrens ret = (zpool_destroy(zhp) != 0); 837fa9e4066Sahrens 838fa9e4066Sahrens zpool_close(zhp); 839fa9e4066Sahrens 840fa9e4066Sahrens return (ret); 841fa9e4066Sahrens } 842fa9e4066Sahrens 843fa9e4066Sahrens /* 844fa9e4066Sahrens * zpool export [-f] <pool> ... 845fa9e4066Sahrens * 846fa9e4066Sahrens * -f Forcefully unmount datasets 847fa9e4066Sahrens * 848b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 849fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 850fa9e4066Sahrens * then the datasets will be forcefully unmounted. 851fa9e4066Sahrens */ 852fa9e4066Sahrens int 853fa9e4066Sahrens zpool_do_export(int argc, char **argv) 854fa9e4066Sahrens { 85599653d4eSeschrock boolean_t force = B_FALSE; 856fa9e4066Sahrens int c; 857fa9e4066Sahrens zpool_handle_t *zhp; 858fa9e4066Sahrens int ret; 859fa9e4066Sahrens int i; 860fa9e4066Sahrens 861fa9e4066Sahrens /* check options */ 862fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 863fa9e4066Sahrens switch (c) { 864fa9e4066Sahrens case 'f': 86599653d4eSeschrock force = B_TRUE; 866fa9e4066Sahrens break; 867fa9e4066Sahrens case '?': 868fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 869fa9e4066Sahrens optopt); 87099653d4eSeschrock usage(B_FALSE); 871fa9e4066Sahrens } 872fa9e4066Sahrens } 873fa9e4066Sahrens 874fa9e4066Sahrens argc -= optind; 875fa9e4066Sahrens argv += optind; 876fa9e4066Sahrens 877fa9e4066Sahrens /* check arguments */ 878fa9e4066Sahrens if (argc < 1) { 879fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 88099653d4eSeschrock usage(B_FALSE); 881fa9e4066Sahrens } 882fa9e4066Sahrens 883fa9e4066Sahrens ret = 0; 884fa9e4066Sahrens for (i = 0; i < argc; i++) { 88599653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 886fa9e4066Sahrens ret = 1; 887fa9e4066Sahrens continue; 888fa9e4066Sahrens } 889fa9e4066Sahrens 890f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 891fa9e4066Sahrens ret = 1; 892fa9e4066Sahrens zpool_close(zhp); 893fa9e4066Sahrens continue; 894fa9e4066Sahrens } 895fa9e4066Sahrens 896fa9e4066Sahrens if (zpool_export(zhp) != 0) 897fa9e4066Sahrens ret = 1; 898fa9e4066Sahrens 899fa9e4066Sahrens zpool_close(zhp); 900fa9e4066Sahrens } 901fa9e4066Sahrens 902fa9e4066Sahrens return (ret); 903fa9e4066Sahrens } 904fa9e4066Sahrens 905fa9e4066Sahrens /* 906fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 907fa9e4066Sahrens * name column. 908fa9e4066Sahrens */ 909fa9e4066Sahrens static int 910c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 911fa9e4066Sahrens { 91299653d4eSeschrock char *name = zpool_vdev_name(g_zfs, zhp, nv); 913fa9e4066Sahrens nvlist_t **child; 914fa9e4066Sahrens uint_t c, children; 915fa9e4066Sahrens int ret; 916fa9e4066Sahrens 917fa9e4066Sahrens if (strlen(name) + depth > max) 918fa9e4066Sahrens max = strlen(name) + depth; 919fa9e4066Sahrens 920afefbcddSeschrock free(name); 921afefbcddSeschrock 92299653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 92399653d4eSeschrock &child, &children) == 0) { 924fa9e4066Sahrens for (c = 0; c < children; c++) 92599653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 92699653d4eSeschrock max)) > max) 927fa9e4066Sahrens max = ret; 92899653d4eSeschrock } 92999653d4eSeschrock 93099653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 93199653d4eSeschrock &child, &children) == 0) { 93299653d4eSeschrock for (c = 0; c < children; c++) 93399653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 93499653d4eSeschrock max)) > max) 93599653d4eSeschrock max = ret; 93699653d4eSeschrock } 93799653d4eSeschrock 938fa9e4066Sahrens 939fa9e4066Sahrens return (max); 940fa9e4066Sahrens } 941fa9e4066Sahrens 942fa9e4066Sahrens 943fa9e4066Sahrens /* 944fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 945fa9e4066Sahrens * pool, printing out the name and status for each one. 946fa9e4066Sahrens */ 947fa9e4066Sahrens void 9488654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth, 9498654d025Sperrin boolean_t print_logs) 950fa9e4066Sahrens { 951fa9e4066Sahrens nvlist_t **child; 952fa9e4066Sahrens uint_t c, children; 953fa9e4066Sahrens vdev_stat_t *vs; 954afefbcddSeschrock char *type, *vname; 955fa9e4066Sahrens 956fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 957fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_MISSING) == 0) 958fa9e4066Sahrens return; 959fa9e4066Sahrens 960fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 961fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 962fa9e4066Sahrens 963fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 9643d7072f8Seschrock (void) printf(" %s", state_to_name(vs)); 965fa9e4066Sahrens 966fa9e4066Sahrens if (vs->vs_aux != 0) { 9673d7072f8Seschrock (void) printf(" "); 968fa9e4066Sahrens 969fa9e4066Sahrens switch (vs->vs_aux) { 970fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 971fa9e4066Sahrens (void) printf(gettext("cannot open")); 972fa9e4066Sahrens break; 973fa9e4066Sahrens 974fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 975fa9e4066Sahrens (void) printf(gettext("missing device")); 976fa9e4066Sahrens break; 977fa9e4066Sahrens 978fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 979fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 980fa9e4066Sahrens break; 981fa9e4066Sahrens 982eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 983eaca9bbdSeschrock (void) printf(gettext("newer version")); 984eaca9bbdSeschrock break; 985eaca9bbdSeschrock 9863d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 9873d7072f8Seschrock (void) printf(gettext("too many errors")); 9883d7072f8Seschrock break; 9893d7072f8Seschrock 990fa9e4066Sahrens default: 991fa9e4066Sahrens (void) printf(gettext("corrupted data")); 992fa9e4066Sahrens break; 993fa9e4066Sahrens } 994fa9e4066Sahrens } 995fa9e4066Sahrens (void) printf("\n"); 996fa9e4066Sahrens 997fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 998fa9e4066Sahrens &child, &children) != 0) 999fa9e4066Sahrens return; 1000fa9e4066Sahrens 1001afefbcddSeschrock for (c = 0; c < children; c++) { 10028654d025Sperrin uint64_t is_log = B_FALSE; 10038654d025Sperrin 10048654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 10058654d025Sperrin &is_log); 10068654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 10078654d025Sperrin continue; 10088654d025Sperrin 100999653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1010afefbcddSeschrock print_import_config(vname, child[c], 10118654d025Sperrin namewidth, depth + 2, B_FALSE); 1012afefbcddSeschrock free(vname); 1013afefbcddSeschrock } 101499653d4eSeschrock 101599653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 101699653d4eSeschrock &child, &children) != 0) 101799653d4eSeschrock return; 101899653d4eSeschrock 101999653d4eSeschrock (void) printf(gettext("\tspares\n")); 102099653d4eSeschrock for (c = 0; c < children; c++) { 102199653d4eSeschrock vname = zpool_vdev_name(g_zfs, NULL, child[c]); 102299653d4eSeschrock (void) printf("\t %s\n", vname); 102399653d4eSeschrock free(vname); 102499653d4eSeschrock } 1025fa9e4066Sahrens } 1026fa9e4066Sahrens 1027fa9e4066Sahrens /* 1028fa9e4066Sahrens * Display the status for the given pool. 1029fa9e4066Sahrens */ 1030fa9e4066Sahrens static void 1031fa9e4066Sahrens show_import(nvlist_t *config) 1032fa9e4066Sahrens { 1033fa9e4066Sahrens uint64_t pool_state; 1034fa9e4066Sahrens vdev_stat_t *vs; 1035fa9e4066Sahrens char *name; 1036fa9e4066Sahrens uint64_t guid; 1037fa9e4066Sahrens char *msgid; 1038fa9e4066Sahrens nvlist_t *nvroot; 1039fa9e4066Sahrens int reason; 104046657f8dSmmusante const char *health; 1041fa9e4066Sahrens uint_t vsc; 1042fa9e4066Sahrens int namewidth; 1043fa9e4066Sahrens 1044fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1045fa9e4066Sahrens &name) == 0); 1046fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1047fa9e4066Sahrens &guid) == 0); 1048fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1049fa9e4066Sahrens &pool_state) == 0); 1050fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1051fa9e4066Sahrens &nvroot) == 0); 1052fa9e4066Sahrens 1053fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1054fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 105546657f8dSmmusante health = state_to_health(vs->vs_state); 1056fa9e4066Sahrens 1057fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1058fa9e4066Sahrens 105946657f8dSmmusante (void) printf(gettext(" pool: %s\n"), name); 106046657f8dSmmusante (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 106146657f8dSmmusante (void) printf(gettext(" state: %s"), health); 10624c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 106346657f8dSmmusante (void) printf(gettext(" (DESTROYED)")); 10644c58d714Sdarrenm (void) printf("\n"); 1065fa9e4066Sahrens 1066fa9e4066Sahrens switch (reason) { 1067fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1068fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1069fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 1070fa9e4066Sahrens (void) printf(gettext("status: One or more devices are missing " 1071fa9e4066Sahrens "from the system.\n")); 1072fa9e4066Sahrens break; 1073fa9e4066Sahrens 1074fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1075fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1076fa9e4066Sahrens (void) printf(gettext("status: One or more devices contains " 1077fa9e4066Sahrens "corrupted data.\n")); 1078fa9e4066Sahrens break; 1079fa9e4066Sahrens 1080fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 1081fa9e4066Sahrens (void) printf(gettext("status: The pool data is corrupted.\n")); 1082fa9e4066Sahrens break; 1083fa9e4066Sahrens 1084441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 1085441d80aaSlling (void) printf(gettext("status: One or more devices " 1086441d80aaSlling "are offlined.\n")); 1087441d80aaSlling break; 1088441d80aaSlling 1089ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 1090ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is " 1091ea8dc4b6Seschrock "corrupted.\n")); 1092ea8dc4b6Seschrock break; 1093ea8dc4b6Seschrock 1094eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 1095eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1096eaca9bbdSeschrock "older on-disk version.\n")); 1097eaca9bbdSeschrock break; 1098eaca9bbdSeschrock 1099eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1100eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 1101eaca9bbdSeschrock "incompatible version.\n")); 1102eaca9bbdSeschrock break; 110395173954Sek110237 case ZPOOL_STATUS_HOSTID_MISMATCH: 110495173954Sek110237 (void) printf(gettext("status: The pool was last accessed by " 110595173954Sek110237 "another system.\n")); 110695173954Sek110237 break; 11073d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 11083d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 11093d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 11103d7072f8Seschrock "faulted.\n")); 11113d7072f8Seschrock break; 11123d7072f8Seschrock 1113fa9e4066Sahrens default: 1114fa9e4066Sahrens /* 1115fa9e4066Sahrens * No other status can be seen when importing pools. 1116fa9e4066Sahrens */ 1117fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1118fa9e4066Sahrens } 1119fa9e4066Sahrens 1120fa9e4066Sahrens /* 1121fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1122fa9e4066Sahrens */ 112346657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 1124eaca9bbdSeschrock if (reason == ZPOOL_STATUS_VERSION_OLDER) 1125eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1126eaca9bbdSeschrock "imported using its name or numeric identifier, " 1127eaca9bbdSeschrock "though\n\tsome features will not be available " 1128eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 112995173954Sek110237 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 113095173954Sek110237 (void) printf(gettext("action: The pool can be " 113195173954Sek110237 "imported using its name or numeric " 113295173954Sek110237 "identifier and\n\tthe '-f' flag.\n")); 1133fa9e4066Sahrens else 1134eaca9bbdSeschrock (void) printf(gettext("action: The pool can be " 1135eaca9bbdSeschrock "imported using its name or numeric " 1136eaca9bbdSeschrock "identifier.\n")); 113746657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1138fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported " 1139fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1140eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1141fa9e4066Sahrens } else { 1142eaca9bbdSeschrock switch (reason) { 1143eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 1144eaca9bbdSeschrock (void) printf(gettext("action: The pool cannot be " 1145eaca9bbdSeschrock "imported. Access the pool on a system running " 1146eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1147eaca9bbdSeschrock "backup.\n")); 1148eaca9bbdSeschrock break; 1149eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1150eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1151eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 1152fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1153fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1154fa9e4066Sahrens "again.\n")); 1155eaca9bbdSeschrock break; 1156eaca9bbdSeschrock default: 1157fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 1158fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1159fa9e4066Sahrens } 1160eaca9bbdSeschrock } 1161eaca9bbdSeschrock 116246657f8dSmmusante /* 116346657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 116446657f8dSmmusante * is "corrupt data": 116546657f8dSmmusante */ 116646657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 116746657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 116846657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1169eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1170eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1171eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1172eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1173eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 1174eaca9bbdSeschrock "on another system, but can be imported using\n\t" 1175eaca9bbdSeschrock "the '-f' flag.\n")); 1176eaca9bbdSeschrock } 1177fa9e4066Sahrens 1178fa9e4066Sahrens if (msgid != NULL) 1179fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1180fa9e4066Sahrens msgid); 1181fa9e4066Sahrens 1182fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 1183fa9e4066Sahrens 1184c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1185fa9e4066Sahrens if (namewidth < 10) 1186fa9e4066Sahrens namewidth = 10; 11878654d025Sperrin 11888654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_FALSE); 11898654d025Sperrin if (num_logs(nvroot) > 0) { 11908654d025Sperrin (void) printf(gettext("\tlogs\n")); 11918654d025Sperrin print_import_config(name, nvroot, namewidth, 0, B_TRUE); 11928654d025Sperrin } 1193fa9e4066Sahrens 1194fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 119546657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1196fa9e4066Sahrens "be part of this pool, though their\n\texact " 119746657f8dSmmusante "configuration cannot be determined.\n")); 1198fa9e4066Sahrens } 1199fa9e4066Sahrens } 1200fa9e4066Sahrens 1201fa9e4066Sahrens /* 1202fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1203fa9e4066Sahrens * lifting off to zpool_import(), and then mounts the datasets contained within 1204fa9e4066Sahrens * the pool. 1205fa9e4066Sahrens */ 1206fa9e4066Sahrens static int 1207fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 1208ecd6cf80Smarks const char *altroot, int force, nvlist_t *props) 1209fa9e4066Sahrens { 1210fa9e4066Sahrens zpool_handle_t *zhp; 1211fa9e4066Sahrens char *name; 1212fa9e4066Sahrens uint64_t state; 1213eaca9bbdSeschrock uint64_t version; 1214ecd6cf80Smarks int error = 0; 1215fa9e4066Sahrens 1216fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1217fa9e4066Sahrens &name) == 0); 1218fa9e4066Sahrens 1219fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1220fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1221eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1222eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1223e7437265Sahrens if (version > SPA_VERSION) { 1224eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1225eaca9bbdSeschrock "is formatted using a newer ZFS version\n"), name); 1226eaca9bbdSeschrock return (1); 1227eaca9bbdSeschrock } else if (state != POOL_STATE_EXPORTED && !force) { 122895173954Sek110237 uint64_t hostid; 122995173954Sek110237 123095173954Sek110237 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 123195173954Sek110237 &hostid) == 0) { 123295173954Sek110237 if ((unsigned long)hostid != gethostid()) { 123395173954Sek110237 char *hostname; 123495173954Sek110237 uint64_t timestamp; 123595173954Sek110237 time_t t; 123695173954Sek110237 123795173954Sek110237 verify(nvlist_lookup_string(config, 123895173954Sek110237 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 123995173954Sek110237 verify(nvlist_lookup_uint64(config, 124095173954Sek110237 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 124195173954Sek110237 t = timestamp; 124295173954Sek110237 (void) fprintf(stderr, gettext("cannot import " 124395173954Sek110237 "'%s': pool may be in use from other " 124495173954Sek110237 "system, it was last accessed by %s " 124595173954Sek110237 "(hostid: 0x%lx) on %s"), name, hostname, 124695173954Sek110237 (unsigned long)hostid, 124795173954Sek110237 asctime(localtime(&t))); 124895173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to " 124995173954Sek110237 "import anyway\n")); 1250fa9e4066Sahrens return (1); 1251fa9e4066Sahrens } 125295173954Sek110237 } else { 125395173954Sek110237 (void) fprintf(stderr, gettext("cannot import '%s': " 125495173954Sek110237 "pool may be in use from other system\n"), name); 125595173954Sek110237 (void) fprintf(stderr, gettext("use '-f' to import " 125695173954Sek110237 "anyway\n")); 125795173954Sek110237 return (1); 125895173954Sek110237 } 125995173954Sek110237 } 1260fa9e4066Sahrens 126199653d4eSeschrock if (zpool_import(g_zfs, config, newname, altroot) != 0) 1262fa9e4066Sahrens return (1); 1263fa9e4066Sahrens 1264fa9e4066Sahrens if (newname != NULL) 1265fa9e4066Sahrens name = (char *)newname; 1266fa9e4066Sahrens 126799653d4eSeschrock verify((zhp = zpool_open(g_zfs, name)) != NULL); 1268fa9e4066Sahrens 1269ecd6cf80Smarks if (props) { 1270ecd6cf80Smarks nvpair_t *pair = nvlist_next_nvpair(props, NULL); 1271ecd6cf80Smarks char *value; 1272ecd6cf80Smarks 1273ecd6cf80Smarks if (pair != NULL) { 1274ecd6cf80Smarks do { 1275ecd6cf80Smarks verify((nvpair_value_string(pair, 1276ecd6cf80Smarks &value)) == 0); 1277ecd6cf80Smarks 1278ecd6cf80Smarks if ((error = zpool_set_prop(zhp, 1279ecd6cf80Smarks nvpair_name(pair), value)) != 0) 1280ecd6cf80Smarks break; 1281ecd6cf80Smarks 1282ecd6cf80Smarks } while (pair = nvlist_next_nvpair(props, pair)); 1283ecd6cf80Smarks } 1284ecd6cf80Smarks } 1285ecd6cf80Smarks 1286ecd6cf80Smarks 1287f3861e1aSahl if (zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1288fa9e4066Sahrens zpool_close(zhp); 1289fa9e4066Sahrens return (1); 1290fa9e4066Sahrens } 1291fa9e4066Sahrens 1292fa9e4066Sahrens zpool_close(zhp); 1293ecd6cf80Smarks return (error); 1294fa9e4066Sahrens } 1295fa9e4066Sahrens 1296fa9e4066Sahrens /* 12974c58d714Sdarrenm * zpool import [-d dir] [-D] 12984c58d714Sdarrenm * import [-R root] [-D] [-d dir] [-f] -a 12994c58d714Sdarrenm * import [-R root] [-D] [-d dir] [-f] <pool | id> [newpool] 1300fa9e4066Sahrens * 1301fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1302fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1303fa9e4066Sahrens * 13044c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 13054c58d714Sdarrenm * specified destroyed pools. 13064c58d714Sdarrenm * 1307fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1308fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1309fa9e4066Sahrens * is rebooted. 1310fa9e4066Sahrens * 1311fa9e4066Sahrens * -f Force import, even if it appears that the pool is active. 1312fa9e4066Sahrens * 1313fa9e4066Sahrens * -a Import all pools found. 1314fa9e4066Sahrens * 1315ecd6cf80Smarks * -o temporary mount options. 1316ecd6cf80Smarks * 1317ecd6cf80Smarks * -p property=value 1318ecd6cf80Smarks * 1319fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 1320fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 1321fa9e4066Sahrens */ 1322fa9e4066Sahrens int 1323fa9e4066Sahrens zpool_do_import(int argc, char **argv) 1324fa9e4066Sahrens { 1325fa9e4066Sahrens char **searchdirs = NULL; 1326fa9e4066Sahrens int nsearch = 0; 1327fa9e4066Sahrens int c; 1328fa9e4066Sahrens int err; 1329fa9e4066Sahrens nvlist_t *pools; 133099653d4eSeschrock boolean_t do_all = B_FALSE; 133199653d4eSeschrock boolean_t do_destroyed = B_FALSE; 1332fa9e4066Sahrens char *altroot = NULL; 1333fa9e4066Sahrens char *mntopts = NULL; 133499653d4eSeschrock boolean_t do_force = B_FALSE; 1335fa9e4066Sahrens nvpair_t *elem; 1336fa9e4066Sahrens nvlist_t *config; 1337fa9e4066Sahrens uint64_t searchguid; 1338fa9e4066Sahrens char *searchname; 1339ecd6cf80Smarks char *propname; 1340ecd6cf80Smarks char *propval, *strval; 1341fa9e4066Sahrens nvlist_t *found_config; 1342ecd6cf80Smarks nvlist_t *props = NULL; 134399653d4eSeschrock boolean_t first; 13444c58d714Sdarrenm uint64_t pool_state; 1345fa9e4066Sahrens 1346fa9e4066Sahrens /* check options */ 1347ecd6cf80Smarks while ((c = getopt(argc, argv, ":Dfd:R:ao:p:")) != -1) { 1348fa9e4066Sahrens switch (c) { 1349fa9e4066Sahrens case 'a': 135099653d4eSeschrock do_all = B_TRUE; 1351fa9e4066Sahrens break; 1352fa9e4066Sahrens case 'd': 1353fa9e4066Sahrens if (searchdirs == NULL) { 1354fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1355fa9e4066Sahrens } else { 1356fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 1357fa9e4066Sahrens sizeof (char *)); 1358fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 1359fa9e4066Sahrens sizeof (char *)); 1360fa9e4066Sahrens free(searchdirs); 1361fa9e4066Sahrens searchdirs = tmp; 1362fa9e4066Sahrens } 1363fa9e4066Sahrens searchdirs[nsearch++] = optarg; 1364fa9e4066Sahrens break; 13654c58d714Sdarrenm case 'D': 136699653d4eSeschrock do_destroyed = B_TRUE; 13674c58d714Sdarrenm break; 1368fa9e4066Sahrens case 'f': 136999653d4eSeschrock do_force = B_TRUE; 1370fa9e4066Sahrens break; 1371fa9e4066Sahrens case 'o': 1372fa9e4066Sahrens mntopts = optarg; 1373fa9e4066Sahrens break; 1374fa9e4066Sahrens case 'R': 1375fa9e4066Sahrens altroot = optarg; 1376fa9e4066Sahrens break; 1377fa9e4066Sahrens case ':': 1378fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 1379fa9e4066Sahrens "'%c' option\n"), optopt); 138099653d4eSeschrock usage(B_FALSE); 1381fa9e4066Sahrens break; 1382ecd6cf80Smarks case 'p': 1383ecd6cf80Smarks if (props == NULL && 1384ecd6cf80Smarks nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 1385ecd6cf80Smarks (void) fprintf(stderr, 1386ecd6cf80Smarks gettext("internal error: " 1387ecd6cf80Smarks "out of memory\n")); 1388ecd6cf80Smarks err = B_TRUE; 1389ecd6cf80Smarks goto error; 1390ecd6cf80Smarks } 1391ecd6cf80Smarks 1392ecd6cf80Smarks propname = optarg; 1393ecd6cf80Smarks if ((propval = strchr(propname, '=')) == NULL) { 1394ecd6cf80Smarks (void) fprintf(stderr, gettext("missing " 1395ecd6cf80Smarks "'=' for -o option\n")); 1396ecd6cf80Smarks err = B_TRUE; 1397ecd6cf80Smarks goto error; 1398ecd6cf80Smarks } 1399ecd6cf80Smarks *propval = '\0'; 1400ecd6cf80Smarks propval++; 1401ecd6cf80Smarks 1402ecd6cf80Smarks if (zpool_name_to_prop(propname) == ZFS_PROP_INVAL) { 1403ecd6cf80Smarks (void) fprintf(stderr, 1404ecd6cf80Smarks gettext("property '%s' is " 1405ecd6cf80Smarks "not a valid pool property\n"), propname); 1406ecd6cf80Smarks err = B_TRUE; 1407ecd6cf80Smarks goto error; 1408ecd6cf80Smarks } 1409ecd6cf80Smarks 1410ecd6cf80Smarks if (nvlist_lookup_string(props, propname, 1411ecd6cf80Smarks &strval) == 0) { 1412ecd6cf80Smarks (void) fprintf(stderr, gettext("property '%s' " 1413ecd6cf80Smarks "specified multiple times\n"), propname); 1414ecd6cf80Smarks err = B_TRUE; 1415ecd6cf80Smarks goto error; 1416ecd6cf80Smarks } 1417ecd6cf80Smarks if (nvlist_add_string(props, propname, propval) != 0) { 1418ecd6cf80Smarks (void) fprintf(stderr, gettext("internal " 1419ecd6cf80Smarks "error: out of memory\n")); 1420ecd6cf80Smarks err = B_TRUE; 1421ecd6cf80Smarks goto error; 1422ecd6cf80Smarks } 1423ecd6cf80Smarks break; 1424fa9e4066Sahrens case '?': 1425fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1426fa9e4066Sahrens optopt); 142799653d4eSeschrock usage(B_FALSE); 1428fa9e4066Sahrens } 1429fa9e4066Sahrens } 1430fa9e4066Sahrens 1431fa9e4066Sahrens argc -= optind; 1432fa9e4066Sahrens argv += optind; 1433fa9e4066Sahrens 1434fa9e4066Sahrens if (searchdirs == NULL) { 1435fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1436fa9e4066Sahrens searchdirs[0] = "/dev/dsk"; 1437fa9e4066Sahrens nsearch = 1; 1438fa9e4066Sahrens } 1439fa9e4066Sahrens 1440fa9e4066Sahrens /* check argument count */ 1441fa9e4066Sahrens if (do_all) { 1442fa9e4066Sahrens if (argc != 0) { 1443fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 144499653d4eSeschrock usage(B_FALSE); 1445fa9e4066Sahrens } 1446fa9e4066Sahrens } else { 1447fa9e4066Sahrens if (argc > 2) { 1448fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 144999653d4eSeschrock usage(B_FALSE); 1450fa9e4066Sahrens } 1451fa9e4066Sahrens 1452fa9e4066Sahrens /* 1453fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 1454fa9e4066Sahrens * here because otherwise any attempt to discover pools will 1455fa9e4066Sahrens * silently fail. 1456fa9e4066Sahrens */ 1457fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1458fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 1459fa9e4066Sahrens "discover pools: permission denied\n")); 146099653d4eSeschrock free(searchdirs); 1461fa9e4066Sahrens return (1); 1462fa9e4066Sahrens } 1463fa9e4066Sahrens } 1464fa9e4066Sahrens 146599653d4eSeschrock if ((pools = zpool_find_import(g_zfs, nsearch, searchdirs)) == NULL) { 146699653d4eSeschrock free(searchdirs); 1467fa9e4066Sahrens return (1); 146899653d4eSeschrock } 1469fa9e4066Sahrens 1470fa9e4066Sahrens /* 1471fa9e4066Sahrens * We now have a list of all available pools in the given directories. 1472fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 1473fa9e4066Sahrens * 1474fa9e4066Sahrens * <none> Iterate through all pools and display information about 1475fa9e4066Sahrens * each one. 1476fa9e4066Sahrens * 1477fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 1478fa9e4066Sahrens * 1479fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 1480fa9e4066Sahrens * name and import that one. 14814c58d714Sdarrenm * 14824c58d714Sdarrenm * -D Above options applies only to destroyed pools. 1483fa9e4066Sahrens */ 1484fa9e4066Sahrens if (argc != 0) { 1485fa9e4066Sahrens char *endptr; 1486fa9e4066Sahrens 1487fa9e4066Sahrens errno = 0; 1488fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 1489fa9e4066Sahrens if (errno != 0 || *endptr != '\0') 1490fa9e4066Sahrens searchname = argv[0]; 1491fa9e4066Sahrens else 1492fa9e4066Sahrens searchname = NULL; 1493fa9e4066Sahrens found_config = NULL; 1494fa9e4066Sahrens } 1495fa9e4066Sahrens 1496fa9e4066Sahrens err = 0; 1497fa9e4066Sahrens elem = NULL; 149899653d4eSeschrock first = B_TRUE; 1499fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1500fa9e4066Sahrens 1501fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 1502fa9e4066Sahrens 15034c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 15044c58d714Sdarrenm &pool_state) == 0); 15054c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 15064c58d714Sdarrenm continue; 15074c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 15084c58d714Sdarrenm continue; 15094c58d714Sdarrenm 1510fa9e4066Sahrens if (argc == 0) { 1511fa9e4066Sahrens if (first) 151299653d4eSeschrock first = B_FALSE; 15133bb79becSeschrock else if (!do_all) 1514fa9e4066Sahrens (void) printf("\n"); 1515fa9e4066Sahrens 1516fa9e4066Sahrens if (do_all) 1517fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 1518ecd6cf80Smarks altroot, do_force, props); 1519fa9e4066Sahrens else 1520fa9e4066Sahrens show_import(config); 1521fa9e4066Sahrens } else if (searchname != NULL) { 1522fa9e4066Sahrens char *name; 1523fa9e4066Sahrens 1524fa9e4066Sahrens /* 1525fa9e4066Sahrens * We are searching for a pool based on name. 1526fa9e4066Sahrens */ 1527fa9e4066Sahrens verify(nvlist_lookup_string(config, 1528fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1529fa9e4066Sahrens 1530fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 1531fa9e4066Sahrens if (found_config != NULL) { 1532fa9e4066Sahrens (void) fprintf(stderr, gettext( 1533fa9e4066Sahrens "cannot import '%s': more than " 1534fa9e4066Sahrens "one matching pool\n"), searchname); 1535fa9e4066Sahrens (void) fprintf(stderr, gettext( 1536fa9e4066Sahrens "import by numeric ID instead\n")); 153799653d4eSeschrock err = B_TRUE; 1538fa9e4066Sahrens } 1539fa9e4066Sahrens found_config = config; 1540fa9e4066Sahrens } 1541fa9e4066Sahrens } else { 1542fa9e4066Sahrens uint64_t guid; 1543fa9e4066Sahrens 1544fa9e4066Sahrens /* 1545fa9e4066Sahrens * Search for a pool by guid. 1546fa9e4066Sahrens */ 1547fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1548fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1549fa9e4066Sahrens 1550fa9e4066Sahrens if (guid == searchguid) 1551fa9e4066Sahrens found_config = config; 1552fa9e4066Sahrens } 1553fa9e4066Sahrens } 1554fa9e4066Sahrens 1555fa9e4066Sahrens /* 1556fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 1557fa9e4066Sahrens * pool, and then do the import. 1558fa9e4066Sahrens */ 1559fa9e4066Sahrens if (argc != 0 && err == 0) { 1560fa9e4066Sahrens if (found_config == NULL) { 1561fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 1562fa9e4066Sahrens "no such pool available\n"), argv[0]); 156399653d4eSeschrock err = B_TRUE; 1564fa9e4066Sahrens } else { 1565fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 1566ecd6cf80Smarks argv[1], mntopts, altroot, do_force, props); 1567fa9e4066Sahrens } 1568fa9e4066Sahrens } 1569fa9e4066Sahrens 1570fa9e4066Sahrens /* 1571fa9e4066Sahrens * If we were just looking for pools, report an error if none were 1572fa9e4066Sahrens * found. 1573fa9e4066Sahrens */ 1574fa9e4066Sahrens if (argc == 0 && first) 1575fa9e4066Sahrens (void) fprintf(stderr, 1576fa9e4066Sahrens gettext("no pools available to import\n")); 1577fa9e4066Sahrens 1578ecd6cf80Smarks error: 1579ecd6cf80Smarks if (props) 1580ecd6cf80Smarks nvlist_free(props); 1581fa9e4066Sahrens nvlist_free(pools); 158299653d4eSeschrock free(searchdirs); 1583fa9e4066Sahrens 1584fa9e4066Sahrens return (err ? 1 : 0); 1585fa9e4066Sahrens } 1586fa9e4066Sahrens 1587fa9e4066Sahrens typedef struct iostat_cbdata { 1588fa9e4066Sahrens zpool_list_t *cb_list; 1589fa9e4066Sahrens int cb_verbose; 1590fa9e4066Sahrens int cb_iteration; 1591fa9e4066Sahrens int cb_namewidth; 1592fa9e4066Sahrens } iostat_cbdata_t; 1593fa9e4066Sahrens 1594fa9e4066Sahrens static void 1595fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 1596fa9e4066Sahrens { 1597fa9e4066Sahrens int i = 0; 1598fa9e4066Sahrens 1599fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 1600fa9e4066Sahrens (void) printf("-"); 1601fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1602fa9e4066Sahrens } 1603fa9e4066Sahrens 1604fa9e4066Sahrens static void 1605fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 1606fa9e4066Sahrens { 1607fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 1608fa9e4066Sahrens cb->cb_namewidth, ""); 1609fa9e4066Sahrens (void) printf("%-*s used avail read write read write\n", 1610fa9e4066Sahrens cb->cb_namewidth, "pool"); 1611fa9e4066Sahrens print_iostat_separator(cb); 1612fa9e4066Sahrens } 1613fa9e4066Sahrens 1614fa9e4066Sahrens /* 1615fa9e4066Sahrens * Display a single statistic. 1616fa9e4066Sahrens */ 1617fa9e4066Sahrens void 1618fa9e4066Sahrens print_one_stat(uint64_t value) 1619fa9e4066Sahrens { 1620fa9e4066Sahrens char buf[64]; 1621fa9e4066Sahrens 1622fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 1623fa9e4066Sahrens (void) printf(" %5s", buf); 1624fa9e4066Sahrens } 1625fa9e4066Sahrens 1626fa9e4066Sahrens /* 1627fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 1628fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 1629fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 1630fa9e4066Sahrens */ 1631fa9e4066Sahrens void 1632c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1633c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1634fa9e4066Sahrens { 1635fa9e4066Sahrens nvlist_t **oldchild, **newchild; 1636fa9e4066Sahrens uint_t c, children; 1637fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 1638fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 1639fa9e4066Sahrens uint64_t tdelta; 1640fa9e4066Sahrens double scale; 1641afefbcddSeschrock char *vname; 1642fa9e4066Sahrens 1643fa9e4066Sahrens if (oldnv != NULL) { 1644fa9e4066Sahrens verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1645fa9e4066Sahrens (uint64_t **)&oldvs, &c) == 0); 1646fa9e4066Sahrens } else { 1647fa9e4066Sahrens oldvs = &zerovs; 1648fa9e4066Sahrens } 1649fa9e4066Sahrens 1650fa9e4066Sahrens verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1651fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 1652fa9e4066Sahrens 1653fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 1654fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 1655fa9e4066Sahrens else 1656fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 1657fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1658fa9e4066Sahrens 1659fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1660fa9e4066Sahrens 1661fa9e4066Sahrens if (tdelta == 0) 1662fa9e4066Sahrens scale = 1.0; 1663fa9e4066Sahrens else 1664fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 1665fa9e4066Sahrens 1666fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 1667fa9e4066Sahrens if (newvs->vs_space == 0) { 1668fa9e4066Sahrens (void) printf(" - -"); 1669fa9e4066Sahrens } else { 1670fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 1671fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 1672fa9e4066Sahrens } 1673fa9e4066Sahrens 1674fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1675fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 1676fa9e4066Sahrens 1677fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1678fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1679fa9e4066Sahrens 1680fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1681fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 1682fa9e4066Sahrens 1683fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1684fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1685fa9e4066Sahrens 1686fa9e4066Sahrens (void) printf("\n"); 1687fa9e4066Sahrens 1688fa9e4066Sahrens if (!cb->cb_verbose) 1689fa9e4066Sahrens return; 1690fa9e4066Sahrens 1691fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1692fa9e4066Sahrens &newchild, &children) != 0) 1693fa9e4066Sahrens return; 1694fa9e4066Sahrens 1695fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1696fa9e4066Sahrens &oldchild, &c) != 0) 1697fa9e4066Sahrens return; 1698fa9e4066Sahrens 1699afefbcddSeschrock for (c = 0; c < children; c++) { 170099653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1701c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1702afefbcddSeschrock newchild[c], cb, depth + 2); 1703afefbcddSeschrock free(vname); 1704afefbcddSeschrock } 1705fa9e4066Sahrens } 1706fa9e4066Sahrens 1707088e9d47Seschrock static int 1708088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 1709088e9d47Seschrock { 1710088e9d47Seschrock iostat_cbdata_t *cb = data; 171194de1d4cSeschrock boolean_t missing; 1712088e9d47Seschrock 1713088e9d47Seschrock /* 1714088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 1715088e9d47Seschrock */ 171694de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 171794de1d4cSeschrock return (-1); 171894de1d4cSeschrock 171994de1d4cSeschrock if (missing) 1720088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 1721088e9d47Seschrock 1722088e9d47Seschrock return (0); 1723088e9d47Seschrock } 1724088e9d47Seschrock 1725fa9e4066Sahrens /* 1726fa9e4066Sahrens * Callback to print out the iostats for the given pool. 1727fa9e4066Sahrens */ 1728fa9e4066Sahrens int 1729fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 1730fa9e4066Sahrens { 1731fa9e4066Sahrens iostat_cbdata_t *cb = data; 1732fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 1733fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 1734fa9e4066Sahrens 1735088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 1736fa9e4066Sahrens 1737088e9d47Seschrock if (cb->cb_iteration == 1) 1738fa9e4066Sahrens oldconfig = NULL; 1739fa9e4066Sahrens 1740fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1741fa9e4066Sahrens &newnvroot) == 0); 1742fa9e4066Sahrens 1743088e9d47Seschrock if (oldconfig == NULL) 1744fa9e4066Sahrens oldnvroot = NULL; 1745088e9d47Seschrock else 1746088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 1747088e9d47Seschrock &oldnvroot) == 0); 1748fa9e4066Sahrens 1749fa9e4066Sahrens /* 1750fa9e4066Sahrens * Print out the statistics for the pool. 1751fa9e4066Sahrens */ 1752c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1753fa9e4066Sahrens 1754fa9e4066Sahrens if (cb->cb_verbose) 1755fa9e4066Sahrens print_iostat_separator(cb); 1756fa9e4066Sahrens 1757fa9e4066Sahrens return (0); 1758fa9e4066Sahrens } 1759fa9e4066Sahrens 1760fa9e4066Sahrens int 1761fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 1762fa9e4066Sahrens { 1763fa9e4066Sahrens iostat_cbdata_t *cb = data; 1764fa9e4066Sahrens nvlist_t *config, *nvroot; 1765fa9e4066Sahrens 1766088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 1767fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1768fa9e4066Sahrens &nvroot) == 0); 1769fa9e4066Sahrens if (!cb->cb_verbose) 1770fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1771fa9e4066Sahrens else 1772c67d9675Seschrock cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 1773fa9e4066Sahrens } 1774fa9e4066Sahrens 1775fa9e4066Sahrens /* 1776fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 1777fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 1778fa9e4066Sahrens */ 1779fa9e4066Sahrens if (cb->cb_namewidth < 10) 1780fa9e4066Sahrens cb->cb_namewidth = 10; 1781fa9e4066Sahrens if (cb->cb_namewidth > 38) 1782fa9e4066Sahrens cb->cb_namewidth = 38; 1783fa9e4066Sahrens 1784fa9e4066Sahrens return (0); 1785fa9e4066Sahrens } 1786fa9e4066Sahrens 1787fa9e4066Sahrens /* 1788fa9e4066Sahrens * zpool iostat [-v] [pool] ... [interval [count]] 1789fa9e4066Sahrens * 1790fa9e4066Sahrens * -v Display statistics for individual vdevs 1791fa9e4066Sahrens * 1792fa9e4066Sahrens * This command can be tricky because we want to be able to deal with pool 1793fa9e4066Sahrens * creation/destruction as well as vdev configuration changes. The bulk of this 1794fa9e4066Sahrens * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1795fa9e4066Sahrens * on pool_list_update() to detect the addition of new pools. Configuration 1796fa9e4066Sahrens * changes are all handled within libzfs. 1797fa9e4066Sahrens */ 1798fa9e4066Sahrens int 1799fa9e4066Sahrens zpool_do_iostat(int argc, char **argv) 1800fa9e4066Sahrens { 1801fa9e4066Sahrens int c; 1802fa9e4066Sahrens int ret; 1803fa9e4066Sahrens int npools; 1804fa9e4066Sahrens unsigned long interval = 0, count = 0; 1805fa9e4066Sahrens zpool_list_t *list; 180699653d4eSeschrock boolean_t verbose = B_FALSE; 1807fa9e4066Sahrens iostat_cbdata_t cb; 1808fa9e4066Sahrens 1809fa9e4066Sahrens /* check options */ 1810fa9e4066Sahrens while ((c = getopt(argc, argv, "v")) != -1) { 1811fa9e4066Sahrens switch (c) { 1812fa9e4066Sahrens case 'v': 181399653d4eSeschrock verbose = B_TRUE; 1814fa9e4066Sahrens break; 1815fa9e4066Sahrens case '?': 1816fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1817fa9e4066Sahrens optopt); 181899653d4eSeschrock usage(B_FALSE); 1819fa9e4066Sahrens } 1820fa9e4066Sahrens } 1821fa9e4066Sahrens 1822fa9e4066Sahrens argc -= optind; 1823fa9e4066Sahrens argv += optind; 1824fa9e4066Sahrens 1825fa9e4066Sahrens /* 1826fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 1827fa9e4066Sahrens */ 1828fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1829fa9e4066Sahrens char *end; 1830fa9e4066Sahrens 1831fa9e4066Sahrens errno = 0; 1832fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1833fa9e4066Sahrens 1834fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1835fa9e4066Sahrens if (interval == 0) { 1836fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1837fa9e4066Sahrens "cannot be zero\n")); 183899653d4eSeschrock usage(B_FALSE); 1839fa9e4066Sahrens } 1840fa9e4066Sahrens 1841fa9e4066Sahrens /* 1842fa9e4066Sahrens * Ignore the last parameter 1843fa9e4066Sahrens */ 1844fa9e4066Sahrens argc--; 1845fa9e4066Sahrens } else { 1846fa9e4066Sahrens /* 1847fa9e4066Sahrens * If this is not a valid number, just plow on. The 1848fa9e4066Sahrens * user will get a more informative error message later 1849fa9e4066Sahrens * on. 1850fa9e4066Sahrens */ 1851fa9e4066Sahrens interval = 0; 1852fa9e4066Sahrens } 1853fa9e4066Sahrens } 1854fa9e4066Sahrens 1855fa9e4066Sahrens /* 1856fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 1857fa9e4066Sahrens * and an integer. 1858fa9e4066Sahrens */ 1859fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1860fa9e4066Sahrens char *end; 1861fa9e4066Sahrens 1862fa9e4066Sahrens errno = 0; 1863fa9e4066Sahrens count = interval; 1864fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1865fa9e4066Sahrens 1866fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1867fa9e4066Sahrens if (interval == 0) { 1868fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1869fa9e4066Sahrens "cannot be zero\n")); 187099653d4eSeschrock usage(B_FALSE); 1871fa9e4066Sahrens } 1872fa9e4066Sahrens 1873fa9e4066Sahrens /* 1874fa9e4066Sahrens * Ignore the last parameter 1875fa9e4066Sahrens */ 1876fa9e4066Sahrens argc--; 1877fa9e4066Sahrens } else { 1878fa9e4066Sahrens interval = 0; 1879fa9e4066Sahrens } 1880fa9e4066Sahrens } 1881fa9e4066Sahrens 1882fa9e4066Sahrens /* 1883fa9e4066Sahrens * Construct the list of all interesting pools. 1884fa9e4066Sahrens */ 1885fa9e4066Sahrens ret = 0; 1886b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 1887fa9e4066Sahrens return (1); 1888fa9e4066Sahrens 188999653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 189099653d4eSeschrock pool_list_free(list); 1891fa9e4066Sahrens return (1); 189299653d4eSeschrock } 1893fa9e4066Sahrens 1894fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 189599653d4eSeschrock pool_list_free(list); 1896fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 1897fa9e4066Sahrens return (1); 1898fa9e4066Sahrens } 1899fa9e4066Sahrens 1900fa9e4066Sahrens /* 1901fa9e4066Sahrens * Enter the main iostat loop. 1902fa9e4066Sahrens */ 1903fa9e4066Sahrens cb.cb_list = list; 1904fa9e4066Sahrens cb.cb_verbose = verbose; 1905fa9e4066Sahrens cb.cb_iteration = 0; 1906fa9e4066Sahrens cb.cb_namewidth = 0; 1907fa9e4066Sahrens 1908fa9e4066Sahrens for (;;) { 1909fa9e4066Sahrens pool_list_update(list); 1910fa9e4066Sahrens 1911fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 1912fa9e4066Sahrens break; 1913fa9e4066Sahrens 1914fa9e4066Sahrens /* 1915088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 1916088e9d47Seschrock * before calculating the maximum name width, so that any 1917088e9d47Seschrock * configuration changes are properly accounted for. 1918088e9d47Seschrock */ 191999653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 1920088e9d47Seschrock 1921088e9d47Seschrock /* 1922fa9e4066Sahrens * Iterate over all pools to determine the maximum width 1923fa9e4066Sahrens * for the pool / device name column across all pools. 1924fa9e4066Sahrens */ 1925fa9e4066Sahrens cb.cb_namewidth = 0; 192699653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 1927fa9e4066Sahrens 1928fa9e4066Sahrens /* 1929fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 1930fa9e4066Sahrens */ 1931fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 1932fa9e4066Sahrens print_iostat_header(&cb); 1933fa9e4066Sahrens 193499653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 1935fa9e4066Sahrens 1936fa9e4066Sahrens /* 1937fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 1938fa9e4066Sahrens * (which prints a separator for us), then print a separator. 1939fa9e4066Sahrens */ 1940fa9e4066Sahrens if (npools > 1 && !verbose) 1941fa9e4066Sahrens print_iostat_separator(&cb); 1942fa9e4066Sahrens 1943fa9e4066Sahrens if (verbose) 1944fa9e4066Sahrens (void) printf("\n"); 1945fa9e4066Sahrens 194639c23413Seschrock /* 194739c23413Seschrock * Flush the output so that redirection to a file isn't buffered 194839c23413Seschrock * indefinitely. 194939c23413Seschrock */ 195039c23413Seschrock (void) fflush(stdout); 195139c23413Seschrock 1952fa9e4066Sahrens if (interval == 0) 1953fa9e4066Sahrens break; 1954fa9e4066Sahrens 1955fa9e4066Sahrens if (count != 0 && --count == 0) 1956fa9e4066Sahrens break; 1957fa9e4066Sahrens 1958fa9e4066Sahrens (void) sleep(interval); 1959fa9e4066Sahrens } 1960fa9e4066Sahrens 1961fa9e4066Sahrens pool_list_free(list); 1962fa9e4066Sahrens 1963fa9e4066Sahrens return (ret); 1964fa9e4066Sahrens } 1965fa9e4066Sahrens 1966fa9e4066Sahrens typedef struct list_cbdata { 196799653d4eSeschrock boolean_t cb_scripted; 196899653d4eSeschrock boolean_t cb_first; 1969fa9e4066Sahrens int cb_fields[MAX_FIELDS]; 1970fa9e4066Sahrens int cb_fieldcount; 1971fa9e4066Sahrens } list_cbdata_t; 1972fa9e4066Sahrens 1973fa9e4066Sahrens /* 1974fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 1975fa9e4066Sahrens */ 1976fa9e4066Sahrens void 1977fa9e4066Sahrens print_header(int *fields, size_t count) 1978fa9e4066Sahrens { 1979fa9e4066Sahrens int i; 1980fa9e4066Sahrens column_def_t *col; 1981fa9e4066Sahrens const char *fmt; 1982fa9e4066Sahrens 1983fa9e4066Sahrens for (i = 0; i < count; i++) { 1984fa9e4066Sahrens col = &column_table[fields[i]]; 1985fa9e4066Sahrens if (i != 0) 1986fa9e4066Sahrens (void) printf(" "); 1987fa9e4066Sahrens if (col->cd_justify == left_justify) 1988fa9e4066Sahrens fmt = "%-*s"; 1989fa9e4066Sahrens else 1990fa9e4066Sahrens fmt = "%*s"; 1991fa9e4066Sahrens 1992fa9e4066Sahrens (void) printf(fmt, i == count - 1 ? strlen(col->cd_title) : 1993fa9e4066Sahrens col->cd_width, col->cd_title); 1994fa9e4066Sahrens } 1995fa9e4066Sahrens 1996fa9e4066Sahrens (void) printf("\n"); 1997fa9e4066Sahrens } 1998fa9e4066Sahrens 1999fa9e4066Sahrens int 2000fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data) 2001fa9e4066Sahrens { 2002fa9e4066Sahrens list_cbdata_t *cbp = data; 2003fa9e4066Sahrens nvlist_t *config; 2004fa9e4066Sahrens int i; 2005fa9e4066Sahrens char buf[ZPOOL_MAXNAMELEN]; 2006fa9e4066Sahrens uint64_t total; 2007fa9e4066Sahrens uint64_t used; 2008fa9e4066Sahrens const char *fmt; 2009fa9e4066Sahrens column_def_t *col; 2010fa9e4066Sahrens 2011fa9e4066Sahrens if (cbp->cb_first) { 2012fa9e4066Sahrens if (!cbp->cb_scripted) 2013fa9e4066Sahrens print_header(cbp->cb_fields, cbp->cb_fieldcount); 201499653d4eSeschrock cbp->cb_first = B_FALSE; 2015fa9e4066Sahrens } 2016fa9e4066Sahrens 2017fa9e4066Sahrens if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2018fa9e4066Sahrens config = NULL; 2019fa9e4066Sahrens } else { 2020088e9d47Seschrock config = zpool_get_config(zhp, NULL); 2021fa9e4066Sahrens total = zpool_get_space_total(zhp); 2022fa9e4066Sahrens used = zpool_get_space_used(zhp); 2023fa9e4066Sahrens } 2024fa9e4066Sahrens 2025fa9e4066Sahrens for (i = 0; i < cbp->cb_fieldcount; i++) { 2026fa9e4066Sahrens if (i != 0) { 2027fa9e4066Sahrens if (cbp->cb_scripted) 2028fa9e4066Sahrens (void) printf("\t"); 2029fa9e4066Sahrens else 2030fa9e4066Sahrens (void) printf(" "); 2031fa9e4066Sahrens } 2032fa9e4066Sahrens 2033fa9e4066Sahrens col = &column_table[cbp->cb_fields[i]]; 2034fa9e4066Sahrens 2035fa9e4066Sahrens switch (cbp->cb_fields[i]) { 2036fa9e4066Sahrens case ZPOOL_FIELD_NAME: 2037fa9e4066Sahrens (void) strlcpy(buf, zpool_get_name(zhp), sizeof (buf)); 2038fa9e4066Sahrens break; 2039fa9e4066Sahrens 2040fa9e4066Sahrens case ZPOOL_FIELD_SIZE: 2041fa9e4066Sahrens if (config == NULL) 2042fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 2043fa9e4066Sahrens else 2044fa9e4066Sahrens zfs_nicenum(total, buf, sizeof (buf)); 2045fa9e4066Sahrens break; 2046fa9e4066Sahrens 2047fa9e4066Sahrens case ZPOOL_FIELD_USED: 2048fa9e4066Sahrens if (config == NULL) 2049fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 2050fa9e4066Sahrens else 2051fa9e4066Sahrens zfs_nicenum(used, buf, sizeof (buf)); 2052fa9e4066Sahrens break; 2053fa9e4066Sahrens 2054fa9e4066Sahrens case ZPOOL_FIELD_AVAILABLE: 2055fa9e4066Sahrens if (config == NULL) 2056fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 2057fa9e4066Sahrens else 2058fa9e4066Sahrens zfs_nicenum(total - used, buf, sizeof (buf)); 2059fa9e4066Sahrens break; 2060fa9e4066Sahrens 2061fa9e4066Sahrens case ZPOOL_FIELD_CAPACITY: 2062fa9e4066Sahrens if (config == NULL) { 2063fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 2064fa9e4066Sahrens } else { 2065fa9e4066Sahrens uint64_t capacity = (total == 0 ? 0 : 2066fa9e4066Sahrens (used * 100 / total)); 2067fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%llu%%", 20685ad82045Snd150628 (u_longlong_t)capacity); 2069fa9e4066Sahrens } 2070fa9e4066Sahrens break; 2071fa9e4066Sahrens 2072fa9e4066Sahrens case ZPOOL_FIELD_HEALTH: 2073fa9e4066Sahrens if (config == NULL) { 2074fa9e4066Sahrens (void) strlcpy(buf, "FAULTED", sizeof (buf)); 2075fa9e4066Sahrens } else { 2076fa9e4066Sahrens nvlist_t *nvroot; 2077fa9e4066Sahrens vdev_stat_t *vs; 2078fa9e4066Sahrens uint_t vsc; 2079fa9e4066Sahrens 2080fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, 2081fa9e4066Sahrens ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 2082fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, 2083fa9e4066Sahrens ZPOOL_CONFIG_STATS, (uint64_t **)&vs, 2084fa9e4066Sahrens &vsc) == 0); 2085ea8dc4b6Seschrock (void) strlcpy(buf, state_to_name(vs), 2086fa9e4066Sahrens sizeof (buf)); 2087fa9e4066Sahrens } 2088fa9e4066Sahrens break; 2089fa9e4066Sahrens 2090fa9e4066Sahrens case ZPOOL_FIELD_ROOT: 2091fa9e4066Sahrens if (config == NULL) 2092fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 2093fa9e4066Sahrens else if (zpool_get_root(zhp, buf, sizeof (buf)) != 0) 2094fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 2095fa9e4066Sahrens break; 2096fa9e4066Sahrens } 2097fa9e4066Sahrens 2098fa9e4066Sahrens if (cbp->cb_scripted) 2099fa9e4066Sahrens (void) printf("%s", buf); 2100fa9e4066Sahrens else { 2101fa9e4066Sahrens if (col->cd_justify == left_justify) 2102fa9e4066Sahrens fmt = "%-*s"; 2103fa9e4066Sahrens else 2104fa9e4066Sahrens fmt = "%*s"; 2105fa9e4066Sahrens 2106fa9e4066Sahrens (void) printf(fmt, i == cbp->cb_fieldcount - 1 ? 2107fa9e4066Sahrens strlen(buf) : col->cd_width, buf); 2108fa9e4066Sahrens } 2109fa9e4066Sahrens } 2110fa9e4066Sahrens 2111fa9e4066Sahrens (void) printf("\n"); 2112fa9e4066Sahrens 2113fa9e4066Sahrens return (0); 2114fa9e4066Sahrens } 2115fa9e4066Sahrens 2116fa9e4066Sahrens /* 2117fa9e4066Sahrens * zpool list [-H] [-o field[,field]*] [pool] ... 2118fa9e4066Sahrens * 2119fa9e4066Sahrens * -H Scripted mode. Don't display headers, and separate fields by 2120fa9e4066Sahrens * a single tab. 2121fa9e4066Sahrens * -o List of fields to display. Defaults to all fields, or 2122fa9e4066Sahrens * "name,size,used,available,capacity,health,root" 2123fa9e4066Sahrens * 2124fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 2125fa9e4066Sahrens * statistics for each one, as well as health status summary. 2126fa9e4066Sahrens */ 2127fa9e4066Sahrens int 2128fa9e4066Sahrens zpool_do_list(int argc, char **argv) 2129fa9e4066Sahrens { 2130fa9e4066Sahrens int c; 2131fa9e4066Sahrens int ret; 2132fa9e4066Sahrens list_cbdata_t cb = { 0 }; 2133fa9e4066Sahrens static char default_fields[] = 2134fa9e4066Sahrens "name,size,used,available,capacity,health,root"; 2135fa9e4066Sahrens char *fields = default_fields; 2136fa9e4066Sahrens char *value; 2137fa9e4066Sahrens 2138fa9e4066Sahrens /* check options */ 2139fa9e4066Sahrens while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2140fa9e4066Sahrens switch (c) { 2141fa9e4066Sahrens case 'H': 214299653d4eSeschrock cb.cb_scripted = B_TRUE; 2143fa9e4066Sahrens break; 2144fa9e4066Sahrens case 'o': 2145fa9e4066Sahrens fields = optarg; 2146fa9e4066Sahrens break; 2147fa9e4066Sahrens case ':': 2148fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2149fa9e4066Sahrens "'%c' option\n"), optopt); 215099653d4eSeschrock usage(B_FALSE); 2151fa9e4066Sahrens break; 2152fa9e4066Sahrens case '?': 2153fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2154fa9e4066Sahrens optopt); 215599653d4eSeschrock usage(B_FALSE); 2156fa9e4066Sahrens } 2157fa9e4066Sahrens } 2158fa9e4066Sahrens 2159fa9e4066Sahrens argc -= optind; 2160fa9e4066Sahrens argv += optind; 2161fa9e4066Sahrens 2162fa9e4066Sahrens while (*fields != '\0') { 2163fa9e4066Sahrens if (cb.cb_fieldcount == MAX_FIELDS) { 2164fa9e4066Sahrens (void) fprintf(stderr, gettext("too many " 2165fa9e4066Sahrens "properties given to -o option\n")); 216699653d4eSeschrock usage(B_FALSE); 2167fa9e4066Sahrens } 2168fa9e4066Sahrens 2169fa9e4066Sahrens if ((cb.cb_fields[cb.cb_fieldcount] = getsubopt(&fields, 2170fa9e4066Sahrens column_subopts, &value)) == -1) { 2171fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid property " 2172fa9e4066Sahrens "'%s'\n"), value); 217399653d4eSeschrock usage(B_FALSE); 2174fa9e4066Sahrens } 2175fa9e4066Sahrens 2176fa9e4066Sahrens cb.cb_fieldcount++; 2177fa9e4066Sahrens } 2178fa9e4066Sahrens 2179fa9e4066Sahrens 218099653d4eSeschrock cb.cb_first = B_TRUE; 2181fa9e4066Sahrens 2182b1b8ab34Slling ret = for_each_pool(argc, argv, B_TRUE, NULL, list_callback, &cb); 2183fa9e4066Sahrens 2184fce7d82bSmmusante if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2185fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 2186fa9e4066Sahrens return (0); 2187fa9e4066Sahrens } 2188fa9e4066Sahrens 2189fa9e4066Sahrens return (ret); 2190fa9e4066Sahrens } 2191fa9e4066Sahrens 2192fa9e4066Sahrens static nvlist_t * 2193fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name) 2194fa9e4066Sahrens { 2195fa9e4066Sahrens nvlist_t **child; 2196fa9e4066Sahrens uint_t c, children; 2197fa9e4066Sahrens nvlist_t *match; 2198fa9e4066Sahrens char *path; 2199fa9e4066Sahrens 2200fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2201fa9e4066Sahrens &child, &children) != 0) { 2202fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2203fa9e4066Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0) 2204fa9e4066Sahrens name += 9; 2205fa9e4066Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0) 2206fa9e4066Sahrens path += 9; 2207fa9e4066Sahrens if (strcmp(name, path) == 0) 2208fa9e4066Sahrens return (nv); 2209fa9e4066Sahrens return (NULL); 2210fa9e4066Sahrens } 2211fa9e4066Sahrens 2212fa9e4066Sahrens for (c = 0; c < children; c++) 2213fa9e4066Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2214fa9e4066Sahrens return (match); 2215fa9e4066Sahrens 2216fa9e4066Sahrens return (NULL); 2217fa9e4066Sahrens } 2218fa9e4066Sahrens 2219fa9e4066Sahrens static int 2220fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 2221fa9e4066Sahrens { 222299653d4eSeschrock boolean_t force = B_FALSE; 2223fa9e4066Sahrens int c; 2224fa9e4066Sahrens nvlist_t *nvroot; 2225fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 2226fa9e4066Sahrens zpool_handle_t *zhp; 222799653d4eSeschrock int ret; 2228fa9e4066Sahrens 2229fa9e4066Sahrens /* check options */ 2230fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2231fa9e4066Sahrens switch (c) { 2232fa9e4066Sahrens case 'f': 223399653d4eSeschrock force = B_TRUE; 2234fa9e4066Sahrens break; 2235fa9e4066Sahrens case '?': 2236fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2237fa9e4066Sahrens optopt); 223899653d4eSeschrock usage(B_FALSE); 2239fa9e4066Sahrens } 2240fa9e4066Sahrens } 2241fa9e4066Sahrens 2242fa9e4066Sahrens argc -= optind; 2243fa9e4066Sahrens argv += optind; 2244fa9e4066Sahrens 2245fa9e4066Sahrens /* get pool name and check number of arguments */ 2246fa9e4066Sahrens if (argc < 1) { 2247fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 224899653d4eSeschrock usage(B_FALSE); 2249fa9e4066Sahrens } 2250fa9e4066Sahrens 2251fa9e4066Sahrens poolname = argv[0]; 2252fa9e4066Sahrens 2253fa9e4066Sahrens if (argc < 2) { 2254fa9e4066Sahrens (void) fprintf(stderr, 2255fa9e4066Sahrens gettext("missing <device> specification\n")); 225699653d4eSeschrock usage(B_FALSE); 2257fa9e4066Sahrens } 2258fa9e4066Sahrens 2259fa9e4066Sahrens old_disk = argv[1]; 2260fa9e4066Sahrens 2261fa9e4066Sahrens if (argc < 3) { 2262fa9e4066Sahrens if (!replacing) { 2263fa9e4066Sahrens (void) fprintf(stderr, 2264fa9e4066Sahrens gettext("missing <new_device> specification\n")); 226599653d4eSeschrock usage(B_FALSE); 2266fa9e4066Sahrens } 2267fa9e4066Sahrens new_disk = old_disk; 2268fa9e4066Sahrens argc -= 1; 2269fa9e4066Sahrens argv += 1; 2270fa9e4066Sahrens } else { 2271fa9e4066Sahrens new_disk = argv[2]; 2272fa9e4066Sahrens argc -= 2; 2273fa9e4066Sahrens argv += 2; 2274fa9e4066Sahrens } 2275fa9e4066Sahrens 2276fa9e4066Sahrens if (argc > 1) { 2277fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 227899653d4eSeschrock usage(B_FALSE); 2279fa9e4066Sahrens } 2280fa9e4066Sahrens 228199653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2282fa9e4066Sahrens return (1); 2283fa9e4066Sahrens 22848488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 2285fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2286fa9e4066Sahrens poolname); 2287fa9e4066Sahrens zpool_close(zhp); 2288fa9e4066Sahrens return (1); 2289fa9e4066Sahrens } 2290fa9e4066Sahrens 22918488aeb5Staylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv); 2292fa9e4066Sahrens if (nvroot == NULL) { 2293fa9e4066Sahrens zpool_close(zhp); 2294fa9e4066Sahrens return (1); 2295fa9e4066Sahrens } 2296fa9e4066Sahrens 229799653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 229899653d4eSeschrock 229999653d4eSeschrock nvlist_free(nvroot); 230099653d4eSeschrock zpool_close(zhp); 230199653d4eSeschrock 230299653d4eSeschrock return (ret); 2303fa9e4066Sahrens } 2304fa9e4066Sahrens 2305fa9e4066Sahrens /* 2306fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 2307fa9e4066Sahrens * 2308fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2309fa9e4066Sahrens * 2310fa9e4066Sahrens * Replace <device> with <new_device>. 2311fa9e4066Sahrens */ 2312fa9e4066Sahrens /* ARGSUSED */ 2313fa9e4066Sahrens int 2314fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 2315fa9e4066Sahrens { 2316fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2317fa9e4066Sahrens } 2318fa9e4066Sahrens 2319fa9e4066Sahrens /* 2320fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 2321fa9e4066Sahrens * 2322fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 2323fa9e4066Sahrens * 2324fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 2325fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 2326fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 2327fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 2328fa9e4066Sahrens */ 2329fa9e4066Sahrens int 2330fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 2331fa9e4066Sahrens { 2332fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2333fa9e4066Sahrens } 2334fa9e4066Sahrens 2335fa9e4066Sahrens /* 2336fa9e4066Sahrens * zpool detach [-f] <pool> <device> 2337fa9e4066Sahrens * 2338fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 2339fa9e4066Sahrens * (not supported yet) 2340fa9e4066Sahrens * 2341fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 2342fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 2343fa9e4066Sahrens * has the only valid copy of some data. 2344fa9e4066Sahrens */ 2345fa9e4066Sahrens /* ARGSUSED */ 2346fa9e4066Sahrens int 2347fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 2348fa9e4066Sahrens { 2349fa9e4066Sahrens int c; 2350fa9e4066Sahrens char *poolname, *path; 2351fa9e4066Sahrens zpool_handle_t *zhp; 235299653d4eSeschrock int ret; 2353fa9e4066Sahrens 2354fa9e4066Sahrens /* check options */ 2355fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2356fa9e4066Sahrens switch (c) { 2357fa9e4066Sahrens case 'f': 2358fa9e4066Sahrens case '?': 2359fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2360fa9e4066Sahrens optopt); 236199653d4eSeschrock usage(B_FALSE); 2362fa9e4066Sahrens } 2363fa9e4066Sahrens } 2364fa9e4066Sahrens 2365fa9e4066Sahrens argc -= optind; 2366fa9e4066Sahrens argv += optind; 2367fa9e4066Sahrens 2368fa9e4066Sahrens /* get pool name and check number of arguments */ 2369fa9e4066Sahrens if (argc < 1) { 2370fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 237199653d4eSeschrock usage(B_FALSE); 2372fa9e4066Sahrens } 2373fa9e4066Sahrens 2374fa9e4066Sahrens if (argc < 2) { 2375fa9e4066Sahrens (void) fprintf(stderr, 2376fa9e4066Sahrens gettext("missing <device> specification\n")); 237799653d4eSeschrock usage(B_FALSE); 2378fa9e4066Sahrens } 2379fa9e4066Sahrens 2380fa9e4066Sahrens poolname = argv[0]; 2381fa9e4066Sahrens path = argv[1]; 2382fa9e4066Sahrens 238399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2384fa9e4066Sahrens return (1); 2385fa9e4066Sahrens 238699653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 238799653d4eSeschrock 238899653d4eSeschrock zpool_close(zhp); 238999653d4eSeschrock 239099653d4eSeschrock return (ret); 2391fa9e4066Sahrens } 2392fa9e4066Sahrens 2393fa9e4066Sahrens /* 2394441d80aaSlling * zpool online <pool> <device> ... 2395fa9e4066Sahrens */ 2396fa9e4066Sahrens int 2397fa9e4066Sahrens zpool_do_online(int argc, char **argv) 2398fa9e4066Sahrens { 2399fa9e4066Sahrens int c, i; 2400fa9e4066Sahrens char *poolname; 2401fa9e4066Sahrens zpool_handle_t *zhp; 2402fa9e4066Sahrens int ret = 0; 24033d7072f8Seschrock vdev_state_t newstate; 2404fa9e4066Sahrens 2405fa9e4066Sahrens /* check options */ 2406fa9e4066Sahrens while ((c = getopt(argc, argv, "t")) != -1) { 2407fa9e4066Sahrens switch (c) { 2408fa9e4066Sahrens case 't': 2409fa9e4066Sahrens case '?': 2410fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2411fa9e4066Sahrens optopt); 241299653d4eSeschrock usage(B_FALSE); 2413fa9e4066Sahrens } 2414fa9e4066Sahrens } 2415fa9e4066Sahrens 2416fa9e4066Sahrens argc -= optind; 2417fa9e4066Sahrens argv += optind; 2418fa9e4066Sahrens 2419fa9e4066Sahrens /* get pool name and check number of arguments */ 2420fa9e4066Sahrens if (argc < 1) { 2421fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 242299653d4eSeschrock usage(B_FALSE); 2423fa9e4066Sahrens } 2424fa9e4066Sahrens if (argc < 2) { 2425fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 242699653d4eSeschrock usage(B_FALSE); 2427fa9e4066Sahrens } 2428fa9e4066Sahrens 2429fa9e4066Sahrens poolname = argv[0]; 2430fa9e4066Sahrens 243199653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2432fa9e4066Sahrens return (1); 2433fa9e4066Sahrens 24343d7072f8Seschrock for (i = 1; i < argc; i++) { 24353d7072f8Seschrock if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) { 24363d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 24373d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 24383d7072f8Seschrock "onlined, but remains in faulted state\n"), 2439fa9e4066Sahrens argv[i]); 24403d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 24413d7072f8Seschrock (void) printf(gettext("use 'zpool " 24423d7072f8Seschrock "clear' to restore a faulted " 24433d7072f8Seschrock "device\n")); 2444fa9e4066Sahrens else 24453d7072f8Seschrock (void) printf(gettext("use 'zpool " 24463d7072f8Seschrock "replace' to replace devices " 24473d7072f8Seschrock "that are no longer present\n")); 24483d7072f8Seschrock } 24493d7072f8Seschrock } else { 2450fa9e4066Sahrens ret = 1; 24513d7072f8Seschrock } 24523d7072f8Seschrock } 2453fa9e4066Sahrens 245499653d4eSeschrock zpool_close(zhp); 245599653d4eSeschrock 2456fa9e4066Sahrens return (ret); 2457fa9e4066Sahrens } 2458fa9e4066Sahrens 2459fa9e4066Sahrens /* 2460441d80aaSlling * zpool offline [-ft] <pool> <device> ... 2461fa9e4066Sahrens * 2462fa9e4066Sahrens * -f Force the device into the offline state, even if doing 2463fa9e4066Sahrens * so would appear to compromise pool availability. 2464fa9e4066Sahrens * (not supported yet) 2465fa9e4066Sahrens * 2466fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 2467fa9e4066Sahrens * state will not be persistent across reboots. 2468fa9e4066Sahrens */ 2469fa9e4066Sahrens /* ARGSUSED */ 2470fa9e4066Sahrens int 2471fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 2472fa9e4066Sahrens { 2473fa9e4066Sahrens int c, i; 2474fa9e4066Sahrens char *poolname; 2475fa9e4066Sahrens zpool_handle_t *zhp; 247699653d4eSeschrock int ret = 0; 247799653d4eSeschrock boolean_t istmp = B_FALSE; 2478fa9e4066Sahrens 2479fa9e4066Sahrens /* check options */ 2480fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 2481fa9e4066Sahrens switch (c) { 2482fa9e4066Sahrens case 't': 248399653d4eSeschrock istmp = B_TRUE; 2484441d80aaSlling break; 2485441d80aaSlling case 'f': 2486fa9e4066Sahrens case '?': 2487fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2488fa9e4066Sahrens optopt); 248999653d4eSeschrock usage(B_FALSE); 2490fa9e4066Sahrens } 2491fa9e4066Sahrens } 2492fa9e4066Sahrens 2493fa9e4066Sahrens argc -= optind; 2494fa9e4066Sahrens argv += optind; 2495fa9e4066Sahrens 2496fa9e4066Sahrens /* get pool name and check number of arguments */ 2497fa9e4066Sahrens if (argc < 1) { 2498fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 249999653d4eSeschrock usage(B_FALSE); 2500fa9e4066Sahrens } 2501fa9e4066Sahrens if (argc < 2) { 2502fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 250399653d4eSeschrock usage(B_FALSE); 2504fa9e4066Sahrens } 2505fa9e4066Sahrens 2506fa9e4066Sahrens poolname = argv[0]; 2507fa9e4066Sahrens 250899653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2509fa9e4066Sahrens return (1); 2510fa9e4066Sahrens 25113d7072f8Seschrock for (i = 1; i < argc; i++) { 25123d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2513fa9e4066Sahrens ret = 1; 25143d7072f8Seschrock } 2515fa9e4066Sahrens 251699653d4eSeschrock zpool_close(zhp); 251799653d4eSeschrock 2518fa9e4066Sahrens return (ret); 2519fa9e4066Sahrens } 2520fa9e4066Sahrens 2521ea8dc4b6Seschrock /* 2522ea8dc4b6Seschrock * zpool clear <pool> [device] 2523ea8dc4b6Seschrock * 2524ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 2525ea8dc4b6Seschrock */ 2526ea8dc4b6Seschrock int 2527ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 2528ea8dc4b6Seschrock { 2529ea8dc4b6Seschrock int ret = 0; 2530ea8dc4b6Seschrock zpool_handle_t *zhp; 2531ea8dc4b6Seschrock char *pool, *device; 2532ea8dc4b6Seschrock 2533ea8dc4b6Seschrock if (argc < 2) { 2534ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 253599653d4eSeschrock usage(B_FALSE); 2536ea8dc4b6Seschrock } 2537ea8dc4b6Seschrock 2538ea8dc4b6Seschrock if (argc > 3) { 2539ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 254099653d4eSeschrock usage(B_FALSE); 2541ea8dc4b6Seschrock } 2542ea8dc4b6Seschrock 2543ea8dc4b6Seschrock pool = argv[1]; 2544ea8dc4b6Seschrock device = argc == 3 ? argv[2] : NULL; 2545ea8dc4b6Seschrock 254699653d4eSeschrock if ((zhp = zpool_open(g_zfs, pool)) == NULL) 2547ea8dc4b6Seschrock return (1); 2548ea8dc4b6Seschrock 2549ea8dc4b6Seschrock if (zpool_clear(zhp, device) != 0) 2550ea8dc4b6Seschrock ret = 1; 2551ea8dc4b6Seschrock 2552ea8dc4b6Seschrock zpool_close(zhp); 2553ea8dc4b6Seschrock 2554ea8dc4b6Seschrock return (ret); 2555ea8dc4b6Seschrock } 2556ea8dc4b6Seschrock 2557fa9e4066Sahrens typedef struct scrub_cbdata { 2558fa9e4066Sahrens int cb_type; 255906eeb2adSek110237 int cb_argc; 256006eeb2adSek110237 char **cb_argv; 2561fa9e4066Sahrens } scrub_cbdata_t; 2562fa9e4066Sahrens 2563fa9e4066Sahrens int 2564fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 2565fa9e4066Sahrens { 2566fa9e4066Sahrens scrub_cbdata_t *cb = data; 256706eeb2adSek110237 int err; 2568fa9e4066Sahrens 2569ea8dc4b6Seschrock /* 2570ea8dc4b6Seschrock * Ignore faulted pools. 2571ea8dc4b6Seschrock */ 2572ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2573ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2574ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 2575ea8dc4b6Seschrock return (1); 2576ea8dc4b6Seschrock } 2577ea8dc4b6Seschrock 257806eeb2adSek110237 err = zpool_scrub(zhp, cb->cb_type); 257906eeb2adSek110237 258006eeb2adSek110237 return (err != 0); 2581fa9e4066Sahrens } 2582fa9e4066Sahrens 2583fa9e4066Sahrens /* 2584fa9e4066Sahrens * zpool scrub [-s] <pool> ... 2585fa9e4066Sahrens * 2586fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 2587fa9e4066Sahrens */ 2588fa9e4066Sahrens int 2589fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 2590fa9e4066Sahrens { 2591fa9e4066Sahrens int c; 2592fa9e4066Sahrens scrub_cbdata_t cb; 2593fa9e4066Sahrens 2594fa9e4066Sahrens cb.cb_type = POOL_SCRUB_EVERYTHING; 2595fa9e4066Sahrens 2596fa9e4066Sahrens /* check options */ 2597fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 2598fa9e4066Sahrens switch (c) { 2599fa9e4066Sahrens case 's': 2600fa9e4066Sahrens cb.cb_type = POOL_SCRUB_NONE; 2601fa9e4066Sahrens break; 2602fa9e4066Sahrens case '?': 2603fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2604fa9e4066Sahrens optopt); 260599653d4eSeschrock usage(B_FALSE); 2606fa9e4066Sahrens } 2607fa9e4066Sahrens } 2608fa9e4066Sahrens 260906eeb2adSek110237 cb.cb_argc = argc; 261006eeb2adSek110237 cb.cb_argv = argv; 2611fa9e4066Sahrens argc -= optind; 2612fa9e4066Sahrens argv += optind; 2613fa9e4066Sahrens 2614fa9e4066Sahrens if (argc < 1) { 2615fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 261699653d4eSeschrock usage(B_FALSE); 2617fa9e4066Sahrens } 2618fa9e4066Sahrens 2619b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2620fa9e4066Sahrens } 2621fa9e4066Sahrens 2622fa9e4066Sahrens typedef struct status_cbdata { 2623fa9e4066Sahrens int cb_count; 2624e9dbad6fSeschrock boolean_t cb_allpools; 262599653d4eSeschrock boolean_t cb_verbose; 262699653d4eSeschrock boolean_t cb_explain; 262799653d4eSeschrock boolean_t cb_first; 2628fa9e4066Sahrens } status_cbdata_t; 2629fa9e4066Sahrens 2630fa9e4066Sahrens /* 2631fa9e4066Sahrens * Print out detailed scrub status. 2632fa9e4066Sahrens */ 2633fa9e4066Sahrens void 2634fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot) 2635fa9e4066Sahrens { 2636fa9e4066Sahrens vdev_stat_t *vs; 2637fa9e4066Sahrens uint_t vsc; 2638fa9e4066Sahrens time_t start, end, now; 2639fa9e4066Sahrens double fraction_done; 2640fa9e4066Sahrens uint64_t examined, total, minutes_left; 2641fa9e4066Sahrens char *scrub_type; 2642fa9e4066Sahrens 2643fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2644fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 2645fa9e4066Sahrens 2646fa9e4066Sahrens /* 2647fa9e4066Sahrens * If there's never been a scrub, there's not much to say. 2648fa9e4066Sahrens */ 2649fa9e4066Sahrens if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2650fa9e4066Sahrens (void) printf(gettext("none requested\n")); 2651fa9e4066Sahrens return; 2652fa9e4066Sahrens } 2653fa9e4066Sahrens 2654fa9e4066Sahrens scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2655fa9e4066Sahrens "resilver" : "scrub"; 2656fa9e4066Sahrens 2657fa9e4066Sahrens start = vs->vs_scrub_start; 2658fa9e4066Sahrens end = vs->vs_scrub_end; 2659fa9e4066Sahrens now = time(NULL); 2660fa9e4066Sahrens examined = vs->vs_scrub_examined; 2661fa9e4066Sahrens total = vs->vs_alloc; 2662fa9e4066Sahrens 2663fa9e4066Sahrens if (end != 0) { 2664fa9e4066Sahrens (void) printf(gettext("%s %s with %llu errors on %s"), 2665fa9e4066Sahrens scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 2666fa9e4066Sahrens (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2667fa9e4066Sahrens return; 2668fa9e4066Sahrens } 2669fa9e4066Sahrens 2670fa9e4066Sahrens if (examined == 0) 2671fa9e4066Sahrens examined = 1; 2672fa9e4066Sahrens if (examined > total) 2673fa9e4066Sahrens total = examined; 2674fa9e4066Sahrens 2675fa9e4066Sahrens fraction_done = (double)examined / total; 2676fa9e4066Sahrens minutes_left = (uint64_t)((now - start) * 2677fa9e4066Sahrens (1 - fraction_done) / fraction_done / 60); 2678fa9e4066Sahrens 2679fa9e4066Sahrens (void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"), 2680fa9e4066Sahrens scrub_type, 100 * fraction_done, 2681fa9e4066Sahrens (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2682fa9e4066Sahrens } 2683fa9e4066Sahrens 268499653d4eSeschrock typedef struct spare_cbdata { 268599653d4eSeschrock uint64_t cb_guid; 268699653d4eSeschrock zpool_handle_t *cb_zhp; 268799653d4eSeschrock } spare_cbdata_t; 268899653d4eSeschrock 268999653d4eSeschrock static boolean_t 269099653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search) 269199653d4eSeschrock { 269299653d4eSeschrock uint64_t guid; 269399653d4eSeschrock nvlist_t **child; 269499653d4eSeschrock uint_t c, children; 269599653d4eSeschrock 269699653d4eSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 269799653d4eSeschrock search == guid) 269899653d4eSeschrock return (B_TRUE); 269999653d4eSeschrock 270099653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 270199653d4eSeschrock &child, &children) == 0) { 270299653d4eSeschrock for (c = 0; c < children; c++) 270399653d4eSeschrock if (find_vdev(child[c], search)) 270499653d4eSeschrock return (B_TRUE); 270599653d4eSeschrock } 270699653d4eSeschrock 270799653d4eSeschrock return (B_FALSE); 270899653d4eSeschrock } 270999653d4eSeschrock 271099653d4eSeschrock static int 271199653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data) 271299653d4eSeschrock { 271399653d4eSeschrock spare_cbdata_t *cbp = data; 271499653d4eSeschrock nvlist_t *config, *nvroot; 271599653d4eSeschrock 271699653d4eSeschrock config = zpool_get_config(zhp, NULL); 271799653d4eSeschrock verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 271899653d4eSeschrock &nvroot) == 0); 271999653d4eSeschrock 272099653d4eSeschrock if (find_vdev(nvroot, cbp->cb_guid)) { 272199653d4eSeschrock cbp->cb_zhp = zhp; 272299653d4eSeschrock return (1); 272399653d4eSeschrock } 272499653d4eSeschrock 272599653d4eSeschrock zpool_close(zhp); 272699653d4eSeschrock return (0); 272799653d4eSeschrock } 272899653d4eSeschrock 2729fa9e4066Sahrens /* 2730fa9e4066Sahrens * Print out configuration state as requested by status_callback. 2731fa9e4066Sahrens */ 2732fa9e4066Sahrens void 2733c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 27348654d025Sperrin int namewidth, int depth, boolean_t isspare, boolean_t print_logs) 2735fa9e4066Sahrens { 2736fa9e4066Sahrens nvlist_t **child; 2737fa9e4066Sahrens uint_t c, children; 2738fa9e4066Sahrens vdev_stat_t *vs; 2739ea8dc4b6Seschrock char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 2740afefbcddSeschrock char *vname; 2741ea8dc4b6Seschrock uint64_t notpresent; 274299653d4eSeschrock spare_cbdata_t cb; 274399653d4eSeschrock const char *state; 2744fa9e4066Sahrens 2745fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2746fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 2747fa9e4066Sahrens 2748fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2749fa9e4066Sahrens &child, &children) != 0) 2750fa9e4066Sahrens children = 0; 2751fa9e4066Sahrens 275299653d4eSeschrock state = state_to_name(vs); 275399653d4eSeschrock if (isspare) { 275499653d4eSeschrock /* 275599653d4eSeschrock * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 275699653d4eSeschrock * online drives. 275799653d4eSeschrock */ 275899653d4eSeschrock if (vs->vs_aux == VDEV_AUX_SPARED) 275999653d4eSeschrock state = "INUSE"; 276099653d4eSeschrock else if (vs->vs_state == VDEV_STATE_HEALTHY) 276199653d4eSeschrock state = "AVAIL"; 276299653d4eSeschrock } 2763fa9e4066Sahrens 276499653d4eSeschrock (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 276599653d4eSeschrock name, state); 276699653d4eSeschrock 276799653d4eSeschrock if (!isspare) { 2768fa9e4066Sahrens zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 2769fa9e4066Sahrens zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 2770fa9e4066Sahrens zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 2771fa9e4066Sahrens (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 277299653d4eSeschrock } 2773fa9e4066Sahrens 2774ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2775ea8dc4b6Seschrock ¬present) == 0) { 2776ea8dc4b6Seschrock char *path; 2777ea8dc4b6Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 27780917b783Seschrock (void) printf(" was %s", path); 2779ea8dc4b6Seschrock } else if (vs->vs_aux != 0) { 2780fa9e4066Sahrens (void) printf(" "); 2781fa9e4066Sahrens 2782fa9e4066Sahrens switch (vs->vs_aux) { 2783fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 2784fa9e4066Sahrens (void) printf(gettext("cannot open")); 2785fa9e4066Sahrens break; 2786fa9e4066Sahrens 2787fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 2788fa9e4066Sahrens (void) printf(gettext("missing device")); 2789fa9e4066Sahrens break; 2790fa9e4066Sahrens 2791fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 2792fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 2793fa9e4066Sahrens break; 2794fa9e4066Sahrens 2795eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 2796eaca9bbdSeschrock (void) printf(gettext("newer version")); 2797eaca9bbdSeschrock break; 2798eaca9bbdSeschrock 279999653d4eSeschrock case VDEV_AUX_SPARED: 280099653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 280199653d4eSeschrock &cb.cb_guid) == 0); 280299653d4eSeschrock if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 280399653d4eSeschrock if (strcmp(zpool_get_name(cb.cb_zhp), 280499653d4eSeschrock zpool_get_name(zhp)) == 0) 280599653d4eSeschrock (void) printf(gettext("currently in " 280699653d4eSeschrock "use")); 280799653d4eSeschrock else 280899653d4eSeschrock (void) printf(gettext("in use by " 280999653d4eSeschrock "pool '%s'"), 281099653d4eSeschrock zpool_get_name(cb.cb_zhp)); 281199653d4eSeschrock zpool_close(cb.cb_zhp); 281299653d4eSeschrock } else { 281399653d4eSeschrock (void) printf(gettext("currently in use")); 281499653d4eSeschrock } 281599653d4eSeschrock break; 281699653d4eSeschrock 28173d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 28183d7072f8Seschrock (void) printf(gettext("too many errors")); 28193d7072f8Seschrock break; 28203d7072f8Seschrock 2821fa9e4066Sahrens default: 2822fa9e4066Sahrens (void) printf(gettext("corrupted data")); 2823fa9e4066Sahrens break; 2824fa9e4066Sahrens } 2825fa9e4066Sahrens } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2826fa9e4066Sahrens /* 2827fa9e4066Sahrens * Report bytes resilvered/repaired on leaf devices. 2828fa9e4066Sahrens */ 2829fa9e4066Sahrens zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2830fa9e4066Sahrens (void) printf(gettext(" %s %s"), repaired, 2831fa9e4066Sahrens (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2832fa9e4066Sahrens "resilvered" : "repaired"); 2833fa9e4066Sahrens } 2834fa9e4066Sahrens 2835fa9e4066Sahrens (void) printf("\n"); 2836fa9e4066Sahrens 2837afefbcddSeschrock for (c = 0; c < children; c++) { 28388654d025Sperrin uint64_t is_log = B_FALSE; 28398654d025Sperrin 28408654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 28418654d025Sperrin &is_log); 28428654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 28438654d025Sperrin continue; 284499653d4eSeschrock vname = zpool_vdev_name(g_zfs, zhp, child[c]); 2845c67d9675Seschrock print_status_config(zhp, vname, child[c], 28468654d025Sperrin namewidth, depth + 2, isspare, B_FALSE); 2847afefbcddSeschrock free(vname); 2848afefbcddSeschrock } 2849fa9e4066Sahrens } 2850fa9e4066Sahrens 2851ea8dc4b6Seschrock static void 2852ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 2853ea8dc4b6Seschrock { 285475519f38Sek110237 nvlist_t *nverrlist = NULL; 285555434c77Sek110237 nvpair_t *elem; 285655434c77Sek110237 char *pathname; 285755434c77Sek110237 size_t len = MAXPATHLEN * 2; 2858ea8dc4b6Seschrock 285955434c77Sek110237 if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2860ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 2861ea8dc4b6Seschrock "(insufficient privileges)\n"); 2862ea8dc4b6Seschrock return; 2863ea8dc4b6Seschrock } 2864ea8dc4b6Seschrock 286555434c77Sek110237 (void) printf("errors: Permanent errors have been " 286655434c77Sek110237 "detected in the following files:\n\n"); 2867ea8dc4b6Seschrock 286855434c77Sek110237 pathname = safe_malloc(len); 286955434c77Sek110237 elem = NULL; 287055434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 287155434c77Sek110237 nvlist_t *nv; 287255434c77Sek110237 uint64_t dsobj, obj; 2873ea8dc4b6Seschrock 287455434c77Sek110237 verify(nvpair_value_nvlist(elem, &nv) == 0); 287555434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 287655434c77Sek110237 &dsobj) == 0); 287755434c77Sek110237 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 287855434c77Sek110237 &obj) == 0); 287955434c77Sek110237 zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 288055434c77Sek110237 (void) printf("%7s %s\n", "", pathname); 2881ea8dc4b6Seschrock } 288255434c77Sek110237 free(pathname); 288355434c77Sek110237 nvlist_free(nverrlist); 2884ea8dc4b6Seschrock } 2885ea8dc4b6Seschrock 288699653d4eSeschrock static void 288799653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 288899653d4eSeschrock int namewidth) 288999653d4eSeschrock { 289099653d4eSeschrock uint_t i; 289199653d4eSeschrock char *name; 289299653d4eSeschrock 289399653d4eSeschrock if (nspares == 0) 289499653d4eSeschrock return; 289599653d4eSeschrock 289699653d4eSeschrock (void) printf(gettext("\tspares\n")); 289799653d4eSeschrock 289899653d4eSeschrock for (i = 0; i < nspares; i++) { 289999653d4eSeschrock name = zpool_vdev_name(g_zfs, zhp, spares[i]); 290099653d4eSeschrock print_status_config(zhp, name, spares[i], 29018654d025Sperrin namewidth, 2, B_TRUE, B_FALSE); 290299653d4eSeschrock free(name); 290399653d4eSeschrock } 290499653d4eSeschrock } 290599653d4eSeschrock 2906fa9e4066Sahrens /* 2907fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 2908fa9e4066Sahrens * 2909fa9e4066Sahrens * pool: tank 2910fa9e4066Sahrens * status: DEGRADED 2911fa9e4066Sahrens * reason: One or more devices ... 2912fa9e4066Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01 2913fa9e4066Sahrens * config: 2914fa9e4066Sahrens * mirror DEGRADED 2915fa9e4066Sahrens * c1t0d0 OK 2916ea8dc4b6Seschrock * c2t0d0 UNAVAIL 2917fa9e4066Sahrens * 2918fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 2919fa9e4066Sahrens * option is specified, then we print out error rate information as well. 2920fa9e4066Sahrens */ 2921fa9e4066Sahrens int 2922fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 2923fa9e4066Sahrens { 2924fa9e4066Sahrens status_cbdata_t *cbp = data; 2925fa9e4066Sahrens nvlist_t *config, *nvroot; 2926fa9e4066Sahrens char *msgid; 2927fa9e4066Sahrens int reason; 292846657f8dSmmusante const char *health; 292946657f8dSmmusante uint_t c; 293046657f8dSmmusante vdev_stat_t *vs; 2931fa9e4066Sahrens 2932088e9d47Seschrock config = zpool_get_config(zhp, NULL); 2933fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 2934fa9e4066Sahrens 2935fa9e4066Sahrens cbp->cb_count++; 2936fa9e4066Sahrens 2937fa9e4066Sahrens /* 2938fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 2939fa9e4066Sahrens * problems. 2940fa9e4066Sahrens */ 2941e9dbad6fSeschrock if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 2942e9dbad6fSeschrock if (!cbp->cb_allpools) { 2943e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 2944e9dbad6fSeschrock zpool_get_name(zhp)); 2945e9dbad6fSeschrock if (cbp->cb_first) 2946e9dbad6fSeschrock cbp->cb_first = B_FALSE; 2947e9dbad6fSeschrock } 2948fa9e4066Sahrens return (0); 2949e9dbad6fSeschrock } 2950fa9e4066Sahrens 2951fa9e4066Sahrens if (cbp->cb_first) 295299653d4eSeschrock cbp->cb_first = B_FALSE; 2953fa9e4066Sahrens else 2954fa9e4066Sahrens (void) printf("\n"); 2955fa9e4066Sahrens 295646657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 295746657f8dSmmusante &nvroot) == 0); 295846657f8dSmmusante verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 295946657f8dSmmusante (uint64_t **)&vs, &c) == 0); 296046657f8dSmmusante health = state_to_name(vs); 2961fa9e4066Sahrens 2962fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 2963fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 2964fa9e4066Sahrens 2965fa9e4066Sahrens switch (reason) { 2966fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 2967fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2968fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 2969fa9e4066Sahrens "continue functioning in a degraded state.\n")); 2970fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2971fa9e4066Sahrens "online it using 'zpool online'.\n")); 2972fa9e4066Sahrens break; 2973fa9e4066Sahrens 2974fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 2975fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2976fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 2977fa9e4066Sahrens "pool to continue functioning.\n")); 2978fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2979fa9e4066Sahrens "online it using 'zpool online'.\n")); 2980fa9e4066Sahrens break; 2981fa9e4066Sahrens 2982fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 2983fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2984fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 2985fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 2986fa9e4066Sahrens "functioning in a degraded state.\n")); 2987fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 2988fa9e4066Sahrens "'zpool replace'.\n")); 2989fa9e4066Sahrens break; 2990fa9e4066Sahrens 2991fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 2992fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2993b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 2994fa9e4066Sahrens "There are insufficient replicas for the pool to " 2995fa9e4066Sahrens "continue\n\tfunctioning.\n")); 2996fa9e4066Sahrens (void) printf(gettext("action: Destroy and re-create the pool " 2997fa9e4066Sahrens "from a backup source.\n")); 2998fa9e4066Sahrens break; 2999fa9e4066Sahrens 3000fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 3001fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 3002fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 3003fa9e4066Sahrens "made to correct the error. Applications are " 3004fa9e4066Sahrens "unaffected.\n")); 3005fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 3006fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 3007ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 3008fa9e4066Sahrens "replace'.\n")); 3009fa9e4066Sahrens break; 3010fa9e4066Sahrens 3011fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 3012fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 3013d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 3014fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 3015fa9e4066Sahrens "a\n\tdegraded state.\n")); 3016fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 3017fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 3018fa9e4066Sahrens "replace'.\n")); 3019fa9e4066Sahrens break; 3020fa9e4066Sahrens 3021fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 3022fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 3023fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 3024fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 3025fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 3026fa9e4066Sahrens "complete.\n")); 3027fa9e4066Sahrens break; 3028fa9e4066Sahrens 3029ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 3030ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 3031ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 3032ea8dc4b6Seschrock "Applications may be affected.\n")); 3033ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 3034ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 3035ea8dc4b6Seschrock "backup.\n")); 3036ea8dc4b6Seschrock break; 3037ea8dc4b6Seschrock 3038ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 3039ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 3040ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 3041ea8dc4b6Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 3042ea8dc4b6Seschrock "from a backup source.\n")); 3043ea8dc4b6Seschrock break; 3044ea8dc4b6Seschrock 3045eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 3046eaca9bbdSeschrock (void) printf(gettext("status: The pool is formatted using an " 3047eaca9bbdSeschrock "older on-disk format. The pool can\n\tstill be used, but " 3048eaca9bbdSeschrock "some features are unavailable.\n")); 3049eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 3050eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 3051eaca9bbdSeschrock "be accessible on older software versions.\n")); 3052eaca9bbdSeschrock break; 3053eaca9bbdSeschrock 3054eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 3055eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 3056eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 3057eaca9bbdSeschrock "be accessed on this system.\n")); 3058eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 3059eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 3060eaca9bbdSeschrock "backup.\n")); 3061eaca9bbdSeschrock break; 3062eaca9bbdSeschrock 30633d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 30643d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 30653d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 30663d7072f8Seschrock "replicas exist for the pool to continue functioning " 30673d7072f8Seschrock "in a\n\tdegraded state.\n")); 30683d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 30693d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 30703d7072f8Seschrock break; 30713d7072f8Seschrock 30723d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 30733d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 30743d7072f8Seschrock "faulted in response to persistent errors. There are " 30753d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 30763d7072f8Seschrock "functioning.\n")); 30773d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 30783d7072f8Seschrock "from a backup source. Manually marking the device\n" 30793d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 30803d7072f8Seschrock "to be recovered.\n")); 30813d7072f8Seschrock break; 30823d7072f8Seschrock 3083fa9e4066Sahrens default: 3084fa9e4066Sahrens /* 3085fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 3086fa9e4066Sahrens */ 3087fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 3088fa9e4066Sahrens } 3089fa9e4066Sahrens 3090fa9e4066Sahrens if (msgid != NULL) 3091fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3092fa9e4066Sahrens msgid); 3093fa9e4066Sahrens 3094fa9e4066Sahrens if (config != NULL) { 3095fa9e4066Sahrens int namewidth; 3096ea8dc4b6Seschrock uint64_t nerr; 309799653d4eSeschrock nvlist_t **spares; 309899653d4eSeschrock uint_t nspares; 3099fa9e4066Sahrens 3100fa9e4066Sahrens 3101fa9e4066Sahrens (void) printf(gettext(" scrub: ")); 3102fa9e4066Sahrens print_scrub_status(nvroot); 3103fa9e4066Sahrens 3104c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 3105fa9e4066Sahrens if (namewidth < 10) 3106fa9e4066Sahrens namewidth = 10; 3107fa9e4066Sahrens 3108fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 3109fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3110fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3111c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 31128654d025Sperrin namewidth, 0, B_FALSE, B_FALSE); 31138654d025Sperrin if (num_logs(nvroot) > 0) 31148654d025Sperrin print_status_config(zhp, "logs", nvroot, namewidth, 0, 31158654d025Sperrin B_FALSE, B_TRUE); 311699653d4eSeschrock 311799653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 311899653d4eSeschrock &spares, &nspares) == 0) 311999653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 3120ea8dc4b6Seschrock 3121ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3122ea8dc4b6Seschrock &nerr) == 0) { 312355434c77Sek110237 nvlist_t *nverrlist = NULL; 312455434c77Sek110237 3125ea8dc4b6Seschrock /* 3126ea8dc4b6Seschrock * If the approximate error count is small, get a 3127ea8dc4b6Seschrock * precise count by fetching the entire log and 3128ea8dc4b6Seschrock * uniquifying the results. 3129ea8dc4b6Seschrock */ 313075519f38Sek110237 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 313155434c77Sek110237 zpool_get_errlog(zhp, &nverrlist) == 0) { 313255434c77Sek110237 nvpair_t *elem; 313355434c77Sek110237 313455434c77Sek110237 elem = NULL; 313555434c77Sek110237 nerr = 0; 313655434c77Sek110237 while ((elem = nvlist_next_nvpair(nverrlist, 313755434c77Sek110237 elem)) != NULL) { 313855434c77Sek110237 nerr++; 313955434c77Sek110237 } 314055434c77Sek110237 } 314155434c77Sek110237 nvlist_free(nverrlist); 3142ea8dc4b6Seschrock 3143ea8dc4b6Seschrock (void) printf("\n"); 314499653d4eSeschrock 3145ea8dc4b6Seschrock if (nerr == 0) 3146ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 3147ea8dc4b6Seschrock "errors\n")); 3148ea8dc4b6Seschrock else if (!cbp->cb_verbose) 3149e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 31505ad82045Snd150628 "errors, use '-v' for a list\n"), 31515ad82045Snd150628 (u_longlong_t)nerr); 3152ea8dc4b6Seschrock else 3153ea8dc4b6Seschrock print_error_log(zhp); 3154ea8dc4b6Seschrock } 3155fa9e4066Sahrens } else { 3156fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 3157fa9e4066Sahrens "determined.\n")); 3158fa9e4066Sahrens } 3159fa9e4066Sahrens 3160fa9e4066Sahrens return (0); 3161fa9e4066Sahrens } 3162fa9e4066Sahrens 3163fa9e4066Sahrens /* 3164fa9e4066Sahrens * zpool status [-vx] [pool] ... 3165fa9e4066Sahrens * 3166fa9e4066Sahrens * -v Display complete error logs 3167fa9e4066Sahrens * -x Display only pools with potential problems 3168fa9e4066Sahrens * 3169fa9e4066Sahrens * Describes the health status of all pools or some subset. 3170fa9e4066Sahrens */ 3171fa9e4066Sahrens int 3172fa9e4066Sahrens zpool_do_status(int argc, char **argv) 3173fa9e4066Sahrens { 3174fa9e4066Sahrens int c; 3175fa9e4066Sahrens int ret; 3176fa9e4066Sahrens status_cbdata_t cb = { 0 }; 3177fa9e4066Sahrens 3178fa9e4066Sahrens /* check options */ 3179fa9e4066Sahrens while ((c = getopt(argc, argv, "vx")) != -1) { 3180fa9e4066Sahrens switch (c) { 3181fa9e4066Sahrens case 'v': 318299653d4eSeschrock cb.cb_verbose = B_TRUE; 3183fa9e4066Sahrens break; 3184fa9e4066Sahrens case 'x': 318599653d4eSeschrock cb.cb_explain = B_TRUE; 3186fa9e4066Sahrens break; 3187fa9e4066Sahrens case '?': 3188fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3189fa9e4066Sahrens optopt); 319099653d4eSeschrock usage(B_FALSE); 3191fa9e4066Sahrens } 3192fa9e4066Sahrens } 3193fa9e4066Sahrens 3194fa9e4066Sahrens argc -= optind; 3195fa9e4066Sahrens argv += optind; 3196fa9e4066Sahrens 319799653d4eSeschrock cb.cb_first = B_TRUE; 3198fa9e4066Sahrens 3199e9dbad6fSeschrock if (argc == 0) 3200e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 3201e9dbad6fSeschrock 3202b1b8ab34Slling ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3203fa9e4066Sahrens 3204fa9e4066Sahrens if (argc == 0 && cb.cb_count == 0) 3205fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 3206e9dbad6fSeschrock else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3207fa9e4066Sahrens (void) printf(gettext("all pools are healthy\n")); 3208fa9e4066Sahrens 3209fa9e4066Sahrens return (ret); 3210fa9e4066Sahrens } 3211fa9e4066Sahrens 3212eaca9bbdSeschrock typedef struct upgrade_cbdata { 3213eaca9bbdSeschrock int cb_all; 3214eaca9bbdSeschrock int cb_first; 3215eaca9bbdSeschrock int cb_newer; 321606eeb2adSek110237 int cb_argc; 3217e7437265Sahrens uint64_t cb_numupgraded; 3218e7437265Sahrens uint64_t cb_numsamegraded; 321906eeb2adSek110237 char **cb_argv; 3220eaca9bbdSeschrock } upgrade_cbdata_t; 3221eaca9bbdSeschrock 3222eaca9bbdSeschrock static int 3223eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 3224eaca9bbdSeschrock { 3225eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 3226eaca9bbdSeschrock nvlist_t *config; 3227eaca9bbdSeschrock uint64_t version; 3228eaca9bbdSeschrock int ret = 0; 3229eaca9bbdSeschrock 3230eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 3231eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3232eaca9bbdSeschrock &version) == 0); 3233eaca9bbdSeschrock 3234e7437265Sahrens if (!cbp->cb_newer && version < SPA_VERSION) { 3235eaca9bbdSeschrock if (!cbp->cb_all) { 3236eaca9bbdSeschrock if (cbp->cb_first) { 3237eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3238eaca9bbdSeschrock "out of date, and can be upgraded. After " 3239eaca9bbdSeschrock "being\nupgraded, these pools will no " 3240eaca9bbdSeschrock "longer be accessible by older software " 3241eaca9bbdSeschrock "versions.\n\n")); 3242eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3243eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 324499653d4eSeschrock cbp->cb_first = B_FALSE; 3245eaca9bbdSeschrock } 3246eaca9bbdSeschrock 32475ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3248eaca9bbdSeschrock zpool_get_name(zhp)); 3249eaca9bbdSeschrock } else { 325099653d4eSeschrock cbp->cb_first = B_FALSE; 3251eaca9bbdSeschrock ret = zpool_upgrade(zhp); 325206eeb2adSek110237 if (!ret) { 3253eaca9bbdSeschrock (void) printf(gettext("Successfully upgraded " 3254eaca9bbdSeschrock "'%s'\n"), zpool_get_name(zhp)); 3255eaca9bbdSeschrock } 325606eeb2adSek110237 } 3257e7437265Sahrens } else if (cbp->cb_newer && version > SPA_VERSION) { 3258eaca9bbdSeschrock assert(!cbp->cb_all); 3259eaca9bbdSeschrock 3260eaca9bbdSeschrock if (cbp->cb_first) { 3261eaca9bbdSeschrock (void) printf(gettext("The following pools are " 3262eaca9bbdSeschrock "formatted using a newer software version and\n" 3263eaca9bbdSeschrock "cannot be accessed on the current system.\n\n")); 3264eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 3265eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 326699653d4eSeschrock cbp->cb_first = B_FALSE; 3267eaca9bbdSeschrock } 3268eaca9bbdSeschrock 32695ad82045Snd150628 (void) printf("%2llu %s\n", (u_longlong_t)version, 3270eaca9bbdSeschrock zpool_get_name(zhp)); 3271eaca9bbdSeschrock } 3272eaca9bbdSeschrock 3273eaca9bbdSeschrock zpool_close(zhp); 3274eaca9bbdSeschrock return (ret); 3275eaca9bbdSeschrock } 3276eaca9bbdSeschrock 3277eaca9bbdSeschrock /* ARGSUSED */ 3278eaca9bbdSeschrock static int 327906eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data) 3280eaca9bbdSeschrock { 3281eaca9bbdSeschrock nvlist_t *config; 3282eaca9bbdSeschrock uint64_t version; 3283eaca9bbdSeschrock int ret; 3284eaca9bbdSeschrock 3285eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 3286eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3287eaca9bbdSeschrock &version) == 0); 3288eaca9bbdSeschrock 32898654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 32908654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 32918654d025Sperrin "Pool 'log' must be renamed using export and import" 32928654d025Sperrin " to upgrade.\n")); 32938654d025Sperrin return (1); 32948654d025Sperrin } 3295e7437265Sahrens if (version == SPA_VERSION) { 3296eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 3297eaca9bbdSeschrock "using the current version.\n"), zpool_get_name(zhp)); 3298eaca9bbdSeschrock return (0); 3299eaca9bbdSeschrock } 3300eaca9bbdSeschrock 3301eaca9bbdSeschrock ret = zpool_upgrade(zhp); 330206eeb2adSek110237 330306eeb2adSek110237 if (!ret) { 330444cd46caSbillm (void) printf(gettext("Successfully upgraded '%s' " 330544cd46caSbillm "from version %llu to version %llu\n"), zpool_get_name(zhp), 3306e7437265Sahrens (u_longlong_t)version, (u_longlong_t)SPA_VERSION); 330706eeb2adSek110237 } 3308eaca9bbdSeschrock 3309eaca9bbdSeschrock return (ret != 0); 3310eaca9bbdSeschrock } 3311eaca9bbdSeschrock 3312eaca9bbdSeschrock /* 3313eaca9bbdSeschrock * zpool upgrade 3314eaca9bbdSeschrock * zpool upgrade -v 3315eaca9bbdSeschrock * zpool upgrade <-a | pool> 3316eaca9bbdSeschrock * 3317eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 3318eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 3319eaca9bbdSeschrock * upgrade all pools. 3320eaca9bbdSeschrock */ 3321eaca9bbdSeschrock int 3322eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 3323eaca9bbdSeschrock { 3324eaca9bbdSeschrock int c; 3325eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 3326eaca9bbdSeschrock int ret = 0; 3327eaca9bbdSeschrock boolean_t showversions = B_FALSE; 3328eaca9bbdSeschrock 3329eaca9bbdSeschrock /* check options */ 3330eaca9bbdSeschrock while ((c = getopt(argc, argv, "av")) != -1) { 3331eaca9bbdSeschrock switch (c) { 3332eaca9bbdSeschrock case 'a': 333399653d4eSeschrock cb.cb_all = B_TRUE; 3334eaca9bbdSeschrock break; 3335eaca9bbdSeschrock case 'v': 3336eaca9bbdSeschrock showversions = B_TRUE; 3337eaca9bbdSeschrock break; 3338eaca9bbdSeschrock case '?': 3339eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3340eaca9bbdSeschrock optopt); 334199653d4eSeschrock usage(B_FALSE); 3342eaca9bbdSeschrock } 3343eaca9bbdSeschrock } 3344eaca9bbdSeschrock 334506eeb2adSek110237 cb.cb_argc = argc; 334606eeb2adSek110237 cb.cb_argv = argv; 3347eaca9bbdSeschrock argc -= optind; 3348eaca9bbdSeschrock argv += optind; 3349eaca9bbdSeschrock 3350eaca9bbdSeschrock if (showversions) { 3351eaca9bbdSeschrock if (cb.cb_all || argc != 0) { 3352eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 3353eaca9bbdSeschrock "incompatible with other arguments\n")); 335499653d4eSeschrock usage(B_FALSE); 3355eaca9bbdSeschrock } 3356eaca9bbdSeschrock } else if (cb.cb_all) { 3357eaca9bbdSeschrock if (argc != 0) { 3358eaca9bbdSeschrock (void) fprintf(stderr, gettext("-a option is " 3359eaca9bbdSeschrock "incompatible with other arguments\n")); 336099653d4eSeschrock usage(B_FALSE); 3361eaca9bbdSeschrock } 3362eaca9bbdSeschrock } 3363eaca9bbdSeschrock 3364e7437265Sahrens (void) printf(gettext("This system is currently running " 3365e7437265Sahrens "ZFS pool version %llu.\n\n"), SPA_VERSION); 336699653d4eSeschrock cb.cb_first = B_TRUE; 3367eaca9bbdSeschrock if (showversions) { 3368eaca9bbdSeschrock (void) printf(gettext("The following versions are " 3369d7d4af51Smmusante "supported:\n\n")); 3370eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 3371eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 3372eaca9bbdSeschrock "---------------\n"); 337399653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 337444cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 337544cd46caSbillm "(replicated metadata)\n")); 337699653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 337799653d4eSeschrock "RAID-Z\n")); 3378d7306b64Sek110237 (void) printf(gettext(" 4 zpool history\n")); 3379c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 3380c9431fa1Sahl "algorithm\n")); 3381ecd6cf80Smarks (void) printf(gettext(" 6 pool properties\n")); 33828654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 3383ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 33848654d025Sperrin (void) printf(gettext("For more information on a particular " 3385eaca9bbdSeschrock "version, including supported releases, see:\n\n")); 3386eaca9bbdSeschrock (void) printf("http://www.opensolaris.org/os/community/zfs/" 3387eaca9bbdSeschrock "version/N\n\n"); 3388eaca9bbdSeschrock (void) printf(gettext("Where 'N' is the version number.\n")); 3389eaca9bbdSeschrock } else if (argc == 0) { 3390eaca9bbdSeschrock int notfound; 3391eaca9bbdSeschrock 339299653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3393eaca9bbdSeschrock notfound = cb.cb_first; 3394eaca9bbdSeschrock 3395eaca9bbdSeschrock if (!cb.cb_all && ret == 0) { 3396eaca9bbdSeschrock if (!cb.cb_first) 3397eaca9bbdSeschrock (void) printf("\n"); 3398eaca9bbdSeschrock cb.cb_first = B_TRUE; 3399eaca9bbdSeschrock cb.cb_newer = B_TRUE; 340099653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3401eaca9bbdSeschrock if (!cb.cb_first) { 3402eaca9bbdSeschrock notfound = B_FALSE; 3403eaca9bbdSeschrock (void) printf("\n"); 3404eaca9bbdSeschrock } 3405eaca9bbdSeschrock } 3406eaca9bbdSeschrock 3407eaca9bbdSeschrock if (ret == 0) { 3408eaca9bbdSeschrock if (notfound) 3409eaca9bbdSeschrock (void) printf(gettext("All pools are formatted " 3410eaca9bbdSeschrock "using this version.\n")); 3411eaca9bbdSeschrock else if (!cb.cb_all) 3412eaca9bbdSeschrock (void) printf(gettext("Use 'zpool upgrade -v' " 3413eaca9bbdSeschrock "for a list of available versions and " 3414eaca9bbdSeschrock "their associated\nfeatures.\n")); 3415eaca9bbdSeschrock } 3416eaca9bbdSeschrock } else { 3417b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 3418b1b8ab34Slling upgrade_one, &cb); 341906eeb2adSek110237 } 342006eeb2adSek110237 342106eeb2adSek110237 return (ret); 342206eeb2adSek110237 } 342306eeb2adSek110237 3424ecd6cf80Smarks typedef struct hist_cbdata { 3425ecd6cf80Smarks boolean_t first; 3426ecd6cf80Smarks int longfmt; 3427ecd6cf80Smarks int internal; 3428ecd6cf80Smarks } hist_cbdata_t; 3429ecd6cf80Smarks 3430ecd6cf80Smarks char *hist_event_table[LOG_END] = { 3431ecd6cf80Smarks "invalid event", 3432ecd6cf80Smarks "pool create", 3433ecd6cf80Smarks "vdev add", 3434ecd6cf80Smarks "pool remove", 3435ecd6cf80Smarks "pool destroy", 3436ecd6cf80Smarks "pool export", 3437ecd6cf80Smarks "pool import", 3438ecd6cf80Smarks "vdev attach", 3439ecd6cf80Smarks "vdev replace", 3440ecd6cf80Smarks "vdev detach", 3441ecd6cf80Smarks "vdev online", 3442ecd6cf80Smarks "vdev offline", 3443ecd6cf80Smarks "vdev upgrade", 3444ecd6cf80Smarks "pool clear", 3445ecd6cf80Smarks "pool scrub", 3446ecd6cf80Smarks "pool property set", 3447ecd6cf80Smarks "create", 3448ecd6cf80Smarks "clone", 3449ecd6cf80Smarks "destroy", 3450ecd6cf80Smarks "destroy_begin_sync", 3451ecd6cf80Smarks "inherit", 3452ecd6cf80Smarks "property set", 3453ecd6cf80Smarks "quota set", 3454ecd6cf80Smarks "permission update", 3455ecd6cf80Smarks "permission remove", 3456ecd6cf80Smarks "permission who remove", 3457ecd6cf80Smarks "promote", 3458ecd6cf80Smarks "receive", 3459ecd6cf80Smarks "rename", 3460ecd6cf80Smarks "reservation set", 3461ecd6cf80Smarks "replay_inc_sync", 3462ecd6cf80Smarks "replay_full_sync", 3463ecd6cf80Smarks "rollback", 3464ecd6cf80Smarks "snapshot", 3465e7437265Sahrens "filesystem version upgrade", 3466ecd6cf80Smarks }; 3467ecd6cf80Smarks 346806eeb2adSek110237 /* 346906eeb2adSek110237 * Print out the command history for a specific pool. 347006eeb2adSek110237 */ 347106eeb2adSek110237 static int 347206eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data) 347306eeb2adSek110237 { 347406eeb2adSek110237 nvlist_t *nvhis; 347506eeb2adSek110237 nvlist_t **records; 347606eeb2adSek110237 uint_t numrecords; 347706eeb2adSek110237 char *cmdstr; 3478ecd6cf80Smarks char *pathstr; 347906eeb2adSek110237 uint64_t dst_time; 348006eeb2adSek110237 time_t tsec; 348106eeb2adSek110237 struct tm t; 348206eeb2adSek110237 char tbuf[30]; 348306eeb2adSek110237 int ret, i; 3484ecd6cf80Smarks uint64_t who; 3485ecd6cf80Smarks struct passwd *pwd; 3486ecd6cf80Smarks char *hostname; 3487ecd6cf80Smarks char *zonename; 3488ecd6cf80Smarks char internalstr[MAXPATHLEN]; 3489ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 3490ecd6cf80Smarks uint64_t txg; 3491ecd6cf80Smarks uint64_t ievent; 349206eeb2adSek110237 3493ecd6cf80Smarks cb->first = B_FALSE; 349406eeb2adSek110237 349506eeb2adSek110237 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 349606eeb2adSek110237 349706eeb2adSek110237 if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 349806eeb2adSek110237 return (ret); 349906eeb2adSek110237 350006eeb2adSek110237 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 350106eeb2adSek110237 &records, &numrecords) == 0); 350206eeb2adSek110237 for (i = 0; i < numrecords; i++) { 350306eeb2adSek110237 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3504ecd6cf80Smarks &dst_time) != 0) 3505ecd6cf80Smarks continue; 3506ecd6cf80Smarks 3507ecd6cf80Smarks /* is it an internal event or a standard event? */ 3508ecd6cf80Smarks if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3509ecd6cf80Smarks &cmdstr) != 0) { 3510ecd6cf80Smarks if (cb->internal == 0) 3511ecd6cf80Smarks continue; 3512ecd6cf80Smarks 3513ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3514ecd6cf80Smarks ZPOOL_HIST_INT_EVENT, &ievent) != 0) 3515ecd6cf80Smarks continue; 3516ecd6cf80Smarks verify(nvlist_lookup_uint64(records[i], 3517ecd6cf80Smarks ZPOOL_HIST_TXG, &txg) == 0); 3518ecd6cf80Smarks verify(nvlist_lookup_string(records[i], 3519ecd6cf80Smarks ZPOOL_HIST_INT_STR, &pathstr) == 0); 3520ecd6cf80Smarks if (ievent > LOG_END) 3521ecd6cf80Smarks continue; 3522ecd6cf80Smarks (void) snprintf(internalstr, 3523ecd6cf80Smarks sizeof (internalstr), 3524ecd6cf80Smarks "[internal %s txg:%lld] %s", 3525ecd6cf80Smarks hist_event_table[ievent], txg, 3526ecd6cf80Smarks pathstr); 3527ecd6cf80Smarks cmdstr = internalstr; 3528ecd6cf80Smarks } 352906eeb2adSek110237 tsec = dst_time; 353006eeb2adSek110237 (void) localtime_r(&tsec, &t); 353106eeb2adSek110237 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3532ecd6cf80Smarks (void) printf("%s %s", tbuf, cmdstr); 3533ecd6cf80Smarks 3534ecd6cf80Smarks if (!cb->longfmt) { 3535ecd6cf80Smarks (void) printf("\n"); 3536ecd6cf80Smarks continue; 353706eeb2adSek110237 } 3538ecd6cf80Smarks (void) printf(" ["); 3539ecd6cf80Smarks if (nvlist_lookup_uint64(records[i], 3540ecd6cf80Smarks ZPOOL_HIST_WHO, &who) == 0) { 3541ecd6cf80Smarks pwd = getpwuid((uid_t)who); 3542ecd6cf80Smarks if (pwd) 3543ecd6cf80Smarks (void) printf("user %s on", 3544ecd6cf80Smarks pwd->pw_name); 3545ecd6cf80Smarks else 3546ecd6cf80Smarks (void) printf("user %d on", 3547ecd6cf80Smarks (int)who); 3548ecd6cf80Smarks } else { 3549ecd6cf80Smarks (void) printf(gettext("no info]\n")); 3550ecd6cf80Smarks continue; 3551ecd6cf80Smarks } 3552ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3553ecd6cf80Smarks ZPOOL_HIST_HOST, &hostname) == 0) { 3554ecd6cf80Smarks (void) printf(" %s", hostname); 3555ecd6cf80Smarks } 3556ecd6cf80Smarks if (nvlist_lookup_string(records[i], 3557ecd6cf80Smarks ZPOOL_HIST_ZONE, &zonename) == 0) { 3558ecd6cf80Smarks (void) printf(":%s", zonename); 3559ecd6cf80Smarks } 3560ecd6cf80Smarks 3561ecd6cf80Smarks (void) printf("]"); 3562ecd6cf80Smarks (void) printf("\n"); 356306eeb2adSek110237 } 356406eeb2adSek110237 (void) printf("\n"); 356506eeb2adSek110237 nvlist_free(nvhis); 356606eeb2adSek110237 356706eeb2adSek110237 return (ret); 356806eeb2adSek110237 } 356906eeb2adSek110237 357006eeb2adSek110237 /* 357106eeb2adSek110237 * zpool history <pool> 357206eeb2adSek110237 * 357306eeb2adSek110237 * Displays the history of commands that modified pools. 357406eeb2adSek110237 */ 3575ecd6cf80Smarks 3576ecd6cf80Smarks 357706eeb2adSek110237 int 357806eeb2adSek110237 zpool_do_history(int argc, char **argv) 357906eeb2adSek110237 { 3580ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 358106eeb2adSek110237 int ret; 3582ecd6cf80Smarks int c; 358306eeb2adSek110237 3584ecd6cf80Smarks cbdata.first = B_TRUE; 3585ecd6cf80Smarks /* check options */ 3586ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 3587ecd6cf80Smarks switch (c) { 3588ecd6cf80Smarks case 'l': 3589ecd6cf80Smarks cbdata.longfmt = 1; 3590ecd6cf80Smarks break; 3591ecd6cf80Smarks case 'i': 3592ecd6cf80Smarks cbdata.internal = 1; 3593ecd6cf80Smarks break; 3594ecd6cf80Smarks case '?': 3595ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3596ecd6cf80Smarks optopt); 3597ecd6cf80Smarks usage(B_FALSE); 3598ecd6cf80Smarks } 3599ecd6cf80Smarks } 360006eeb2adSek110237 argc -= optind; 360106eeb2adSek110237 argv += optind; 360206eeb2adSek110237 3603b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3604ecd6cf80Smarks &cbdata); 360506eeb2adSek110237 3606ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 360706eeb2adSek110237 (void) printf(gettext("no pools available\n")); 360806eeb2adSek110237 return (0); 3609eaca9bbdSeschrock } 3610eaca9bbdSeschrock 3611eaca9bbdSeschrock return (ret); 3612eaca9bbdSeschrock } 3613eaca9bbdSeschrock 3614b1b8ab34Slling static int 3615b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 3616b1b8ab34Slling { 3617b1b8ab34Slling libzfs_get_cbdata_t *cbp = (libzfs_get_cbdata_t *)data; 3618b1b8ab34Slling char value[MAXNAMELEN]; 3619b1b8ab34Slling zfs_source_t srctype; 3620b1b8ab34Slling zpool_proplist_t *pl; 3621b1b8ab34Slling 3622b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3623b1b8ab34Slling 3624b1b8ab34Slling /* 3625b1b8ab34Slling * Skip the special fake placeholder. 3626b1b8ab34Slling */ 3627b1b8ab34Slling if (pl->pl_prop == ZFS_PROP_NAME && 3628b1b8ab34Slling pl == cbp->cb_proplist) 3629b1b8ab34Slling continue; 3630b1b8ab34Slling 3631b1b8ab34Slling if (zpool_get_prop(zhp, pl->pl_prop, 3632b1b8ab34Slling value, sizeof (value), &srctype) != 0) 3633b1b8ab34Slling continue; 3634b1b8ab34Slling 3635b1b8ab34Slling libzfs_print_one_property(zpool_get_name(zhp), cbp, 3636b1b8ab34Slling zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3637b1b8ab34Slling } 3638b1b8ab34Slling return (0); 3639b1b8ab34Slling } 3640b1b8ab34Slling 3641b1b8ab34Slling int 3642b1b8ab34Slling zpool_do_get(int argc, char **argv) 3643b1b8ab34Slling { 3644b1b8ab34Slling libzfs_get_cbdata_t cb = { 0 }; 3645b1b8ab34Slling zpool_proplist_t fake_name = { 0 }; 3646b1b8ab34Slling int ret; 3647b1b8ab34Slling 3648b1b8ab34Slling if (argc < 3) 3649b1b8ab34Slling usage(B_FALSE); 3650b1b8ab34Slling 3651b1b8ab34Slling cb.cb_first = B_TRUE; 3652b1b8ab34Slling cb.cb_sources = ZFS_SRC_ALL; 3653b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 3654b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 3655b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 3656b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 3657b1b8ab34Slling 3658b1b8ab34Slling if (zpool_get_proplist(g_zfs, argv[1], &cb.cb_proplist) != 0) 3659b1b8ab34Slling usage(B_FALSE); 3660b1b8ab34Slling 3661b1b8ab34Slling if (cb.cb_proplist != NULL) { 3662b1b8ab34Slling fake_name.pl_prop = ZFS_PROP_NAME; 3663b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 3664b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 3665b1b8ab34Slling cb.cb_proplist = &fake_name; 3666b1b8ab34Slling } 3667b1b8ab34Slling 3668b1b8ab34Slling ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3669b1b8ab34Slling get_callback, &cb); 3670b1b8ab34Slling 3671b1b8ab34Slling if (cb.cb_proplist == &fake_name) 3672b1b8ab34Slling zfs_free_proplist(fake_name.pl_next); 3673b1b8ab34Slling else 3674b1b8ab34Slling zfs_free_proplist(cb.cb_proplist); 3675b1b8ab34Slling 3676b1b8ab34Slling return (ret); 3677b1b8ab34Slling } 3678b1b8ab34Slling 3679b1b8ab34Slling typedef struct set_cbdata { 3680b1b8ab34Slling char *cb_propname; 3681b1b8ab34Slling char *cb_value; 3682b1b8ab34Slling boolean_t cb_any_successful; 3683b1b8ab34Slling } set_cbdata_t; 3684b1b8ab34Slling 3685b1b8ab34Slling int 3686b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 3687b1b8ab34Slling { 3688b1b8ab34Slling int error; 3689b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 3690b1b8ab34Slling 3691b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3692b1b8ab34Slling 3693b1b8ab34Slling if (!error) 3694b1b8ab34Slling cb->cb_any_successful = B_TRUE; 3695b1b8ab34Slling 3696b1b8ab34Slling return (error); 3697b1b8ab34Slling } 3698b1b8ab34Slling 3699b1b8ab34Slling int 3700b1b8ab34Slling zpool_do_set(int argc, char **argv) 3701b1b8ab34Slling { 3702b1b8ab34Slling set_cbdata_t cb = { 0 }; 3703b1b8ab34Slling int error; 3704b1b8ab34Slling 3705b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 3706b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3707b1b8ab34Slling argv[1][1]); 3708b1b8ab34Slling usage(B_FALSE); 3709b1b8ab34Slling } 3710b1b8ab34Slling 3711b1b8ab34Slling if (argc < 2) { 3712b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 3713b1b8ab34Slling "argument\n")); 3714b1b8ab34Slling usage(B_FALSE); 3715b1b8ab34Slling } 3716b1b8ab34Slling 3717b1b8ab34Slling if (argc < 3) { 3718b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 3719b1b8ab34Slling usage(B_FALSE); 3720b1b8ab34Slling } 3721b1b8ab34Slling 3722b1b8ab34Slling if (argc > 3) { 3723b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 3724b1b8ab34Slling usage(B_FALSE); 3725b1b8ab34Slling } 3726b1b8ab34Slling 3727b1b8ab34Slling cb.cb_propname = argv[1]; 3728b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 3729b1b8ab34Slling if (cb.cb_value == NULL) { 3730b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 3731b1b8ab34Slling "property=value argument\n")); 3732b1b8ab34Slling usage(B_FALSE); 3733b1b8ab34Slling } 3734b1b8ab34Slling 3735b1b8ab34Slling *(cb.cb_value) = '\0'; 3736b1b8ab34Slling cb.cb_value++; 3737b1b8ab34Slling 3738b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3739b1b8ab34Slling set_callback, &cb); 3740b1b8ab34Slling 3741b1b8ab34Slling return (error); 3742b1b8ab34Slling } 3743b1b8ab34Slling 3744b1b8ab34Slling static int 3745b1b8ab34Slling find_command_idx(char *command, int *idx) 3746b1b8ab34Slling { 3747b1b8ab34Slling int i; 3748b1b8ab34Slling 3749b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 3750b1b8ab34Slling if (command_table[i].name == NULL) 3751b1b8ab34Slling continue; 3752b1b8ab34Slling 3753b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 3754b1b8ab34Slling *idx = i; 3755b1b8ab34Slling return (0); 3756b1b8ab34Slling } 3757b1b8ab34Slling } 3758b1b8ab34Slling return (1); 3759b1b8ab34Slling } 3760b1b8ab34Slling 3761fa9e4066Sahrens int 3762fa9e4066Sahrens main(int argc, char **argv) 3763fa9e4066Sahrens { 3764fa9e4066Sahrens int ret; 3765fa9e4066Sahrens int i; 3766fa9e4066Sahrens char *cmdname; 3767fa9e4066Sahrens 3768fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 3769fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 3770fa9e4066Sahrens 377199653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 377299653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 3773203a47d8Snd150628 "initialize ZFS library\n")); 377499653d4eSeschrock return (1); 377599653d4eSeschrock } 377699653d4eSeschrock 377799653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 377899653d4eSeschrock 3779fa9e4066Sahrens opterr = 0; 3780fa9e4066Sahrens 3781fa9e4066Sahrens /* 3782fa9e4066Sahrens * Make sure the user has specified some command. 3783fa9e4066Sahrens */ 3784fa9e4066Sahrens if (argc < 2) { 3785fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 378699653d4eSeschrock usage(B_FALSE); 3787fa9e4066Sahrens } 3788fa9e4066Sahrens 3789fa9e4066Sahrens cmdname = argv[1]; 3790fa9e4066Sahrens 3791ecd6cf80Smarks /* Handle special case of pool create for staging history */ 3792ecd6cf80Smarks if (strcmp(cmdname, "create") != 0) 3793228975ccSek110237 zpool_stage_history(g_zfs, argc, argv, B_FALSE); 3794ecd6cf80Smarks else 3795228975ccSek110237 zpool_stage_history(g_zfs, argc, argv, B_FALSE); 3796ecd6cf80Smarks 3797fa9e4066Sahrens /* 3798fa9e4066Sahrens * Special case '-?' 3799fa9e4066Sahrens */ 3800fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 380199653d4eSeschrock usage(B_TRUE); 3802fa9e4066Sahrens 3803fa9e4066Sahrens /* 3804fa9e4066Sahrens * Run the appropriate command. 3805fa9e4066Sahrens */ 3806b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 3807fa9e4066Sahrens current_command = &command_table[i]; 3808fa9e4066Sahrens ret = command_table[i].func(argc - 1, argv + 1); 380991ebeef5Sahrens } else if (strchr(cmdname, '=')) { 381091ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 381191ebeef5Sahrens current_command = &command_table[i]; 381291ebeef5Sahrens ret = command_table[i].func(argc, argv); 381391ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 3814fa9e4066Sahrens /* 381591ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 381691ebeef5Sahrens * it as such. 3817fa9e4066Sahrens */ 3818ea8dc4b6Seschrock char buf[16384]; 3819ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 3820fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 3821fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 382291ebeef5Sahrens } else { 3823fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 3824fa9e4066Sahrens "command '%s'\n"), cmdname); 382599653d4eSeschrock usage(B_FALSE); 3826fa9e4066Sahrens } 3827fa9e4066Sahrens 382899653d4eSeschrock libzfs_fini(g_zfs); 382999653d4eSeschrock 3830fa9e4066Sahrens /* 3831fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3832fa9e4066Sahrens * for the purposes of running ::findleaks. 3833fa9e4066Sahrens */ 3834fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 3835fa9e4066Sahrens (void) printf("dumping core by request\n"); 3836fa9e4066Sahrens abort(); 3837fa9e4066Sahrens } 3838fa9e4066Sahrens 3839fa9e4066Sahrens return (ret); 3840fa9e4066Sahrens } 3841