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 /* 233f9d6ad7SLin Ling * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24ca0cc391SMatthew Ahrens * Copyright (c) 2011, 2015 by Delphix. All rights reserved. 25e1d5e507SFrederik Wessels * Copyright (c) 2012 by Frederik Wessels. All rights reserved. 269edf9ebdSPrasad Joshi * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved. 27b327cd3fSIgor Kozhukhov * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. 28*6401734dSWill Andrews * Copyright 2016 Nexenta Systems, Inc. 29fa9e4066Sahrens */ 30fa9e4066Sahrens 31fa9e4066Sahrens #include <assert.h> 32fa9e4066Sahrens #include <ctype.h> 33fa9e4066Sahrens #include <dirent.h> 34fa9e4066Sahrens #include <errno.h> 35fa9e4066Sahrens #include <fcntl.h> 36fa9e4066Sahrens #include <libgen.h> 37fa9e4066Sahrens #include <libintl.h> 38fa9e4066Sahrens #include <libuutil.h> 39fa9e4066Sahrens #include <locale.h> 40fa9e4066Sahrens #include <stdio.h> 41fa9e4066Sahrens #include <stdlib.h> 42fa9e4066Sahrens #include <string.h> 43fa9e4066Sahrens #include <strings.h> 44fa9e4066Sahrens #include <unistd.h> 45fa9e4066Sahrens #include <priv.h> 46ecd6cf80Smarks #include <pwd.h> 47ecd6cf80Smarks #include <zone.h> 484263d13fSGeorge Wilson #include <zfs_prop.h> 49b1b8ab34Slling #include <sys/fs/zfs.h> 50fa9e4066Sahrens #include <sys/stat.h> 51fa9e4066Sahrens 52fa9e4066Sahrens #include <libzfs.h> 53fa9e4066Sahrens 54fa9e4066Sahrens #include "zpool_util.h" 55b7b97454Sperrin #include "zfs_comutil.h" 56ad135b5dSChristopher Siden #include "zfeature_common.h" 57fa9e4066Sahrens 5826fd7700SKrishnendu Sadhukhan - Sun Microsystems #include "statcommon.h" 5926fd7700SKrishnendu Sadhukhan - Sun Microsystems 60fa9e4066Sahrens static int zpool_do_create(int, char **); 61fa9e4066Sahrens static int zpool_do_destroy(int, char **); 62fa9e4066Sahrens 63fa9e4066Sahrens static int zpool_do_add(int, char **); 6499653d4eSeschrock static int zpool_do_remove(int, char **); 65*6401734dSWill Andrews static int zpool_do_labelclear(int, char **); 66fa9e4066Sahrens 67fa9e4066Sahrens static int zpool_do_list(int, char **); 68fa9e4066Sahrens static int zpool_do_iostat(int, char **); 69fa9e4066Sahrens static int zpool_do_status(int, char **); 70fa9e4066Sahrens 71fa9e4066Sahrens static int zpool_do_online(int, char **); 72fa9e4066Sahrens static int zpool_do_offline(int, char **); 73ea8dc4b6Seschrock static int zpool_do_clear(int, char **); 744263d13fSGeorge Wilson static int zpool_do_reopen(int, char **); 75fa9e4066Sahrens 76e9103aaeSGarrett D'Amore static int zpool_do_reguid(int, char **); 77e9103aaeSGarrett D'Amore 78fa9e4066Sahrens static int zpool_do_attach(int, char **); 79fa9e4066Sahrens static int zpool_do_detach(int, char **); 80fa9e4066Sahrens static int zpool_do_replace(int, char **); 811195e687SMark J Musante static int zpool_do_split(int, char **); 82fa9e4066Sahrens 83fa9e4066Sahrens static int zpool_do_scrub(int, char **); 84fa9e4066Sahrens 85fa9e4066Sahrens static int zpool_do_import(int, char **); 86fa9e4066Sahrens static int zpool_do_export(int, char **); 87fa9e4066Sahrens 88eaca9bbdSeschrock static int zpool_do_upgrade(int, char **); 89eaca9bbdSeschrock 9006eeb2adSek static int zpool_do_history(int, char **); 9106eeb2adSek 92b1b8ab34Slling static int zpool_do_get(int, char **); 93b1b8ab34Slling static int zpool_do_set(int, char **); 94b1b8ab34Slling 95fa9e4066Sahrens /* 96fa9e4066Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 97fa9e4066Sahrens * debugging facilities. 98fa9e4066Sahrens */ 9929ab75c9Srm 10029ab75c9Srm #ifdef DEBUG 101fa9e4066Sahrens const char * 10299653d4eSeschrock _umem_debug_init(void) 103fa9e4066Sahrens { 104fa9e4066Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 105fa9e4066Sahrens } 106fa9e4066Sahrens 107fa9e4066Sahrens const char * 108fa9e4066Sahrens _umem_logging_init(void) 109fa9e4066Sahrens { 110fa9e4066Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 111fa9e4066Sahrens } 11229ab75c9Srm #endif 113fa9e4066Sahrens 11465cd9f28Seschrock typedef enum { 11565cd9f28Seschrock HELP_ADD, 11665cd9f28Seschrock HELP_ATTACH, 117ea8dc4b6Seschrock HELP_CLEAR, 11865cd9f28Seschrock HELP_CREATE, 11965cd9f28Seschrock HELP_DESTROY, 12065cd9f28Seschrock HELP_DETACH, 12165cd9f28Seschrock HELP_EXPORT, 12206eeb2adSek HELP_HISTORY, 12365cd9f28Seschrock HELP_IMPORT, 12465cd9f28Seschrock HELP_IOSTAT, 125*6401734dSWill Andrews HELP_LABELCLEAR, 12665cd9f28Seschrock HELP_LIST, 12765cd9f28Seschrock HELP_OFFLINE, 12865cd9f28Seschrock HELP_ONLINE, 12965cd9f28Seschrock HELP_REPLACE, 13099653d4eSeschrock HELP_REMOVE, 13165cd9f28Seschrock HELP_SCRUB, 132eaca9bbdSeschrock HELP_STATUS, 133b1b8ab34Slling HELP_UPGRADE, 134b1b8ab34Slling HELP_GET, 1351195e687SMark J Musante HELP_SET, 136e9103aaeSGarrett D'Amore HELP_SPLIT, 1374263d13fSGeorge Wilson HELP_REGUID, 1384263d13fSGeorge Wilson HELP_REOPEN 13965cd9f28Seschrock } zpool_help_t; 14065cd9f28Seschrock 14165cd9f28Seschrock 142fa9e4066Sahrens typedef struct zpool_command { 143fa9e4066Sahrens const char *name; 144fa9e4066Sahrens int (*func)(int, char **); 14565cd9f28Seschrock zpool_help_t usage; 146fa9e4066Sahrens } zpool_command_t; 147fa9e4066Sahrens 148fa9e4066Sahrens /* 149fa9e4066Sahrens * Master command table. Each ZFS command has a name, associated function, and 150ea8dc4b6Seschrock * usage message. The usage messages need to be internationalized, so we have 151ea8dc4b6Seschrock * to have a function to return the usage message based on a command index. 15265cd9f28Seschrock * 15365cd9f28Seschrock * These commands are organized according to how they are displayed in the usage 15465cd9f28Seschrock * message. An empty command (one with a NULL name) indicates an empty line in 15565cd9f28Seschrock * the generic usage message. 156fa9e4066Sahrens */ 157fa9e4066Sahrens static zpool_command_t command_table[] = { 15865cd9f28Seschrock { "create", zpool_do_create, HELP_CREATE }, 15965cd9f28Seschrock { "destroy", zpool_do_destroy, HELP_DESTROY }, 160fa9e4066Sahrens { NULL }, 16165cd9f28Seschrock { "add", zpool_do_add, HELP_ADD }, 16299653d4eSeschrock { "remove", zpool_do_remove, HELP_REMOVE }, 163fa9e4066Sahrens { NULL }, 164*6401734dSWill Andrews { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 165*6401734dSWill Andrews { NULL }, 16665cd9f28Seschrock { "list", zpool_do_list, HELP_LIST }, 16765cd9f28Seschrock { "iostat", zpool_do_iostat, HELP_IOSTAT }, 16865cd9f28Seschrock { "status", zpool_do_status, HELP_STATUS }, 169fa9e4066Sahrens { NULL }, 17065cd9f28Seschrock { "online", zpool_do_online, HELP_ONLINE }, 17165cd9f28Seschrock { "offline", zpool_do_offline, HELP_OFFLINE }, 172ea8dc4b6Seschrock { "clear", zpool_do_clear, HELP_CLEAR }, 1734263d13fSGeorge Wilson { "reopen", zpool_do_reopen, HELP_REOPEN }, 174fa9e4066Sahrens { NULL }, 17565cd9f28Seschrock { "attach", zpool_do_attach, HELP_ATTACH }, 17665cd9f28Seschrock { "detach", zpool_do_detach, HELP_DETACH }, 17765cd9f28Seschrock { "replace", zpool_do_replace, HELP_REPLACE }, 1781195e687SMark J Musante { "split", zpool_do_split, HELP_SPLIT }, 179fa9e4066Sahrens { NULL }, 18065cd9f28Seschrock { "scrub", zpool_do_scrub, HELP_SCRUB }, 181fa9e4066Sahrens { NULL }, 18265cd9f28Seschrock { "import", zpool_do_import, HELP_IMPORT }, 18365cd9f28Seschrock { "export", zpool_do_export, HELP_EXPORT }, 18406eeb2adSek { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 185e9103aaeSGarrett D'Amore { "reguid", zpool_do_reguid, HELP_REGUID }, 18606eeb2adSek { NULL }, 187b1b8ab34Slling { "history", zpool_do_history, HELP_HISTORY }, 188b1b8ab34Slling { "get", zpool_do_get, HELP_GET }, 189b1b8ab34Slling { "set", zpool_do_set, HELP_SET }, 190fa9e4066Sahrens }; 191fa9e4066Sahrens 192fa9e4066Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 193fa9e4066Sahrens 1944445fffbSMatthew Ahrens static zpool_command_t *current_command; 1952a6b87f0Sek static char history_str[HIS_MAX_RECORD_LEN]; 1964445fffbSMatthew Ahrens static boolean_t log_history = B_TRUE; 19726fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE; 19826fd7700SKrishnendu Sadhukhan - Sun Microsystems 19965cd9f28Seschrock static const char * 2009a686fbcSPaul Dagnelie get_usage(zpool_help_t idx) 2019a686fbcSPaul Dagnelie { 20265cd9f28Seschrock switch (idx) { 20365cd9f28Seschrock case HELP_ADD: 20465cd9f28Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 20565cd9f28Seschrock case HELP_ATTACH: 20665cd9f28Seschrock return (gettext("\tattach [-f] <pool> <device> " 207e45ce728Sahrens "<new-device>\n")); 208ea8dc4b6Seschrock case HELP_CLEAR: 209468c413aSTim Haley return (gettext("\tclear [-nF] <pool> [device]\n")); 21065cd9f28Seschrock case HELP_CREATE: 211ad135b5dSChristopher Siden return (gettext("\tcreate [-fnd] [-o property=value] ... \n" 2120a48a24eStimh "\t [-O file-system-property=value] ... \n" 213990b4856Slling "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 21465cd9f28Seschrock case HELP_DESTROY: 21565cd9f28Seschrock return (gettext("\tdestroy [-f] <pool>\n")); 21665cd9f28Seschrock case HELP_DETACH: 21765cd9f28Seschrock return (gettext("\tdetach <pool> <device>\n")); 21865cd9f28Seschrock case HELP_EXPORT: 21965cd9f28Seschrock return (gettext("\texport [-f] <pool> ...\n")); 22006eeb2adSek case HELP_HISTORY: 221ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 22265cd9f28Seschrock case HELP_IMPORT: 2234c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 224f9af39baSGeorge Wilson "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 2252f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 226f9af39baSGeorge Wilson "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 227f9af39baSGeorge Wilson "[-R root] [-F [-n]] -a\n" 2282f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 229f9af39baSGeorge Wilson "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 230f9af39baSGeorge Wilson "[-R root] [-F [-n]]\n" 231f9af39baSGeorge Wilson "\t <pool | id> [newpool]\n")); 23265cd9f28Seschrock case HELP_IOSTAT: 23326fd7700SKrishnendu Sadhukhan - Sun Microsystems return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 23465cd9f28Seschrock "[count]]\n")); 235*6401734dSWill Andrews case HELP_LABELCLEAR: 236*6401734dSWill Andrews return (gettext("\tlabelclear [-f] <vdev>\n")); 23765cd9f28Seschrock case HELP_LIST: 238c58b3526SAdam Stevko return (gettext("\tlist [-Hp] [-o property[,...]] " 2393f9d6ad7SLin Ling "[-T d|u] [pool] ... [interval [count]]\n")); 24065cd9f28Seschrock case HELP_OFFLINE: 241441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 24265cd9f28Seschrock case HELP_ONLINE: 243441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 24465cd9f28Seschrock case HELP_REPLACE: 24565cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 246e45ce728Sahrens "[new-device]\n")); 24799653d4eSeschrock case HELP_REMOVE: 248fa94a07fSbrendan return (gettext("\tremove <pool> <device> ...\n")); 2494263d13fSGeorge Wilson case HELP_REOPEN: 25031d7e8faSGeorge Wilson return (gettext("\treopen <pool>\n")); 25165cd9f28Seschrock case HELP_SCRUB: 25265cd9f28Seschrock return (gettext("\tscrub [-s] <pool> ...\n")); 25365cd9f28Seschrock case HELP_STATUS: 2543f9d6ad7SLin Ling return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 2553f9d6ad7SLin Ling "[count]]\n")); 256eaca9bbdSeschrock case HELP_UPGRADE: 257eaca9bbdSeschrock return (gettext("\tupgrade\n" 258eaca9bbdSeschrock "\tupgrade -v\n" 259990b4856Slling "\tupgrade [-V version] <-a | pool ...>\n")); 260b1b8ab34Slling case HELP_GET: 261c58b3526SAdam Stevko return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] " 262c58b3526SAdam Stevko "<\"all\" | property[,...]> <pool> ...\n")); 263b1b8ab34Slling case HELP_SET: 264b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 2651195e687SMark J Musante case HELP_SPLIT: 2661195e687SMark J Musante return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 2671195e687SMark J Musante "\t [-o property=value] <pool> <newpool> " 2681195e687SMark J Musante "[<device> ...]\n")); 269e9103aaeSGarrett D'Amore case HELP_REGUID: 270e9103aaeSGarrett D'Amore return (gettext("\treguid <pool>\n")); 27165cd9f28Seschrock } 27265cd9f28Seschrock 27365cd9f28Seschrock abort(); 27465cd9f28Seschrock /* NOTREACHED */ 27565cd9f28Seschrock } 27665cd9f28Seschrock 277fa9e4066Sahrens 278b1b8ab34Slling /* 279b1b8ab34Slling * Callback routine that will print out a pool property value. 280b1b8ab34Slling */ 281990b4856Slling static int 282990b4856Slling print_prop_cb(int prop, void *cb) 283b1b8ab34Slling { 284b1b8ab34Slling FILE *fp = cb; 285b1b8ab34Slling 286b24ab676SJeff Bonwick (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 287b1b8ab34Slling 288990b4856Slling if (zpool_prop_readonly(prop)) 289990b4856Slling (void) fprintf(fp, " NO "); 290990b4856Slling else 291b24ab676SJeff Bonwick (void) fprintf(fp, " YES "); 292990b4856Slling 293b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 294b1b8ab34Slling (void) fprintf(fp, "-\n"); 295b1b8ab34Slling else 296b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 297b1b8ab34Slling 298990b4856Slling return (ZPROP_CONT); 299b1b8ab34Slling } 300b1b8ab34Slling 301fa9e4066Sahrens /* 302fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 303fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 304fa9e4066Sahrens * a complete usage message. 305fa9e4066Sahrens */ 306fa9e4066Sahrens void 30799653d4eSeschrock usage(boolean_t requested) 308fa9e4066Sahrens { 309fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 310fa9e4066Sahrens 311fa9e4066Sahrens if (current_command == NULL) { 312fa9e4066Sahrens int i; 313fa9e4066Sahrens 314fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 315fa9e4066Sahrens (void) fprintf(fp, 316fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 317fa9e4066Sahrens 318fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 319fa9e4066Sahrens if (command_table[i].name == NULL) 320fa9e4066Sahrens (void) fprintf(fp, "\n"); 321fa9e4066Sahrens else 322fa9e4066Sahrens (void) fprintf(fp, "%s", 32365cd9f28Seschrock get_usage(command_table[i].usage)); 324fa9e4066Sahrens } 325fa9e4066Sahrens } else { 326fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 32765cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 328fa9e4066Sahrens } 329fa9e4066Sahrens 330b1b8ab34Slling if (current_command != NULL && 331b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 332990b4856Slling (strcmp(current_command->name, "get") == 0) || 333990b4856Slling (strcmp(current_command->name, "list") == 0))) { 334b1b8ab34Slling 335b1b8ab34Slling (void) fprintf(fp, 336b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 337b1b8ab34Slling 338b24ab676SJeff Bonwick (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 339990b4856Slling "PROPERTY", "EDIT", "VALUES"); 340b1b8ab34Slling 341b1b8ab34Slling /* Iterate over all properties */ 342990b4856Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 343990b4856Slling ZFS_TYPE_POOL); 344ad135b5dSChristopher Siden 345ad135b5dSChristopher Siden (void) fprintf(fp, "\t%-15s ", "feature@..."); 346ad135b5dSChristopher Siden (void) fprintf(fp, "YES disabled | enabled | active\n"); 347ad135b5dSChristopher Siden 348ad135b5dSChristopher Siden (void) fprintf(fp, gettext("\nThe feature@ properties must be " 349ad135b5dSChristopher Siden "appended with a feature name.\nSee zpool-features(5).\n")); 350b1b8ab34Slling } 351b1b8ab34Slling 352e9dbad6fSeschrock /* 353e9dbad6fSeschrock * See comments at end of main(). 354e9dbad6fSeschrock */ 355e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 356e9dbad6fSeschrock (void) printf("dumping core by request\n"); 357e9dbad6fSeschrock abort(); 358e9dbad6fSeschrock } 359e9dbad6fSeschrock 360fa9e4066Sahrens exit(requested ? 0 : 2); 361fa9e4066Sahrens } 362fa9e4066Sahrens 363fa9e4066Sahrens void 3648654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 3658654d025Sperrin boolean_t print_logs) 366fa9e4066Sahrens { 367fa9e4066Sahrens nvlist_t **child; 368fa9e4066Sahrens uint_t c, children; 369afefbcddSeschrock char *vname; 370fa9e4066Sahrens 371fa9e4066Sahrens if (name != NULL) 372fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 373fa9e4066Sahrens 374fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 375fa9e4066Sahrens &child, &children) != 0) 376fa9e4066Sahrens return; 377fa9e4066Sahrens 378afefbcddSeschrock for (c = 0; c < children; c++) { 3798654d025Sperrin uint64_t is_log = B_FALSE; 3808654d025Sperrin 3818654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3828654d025Sperrin &is_log); 3838654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 3848654d025Sperrin continue; 3858654d025Sperrin 38688ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3878654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 3888654d025Sperrin B_FALSE); 389afefbcddSeschrock free(vname); 390afefbcddSeschrock } 391fa9e4066Sahrens } 392fa9e4066Sahrens 39357221772SChristopher Siden static boolean_t 39457221772SChristopher Siden prop_list_contains_feature(nvlist_t *proplist) 39557221772SChristopher Siden { 39657221772SChristopher Siden nvpair_t *nvp; 39757221772SChristopher Siden for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; 39857221772SChristopher Siden nvp = nvlist_next_nvpair(proplist, nvp)) { 39957221772SChristopher Siden if (zpool_prop_feature(nvpair_name(nvp))) 40057221772SChristopher Siden return (B_TRUE); 40157221772SChristopher Siden } 40257221772SChristopher Siden return (B_FALSE); 40357221772SChristopher Siden } 40457221772SChristopher Siden 405990b4856Slling /* 406990b4856Slling * Add a property pair (name, string-value) into a property nvlist. 407990b4856Slling */ 408990b4856Slling static int 4090a48a24eStimh add_prop_list(const char *propname, char *propval, nvlist_t **props, 4100a48a24eStimh boolean_t poolprop) 411990b4856Slling { 4120a48a24eStimh zpool_prop_t prop = ZPROP_INVAL; 4130a48a24eStimh zfs_prop_t fprop; 414990b4856Slling nvlist_t *proplist; 4150a48a24eStimh const char *normnm; 4160a48a24eStimh char *strval; 417990b4856Slling 418990b4856Slling if (*props == NULL && 419990b4856Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 420990b4856Slling (void) fprintf(stderr, 421990b4856Slling gettext("internal error: out of memory\n")); 422990b4856Slling return (1); 423990b4856Slling } 424990b4856Slling 425990b4856Slling proplist = *props; 426990b4856Slling 4270a48a24eStimh if (poolprop) { 42857221772SChristopher Siden const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); 42957221772SChristopher Siden 430ad135b5dSChristopher Siden if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 431ad135b5dSChristopher Siden !zpool_prop_feature(propname)) { 4320a48a24eStimh (void) fprintf(stderr, gettext("property '%s' is " 4330a48a24eStimh "not a valid pool property\n"), propname); 4340a48a24eStimh return (2); 4350a48a24eStimh } 43657221772SChristopher Siden 43757221772SChristopher Siden /* 43857221772SChristopher Siden * feature@ properties and version should not be specified 43957221772SChristopher Siden * at the same time. 44057221772SChristopher Siden */ 44157221772SChristopher Siden if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && 44257221772SChristopher Siden nvlist_exists(proplist, vname)) || 44357221772SChristopher Siden (prop == ZPOOL_PROP_VERSION && 44457221772SChristopher Siden prop_list_contains_feature(proplist))) { 44557221772SChristopher Siden (void) fprintf(stderr, gettext("'feature@' and " 44657221772SChristopher Siden "'version' properties cannot be specified " 44757221772SChristopher Siden "together\n")); 44857221772SChristopher Siden return (2); 44957221772SChristopher Siden } 45057221772SChristopher Siden 45157221772SChristopher Siden 452ad135b5dSChristopher Siden if (zpool_prop_feature(propname)) 453ad135b5dSChristopher Siden normnm = propname; 454ad135b5dSChristopher Siden else 455ad135b5dSChristopher Siden normnm = zpool_prop_to_name(prop); 4560a48a24eStimh } else { 45714843421SMatthew Ahrens if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 45814843421SMatthew Ahrens normnm = zfs_prop_to_name(fprop); 45914843421SMatthew Ahrens } else { 46014843421SMatthew Ahrens normnm = propname; 4610a48a24eStimh } 462990b4856Slling } 463990b4856Slling 4640a48a24eStimh if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 4650a48a24eStimh prop != ZPOOL_PROP_CACHEFILE) { 466990b4856Slling (void) fprintf(stderr, gettext("property '%s' " 467990b4856Slling "specified multiple times\n"), propname); 468990b4856Slling return (2); 469990b4856Slling } 470990b4856Slling 4710a48a24eStimh if (nvlist_add_string(proplist, normnm, propval) != 0) { 472990b4856Slling (void) fprintf(stderr, gettext("internal " 473990b4856Slling "error: out of memory\n")); 474990b4856Slling return (1); 475990b4856Slling } 476990b4856Slling 477990b4856Slling return (0); 478990b4856Slling } 479990b4856Slling 480fa9e4066Sahrens /* 481fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 482fa9e4066Sahrens * 483fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 484fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 485fa9e4066Sahrens * they were to be added. 486fa9e4066Sahrens * 487fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 488fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 489fa9e4066Sahrens * libzfs. 490fa9e4066Sahrens */ 491fa9e4066Sahrens int 492fa9e4066Sahrens zpool_do_add(int argc, char **argv) 493fa9e4066Sahrens { 49499653d4eSeschrock boolean_t force = B_FALSE; 49599653d4eSeschrock boolean_t dryrun = B_FALSE; 496fa9e4066Sahrens int c; 497fa9e4066Sahrens nvlist_t *nvroot; 498fa9e4066Sahrens char *poolname; 499fa9e4066Sahrens int ret; 500fa9e4066Sahrens zpool_handle_t *zhp; 501fa9e4066Sahrens nvlist_t *config; 502fa9e4066Sahrens 503fa9e4066Sahrens /* check options */ 504fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 505fa9e4066Sahrens switch (c) { 506fa9e4066Sahrens case 'f': 50799653d4eSeschrock force = B_TRUE; 508fa9e4066Sahrens break; 509fa9e4066Sahrens case 'n': 51099653d4eSeschrock dryrun = B_TRUE; 511fa9e4066Sahrens break; 512fa9e4066Sahrens case '?': 513fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 514fa9e4066Sahrens optopt); 51599653d4eSeschrock usage(B_FALSE); 516fa9e4066Sahrens } 517fa9e4066Sahrens } 518fa9e4066Sahrens 519fa9e4066Sahrens argc -= optind; 520fa9e4066Sahrens argv += optind; 521fa9e4066Sahrens 522fa9e4066Sahrens /* get pool name and check number of arguments */ 523fa9e4066Sahrens if (argc < 1) { 524fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 52599653d4eSeschrock usage(B_FALSE); 526fa9e4066Sahrens } 527fa9e4066Sahrens if (argc < 2) { 528fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 52999653d4eSeschrock usage(B_FALSE); 530fa9e4066Sahrens } 531fa9e4066Sahrens 532fa9e4066Sahrens poolname = argv[0]; 533fa9e4066Sahrens 534fa9e4066Sahrens argc--; 535fa9e4066Sahrens argv++; 536fa9e4066Sahrens 53799653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 538fa9e4066Sahrens return (1); 539fa9e4066Sahrens 540088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 541fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 542fa9e4066Sahrens poolname); 543fa9e4066Sahrens zpool_close(zhp); 544fa9e4066Sahrens return (1); 545fa9e4066Sahrens } 546fa9e4066Sahrens 547fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 548705040edSEric Taylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 549705040edSEric Taylor argc, argv); 550fa9e4066Sahrens if (nvroot == NULL) { 551fa9e4066Sahrens zpool_close(zhp); 552fa9e4066Sahrens return (1); 553fa9e4066Sahrens } 554fa9e4066Sahrens 555fa9e4066Sahrens if (dryrun) { 556fa9e4066Sahrens nvlist_t *poolnvroot; 557fa9e4066Sahrens 558fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 559fa9e4066Sahrens &poolnvroot) == 0); 560fa9e4066Sahrens 561fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 562fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 563fa9e4066Sahrens 5648654d025Sperrin /* print original main pool and new tree */ 5658654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 5668654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 5678654d025Sperrin 5688654d025Sperrin /* Do the same for the logs */ 5698654d025Sperrin if (num_logs(poolnvroot) > 0) { 5708654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 5718654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 5728654d025Sperrin } else if (num_logs(nvroot) > 0) { 5738654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 5748654d025Sperrin } 575fa9e4066Sahrens 576fa9e4066Sahrens ret = 0; 577fa9e4066Sahrens } else { 578fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 579fa9e4066Sahrens } 580fa9e4066Sahrens 58199653d4eSeschrock nvlist_free(nvroot); 58299653d4eSeschrock zpool_close(zhp); 58399653d4eSeschrock 58499653d4eSeschrock return (ret); 58599653d4eSeschrock } 58699653d4eSeschrock 58799653d4eSeschrock /* 5883f9d6ad7SLin Ling * zpool remove <pool> <vdev> ... 58999653d4eSeschrock * 5903f9d6ad7SLin Ling * Removes the given vdev from the pool. Currently, this supports removing 5913f9d6ad7SLin Ling * spares, cache, and log devices from the pool. 59299653d4eSeschrock */ 59399653d4eSeschrock int 59499653d4eSeschrock zpool_do_remove(int argc, char **argv) 59599653d4eSeschrock { 59699653d4eSeschrock char *poolname; 597fa94a07fSbrendan int i, ret = 0; 59899653d4eSeschrock zpool_handle_t *zhp; 59999653d4eSeschrock 60099653d4eSeschrock argc--; 60199653d4eSeschrock argv++; 60299653d4eSeschrock 60399653d4eSeschrock /* get pool name and check number of arguments */ 60499653d4eSeschrock if (argc < 1) { 60599653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 60699653d4eSeschrock usage(B_FALSE); 60799653d4eSeschrock } 60899653d4eSeschrock if (argc < 2) { 60999653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 61099653d4eSeschrock usage(B_FALSE); 61199653d4eSeschrock } 61299653d4eSeschrock 61399653d4eSeschrock poolname = argv[0]; 61499653d4eSeschrock 61599653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 61699653d4eSeschrock return (1); 61799653d4eSeschrock 618fa94a07fSbrendan for (i = 1; i < argc; i++) { 619fa94a07fSbrendan if (zpool_vdev_remove(zhp, argv[i]) != 0) 620fa94a07fSbrendan ret = 1; 621fa94a07fSbrendan } 62299653d4eSeschrock 623fa9e4066Sahrens return (ret); 624fa9e4066Sahrens } 625fa9e4066Sahrens 626*6401734dSWill Andrews /* 627*6401734dSWill Andrews * zpool labelclear [-f] <vdev> 628*6401734dSWill Andrews * 629*6401734dSWill Andrews * -f Force clearing the label for the vdevs which are members of 630*6401734dSWill Andrews * the exported or foreign pools. 631*6401734dSWill Andrews * 632*6401734dSWill Andrews * Verifies that the vdev is not active and zeros out the label information 633*6401734dSWill Andrews * on the device. 634*6401734dSWill Andrews */ 635*6401734dSWill Andrews int 636*6401734dSWill Andrews zpool_do_labelclear(int argc, char **argv) 637*6401734dSWill Andrews { 638*6401734dSWill Andrews char vdev[MAXPATHLEN]; 639*6401734dSWill Andrews char *name = NULL; 640*6401734dSWill Andrews struct stat st; 641*6401734dSWill Andrews int c, fd, ret = 0; 642*6401734dSWill Andrews nvlist_t *config; 643*6401734dSWill Andrews pool_state_t state; 644*6401734dSWill Andrews boolean_t inuse = B_FALSE; 645*6401734dSWill Andrews boolean_t force = B_FALSE; 646*6401734dSWill Andrews 647*6401734dSWill Andrews /* check options */ 648*6401734dSWill Andrews while ((c = getopt(argc, argv, "f")) != -1) { 649*6401734dSWill Andrews switch (c) { 650*6401734dSWill Andrews case 'f': 651*6401734dSWill Andrews force = B_TRUE; 652*6401734dSWill Andrews break; 653*6401734dSWill Andrews default: 654*6401734dSWill Andrews (void) fprintf(stderr, gettext("invalid option '%c'\n"), 655*6401734dSWill Andrews optopt); 656*6401734dSWill Andrews usage(B_FALSE); 657*6401734dSWill Andrews } 658*6401734dSWill Andrews } 659*6401734dSWill Andrews 660*6401734dSWill Andrews argc -= optind; 661*6401734dSWill Andrews argv += optind; 662*6401734dSWill Andrews 663*6401734dSWill Andrews /* get vdev name */ 664*6401734dSWill Andrews if (argc < 1) { 665*6401734dSWill Andrews (void) fprintf(stderr, gettext("missing vdev name\n")); 666*6401734dSWill Andrews usage(B_FALSE); 667*6401734dSWill Andrews } 668*6401734dSWill Andrews if (argc > 1) { 669*6401734dSWill Andrews (void) fprintf(stderr, gettext("too many arguments\n")); 670*6401734dSWill Andrews usage(B_FALSE); 671*6401734dSWill Andrews } 672*6401734dSWill Andrews 673*6401734dSWill Andrews /* 674*6401734dSWill Andrews * Check if we were given absolute path and use it as is. 675*6401734dSWill Andrews * Otherwise if the provided vdev name doesn't point to a file, 676*6401734dSWill Andrews * try prepending dsk path and appending s0. 677*6401734dSWill Andrews */ 678*6401734dSWill Andrews (void) strlcpy(vdev, argv[0], sizeof (vdev)); 679*6401734dSWill Andrews if (vdev[0] != '/' && stat(vdev, &st) != 0) { 680*6401734dSWill Andrews char *s; 681*6401734dSWill Andrews 682*6401734dSWill Andrews (void) snprintf(vdev, sizeof (vdev), "%s/%s", 683*6401734dSWill Andrews ZFS_DISK_ROOT, argv[0]); 684*6401734dSWill Andrews if ((s = strrchr(argv[0], 's')) == NULL || 685*6401734dSWill Andrews !isdigit(*(s + 1))) 686*6401734dSWill Andrews (void) strlcat(vdev, "s0", sizeof (vdev)); 687*6401734dSWill Andrews if (stat(vdev, &st) != 0) { 688*6401734dSWill Andrews (void) fprintf(stderr, gettext( 689*6401734dSWill Andrews "failed to find device %s, try specifying absolute " 690*6401734dSWill Andrews "path instead\n"), argv[0]); 691*6401734dSWill Andrews return (1); 692*6401734dSWill Andrews } 693*6401734dSWill Andrews } 694*6401734dSWill Andrews 695*6401734dSWill Andrews if ((fd = open(vdev, O_RDWR)) < 0) { 696*6401734dSWill Andrews (void) fprintf(stderr, gettext("failed to open %s: %s\n"), 697*6401734dSWill Andrews vdev, strerror(errno)); 698*6401734dSWill Andrews return (1); 699*6401734dSWill Andrews } 700*6401734dSWill Andrews 701*6401734dSWill Andrews if (zpool_read_label(fd, &config) != 0 || config == NULL) { 702*6401734dSWill Andrews (void) fprintf(stderr, 703*6401734dSWill Andrews gettext("failed to read label from %s\n"), vdev); 704*6401734dSWill Andrews return (1); 705*6401734dSWill Andrews } 706*6401734dSWill Andrews nvlist_free(config); 707*6401734dSWill Andrews 708*6401734dSWill Andrews ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse); 709*6401734dSWill Andrews if (ret != 0) { 710*6401734dSWill Andrews (void) fprintf(stderr, 711*6401734dSWill Andrews gettext("failed to check state for %s\n"), vdev); 712*6401734dSWill Andrews return (1); 713*6401734dSWill Andrews } 714*6401734dSWill Andrews 715*6401734dSWill Andrews if (!inuse) 716*6401734dSWill Andrews goto wipe_label; 717*6401734dSWill Andrews 718*6401734dSWill Andrews switch (state) { 719*6401734dSWill Andrews default: 720*6401734dSWill Andrews case POOL_STATE_ACTIVE: 721*6401734dSWill Andrews case POOL_STATE_SPARE: 722*6401734dSWill Andrews case POOL_STATE_L2CACHE: 723*6401734dSWill Andrews (void) fprintf(stderr, gettext( 724*6401734dSWill Andrews "%s is a member (%s) of pool \"%s\"\n"), 725*6401734dSWill Andrews vdev, zpool_pool_state_to_name(state), name); 726*6401734dSWill Andrews ret = 1; 727*6401734dSWill Andrews goto errout; 728*6401734dSWill Andrews 729*6401734dSWill Andrews case POOL_STATE_EXPORTED: 730*6401734dSWill Andrews if (force) 731*6401734dSWill Andrews break; 732*6401734dSWill Andrews (void) fprintf(stderr, gettext( 733*6401734dSWill Andrews "use '-f' to override the following error:\n" 734*6401734dSWill Andrews "%s is a member of exported pool \"%s\"\n"), 735*6401734dSWill Andrews vdev, name); 736*6401734dSWill Andrews ret = 1; 737*6401734dSWill Andrews goto errout; 738*6401734dSWill Andrews 739*6401734dSWill Andrews case POOL_STATE_POTENTIALLY_ACTIVE: 740*6401734dSWill Andrews if (force) 741*6401734dSWill Andrews break; 742*6401734dSWill Andrews (void) fprintf(stderr, gettext( 743*6401734dSWill Andrews "use '-f' to override the following error:\n" 744*6401734dSWill Andrews "%s is a member of potentially active pool \"%s\"\n"), 745*6401734dSWill Andrews vdev, name); 746*6401734dSWill Andrews ret = 1; 747*6401734dSWill Andrews goto errout; 748*6401734dSWill Andrews 749*6401734dSWill Andrews case POOL_STATE_DESTROYED: 750*6401734dSWill Andrews /* inuse should never be set for a destroyed pool */ 751*6401734dSWill Andrews assert(0); 752*6401734dSWill Andrews break; 753*6401734dSWill Andrews } 754*6401734dSWill Andrews 755*6401734dSWill Andrews wipe_label: 756*6401734dSWill Andrews ret = zpool_clear_label(fd); 757*6401734dSWill Andrews if (ret != 0) { 758*6401734dSWill Andrews (void) fprintf(stderr, 759*6401734dSWill Andrews gettext("failed to clear label for %s\n"), vdev); 760*6401734dSWill Andrews } 761*6401734dSWill Andrews 762*6401734dSWill Andrews errout: 763*6401734dSWill Andrews free(name); 764*6401734dSWill Andrews (void) close(fd); 765*6401734dSWill Andrews 766*6401734dSWill Andrews return (ret); 767*6401734dSWill Andrews } 768*6401734dSWill Andrews 769fa9e4066Sahrens /* 770ad135b5dSChristopher Siden * zpool create [-fnd] [-o property=value] ... 7710a48a24eStimh * [-O file-system-property=value] ... 7720a48a24eStimh * [-R root] [-m mountpoint] <pool> <dev> ... 773fa9e4066Sahrens * 774fa9e4066Sahrens * -f Force creation, even if devices appear in use 775fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 776fa9e4066Sahrens * were to be created. 777fa9e4066Sahrens * -R Create a pool under an alternate root 778fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 779ad135b5dSChristopher Siden * '/<pool>' 780990b4856Slling * -o Set property=value. 781ad135b5dSChristopher Siden * -d Don't automatically enable all supported pool features 782ad135b5dSChristopher Siden * (individual features can be enabled with -o). 7830a48a24eStimh * -O Set fsproperty=value in the pool's root file system 784fa9e4066Sahrens * 785b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 786fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 787fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 788fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 789fa9e4066Sahrens */ 790fa9e4066Sahrens int 791fa9e4066Sahrens zpool_do_create(int argc, char **argv) 792fa9e4066Sahrens { 79399653d4eSeschrock boolean_t force = B_FALSE; 79499653d4eSeschrock boolean_t dryrun = B_FALSE; 795ad135b5dSChristopher Siden boolean_t enable_all_pool_feat = B_TRUE; 796fa9e4066Sahrens int c; 797990b4856Slling nvlist_t *nvroot = NULL; 798fa9e4066Sahrens char *poolname; 799990b4856Slling int ret = 1; 800fa9e4066Sahrens char *altroot = NULL; 801fa9e4066Sahrens char *mountpoint = NULL; 8020a48a24eStimh nvlist_t *fsprops = NULL; 803990b4856Slling nvlist_t *props = NULL; 8042f8aaab3Seschrock char *propval; 805fa9e4066Sahrens 806fa9e4066Sahrens /* check options */ 807ad135b5dSChristopher Siden while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) { 808fa9e4066Sahrens switch (c) { 809fa9e4066Sahrens case 'f': 81099653d4eSeschrock force = B_TRUE; 811fa9e4066Sahrens break; 812fa9e4066Sahrens case 'n': 81399653d4eSeschrock dryrun = B_TRUE; 814fa9e4066Sahrens break; 815ad135b5dSChristopher Siden case 'd': 816ad135b5dSChristopher Siden enable_all_pool_feat = B_FALSE; 817ad135b5dSChristopher Siden break; 818fa9e4066Sahrens case 'R': 819fa9e4066Sahrens altroot = optarg; 820990b4856Slling if (add_prop_list(zpool_prop_to_name( 8210a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 822990b4856Slling goto errout; 8232f8aaab3Seschrock if (nvlist_lookup_string(props, 8242f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 8252f8aaab3Seschrock &propval) == 0) 8262f8aaab3Seschrock break; 827990b4856Slling if (add_prop_list(zpool_prop_to_name( 8280a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 829990b4856Slling goto errout; 830fa9e4066Sahrens break; 831fa9e4066Sahrens case 'm': 8328b713775SWill Andrews /* Equivalent to -O mountpoint=optarg */ 833fa9e4066Sahrens mountpoint = optarg; 834fa9e4066Sahrens break; 835990b4856Slling case 'o': 836990b4856Slling if ((propval = strchr(optarg, '=')) == NULL) { 837990b4856Slling (void) fprintf(stderr, gettext("missing " 838990b4856Slling "'=' for -o option\n")); 839990b4856Slling goto errout; 840990b4856Slling } 841990b4856Slling *propval = '\0'; 842990b4856Slling propval++; 843990b4856Slling 8440a48a24eStimh if (add_prop_list(optarg, propval, &props, B_TRUE)) 8450a48a24eStimh goto errout; 846ad135b5dSChristopher Siden 847ad135b5dSChristopher Siden /* 848ad135b5dSChristopher Siden * If the user is creating a pool that doesn't support 849ad135b5dSChristopher Siden * feature flags, don't enable any features. 850ad135b5dSChristopher Siden */ 851ad135b5dSChristopher Siden if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 852ad135b5dSChristopher Siden char *end; 853ad135b5dSChristopher Siden u_longlong_t ver; 854ad135b5dSChristopher Siden 855ad135b5dSChristopher Siden ver = strtoull(propval, &end, 10); 856ad135b5dSChristopher Siden if (*end == '\0' && 857ad135b5dSChristopher Siden ver < SPA_VERSION_FEATURES) { 858ad135b5dSChristopher Siden enable_all_pool_feat = B_FALSE; 859ad135b5dSChristopher Siden } 860ad135b5dSChristopher Siden } 861c423721fSXin Li if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) 862c423721fSXin Li altroot = propval; 8630a48a24eStimh break; 8640a48a24eStimh case 'O': 8650a48a24eStimh if ((propval = strchr(optarg, '=')) == NULL) { 8660a48a24eStimh (void) fprintf(stderr, gettext("missing " 8670a48a24eStimh "'=' for -O option\n")); 8680a48a24eStimh goto errout; 8690a48a24eStimh } 8700a48a24eStimh *propval = '\0'; 8710a48a24eStimh propval++; 8720a48a24eStimh 8738b713775SWill Andrews /* 8748b713775SWill Andrews * Mountpoints are checked and then added later. 8758b713775SWill Andrews * Uniquely among properties, they can be specified 8768b713775SWill Andrews * more than once, to avoid conflict with -m. 8778b713775SWill Andrews */ 8788b713775SWill Andrews if (0 == strcmp(optarg, 8798b713775SWill Andrews zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) { 8808b713775SWill Andrews mountpoint = propval; 8818b713775SWill Andrews } else if (add_prop_list(optarg, propval, &fsprops, 8828b713775SWill Andrews B_FALSE)) { 883990b4856Slling goto errout; 8848b713775SWill Andrews } 885990b4856Slling break; 886fa9e4066Sahrens case ':': 887fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 888fa9e4066Sahrens "'%c' option\n"), optopt); 889990b4856Slling goto badusage; 890fa9e4066Sahrens case '?': 891fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 892fa9e4066Sahrens optopt); 893990b4856Slling goto badusage; 894fa9e4066Sahrens } 895fa9e4066Sahrens } 896fa9e4066Sahrens 897fa9e4066Sahrens argc -= optind; 898fa9e4066Sahrens argv += optind; 899fa9e4066Sahrens 900fa9e4066Sahrens /* get pool name and check number of arguments */ 901fa9e4066Sahrens if (argc < 1) { 902fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 903990b4856Slling goto badusage; 904fa9e4066Sahrens } 905fa9e4066Sahrens if (argc < 2) { 906fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 907990b4856Slling goto badusage; 908fa9e4066Sahrens } 909fa9e4066Sahrens 910fa9e4066Sahrens poolname = argv[0]; 911fa9e4066Sahrens 912fa9e4066Sahrens /* 913fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 914fa9e4066Sahrens * user to use 'zfs create' instead. 915fa9e4066Sahrens */ 916fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 917fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 918fa9e4066Sahrens "character '/' in pool name\n"), poolname); 919fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 920fa9e4066Sahrens "create a dataset\n")); 921990b4856Slling goto errout; 922fa9e4066Sahrens } 923fa9e4066Sahrens 924fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 925705040edSEric Taylor nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 926705040edSEric Taylor argc - 1, argv + 1); 927fa9e4066Sahrens if (nvroot == NULL) 9280a48a24eStimh goto errout; 929fa9e4066Sahrens 93099653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 931b7b97454Sperrin if (!zfs_allocatable_devs(nvroot)) { 93299653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 93399653d4eSeschrock "specification: at least one toplevel vdev must be " 93499653d4eSeschrock "specified\n")); 935990b4856Slling goto errout; 93699653d4eSeschrock } 93799653d4eSeschrock 938fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 939fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 940e9dbad6fSeschrock "must be an absolute path\n"), altroot); 941990b4856Slling goto errout; 942fa9e4066Sahrens } 943fa9e4066Sahrens 944fa9e4066Sahrens /* 945fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 946fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 947fa9e4066Sahrens */ 948fa9e4066Sahrens if (mountpoint == NULL || 949fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 950fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 951fa9e4066Sahrens char buf[MAXPATHLEN]; 95211022c7cStimh DIR *dirp; 953fa9e4066Sahrens 954fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 955fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 956fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 957fa9e4066Sahrens "'none'\n"), mountpoint); 958990b4856Slling goto errout; 959fa9e4066Sahrens } 960fa9e4066Sahrens 961fa9e4066Sahrens if (mountpoint == NULL) { 962fa9e4066Sahrens if (altroot != NULL) 963fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 964fa9e4066Sahrens altroot, poolname); 965fa9e4066Sahrens else 966fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 967fa9e4066Sahrens poolname); 968fa9e4066Sahrens } else { 969fa9e4066Sahrens if (altroot != NULL) 970fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 971fa9e4066Sahrens altroot, mountpoint); 972fa9e4066Sahrens else 973fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 974fa9e4066Sahrens mountpoint); 975fa9e4066Sahrens } 976fa9e4066Sahrens 97711022c7cStimh if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 97811022c7cStimh (void) fprintf(stderr, gettext("mountpoint '%s' : " 97911022c7cStimh "%s\n"), buf, strerror(errno)); 980fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 981fa9e4066Sahrens "option to provide a different default\n")); 982990b4856Slling goto errout; 98311022c7cStimh } else if (dirp) { 98411022c7cStimh int count = 0; 98511022c7cStimh 98611022c7cStimh while (count < 3 && readdir(dirp) != NULL) 98711022c7cStimh count++; 98811022c7cStimh (void) closedir(dirp); 98911022c7cStimh 99011022c7cStimh if (count > 2) { 99111022c7cStimh (void) fprintf(stderr, gettext("mountpoint " 99211022c7cStimh "'%s' exists and is not empty\n"), buf); 99311022c7cStimh (void) fprintf(stderr, gettext("use '-m' " 99411022c7cStimh "option to provide a " 99511022c7cStimh "different default\n")); 99611022c7cStimh goto errout; 99711022c7cStimh } 998fa9e4066Sahrens } 999fa9e4066Sahrens } 1000fa9e4066Sahrens 10018b713775SWill Andrews /* 10028b713775SWill Andrews * Now that the mountpoint's validity has been checked, ensure that 10038b713775SWill Andrews * the property is set appropriately prior to creating the pool. 10048b713775SWill Andrews */ 10058b713775SWill Andrews if (mountpoint != NULL) { 10068b713775SWill Andrews ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 10078b713775SWill Andrews mountpoint, &fsprops, B_FALSE); 10088b713775SWill Andrews if (ret != 0) 10098b713775SWill Andrews goto errout; 10108b713775SWill Andrews } 10118b713775SWill Andrews 10128b713775SWill Andrews ret = 1; 1013fa9e4066Sahrens if (dryrun) { 1014fa9e4066Sahrens /* 1015fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 1016fa9e4066Sahrens * through all the vdevs in the list and print out in an 1017fa9e4066Sahrens * appropriate hierarchy. 1018fa9e4066Sahrens */ 1019fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 1020fa9e4066Sahrens "following layout:\n\n"), poolname); 1021fa9e4066Sahrens 10228654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 10238654d025Sperrin if (num_logs(nvroot) > 0) 10248654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 1025fa9e4066Sahrens 1026fa9e4066Sahrens ret = 0; 1027fa9e4066Sahrens } else { 1028fa9e4066Sahrens /* 1029fa9e4066Sahrens * Hand off to libzfs. 1030fa9e4066Sahrens */ 1031ad135b5dSChristopher Siden if (enable_all_pool_feat) { 10322acef22dSMatthew Ahrens spa_feature_t i; 1033ad135b5dSChristopher Siden for (i = 0; i < SPA_FEATURES; i++) { 1034ad135b5dSChristopher Siden char propname[MAXPATHLEN]; 1035ad135b5dSChristopher Siden zfeature_info_t *feat = &spa_feature_table[i]; 1036ad135b5dSChristopher Siden 1037ad135b5dSChristopher Siden (void) snprintf(propname, sizeof (propname), 1038ad135b5dSChristopher Siden "feature@%s", feat->fi_uname); 1039ad135b5dSChristopher Siden 1040ad135b5dSChristopher Siden /* 1041ad135b5dSChristopher Siden * Skip feature if user specified it manually 1042ad135b5dSChristopher Siden * on the command line. 1043ad135b5dSChristopher Siden */ 1044ad135b5dSChristopher Siden if (nvlist_exists(props, propname)) 1045ad135b5dSChristopher Siden continue; 1046ad135b5dSChristopher Siden 10478b713775SWill Andrews ret = add_prop_list(propname, 10488b713775SWill Andrews ZFS_FEATURE_ENABLED, &props, B_TRUE); 10498b713775SWill Andrews if (ret != 0) 1050ad135b5dSChristopher Siden goto errout; 1051ad135b5dSChristopher Siden } 1052ad135b5dSChristopher Siden } 10538b713775SWill Andrews 10548b713775SWill Andrews ret = 1; 10550a48a24eStimh if (zpool_create(g_zfs, poolname, 10560a48a24eStimh nvroot, props, fsprops) == 0) { 105799653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 1058fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 1059fa9e4066Sahrens if (pool != NULL) { 1060fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 1061da6c28aaSamw ret = zfs_shareall(pool); 1062fa9e4066Sahrens zfs_close(pool); 1063fa9e4066Sahrens } 106499653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 106599653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 106699653d4eSeschrock "been omitted\n")); 1067fa9e4066Sahrens } 1068fa9e4066Sahrens } 1069fa9e4066Sahrens 1070990b4856Slling errout: 10712f8aaab3Seschrock nvlist_free(nvroot); 10720a48a24eStimh nvlist_free(fsprops); 10732f8aaab3Seschrock nvlist_free(props); 1074fa9e4066Sahrens return (ret); 1075990b4856Slling badusage: 10760a48a24eStimh nvlist_free(fsprops); 1077990b4856Slling nvlist_free(props); 1078990b4856Slling usage(B_FALSE); 1079990b4856Slling return (2); 1080fa9e4066Sahrens } 1081fa9e4066Sahrens 1082fa9e4066Sahrens /* 1083fa9e4066Sahrens * zpool destroy <pool> 1084fa9e4066Sahrens * 1085fa9e4066Sahrens * -f Forcefully unmount any datasets 1086fa9e4066Sahrens * 1087fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 1088fa9e4066Sahrens */ 1089fa9e4066Sahrens int 1090fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 1091fa9e4066Sahrens { 109299653d4eSeschrock boolean_t force = B_FALSE; 1093fa9e4066Sahrens int c; 1094fa9e4066Sahrens char *pool; 1095fa9e4066Sahrens zpool_handle_t *zhp; 1096fa9e4066Sahrens int ret; 1097fa9e4066Sahrens 1098fa9e4066Sahrens /* check options */ 1099fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 1100fa9e4066Sahrens switch (c) { 1101fa9e4066Sahrens case 'f': 110299653d4eSeschrock force = B_TRUE; 1103fa9e4066Sahrens break; 1104fa9e4066Sahrens case '?': 1105fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1106fa9e4066Sahrens optopt); 110799653d4eSeschrock usage(B_FALSE); 1108fa9e4066Sahrens } 1109fa9e4066Sahrens } 1110fa9e4066Sahrens 1111fa9e4066Sahrens argc -= optind; 1112fa9e4066Sahrens argv += optind; 1113fa9e4066Sahrens 1114fa9e4066Sahrens /* check arguments */ 1115fa9e4066Sahrens if (argc < 1) { 1116fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 111799653d4eSeschrock usage(B_FALSE); 1118fa9e4066Sahrens } 1119fa9e4066Sahrens if (argc > 1) { 1120fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 112199653d4eSeschrock usage(B_FALSE); 1122fa9e4066Sahrens } 1123fa9e4066Sahrens 1124fa9e4066Sahrens pool = argv[0]; 1125fa9e4066Sahrens 112699653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1127fa9e4066Sahrens /* 1128fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 1129fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 1130fa9e4066Sahrens */ 1131fa9e4066Sahrens if (strchr(pool, '/') != NULL) 1132fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1133fa9e4066Sahrens "destroy a dataset\n")); 1134fa9e4066Sahrens return (1); 1135fa9e4066Sahrens } 1136fa9e4066Sahrens 1137f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 1138fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 1139fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 1140fa9e4066Sahrens return (1); 1141fa9e4066Sahrens } 1142fa9e4066Sahrens 11434445fffbSMatthew Ahrens /* The history must be logged as part of the export */ 11444445fffbSMatthew Ahrens log_history = B_FALSE; 11454445fffbSMatthew Ahrens 11464445fffbSMatthew Ahrens ret = (zpool_destroy(zhp, history_str) != 0); 1147fa9e4066Sahrens 1148fa9e4066Sahrens zpool_close(zhp); 1149fa9e4066Sahrens 1150fa9e4066Sahrens return (ret); 1151fa9e4066Sahrens } 1152fa9e4066Sahrens 1153fa9e4066Sahrens /* 1154fa9e4066Sahrens * zpool export [-f] <pool> ... 1155fa9e4066Sahrens * 1156fa9e4066Sahrens * -f Forcefully unmount datasets 1157fa9e4066Sahrens * 1158b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 1159fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 1160fa9e4066Sahrens * then the datasets will be forcefully unmounted. 1161fa9e4066Sahrens */ 1162fa9e4066Sahrens int 1163fa9e4066Sahrens zpool_do_export(int argc, char **argv) 1164fa9e4066Sahrens { 116599653d4eSeschrock boolean_t force = B_FALSE; 1166394ab0cbSGeorge Wilson boolean_t hardforce = B_FALSE; 1167fa9e4066Sahrens int c; 1168fa9e4066Sahrens zpool_handle_t *zhp; 1169fa9e4066Sahrens int ret; 1170fa9e4066Sahrens int i; 1171fa9e4066Sahrens 1172fa9e4066Sahrens /* check options */ 1173394ab0cbSGeorge Wilson while ((c = getopt(argc, argv, "fF")) != -1) { 1174fa9e4066Sahrens switch (c) { 1175fa9e4066Sahrens case 'f': 117699653d4eSeschrock force = B_TRUE; 1177fa9e4066Sahrens break; 1178394ab0cbSGeorge Wilson case 'F': 1179394ab0cbSGeorge Wilson hardforce = B_TRUE; 1180394ab0cbSGeorge Wilson break; 1181fa9e4066Sahrens case '?': 1182fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1183fa9e4066Sahrens optopt); 118499653d4eSeschrock usage(B_FALSE); 1185fa9e4066Sahrens } 1186fa9e4066Sahrens } 1187fa9e4066Sahrens 1188fa9e4066Sahrens argc -= optind; 1189fa9e4066Sahrens argv += optind; 1190fa9e4066Sahrens 1191fa9e4066Sahrens /* check arguments */ 1192fa9e4066Sahrens if (argc < 1) { 1193fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 119499653d4eSeschrock usage(B_FALSE); 1195fa9e4066Sahrens } 1196fa9e4066Sahrens 1197fa9e4066Sahrens ret = 0; 1198fa9e4066Sahrens for (i = 0; i < argc; i++) { 119999653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1200fa9e4066Sahrens ret = 1; 1201fa9e4066Sahrens continue; 1202fa9e4066Sahrens } 1203fa9e4066Sahrens 1204f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 1205fa9e4066Sahrens ret = 1; 1206fa9e4066Sahrens zpool_close(zhp); 1207fa9e4066Sahrens continue; 1208fa9e4066Sahrens } 1209fa9e4066Sahrens 12104445fffbSMatthew Ahrens /* The history must be logged as part of the export */ 12114445fffbSMatthew Ahrens log_history = B_FALSE; 12124445fffbSMatthew Ahrens 1213394ab0cbSGeorge Wilson if (hardforce) { 12144445fffbSMatthew Ahrens if (zpool_export_force(zhp, history_str) != 0) 1215394ab0cbSGeorge Wilson ret = 1; 12164445fffbSMatthew Ahrens } else if (zpool_export(zhp, force, history_str) != 0) { 1217fa9e4066Sahrens ret = 1; 1218394ab0cbSGeorge Wilson } 1219fa9e4066Sahrens 1220fa9e4066Sahrens zpool_close(zhp); 1221fa9e4066Sahrens } 1222fa9e4066Sahrens 1223fa9e4066Sahrens return (ret); 1224fa9e4066Sahrens } 1225fa9e4066Sahrens 1226fa9e4066Sahrens /* 1227fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 1228fa9e4066Sahrens * name column. 1229fa9e4066Sahrens */ 1230fa9e4066Sahrens static int 1231c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1232fa9e4066Sahrens { 123388ecc943SGeorge Wilson char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1234fa9e4066Sahrens nvlist_t **child; 1235fa9e4066Sahrens uint_t c, children; 1236fa9e4066Sahrens int ret; 1237fa9e4066Sahrens 1238fa9e4066Sahrens if (strlen(name) + depth > max) 1239fa9e4066Sahrens max = strlen(name) + depth; 1240fa9e4066Sahrens 1241afefbcddSeschrock free(name); 1242afefbcddSeschrock 124399653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 124499653d4eSeschrock &child, &children) == 0) { 124599653d4eSeschrock for (c = 0; c < children; c++) 124699653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 124799653d4eSeschrock max)) > max) 124899653d4eSeschrock max = ret; 124999653d4eSeschrock } 125099653d4eSeschrock 1251fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1252fa94a07fSbrendan &child, &children) == 0) { 1253fa94a07fSbrendan for (c = 0; c < children; c++) 1254fa94a07fSbrendan if ((ret = max_width(zhp, child[c], depth + 2, 1255fa94a07fSbrendan max)) > max) 1256fa94a07fSbrendan max = ret; 1257fa94a07fSbrendan } 1258fa94a07fSbrendan 1259fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 126099653d4eSeschrock &child, &children) == 0) { 126199653d4eSeschrock for (c = 0; c < children; c++) 126299653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 126399653d4eSeschrock max)) > max) 126499653d4eSeschrock max = ret; 126599653d4eSeschrock } 1266fa9e4066Sahrens 1267fa9e4066Sahrens 1268fa9e4066Sahrens return (max); 1269fa9e4066Sahrens } 1270fa9e4066Sahrens 1271e6ca193dSGeorge Wilson typedef struct spare_cbdata { 1272e6ca193dSGeorge Wilson uint64_t cb_guid; 1273e6ca193dSGeorge Wilson zpool_handle_t *cb_zhp; 1274e6ca193dSGeorge Wilson } spare_cbdata_t; 1275e6ca193dSGeorge Wilson 1276e6ca193dSGeorge Wilson static boolean_t 1277e6ca193dSGeorge Wilson find_vdev(nvlist_t *nv, uint64_t search) 1278e6ca193dSGeorge Wilson { 1279e6ca193dSGeorge Wilson uint64_t guid; 1280e6ca193dSGeorge Wilson nvlist_t **child; 1281e6ca193dSGeorge Wilson uint_t c, children; 1282e6ca193dSGeorge Wilson 1283e6ca193dSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1284e6ca193dSGeorge Wilson search == guid) 1285e6ca193dSGeorge Wilson return (B_TRUE); 1286e6ca193dSGeorge Wilson 1287e6ca193dSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1288e6ca193dSGeorge Wilson &child, &children) == 0) { 1289e6ca193dSGeorge Wilson for (c = 0; c < children; c++) 1290e6ca193dSGeorge Wilson if (find_vdev(child[c], search)) 1291e6ca193dSGeorge Wilson return (B_TRUE); 1292e6ca193dSGeorge Wilson } 1293e6ca193dSGeorge Wilson 1294e6ca193dSGeorge Wilson return (B_FALSE); 1295e6ca193dSGeorge Wilson } 1296e6ca193dSGeorge Wilson 1297e6ca193dSGeorge Wilson static int 1298e6ca193dSGeorge Wilson find_spare(zpool_handle_t *zhp, void *data) 1299e6ca193dSGeorge Wilson { 1300e6ca193dSGeorge Wilson spare_cbdata_t *cbp = data; 1301e6ca193dSGeorge Wilson nvlist_t *config, *nvroot; 1302e6ca193dSGeorge Wilson 1303e6ca193dSGeorge Wilson config = zpool_get_config(zhp, NULL); 1304e6ca193dSGeorge Wilson verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1305e6ca193dSGeorge Wilson &nvroot) == 0); 1306e6ca193dSGeorge Wilson 1307e6ca193dSGeorge Wilson if (find_vdev(nvroot, cbp->cb_guid)) { 1308e6ca193dSGeorge Wilson cbp->cb_zhp = zhp; 1309e6ca193dSGeorge Wilson return (1); 1310e6ca193dSGeorge Wilson } 1311e6ca193dSGeorge Wilson 1312e6ca193dSGeorge Wilson zpool_close(zhp); 1313e6ca193dSGeorge Wilson return (0); 1314e6ca193dSGeorge Wilson } 1315e6ca193dSGeorge Wilson 1316e6ca193dSGeorge Wilson /* 1317e6ca193dSGeorge Wilson * Print out configuration state as requested by status_callback. 1318e6ca193dSGeorge Wilson */ 1319e6ca193dSGeorge Wilson void 1320e6ca193dSGeorge Wilson print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1321e6ca193dSGeorge Wilson int namewidth, int depth, boolean_t isspare) 1322e6ca193dSGeorge Wilson { 1323e6ca193dSGeorge Wilson nvlist_t **child; 1324e6ca193dSGeorge Wilson uint_t c, children; 13253f9d6ad7SLin Ling pool_scan_stat_t *ps = NULL; 1326e6ca193dSGeorge Wilson vdev_stat_t *vs; 13273f9d6ad7SLin Ling char rbuf[6], wbuf[6], cbuf[6]; 1328e6ca193dSGeorge Wilson char *vname; 1329e6ca193dSGeorge Wilson uint64_t notpresent; 1330e6ca193dSGeorge Wilson spare_cbdata_t cb; 1331*6401734dSWill Andrews const char *state; 1332e6ca193dSGeorge Wilson 1333e6ca193dSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1334e6ca193dSGeorge Wilson &child, &children) != 0) 1335e6ca193dSGeorge Wilson children = 0; 1336e6ca193dSGeorge Wilson 13373f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 13383f9d6ad7SLin Ling (uint64_t **)&vs, &c) == 0); 13393f9d6ad7SLin Ling 1340e6ca193dSGeorge Wilson state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1341e6ca193dSGeorge Wilson if (isspare) { 1342e6ca193dSGeorge Wilson /* 1343e6ca193dSGeorge Wilson * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1344e6ca193dSGeorge Wilson * online drives. 1345e6ca193dSGeorge Wilson */ 1346e6ca193dSGeorge Wilson if (vs->vs_aux == VDEV_AUX_SPARED) 1347e6ca193dSGeorge Wilson state = "INUSE"; 1348e6ca193dSGeorge Wilson else if (vs->vs_state == VDEV_STATE_HEALTHY) 1349e6ca193dSGeorge Wilson state = "AVAIL"; 1350e6ca193dSGeorge Wilson } 1351e6ca193dSGeorge Wilson 1352e6ca193dSGeorge Wilson (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1353e6ca193dSGeorge Wilson name, state); 1354e6ca193dSGeorge Wilson 1355e6ca193dSGeorge Wilson if (!isspare) { 1356e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1357e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1358e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1359e6ca193dSGeorge Wilson (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1360e6ca193dSGeorge Wilson } 1361e6ca193dSGeorge Wilson 1362e6ca193dSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1363e6ca193dSGeorge Wilson ¬present) == 0) { 1364e6ca193dSGeorge Wilson char *path; 1365e6ca193dSGeorge Wilson verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 1366e6ca193dSGeorge Wilson (void) printf(" was %s", path); 1367e6ca193dSGeorge Wilson } else if (vs->vs_aux != 0) { 1368e6ca193dSGeorge Wilson (void) printf(" "); 1369e6ca193dSGeorge Wilson 1370e6ca193dSGeorge Wilson switch (vs->vs_aux) { 1371e6ca193dSGeorge Wilson case VDEV_AUX_OPEN_FAILED: 1372e6ca193dSGeorge Wilson (void) printf(gettext("cannot open")); 1373e6ca193dSGeorge Wilson break; 1374e6ca193dSGeorge Wilson 1375e6ca193dSGeorge Wilson case VDEV_AUX_BAD_GUID_SUM: 1376e6ca193dSGeorge Wilson (void) printf(gettext("missing device")); 1377e6ca193dSGeorge Wilson break; 1378e6ca193dSGeorge Wilson 1379e6ca193dSGeorge Wilson case VDEV_AUX_NO_REPLICAS: 1380e6ca193dSGeorge Wilson (void) printf(gettext("insufficient replicas")); 1381e6ca193dSGeorge Wilson break; 1382e6ca193dSGeorge Wilson 1383e6ca193dSGeorge Wilson case VDEV_AUX_VERSION_NEWER: 1384e6ca193dSGeorge Wilson (void) printf(gettext("newer version")); 1385e6ca193dSGeorge Wilson break; 1386e6ca193dSGeorge Wilson 1387ad135b5dSChristopher Siden case VDEV_AUX_UNSUP_FEAT: 1388ad135b5dSChristopher Siden (void) printf(gettext("unsupported feature(s)")); 1389ad135b5dSChristopher Siden break; 1390ad135b5dSChristopher Siden 1391e6ca193dSGeorge Wilson case VDEV_AUX_SPARED: 1392e6ca193dSGeorge Wilson verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1393e6ca193dSGeorge Wilson &cb.cb_guid) == 0); 1394e6ca193dSGeorge Wilson if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1395e6ca193dSGeorge Wilson if (strcmp(zpool_get_name(cb.cb_zhp), 1396e6ca193dSGeorge Wilson zpool_get_name(zhp)) == 0) 1397e6ca193dSGeorge Wilson (void) printf(gettext("currently in " 1398e6ca193dSGeorge Wilson "use")); 1399e6ca193dSGeorge Wilson else 1400e6ca193dSGeorge Wilson (void) printf(gettext("in use by " 1401e6ca193dSGeorge Wilson "pool '%s'"), 1402e6ca193dSGeorge Wilson zpool_get_name(cb.cb_zhp)); 1403e6ca193dSGeorge Wilson zpool_close(cb.cb_zhp); 1404e6ca193dSGeorge Wilson } else { 1405e6ca193dSGeorge Wilson (void) printf(gettext("currently in use")); 1406e6ca193dSGeorge Wilson } 1407e6ca193dSGeorge Wilson break; 1408e6ca193dSGeorge Wilson 1409e6ca193dSGeorge Wilson case VDEV_AUX_ERR_EXCEEDED: 1410e6ca193dSGeorge Wilson (void) printf(gettext("too many errors")); 1411e6ca193dSGeorge Wilson break; 1412e6ca193dSGeorge Wilson 1413e6ca193dSGeorge Wilson case VDEV_AUX_IO_FAILURE: 1414e6ca193dSGeorge Wilson (void) printf(gettext("experienced I/O failures")); 1415e6ca193dSGeorge Wilson break; 1416e6ca193dSGeorge Wilson 1417e6ca193dSGeorge Wilson case VDEV_AUX_BAD_LOG: 1418e6ca193dSGeorge Wilson (void) printf(gettext("bad intent log")); 1419e6ca193dSGeorge Wilson break; 1420e6ca193dSGeorge Wilson 1421069f55e2SEric Schrock case VDEV_AUX_EXTERNAL: 1422069f55e2SEric Schrock (void) printf(gettext("external device fault")); 1423069f55e2SEric Schrock break; 1424069f55e2SEric Schrock 14251195e687SMark J Musante case VDEV_AUX_SPLIT_POOL: 14261195e687SMark J Musante (void) printf(gettext("split into new pool")); 14271195e687SMark J Musante break; 14281195e687SMark J Musante 1429e6ca193dSGeorge Wilson default: 1430e6ca193dSGeorge Wilson (void) printf(gettext("corrupted data")); 1431e6ca193dSGeorge Wilson break; 1432e6ca193dSGeorge Wilson } 14333f9d6ad7SLin Ling } 14343f9d6ad7SLin Ling 14353f9d6ad7SLin Ling (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 14363f9d6ad7SLin Ling (uint64_t **)&ps, &c); 14373f9d6ad7SLin Ling 14383f9d6ad7SLin Ling if (ps && ps->pss_state == DSS_SCANNING && 14393f9d6ad7SLin Ling vs->vs_scan_processed != 0 && children == 0) { 14403f9d6ad7SLin Ling (void) printf(gettext(" (%s)"), 14413f9d6ad7SLin Ling (ps->pss_func == POOL_SCAN_RESILVER) ? 14423f9d6ad7SLin Ling "resilvering" : "repairing"); 1443e6ca193dSGeorge Wilson } 1444e6ca193dSGeorge Wilson 1445e6ca193dSGeorge Wilson (void) printf("\n"); 1446e6ca193dSGeorge Wilson 1447e6ca193dSGeorge Wilson for (c = 0; c < children; c++) { 144888ecc943SGeorge Wilson uint64_t islog = B_FALSE, ishole = B_FALSE; 1449e6ca193dSGeorge Wilson 145088ecc943SGeorge Wilson /* Don't print logs or holes here */ 1451e6ca193dSGeorge Wilson (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 145288ecc943SGeorge Wilson &islog); 145388ecc943SGeorge Wilson (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 145488ecc943SGeorge Wilson &ishole); 145588ecc943SGeorge Wilson if (islog || ishole) 1456e6ca193dSGeorge Wilson continue; 145788ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1458e6ca193dSGeorge Wilson print_status_config(zhp, vname, child[c], 1459e6ca193dSGeorge Wilson namewidth, depth + 2, isspare); 1460e6ca193dSGeorge Wilson free(vname); 1461e6ca193dSGeorge Wilson } 1462e6ca193dSGeorge Wilson } 1463e6ca193dSGeorge Wilson 1464fa9e4066Sahrens 1465fa9e4066Sahrens /* 1466fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 1467fa9e4066Sahrens * pool, printing out the name and status for each one. 1468fa9e4066Sahrens */ 1469fa9e4066Sahrens void 1470e6ca193dSGeorge Wilson print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1471fa9e4066Sahrens { 1472fa9e4066Sahrens nvlist_t **child; 1473fa9e4066Sahrens uint_t c, children; 1474fa9e4066Sahrens vdev_stat_t *vs; 1475afefbcddSeschrock char *type, *vname; 1476fa9e4066Sahrens 1477fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 147888ecc943SGeorge Wilson if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 147988ecc943SGeorge Wilson strcmp(type, VDEV_TYPE_HOLE) == 0) 1480fa9e4066Sahrens return; 1481fa9e4066Sahrens 14823f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1483fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 1484fa9e4066Sahrens 1485fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1486990b4856Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1487fa9e4066Sahrens 1488fa9e4066Sahrens if (vs->vs_aux != 0) { 14893d7072f8Seschrock (void) printf(" "); 1490fa9e4066Sahrens 1491fa9e4066Sahrens switch (vs->vs_aux) { 1492fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 1493fa9e4066Sahrens (void) printf(gettext("cannot open")); 1494fa9e4066Sahrens break; 1495fa9e4066Sahrens 1496fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 1497fa9e4066Sahrens (void) printf(gettext("missing device")); 1498fa9e4066Sahrens break; 1499fa9e4066Sahrens 1500fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 1501fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 1502fa9e4066Sahrens break; 1503fa9e4066Sahrens 1504eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 1505eaca9bbdSeschrock (void) printf(gettext("newer version")); 1506eaca9bbdSeschrock break; 1507eaca9bbdSeschrock 1508ad135b5dSChristopher Siden case VDEV_AUX_UNSUP_FEAT: 1509ad135b5dSChristopher Siden (void) printf(gettext("unsupported feature(s)")); 1510ad135b5dSChristopher Siden break; 1511ad135b5dSChristopher Siden 15123d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 15133d7072f8Seschrock (void) printf(gettext("too many errors")); 15143d7072f8Seschrock break; 15153d7072f8Seschrock 1516fa9e4066Sahrens default: 1517fa9e4066Sahrens (void) printf(gettext("corrupted data")); 1518fa9e4066Sahrens break; 1519fa9e4066Sahrens } 1520fa9e4066Sahrens } 1521fa9e4066Sahrens (void) printf("\n"); 1522fa9e4066Sahrens 1523fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1524fa9e4066Sahrens &child, &children) != 0) 1525fa9e4066Sahrens return; 1526fa9e4066Sahrens 1527afefbcddSeschrock for (c = 0; c < children; c++) { 15288654d025Sperrin uint64_t is_log = B_FALSE; 15298654d025Sperrin 15308654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 15318654d025Sperrin &is_log); 1532e6ca193dSGeorge Wilson if (is_log) 15338654d025Sperrin continue; 15348654d025Sperrin 153588ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1536e6ca193dSGeorge Wilson print_import_config(vname, child[c], namewidth, depth + 2); 1537afefbcddSeschrock free(vname); 1538afefbcddSeschrock } 153999653d4eSeschrock 1540fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1541fa94a07fSbrendan &child, &children) == 0) { 1542fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 1543fa94a07fSbrendan for (c = 0; c < children; c++) { 154488ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1545fa94a07fSbrendan (void) printf("\t %s\n", vname); 1546fa94a07fSbrendan free(vname); 1547fa94a07fSbrendan } 1548fa94a07fSbrendan } 154999653d4eSeschrock 1550fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1551fa94a07fSbrendan &child, &children) == 0) { 1552fa94a07fSbrendan (void) printf(gettext("\tspares\n")); 1553fa94a07fSbrendan for (c = 0; c < children; c++) { 155488ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1555fa94a07fSbrendan (void) printf("\t %s\n", vname); 1556fa94a07fSbrendan free(vname); 1557fa94a07fSbrendan } 155899653d4eSeschrock } 1559fa9e4066Sahrens } 1560fa9e4066Sahrens 1561e6ca193dSGeorge Wilson /* 1562e6ca193dSGeorge Wilson * Print log vdevs. 1563e6ca193dSGeorge Wilson * Logs are recorded as top level vdevs in the main pool child array 1564e6ca193dSGeorge Wilson * but with "is_log" set to 1. We use either print_status_config() or 1565e6ca193dSGeorge Wilson * print_import_config() to print the top level logs then any log 1566e6ca193dSGeorge Wilson * children (eg mirrored slogs) are printed recursively - which 1567e6ca193dSGeorge Wilson * works because only the top level vdev is marked "is_log" 1568e6ca193dSGeorge Wilson */ 1569e6ca193dSGeorge Wilson static void 1570e6ca193dSGeorge Wilson print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1571e6ca193dSGeorge Wilson { 1572e6ca193dSGeorge Wilson uint_t c, children; 1573e6ca193dSGeorge Wilson nvlist_t **child; 1574e6ca193dSGeorge Wilson 1575e6ca193dSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1576e6ca193dSGeorge Wilson &children) != 0) 1577e6ca193dSGeorge Wilson return; 1578e6ca193dSGeorge Wilson 1579e6ca193dSGeorge Wilson (void) printf(gettext("\tlogs\n")); 1580e6ca193dSGeorge Wilson 1581e6ca193dSGeorge Wilson for (c = 0; c < children; c++) { 1582e6ca193dSGeorge Wilson uint64_t is_log = B_FALSE; 1583e6ca193dSGeorge Wilson char *name; 1584e6ca193dSGeorge Wilson 1585e6ca193dSGeorge Wilson (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1586e6ca193dSGeorge Wilson &is_log); 1587e6ca193dSGeorge Wilson if (!is_log) 1588e6ca193dSGeorge Wilson continue; 158988ecc943SGeorge Wilson name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1590e6ca193dSGeorge Wilson if (verbose) 1591e6ca193dSGeorge Wilson print_status_config(zhp, name, child[c], namewidth, 1592e6ca193dSGeorge Wilson 2, B_FALSE); 1593e6ca193dSGeorge Wilson else 1594e6ca193dSGeorge Wilson print_import_config(name, child[c], namewidth, 2); 1595e6ca193dSGeorge Wilson free(name); 1596e6ca193dSGeorge Wilson } 1597e6ca193dSGeorge Wilson } 1598468c413aSTim Haley 1599fa9e4066Sahrens /* 1600fa9e4066Sahrens * Display the status for the given pool. 1601fa9e4066Sahrens */ 1602fa9e4066Sahrens static void 1603fa9e4066Sahrens show_import(nvlist_t *config) 1604fa9e4066Sahrens { 1605fa9e4066Sahrens uint64_t pool_state; 1606fa9e4066Sahrens vdev_stat_t *vs; 1607fa9e4066Sahrens char *name; 1608fa9e4066Sahrens uint64_t guid; 1609fa9e4066Sahrens char *msgid; 1610fa9e4066Sahrens nvlist_t *nvroot; 1611fa9e4066Sahrens int reason; 161246657f8dSmmusante const char *health; 1613fa9e4066Sahrens uint_t vsc; 1614fa9e4066Sahrens int namewidth; 16158704186eSDan McDonald char *comment; 1616fa9e4066Sahrens 1617fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1618fa9e4066Sahrens &name) == 0); 1619fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1620fa9e4066Sahrens &guid) == 0); 1621fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1622fa9e4066Sahrens &pool_state) == 0); 1623fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1624fa9e4066Sahrens &nvroot) == 0); 1625fa9e4066Sahrens 16263f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1627fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 1628990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1629fa9e4066Sahrens 1630fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1631fa9e4066Sahrens 16328704186eSDan McDonald (void) printf(gettext(" pool: %s\n"), name); 16338704186eSDan McDonald (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 16348704186eSDan McDonald (void) printf(gettext(" state: %s"), health); 16354c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 1636b1b8ab34Slling (void) printf(gettext(" (DESTROYED)")); 16374c58d714Sdarrenm (void) printf("\n"); 1638fa9e4066Sahrens 1639fa9e4066Sahrens switch (reason) { 1640fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1641fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1642fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 16438704186eSDan McDonald (void) printf(gettext(" status: One or more devices are " 16448704186eSDan McDonald "missing from the system.\n")); 1645fa9e4066Sahrens break; 1646fa9e4066Sahrens 1647fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1648fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 16498704186eSDan McDonald (void) printf(gettext(" status: One or more devices contains " 1650fa9e4066Sahrens "corrupted data.\n")); 1651fa9e4066Sahrens break; 1652fa9e4066Sahrens 1653fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 16548704186eSDan McDonald (void) printf( 16558704186eSDan McDonald gettext(" status: The pool data is corrupted.\n")); 1656fa9e4066Sahrens break; 1657fa9e4066Sahrens 1658441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 16598704186eSDan McDonald (void) printf(gettext(" status: One or more devices " 1660441d80aaSlling "are offlined.\n")); 1661441d80aaSlling break; 1662441d80aaSlling 1663ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 16648704186eSDan McDonald (void) printf(gettext(" status: The pool metadata is " 1665ea8dc4b6Seschrock "corrupted.\n")); 1666ea8dc4b6Seschrock break; 1667ea8dc4b6Seschrock 1668eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 166957221772SChristopher Siden (void) printf(gettext(" status: The pool is formatted using a " 167057221772SChristopher Siden "legacy on-disk version.\n")); 1671eaca9bbdSeschrock break; 1672eaca9bbdSeschrock 1673eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 16748704186eSDan McDonald (void) printf(gettext(" status: The pool is formatted using an " 1675eaca9bbdSeschrock "incompatible version.\n")); 1676eaca9bbdSeschrock break; 1677b87f3af3Sperrin 167857221772SChristopher Siden case ZPOOL_STATUS_FEAT_DISABLED: 167957221772SChristopher Siden (void) printf(gettext(" status: Some supported features are " 168057221772SChristopher Siden "not enabled on the pool.\n")); 168157221772SChristopher Siden break; 168257221772SChristopher Siden 1683ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_READ: 1684ad135b5dSChristopher Siden (void) printf(gettext("status: The pool uses the following " 1685ad135b5dSChristopher Siden "feature(s) not supported on this sytem:\n")); 1686ad135b5dSChristopher Siden zpool_print_unsup_feat(config); 1687ad135b5dSChristopher Siden break; 1688ad135b5dSChristopher Siden 1689ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1690ad135b5dSChristopher Siden (void) printf(gettext("status: The pool can only be accessed " 1691ad135b5dSChristopher Siden "in read-only mode on this system. It\n\tcannot be " 1692ad135b5dSChristopher Siden "accessed in read-write mode because it uses the " 1693ad135b5dSChristopher Siden "following\n\tfeature(s) not supported on this system:\n")); 1694ad135b5dSChristopher Siden zpool_print_unsup_feat(config); 1695ad135b5dSChristopher Siden break; 1696ad135b5dSChristopher Siden 169795173954Sek case ZPOOL_STATUS_HOSTID_MISMATCH: 16988704186eSDan McDonald (void) printf(gettext(" status: The pool was last accessed by " 169995173954Sek "another system.\n")); 170095173954Sek break; 1701b87f3af3Sperrin 17023d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 17033d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 17048704186eSDan McDonald (void) printf(gettext(" status: One or more devices are " 17053d7072f8Seschrock "faulted.\n")); 17063d7072f8Seschrock break; 17073d7072f8Seschrock 1708b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 17098704186eSDan McDonald (void) printf(gettext(" status: An intent log record cannot be " 1710b87f3af3Sperrin "read.\n")); 1711b87f3af3Sperrin break; 1712b87f3af3Sperrin 17133f9d6ad7SLin Ling case ZPOOL_STATUS_RESILVERING: 17148704186eSDan McDonald (void) printf(gettext(" status: One or more devices were being " 17153f9d6ad7SLin Ling "resilvered.\n")); 17163f9d6ad7SLin Ling break; 17173f9d6ad7SLin Ling 1718fa9e4066Sahrens default: 1719fa9e4066Sahrens /* 1720fa9e4066Sahrens * No other status can be seen when importing pools. 1721fa9e4066Sahrens */ 1722fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1723fa9e4066Sahrens } 1724fa9e4066Sahrens 1725fa9e4066Sahrens /* 1726fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1727fa9e4066Sahrens */ 172846657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 172957221772SChristopher Siden if (reason == ZPOOL_STATUS_VERSION_OLDER || 173057221772SChristopher Siden reason == ZPOOL_STATUS_FEAT_DISABLED) { 17318704186eSDan McDonald (void) printf(gettext(" action: The pool can be " 1732eaca9bbdSeschrock "imported using its name or numeric identifier, " 1733eaca9bbdSeschrock "though\n\tsome features will not be available " 1734eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 173557221772SChristopher Siden } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 17368704186eSDan McDonald (void) printf(gettext(" action: The pool can be " 173795173954Sek "imported using its name or numeric " 173895173954Sek "identifier and\n\tthe '-f' flag.\n")); 173957221772SChristopher Siden } else { 17408704186eSDan McDonald (void) printf(gettext(" action: The pool can be " 1741eaca9bbdSeschrock "imported using its name or numeric " 1742eaca9bbdSeschrock "identifier.\n")); 174357221772SChristopher Siden } 174446657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 17458704186eSDan McDonald (void) printf(gettext(" action: The pool can be imported " 1746fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1747eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1748fa9e4066Sahrens } else { 1749eaca9bbdSeschrock switch (reason) { 1750eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 17518704186eSDan McDonald (void) printf(gettext(" action: The pool cannot be " 1752eaca9bbdSeschrock "imported. Access the pool on a system running " 1753eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1754eaca9bbdSeschrock "backup.\n")); 1755eaca9bbdSeschrock break; 1756ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_READ: 1757ad135b5dSChristopher Siden (void) printf(gettext("action: The pool cannot be " 1758ad135b5dSChristopher Siden "imported. Access the pool on a system that " 1759ad135b5dSChristopher Siden "supports\n\tthe required feature(s), or recreate " 1760ad135b5dSChristopher Siden "the pool from backup.\n")); 1761ad135b5dSChristopher Siden break; 1762ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1763ad135b5dSChristopher Siden (void) printf(gettext("action: The pool cannot be " 1764ad135b5dSChristopher Siden "imported in read-write mode. Import the pool " 1765ad135b5dSChristopher Siden "with\n" 1766ad135b5dSChristopher Siden "\t\"-o readonly=on\", access the pool on a system " 1767ad135b5dSChristopher Siden "that supports the\n\trequired feature(s), or " 1768ad135b5dSChristopher Siden "recreate the pool from backup.\n")); 1769ad135b5dSChristopher Siden break; 1770eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1771eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1772eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 17738704186eSDan McDonald (void) printf(gettext(" action: The pool cannot be " 1774fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1775fa9e4066Sahrens "again.\n")); 1776eaca9bbdSeschrock break; 1777eaca9bbdSeschrock default: 17788704186eSDan McDonald (void) printf(gettext(" action: The pool cannot be " 1779fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1780eaca9bbdSeschrock } 1781eaca9bbdSeschrock } 1782eaca9bbdSeschrock 17838704186eSDan McDonald /* Print the comment attached to the pool. */ 17848704186eSDan McDonald if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 17858704186eSDan McDonald (void) printf(gettext("comment: %s\n"), comment); 17868704186eSDan McDonald 178746657f8dSmmusante /* 178846657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 178946657f8dSmmusante * is "corrupt data": 179046657f8dSmmusante */ 179146657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 179246657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 179346657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1794eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1795eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1796eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1797eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1798eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 179918ce54dfSek "another system, but can be imported using\n\t" 1800eaca9bbdSeschrock "the '-f' flag.\n")); 1801fa9e4066Sahrens } 1802fa9e4066Sahrens 1803fa9e4066Sahrens if (msgid != NULL) 1804654b400cSJoshua M. Clulow (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1805fa9e4066Sahrens msgid); 1806fa9e4066Sahrens 18078704186eSDan McDonald (void) printf(gettext(" config:\n\n")); 1808fa9e4066Sahrens 1809c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1810fa9e4066Sahrens if (namewidth < 10) 1811fa9e4066Sahrens namewidth = 10; 18128654d025Sperrin 1813e6ca193dSGeorge Wilson print_import_config(name, nvroot, namewidth, 0); 1814e6ca193dSGeorge Wilson if (num_logs(nvroot) > 0) 1815e6ca193dSGeorge Wilson print_logs(NULL, nvroot, namewidth, B_FALSE); 1816fa9e4066Sahrens 1817fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 181846657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1819fa9e4066Sahrens "be part of this pool, though their\n\texact " 182046657f8dSmmusante "configuration cannot be determined.\n")); 1821fa9e4066Sahrens } 1822fa9e4066Sahrens } 1823fa9e4066Sahrens 1824fa9e4066Sahrens /* 1825fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1826990b4856Slling * lifting off to zpool_import_props(), and then mounts the datasets contained 1827990b4856Slling * within the pool. 1828fa9e4066Sahrens */ 1829fa9e4066Sahrens static int 1830fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 18314b964adaSGeorge Wilson nvlist_t *props, int flags) 1832fa9e4066Sahrens { 1833fa9e4066Sahrens zpool_handle_t *zhp; 1834fa9e4066Sahrens char *name; 1835fa9e4066Sahrens uint64_t state; 1836eaca9bbdSeschrock uint64_t version; 1837fa9e4066Sahrens 1838fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1839fa9e4066Sahrens &name) == 0); 1840fa9e4066Sahrens 1841fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1842fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1843eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1844eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1845ad135b5dSChristopher Siden if (!SPA_VERSION_IS_SUPPORTED(version)) { 1846eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1847ad135b5dSChristopher Siden "is formatted using an unsupported ZFS version\n"), name); 1848eaca9bbdSeschrock return (1); 18494b964adaSGeorge Wilson } else if (state != POOL_STATE_EXPORTED && 18504b964adaSGeorge Wilson !(flags & ZFS_IMPORT_ANY_HOST)) { 185195173954Sek uint64_t hostid; 185295173954Sek 185395173954Sek if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 185495173954Sek &hostid) == 0) { 185595173954Sek if ((unsigned long)hostid != gethostid()) { 185695173954Sek char *hostname; 185795173954Sek uint64_t timestamp; 185895173954Sek time_t t; 185995173954Sek 186095173954Sek verify(nvlist_lookup_string(config, 186195173954Sek ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 186295173954Sek verify(nvlist_lookup_uint64(config, 186395173954Sek ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 186495173954Sek t = timestamp; 186595173954Sek (void) fprintf(stderr, gettext("cannot import " 186695173954Sek "'%s': pool may be in use from other " 186795173954Sek "system, it was last accessed by %s " 186895173954Sek "(hostid: 0x%lx) on %s"), name, hostname, 186995173954Sek (unsigned long)hostid, 187095173954Sek asctime(localtime(&t))); 187195173954Sek (void) fprintf(stderr, gettext("use '-f' to " 187295173954Sek "import anyway\n")); 187395173954Sek return (1); 187495173954Sek } 187595173954Sek } else { 187695173954Sek (void) fprintf(stderr, gettext("cannot import '%s': " 187795173954Sek "pool may be in use from other system\n"), name); 187895173954Sek (void) fprintf(stderr, gettext("use '-f' to import " 187995173954Sek "anyway\n")); 188095173954Sek return (1); 188195173954Sek } 1882fa9e4066Sahrens } 1883fa9e4066Sahrens 18844b964adaSGeorge Wilson if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1885fa9e4066Sahrens return (1); 1886fa9e4066Sahrens 1887fa9e4066Sahrens if (newname != NULL) 1888fa9e4066Sahrens name = (char *)newname; 1889fa9e4066Sahrens 18904f0f5e5bSVictor Latushkin if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 18914f0f5e5bSVictor Latushkin return (1); 1892fa9e4066Sahrens 1893379c004dSEric Schrock if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1894f9af39baSGeorge Wilson !(flags & ZFS_IMPORT_ONLY) && 1895379c004dSEric Schrock zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1896fa9e4066Sahrens zpool_close(zhp); 1897fa9e4066Sahrens return (1); 1898fa9e4066Sahrens } 1899fa9e4066Sahrens 1900fa9e4066Sahrens zpool_close(zhp); 1901468c413aSTim Haley return (0); 1902fa9e4066Sahrens } 1903fa9e4066Sahrens 1904fa9e4066Sahrens /* 19054c58d714Sdarrenm * zpool import [-d dir] [-D] 19062f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 19072f8aaab3Seschrock * [-d dir | -c cachefile] [-f] -a 19082f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1909468c413aSTim Haley * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 19102f8aaab3Seschrock * 19112f8aaab3Seschrock * -c Read pool information from a cachefile instead of searching 19122f8aaab3Seschrock * devices. 1913fa9e4066Sahrens * 1914fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1915fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1916fa9e4066Sahrens * 19174c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 19184c58d714Sdarrenm * specified destroyed pools. 19194c58d714Sdarrenm * 1920fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1921fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1922fa9e4066Sahrens * is rebooted. 1923fa9e4066Sahrens * 1924468c413aSTim Haley * -V Import even in the presence of faulted vdevs. This is an 1925c5904d13Seschrock * intentionally undocumented option for testing purposes, and 1926c5904d13Seschrock * treats the pool configuration as complete, leaving any bad 19274f0f5e5bSVictor Latushkin * vdevs in the FAULTED state. In other words, it does verbatim 19284f0f5e5bSVictor Latushkin * import. 1929c5904d13Seschrock * 1930468c413aSTim Haley * -f Force import, even if it appears that the pool is active. 1931468c413aSTim Haley * 1932468c413aSTim Haley * -F Attempt rewind if necessary. 1933468c413aSTim Haley * 1934468c413aSTim Haley * -n See if rewind would work, but don't actually rewind. 1935468c413aSTim Haley * 1936f9af39baSGeorge Wilson * -N Import the pool but don't mount datasets. 1937f9af39baSGeorge Wilson * 1938f9af39baSGeorge Wilson * -T Specify a starting txg to use for import. This option is 1939f9af39baSGeorge Wilson * intentionally undocumented option for testing purposes. 1940f9af39baSGeorge Wilson * 1941fa9e4066Sahrens * -a Import all pools found. 1942fa9e4066Sahrens * 1943990b4856Slling * -o Set property=value and/or temporary mount options (without '='). 1944ecd6cf80Smarks * 1945fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 1946fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 1947fa9e4066Sahrens */ 1948fa9e4066Sahrens int 1949fa9e4066Sahrens zpool_do_import(int argc, char **argv) 1950fa9e4066Sahrens { 1951fa9e4066Sahrens char **searchdirs = NULL; 1952fa9e4066Sahrens int nsearch = 0; 1953fa9e4066Sahrens int c; 1954d41c4376SMark J Musante int err = 0; 19552f8aaab3Seschrock nvlist_t *pools = NULL; 195699653d4eSeschrock boolean_t do_all = B_FALSE; 195799653d4eSeschrock boolean_t do_destroyed = B_FALSE; 1958fa9e4066Sahrens char *mntopts = NULL; 1959fa9e4066Sahrens nvpair_t *elem; 1960fa9e4066Sahrens nvlist_t *config; 196124e697d4Sck uint64_t searchguid = 0; 196224e697d4Sck char *searchname = NULL; 1963990b4856Slling char *propval; 1964fa9e4066Sahrens nvlist_t *found_config; 1965468c413aSTim Haley nvlist_t *policy = NULL; 1966ecd6cf80Smarks nvlist_t *props = NULL; 196799653d4eSeschrock boolean_t first; 19684b964adaSGeorge Wilson int flags = ZFS_IMPORT_NORMAL; 1969468c413aSTim Haley uint32_t rewind_policy = ZPOOL_NO_REWIND; 1970468c413aSTim Haley boolean_t dryrun = B_FALSE; 1971468c413aSTim Haley boolean_t do_rewind = B_FALSE; 1972468c413aSTim Haley boolean_t xtreme_rewind = B_FALSE; 1973f9af39baSGeorge Wilson uint64_t pool_state, txg = -1ULL; 19742f8aaab3Seschrock char *cachefile = NULL; 1975d41c4376SMark J Musante importargs_t idata = { 0 }; 1976f9af39baSGeorge Wilson char *endptr; 1977fa9e4066Sahrens 1978fa9e4066Sahrens /* check options */ 1979f9af39baSGeorge Wilson while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) { 1980fa9e4066Sahrens switch (c) { 1981fa9e4066Sahrens case 'a': 198299653d4eSeschrock do_all = B_TRUE; 1983fa9e4066Sahrens break; 19842f8aaab3Seschrock case 'c': 19852f8aaab3Seschrock cachefile = optarg; 19862f8aaab3Seschrock break; 1987fa9e4066Sahrens case 'd': 1988fa9e4066Sahrens if (searchdirs == NULL) { 1989fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1990fa9e4066Sahrens } else { 1991fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 1992fa9e4066Sahrens sizeof (char *)); 1993fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 1994fa9e4066Sahrens sizeof (char *)); 1995fa9e4066Sahrens free(searchdirs); 1996fa9e4066Sahrens searchdirs = tmp; 1997fa9e4066Sahrens } 1998fa9e4066Sahrens searchdirs[nsearch++] = optarg; 1999fa9e4066Sahrens break; 20004c58d714Sdarrenm case 'D': 200199653d4eSeschrock do_destroyed = B_TRUE; 20024c58d714Sdarrenm break; 2003fa9e4066Sahrens case 'f': 20044b964adaSGeorge Wilson flags |= ZFS_IMPORT_ANY_HOST; 2005fa9e4066Sahrens break; 2006c5904d13Seschrock case 'F': 2007468c413aSTim Haley do_rewind = B_TRUE; 2008468c413aSTim Haley break; 20094b964adaSGeorge Wilson case 'm': 20104b964adaSGeorge Wilson flags |= ZFS_IMPORT_MISSING_LOG; 20114b964adaSGeorge Wilson break; 2012468c413aSTim Haley case 'n': 2013468c413aSTim Haley dryrun = B_TRUE; 2014c5904d13Seschrock break; 2015f9af39baSGeorge Wilson case 'N': 2016f9af39baSGeorge Wilson flags |= ZFS_IMPORT_ONLY; 2017f9af39baSGeorge Wilson break; 2018fa9e4066Sahrens case 'o': 2019990b4856Slling if ((propval = strchr(optarg, '=')) != NULL) { 2020990b4856Slling *propval = '\0'; 2021990b4856Slling propval++; 20220a48a24eStimh if (add_prop_list(optarg, propval, 20230a48a24eStimh &props, B_TRUE)) 2024990b4856Slling goto error; 2025990b4856Slling } else { 2026990b4856Slling mntopts = optarg; 2027990b4856Slling } 2028fa9e4066Sahrens break; 2029fa9e4066Sahrens case 'R': 2030990b4856Slling if (add_prop_list(zpool_prop_to_name( 20310a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 2032990b4856Slling goto error; 20332f8aaab3Seschrock if (nvlist_lookup_string(props, 20342f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 20352f8aaab3Seschrock &propval) == 0) 20362f8aaab3Seschrock break; 2037990b4856Slling if (add_prop_list(zpool_prop_to_name( 20380a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2039990b4856Slling goto error; 2040fa9e4066Sahrens break; 2041f9af39baSGeorge Wilson case 'T': 2042f9af39baSGeorge Wilson errno = 0; 2043e42d2059SMatthew Ahrens txg = strtoull(optarg, &endptr, 0); 2044f9af39baSGeorge Wilson if (errno != 0 || *endptr != '\0') { 2045f9af39baSGeorge Wilson (void) fprintf(stderr, 2046f9af39baSGeorge Wilson gettext("invalid txg value\n")); 2047f9af39baSGeorge Wilson usage(B_FALSE); 2048f9af39baSGeorge Wilson } 2049f9af39baSGeorge Wilson rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 2050f9af39baSGeorge Wilson break; 2051468c413aSTim Haley case 'V': 20524b964adaSGeorge Wilson flags |= ZFS_IMPORT_VERBATIM; 2053468c413aSTim Haley break; 2054468c413aSTim Haley case 'X': 2055468c413aSTim Haley xtreme_rewind = B_TRUE; 2056468c413aSTim Haley break; 2057fa9e4066Sahrens case ':': 2058fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2059fa9e4066Sahrens "'%c' option\n"), optopt); 206099653d4eSeschrock usage(B_FALSE); 2061fa9e4066Sahrens break; 2062fa9e4066Sahrens case '?': 2063fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2064fa9e4066Sahrens optopt); 206599653d4eSeschrock usage(B_FALSE); 2066fa9e4066Sahrens } 2067fa9e4066Sahrens } 2068fa9e4066Sahrens 2069fa9e4066Sahrens argc -= optind; 2070fa9e4066Sahrens argv += optind; 2071fa9e4066Sahrens 20722f8aaab3Seschrock if (cachefile && nsearch != 0) { 20732f8aaab3Seschrock (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 20742f8aaab3Seschrock usage(B_FALSE); 20752f8aaab3Seschrock } 20762f8aaab3Seschrock 2077468c413aSTim Haley if ((dryrun || xtreme_rewind) && !do_rewind) { 2078468c413aSTim Haley (void) fprintf(stderr, 2079468c413aSTim Haley gettext("-n or -X only meaningful with -F\n")); 2080468c413aSTim Haley usage(B_FALSE); 2081468c413aSTim Haley } 2082468c413aSTim Haley if (dryrun) 2083468c413aSTim Haley rewind_policy = ZPOOL_TRY_REWIND; 2084468c413aSTim Haley else if (do_rewind) 2085468c413aSTim Haley rewind_policy = ZPOOL_DO_REWIND; 2086468c413aSTim Haley if (xtreme_rewind) 2087468c413aSTim Haley rewind_policy |= ZPOOL_EXTREME_REWIND; 2088468c413aSTim Haley 2089468c413aSTim Haley /* In the future, we can capture further policy and include it here */ 2090468c413aSTim Haley if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2091f9af39baSGeorge Wilson nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 2092468c413aSTim Haley nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 2093468c413aSTim Haley goto error; 2094468c413aSTim Haley 2095fa9e4066Sahrens if (searchdirs == NULL) { 2096fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 2097*6401734dSWill Andrews searchdirs[0] = ZFS_DISK_ROOT; 2098fa9e4066Sahrens nsearch = 1; 2099fa9e4066Sahrens } 2100fa9e4066Sahrens 2101fa9e4066Sahrens /* check argument count */ 2102fa9e4066Sahrens if (do_all) { 2103fa9e4066Sahrens if (argc != 0) { 2104fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 210599653d4eSeschrock usage(B_FALSE); 2106fa9e4066Sahrens } 2107fa9e4066Sahrens } else { 2108fa9e4066Sahrens if (argc > 2) { 2109fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 211099653d4eSeschrock usage(B_FALSE); 2111fa9e4066Sahrens } 2112fa9e4066Sahrens 2113fa9e4066Sahrens /* 2114fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 2115fa9e4066Sahrens * here because otherwise any attempt to discover pools will 2116fa9e4066Sahrens * silently fail. 2117fa9e4066Sahrens */ 2118fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2119fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 2120fa9e4066Sahrens "discover pools: permission denied\n")); 212199653d4eSeschrock free(searchdirs); 2122468c413aSTim Haley nvlist_free(policy); 2123fa9e4066Sahrens return (1); 2124fa9e4066Sahrens } 2125fa9e4066Sahrens } 2126fa9e4066Sahrens 2127fa9e4066Sahrens /* 2128fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 2129fa9e4066Sahrens * 2130fa9e4066Sahrens * <none> Iterate through all pools and display information about 2131fa9e4066Sahrens * each one. 2132fa9e4066Sahrens * 2133fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 2134fa9e4066Sahrens * 2135fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 2136fa9e4066Sahrens * name and import that one. 21374c58d714Sdarrenm * 21384c58d714Sdarrenm * -D Above options applies only to destroyed pools. 2139fa9e4066Sahrens */ 2140fa9e4066Sahrens if (argc != 0) { 2141fa9e4066Sahrens char *endptr; 2142fa9e4066Sahrens 2143fa9e4066Sahrens errno = 0; 2144fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 21459edf9ebdSPrasad Joshi if (errno != 0 || *endptr != '\0') { 2146fa9e4066Sahrens searchname = argv[0]; 21479edf9ebdSPrasad Joshi searchguid = 0; 21489edf9ebdSPrasad Joshi } 2149fa9e4066Sahrens found_config = NULL; 2150fa9e4066Sahrens 215124e697d4Sck /* 2152d41c4376SMark J Musante * User specified a name or guid. Ensure it's unique. 215324e697d4Sck */ 2154d41c4376SMark J Musante idata.unique = B_TRUE; 215524e697d4Sck } 215624e697d4Sck 2157d41c4376SMark J Musante 2158d41c4376SMark J Musante idata.path = searchdirs; 2159d41c4376SMark J Musante idata.paths = nsearch; 2160d41c4376SMark J Musante idata.poolname = searchname; 2161d41c4376SMark J Musante idata.guid = searchguid; 2162d41c4376SMark J Musante idata.cachefile = cachefile; 2163d41c4376SMark J Musante 2164d41c4376SMark J Musante pools = zpool_search_import(g_zfs, &idata); 2165d41c4376SMark J Musante 2166d41c4376SMark J Musante if (pools != NULL && idata.exists && 2167d41c4376SMark J Musante (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2168d41c4376SMark J Musante (void) fprintf(stderr, gettext("cannot import '%s': " 2169d41c4376SMark J Musante "a pool with that name already exists\n"), 2170d41c4376SMark J Musante argv[0]); 2171d41c4376SMark J Musante (void) fprintf(stderr, gettext("use the form '%s " 2172d41c4376SMark J Musante "<pool | id> <newpool>' to give it a new name\n"), 2173d41c4376SMark J Musante "zpool import"); 2174d41c4376SMark J Musante err = 1; 2175d41c4376SMark J Musante } else if (pools == NULL && idata.exists) { 2176d41c4376SMark J Musante (void) fprintf(stderr, gettext("cannot import '%s': " 2177d41c4376SMark J Musante "a pool with that name is already created/imported,\n"), 2178d41c4376SMark J Musante argv[0]); 2179d41c4376SMark J Musante (void) fprintf(stderr, gettext("and no additional pools " 2180d41c4376SMark J Musante "with that name were found\n")); 2181d41c4376SMark J Musante err = 1; 2182d41c4376SMark J Musante } else if (pools == NULL) { 218324e697d4Sck if (argc != 0) { 218424e697d4Sck (void) fprintf(stderr, gettext("cannot import '%s': " 218524e697d4Sck "no such pool available\n"), argv[0]); 218624e697d4Sck } 2187d41c4376SMark J Musante err = 1; 2188d41c4376SMark J Musante } 2189d41c4376SMark J Musante 2190d41c4376SMark J Musante if (err == 1) { 219124e697d4Sck free(searchdirs); 2192468c413aSTim Haley nvlist_free(policy); 219324e697d4Sck return (1); 219424e697d4Sck } 219524e697d4Sck 219624e697d4Sck /* 219724e697d4Sck * At this point we have a list of import candidate configs. Even if 219824e697d4Sck * we were searching by pool name or guid, we still need to 219924e697d4Sck * post-process the list to deal with pool state and possible 220024e697d4Sck * duplicate names. 220124e697d4Sck */ 2202fa9e4066Sahrens err = 0; 2203fa9e4066Sahrens elem = NULL; 220499653d4eSeschrock first = B_TRUE; 2205fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2206fa9e4066Sahrens 2207fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 2208fa9e4066Sahrens 22094c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 22104c58d714Sdarrenm &pool_state) == 0); 22114c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 22124c58d714Sdarrenm continue; 22134c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 22144c58d714Sdarrenm continue; 22154c58d714Sdarrenm 2216468c413aSTim Haley verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2217468c413aSTim Haley policy) == 0); 2218468c413aSTim Haley 2219fa9e4066Sahrens if (argc == 0) { 2220fa9e4066Sahrens if (first) 222199653d4eSeschrock first = B_FALSE; 22223bb79becSeschrock else if (!do_all) 2223fa9e4066Sahrens (void) printf("\n"); 2224fa9e4066Sahrens 2225468c413aSTim Haley if (do_all) { 2226fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 22274b964adaSGeorge Wilson props, flags); 2228468c413aSTim Haley } else { 2229fa9e4066Sahrens show_import(config); 2230468c413aSTim Haley } 2231fa9e4066Sahrens } else if (searchname != NULL) { 2232fa9e4066Sahrens char *name; 2233fa9e4066Sahrens 2234fa9e4066Sahrens /* 2235fa9e4066Sahrens * We are searching for a pool based on name. 2236fa9e4066Sahrens */ 2237fa9e4066Sahrens verify(nvlist_lookup_string(config, 2238fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2239fa9e4066Sahrens 2240fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 2241fa9e4066Sahrens if (found_config != NULL) { 2242fa9e4066Sahrens (void) fprintf(stderr, gettext( 2243fa9e4066Sahrens "cannot import '%s': more than " 2244fa9e4066Sahrens "one matching pool\n"), searchname); 2245fa9e4066Sahrens (void) fprintf(stderr, gettext( 2246fa9e4066Sahrens "import by numeric ID instead\n")); 224799653d4eSeschrock err = B_TRUE; 2248fa9e4066Sahrens } 2249fa9e4066Sahrens found_config = config; 2250fa9e4066Sahrens } 2251fa9e4066Sahrens } else { 2252fa9e4066Sahrens uint64_t guid; 2253fa9e4066Sahrens 2254fa9e4066Sahrens /* 2255fa9e4066Sahrens * Search for a pool by guid. 2256fa9e4066Sahrens */ 2257fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 2258fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2259fa9e4066Sahrens 2260fa9e4066Sahrens if (guid == searchguid) 2261fa9e4066Sahrens found_config = config; 2262fa9e4066Sahrens } 2263fa9e4066Sahrens } 2264fa9e4066Sahrens 2265fa9e4066Sahrens /* 2266fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 2267fa9e4066Sahrens * pool, and then do the import. 2268fa9e4066Sahrens */ 2269fa9e4066Sahrens if (argc != 0 && err == 0) { 2270fa9e4066Sahrens if (found_config == NULL) { 2271fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 2272fa9e4066Sahrens "no such pool available\n"), argv[0]); 227399653d4eSeschrock err = B_TRUE; 2274fa9e4066Sahrens } else { 2275fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 22764b964adaSGeorge Wilson argv[1], mntopts, props, flags); 2277fa9e4066Sahrens } 2278fa9e4066Sahrens } 2279fa9e4066Sahrens 2280fa9e4066Sahrens /* 2281fa9e4066Sahrens * If we were just looking for pools, report an error if none were 2282fa9e4066Sahrens * found. 2283fa9e4066Sahrens */ 2284fa9e4066Sahrens if (argc == 0 && first) 2285fa9e4066Sahrens (void) fprintf(stderr, 2286fa9e4066Sahrens gettext("no pools available to import\n")); 2287fa9e4066Sahrens 2288ecd6cf80Smarks error: 22892f8aaab3Seschrock nvlist_free(props); 2290fa9e4066Sahrens nvlist_free(pools); 2291468c413aSTim Haley nvlist_free(policy); 229299653d4eSeschrock free(searchdirs); 2293fa9e4066Sahrens 2294fa9e4066Sahrens return (err ? 1 : 0); 2295fa9e4066Sahrens } 2296fa9e4066Sahrens 2297fa9e4066Sahrens typedef struct iostat_cbdata { 22984263d13fSGeorge Wilson boolean_t cb_verbose; 2299fa9e4066Sahrens int cb_namewidth; 23004263d13fSGeorge Wilson int cb_iteration; 23014263d13fSGeorge Wilson zpool_list_t *cb_list; 2302fa9e4066Sahrens } iostat_cbdata_t; 2303fa9e4066Sahrens 2304fa9e4066Sahrens static void 2305fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 2306fa9e4066Sahrens { 2307fa9e4066Sahrens int i = 0; 2308fa9e4066Sahrens 2309fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 2310fa9e4066Sahrens (void) printf("-"); 2311fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2312fa9e4066Sahrens } 2313fa9e4066Sahrens 2314fa9e4066Sahrens static void 2315fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 2316fa9e4066Sahrens { 2317fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 2318fa9e4066Sahrens cb->cb_namewidth, ""); 2319485bbbf5SGeorge Wilson (void) printf("%-*s alloc free read write read write\n", 2320fa9e4066Sahrens cb->cb_namewidth, "pool"); 2321fa9e4066Sahrens print_iostat_separator(cb); 2322fa9e4066Sahrens } 2323fa9e4066Sahrens 2324fa9e4066Sahrens /* 2325fa9e4066Sahrens * Display a single statistic. 2326fa9e4066Sahrens */ 2327990b4856Slling static void 2328fa9e4066Sahrens print_one_stat(uint64_t value) 2329fa9e4066Sahrens { 2330fa9e4066Sahrens char buf[64]; 2331fa9e4066Sahrens 2332fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 2333fa9e4066Sahrens (void) printf(" %5s", buf); 2334fa9e4066Sahrens } 2335fa9e4066Sahrens 2336fa9e4066Sahrens /* 2337fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 2338fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 2339fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 2340fa9e4066Sahrens */ 2341fa9e4066Sahrens void 2342c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2343c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2344fa9e4066Sahrens { 2345fa9e4066Sahrens nvlist_t **oldchild, **newchild; 2346fa9e4066Sahrens uint_t c, children; 2347fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 2348fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 2349fa9e4066Sahrens uint64_t tdelta; 2350fa9e4066Sahrens double scale; 2351afefbcddSeschrock char *vname; 2352fa9e4066Sahrens 2353fa9e4066Sahrens if (oldnv != NULL) { 23543f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(oldnv, 23553f9d6ad7SLin Ling ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2356fa9e4066Sahrens } else { 2357fa9e4066Sahrens oldvs = &zerovs; 2358fa9e4066Sahrens } 2359fa9e4066Sahrens 23603f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2361fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 2362fa9e4066Sahrens 2363fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 2364fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 2365fa9e4066Sahrens else 2366fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 2367fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2368fa9e4066Sahrens 2369fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2370fa9e4066Sahrens 2371fa9e4066Sahrens if (tdelta == 0) 2372fa9e4066Sahrens scale = 1.0; 2373fa9e4066Sahrens else 2374fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 2375fa9e4066Sahrens 2376fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 2377fa9e4066Sahrens if (newvs->vs_space == 0) { 2378fa9e4066Sahrens (void) printf(" - -"); 2379fa9e4066Sahrens } else { 2380fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 2381fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 2382fa9e4066Sahrens } 2383fa9e4066Sahrens 2384fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2385fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 2386fa9e4066Sahrens 2387fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2388fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2389fa9e4066Sahrens 2390fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2391fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 2392fa9e4066Sahrens 2393fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2394fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2395fa9e4066Sahrens 2396fa9e4066Sahrens (void) printf("\n"); 2397fa9e4066Sahrens 2398fa9e4066Sahrens if (!cb->cb_verbose) 2399fa9e4066Sahrens return; 2400fa9e4066Sahrens 2401fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2402fa9e4066Sahrens &newchild, &children) != 0) 2403fa9e4066Sahrens return; 2404fa9e4066Sahrens 2405fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2406fa9e4066Sahrens &oldchild, &c) != 0) 2407fa9e4066Sahrens return; 2408fa9e4066Sahrens 2409afefbcddSeschrock for (c = 0; c < children; c++) { 24109d439f90SMike Harsch uint64_t ishole = B_FALSE, islog = B_FALSE; 24113f9d6ad7SLin Ling 24129d439f90SMike Harsch (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 24139d439f90SMike Harsch &ishole); 24149d439f90SMike Harsch 24159d439f90SMike Harsch (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 24169d439f90SMike Harsch &islog); 24179d439f90SMike Harsch 24189d439f90SMike Harsch if (ishole || islog) 24193f9d6ad7SLin Ling continue; 24203f9d6ad7SLin Ling 242188ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2422c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2423afefbcddSeschrock newchild[c], cb, depth + 2); 2424afefbcddSeschrock free(vname); 2425afefbcddSeschrock } 2426fa94a07fSbrendan 24279d439f90SMike Harsch /* 24289d439f90SMike Harsch * Log device section 24299d439f90SMike Harsch */ 24309d439f90SMike Harsch 24319d439f90SMike Harsch if (num_logs(newnv) > 0) { 24329d439f90SMike Harsch (void) printf("%-*s - - - - - " 24339d439f90SMike Harsch "-\n", cb->cb_namewidth, "logs"); 24349d439f90SMike Harsch 24359d439f90SMike Harsch for (c = 0; c < children; c++) { 24369d439f90SMike Harsch uint64_t islog = B_FALSE; 24379d439f90SMike Harsch (void) nvlist_lookup_uint64(newchild[c], 24389d439f90SMike Harsch ZPOOL_CONFIG_IS_LOG, &islog); 24399d439f90SMike Harsch 24409d439f90SMike Harsch if (islog) { 24419d439f90SMike Harsch vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 24429d439f90SMike Harsch B_FALSE); 24439d439f90SMike Harsch print_vdev_stats(zhp, vname, oldnv ? 24449d439f90SMike Harsch oldchild[c] : NULL, newchild[c], 24459d439f90SMike Harsch cb, depth + 2); 24469d439f90SMike Harsch free(vname); 24479d439f90SMike Harsch } 24489d439f90SMike Harsch } 24499d439f90SMike Harsch 24509d439f90SMike Harsch } 24519d439f90SMike Harsch 2452fa94a07fSbrendan /* 2453fa94a07fSbrendan * Include level 2 ARC devices in iostat output 2454fa94a07fSbrendan */ 2455fa94a07fSbrendan if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2456fa94a07fSbrendan &newchild, &children) != 0) 2457fa94a07fSbrendan return; 2458fa94a07fSbrendan 2459fa94a07fSbrendan if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2460fa94a07fSbrendan &oldchild, &c) != 0) 2461fa94a07fSbrendan return; 2462fa94a07fSbrendan 2463fa94a07fSbrendan if (children > 0) { 2464fa94a07fSbrendan (void) printf("%-*s - - - - - " 2465fa94a07fSbrendan "-\n", cb->cb_namewidth, "cache"); 2466fa94a07fSbrendan for (c = 0; c < children; c++) { 246788ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 246888ecc943SGeorge Wilson B_FALSE); 2469fa94a07fSbrendan print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2470fa94a07fSbrendan newchild[c], cb, depth + 2); 2471fa94a07fSbrendan free(vname); 2472fa94a07fSbrendan } 2473fa94a07fSbrendan } 2474fa9e4066Sahrens } 2475fa9e4066Sahrens 2476088e9d47Seschrock static int 2477088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 2478088e9d47Seschrock { 2479088e9d47Seschrock iostat_cbdata_t *cb = data; 248094de1d4cSeschrock boolean_t missing; 2481088e9d47Seschrock 2482088e9d47Seschrock /* 2483088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 2484088e9d47Seschrock */ 248594de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 248694de1d4cSeschrock return (-1); 248794de1d4cSeschrock 248894de1d4cSeschrock if (missing) 2489088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 2490088e9d47Seschrock 2491088e9d47Seschrock return (0); 2492088e9d47Seschrock } 2493088e9d47Seschrock 2494fa9e4066Sahrens /* 2495fa9e4066Sahrens * Callback to print out the iostats for the given pool. 2496fa9e4066Sahrens */ 2497fa9e4066Sahrens int 2498fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 2499fa9e4066Sahrens { 2500fa9e4066Sahrens iostat_cbdata_t *cb = data; 2501fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 2502fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 2503fa9e4066Sahrens 2504088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 2505fa9e4066Sahrens 2506088e9d47Seschrock if (cb->cb_iteration == 1) 2507fa9e4066Sahrens oldconfig = NULL; 2508fa9e4066Sahrens 2509fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2510fa9e4066Sahrens &newnvroot) == 0); 2511fa9e4066Sahrens 2512088e9d47Seschrock if (oldconfig == NULL) 2513fa9e4066Sahrens oldnvroot = NULL; 2514088e9d47Seschrock else 2515088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2516088e9d47Seschrock &oldnvroot) == 0); 2517fa9e4066Sahrens 2518fa9e4066Sahrens /* 2519fa9e4066Sahrens * Print out the statistics for the pool. 2520fa9e4066Sahrens */ 2521c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2522fa9e4066Sahrens 2523fa9e4066Sahrens if (cb->cb_verbose) 2524fa9e4066Sahrens print_iostat_separator(cb); 2525fa9e4066Sahrens 2526fa9e4066Sahrens return (0); 2527fa9e4066Sahrens } 2528fa9e4066Sahrens 2529fa9e4066Sahrens int 2530fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 2531fa9e4066Sahrens { 2532fa9e4066Sahrens iostat_cbdata_t *cb = data; 2533fa9e4066Sahrens nvlist_t *config, *nvroot; 2534fa9e4066Sahrens 2535088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2536fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2537fa9e4066Sahrens &nvroot) == 0); 2538fa9e4066Sahrens if (!cb->cb_verbose) 2539fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2540fa9e4066Sahrens else 2541e1d5e507SFrederik Wessels cb->cb_namewidth = max_width(zhp, nvroot, 0, 2542e1d5e507SFrederik Wessels cb->cb_namewidth); 2543fa9e4066Sahrens } 2544fa9e4066Sahrens 2545fa9e4066Sahrens /* 2546fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 2547fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 2548fa9e4066Sahrens */ 2549fa9e4066Sahrens if (cb->cb_namewidth < 10) 2550fa9e4066Sahrens cb->cb_namewidth = 10; 2551fa9e4066Sahrens if (cb->cb_namewidth > 38) 2552fa9e4066Sahrens cb->cb_namewidth = 38; 2553fa9e4066Sahrens 2554fa9e4066Sahrens return (0); 2555fa9e4066Sahrens } 2556fa9e4066Sahrens 2557fa9e4066Sahrens /* 25583f9d6ad7SLin Ling * Parse the input string, get the 'interval' and 'count' value if there is one. 2559fa9e4066Sahrens */ 25603f9d6ad7SLin Ling static void 25613f9d6ad7SLin Ling get_interval_count(int *argcp, char **argv, unsigned long *iv, 25623f9d6ad7SLin Ling unsigned long *cnt) 2563fa9e4066Sahrens { 2564fa9e4066Sahrens unsigned long interval = 0, count = 0; 25653f9d6ad7SLin Ling int argc = *argcp, errno; 2566fa9e4066Sahrens 2567fa9e4066Sahrens /* 2568fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 2569fa9e4066Sahrens */ 2570fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 2571fa9e4066Sahrens char *end; 2572fa9e4066Sahrens 2573fa9e4066Sahrens errno = 0; 2574fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 2575fa9e4066Sahrens 2576fa9e4066Sahrens if (*end == '\0' && errno == 0) { 2577fa9e4066Sahrens if (interval == 0) { 2578fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 2579fa9e4066Sahrens "cannot be zero\n")); 258099653d4eSeschrock usage(B_FALSE); 2581fa9e4066Sahrens } 2582fa9e4066Sahrens /* 2583fa9e4066Sahrens * Ignore the last parameter 2584fa9e4066Sahrens */ 2585fa9e4066Sahrens argc--; 2586fa9e4066Sahrens } else { 2587fa9e4066Sahrens /* 2588fa9e4066Sahrens * If this is not a valid number, just plow on. The 2589fa9e4066Sahrens * user will get a more informative error message later 2590fa9e4066Sahrens * on. 2591fa9e4066Sahrens */ 2592fa9e4066Sahrens interval = 0; 2593fa9e4066Sahrens } 2594fa9e4066Sahrens } 2595fa9e4066Sahrens 2596fa9e4066Sahrens /* 2597fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 25983f9d6ad7SLin Ling * and an interval. 2599fa9e4066Sahrens */ 2600fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 2601fa9e4066Sahrens char *end; 2602fa9e4066Sahrens 2603fa9e4066Sahrens errno = 0; 2604fa9e4066Sahrens count = interval; 2605fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 2606fa9e4066Sahrens 2607fa9e4066Sahrens if (*end == '\0' && errno == 0) { 2608fa9e4066Sahrens if (interval == 0) { 2609fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 2610fa9e4066Sahrens "cannot be zero\n")); 261199653d4eSeschrock usage(B_FALSE); 2612fa9e4066Sahrens } 2613fa9e4066Sahrens 2614fa9e4066Sahrens /* 2615fa9e4066Sahrens * Ignore the last parameter 2616fa9e4066Sahrens */ 2617fa9e4066Sahrens argc--; 2618fa9e4066Sahrens } else { 2619fa9e4066Sahrens interval = 0; 2620fa9e4066Sahrens } 2621fa9e4066Sahrens } 2622fa9e4066Sahrens 26233f9d6ad7SLin Ling *iv = interval; 26243f9d6ad7SLin Ling *cnt = count; 26253f9d6ad7SLin Ling *argcp = argc; 26263f9d6ad7SLin Ling } 26273f9d6ad7SLin Ling 26283f9d6ad7SLin Ling static void 26293f9d6ad7SLin Ling get_timestamp_arg(char c) 26303f9d6ad7SLin Ling { 26313f9d6ad7SLin Ling if (c == 'u') 26323f9d6ad7SLin Ling timestamp_fmt = UDATE; 26333f9d6ad7SLin Ling else if (c == 'd') 26343f9d6ad7SLin Ling timestamp_fmt = DDATE; 26353f9d6ad7SLin Ling else 26363f9d6ad7SLin Ling usage(B_FALSE); 26373f9d6ad7SLin Ling } 26383f9d6ad7SLin Ling 26393f9d6ad7SLin Ling /* 26403f9d6ad7SLin Ling * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 26413f9d6ad7SLin Ling * 26423f9d6ad7SLin Ling * -v Display statistics for individual vdevs 26433f9d6ad7SLin Ling * -T Display a timestamp in date(1) or Unix format 26443f9d6ad7SLin Ling * 26453f9d6ad7SLin Ling * This command can be tricky because we want to be able to deal with pool 26463f9d6ad7SLin Ling * creation/destruction as well as vdev configuration changes. The bulk of this 26473f9d6ad7SLin Ling * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 26483f9d6ad7SLin Ling * on pool_list_update() to detect the addition of new pools. Configuration 26493f9d6ad7SLin Ling * changes are all handled within libzfs. 26503f9d6ad7SLin Ling */ 26513f9d6ad7SLin Ling int 26523f9d6ad7SLin Ling zpool_do_iostat(int argc, char **argv) 26533f9d6ad7SLin Ling { 26543f9d6ad7SLin Ling int c; 26553f9d6ad7SLin Ling int ret; 26563f9d6ad7SLin Ling int npools; 26573f9d6ad7SLin Ling unsigned long interval = 0, count = 0; 26583f9d6ad7SLin Ling zpool_list_t *list; 26593f9d6ad7SLin Ling boolean_t verbose = B_FALSE; 26603f9d6ad7SLin Ling iostat_cbdata_t cb; 26613f9d6ad7SLin Ling 26623f9d6ad7SLin Ling /* check options */ 26633f9d6ad7SLin Ling while ((c = getopt(argc, argv, "T:v")) != -1) { 26643f9d6ad7SLin Ling switch (c) { 26653f9d6ad7SLin Ling case 'T': 26663f9d6ad7SLin Ling get_timestamp_arg(*optarg); 26673f9d6ad7SLin Ling break; 26683f9d6ad7SLin Ling case 'v': 26693f9d6ad7SLin Ling verbose = B_TRUE; 26703f9d6ad7SLin Ling break; 26713f9d6ad7SLin Ling case '?': 26723f9d6ad7SLin Ling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 26733f9d6ad7SLin Ling optopt); 26743f9d6ad7SLin Ling usage(B_FALSE); 26753f9d6ad7SLin Ling } 26763f9d6ad7SLin Ling } 26773f9d6ad7SLin Ling 26783f9d6ad7SLin Ling argc -= optind; 26793f9d6ad7SLin Ling argv += optind; 26803f9d6ad7SLin Ling 26813f9d6ad7SLin Ling get_interval_count(&argc, argv, &interval, &count); 26823f9d6ad7SLin Ling 2683fa9e4066Sahrens /* 2684fa9e4066Sahrens * Construct the list of all interesting pools. 2685fa9e4066Sahrens */ 2686fa9e4066Sahrens ret = 0; 2687b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2688fa9e4066Sahrens return (1); 2689fa9e4066Sahrens 269099653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 269199653d4eSeschrock pool_list_free(list); 2692fa9e4066Sahrens return (1); 269399653d4eSeschrock } 2694fa9e4066Sahrens 2695fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 269699653d4eSeschrock pool_list_free(list); 2697fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 2698fa9e4066Sahrens return (1); 2699fa9e4066Sahrens } 2700fa9e4066Sahrens 2701fa9e4066Sahrens /* 2702fa9e4066Sahrens * Enter the main iostat loop. 2703fa9e4066Sahrens */ 2704fa9e4066Sahrens cb.cb_list = list; 2705fa9e4066Sahrens cb.cb_verbose = verbose; 2706fa9e4066Sahrens cb.cb_iteration = 0; 2707fa9e4066Sahrens cb.cb_namewidth = 0; 2708fa9e4066Sahrens 2709fa9e4066Sahrens for (;;) { 2710fa9e4066Sahrens pool_list_update(list); 2711fa9e4066Sahrens 2712fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 2713fa9e4066Sahrens break; 2714fa9e4066Sahrens 2715088e9d47Seschrock /* 2716088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 2717088e9d47Seschrock * before calculating the maximum name width, so that any 2718088e9d47Seschrock * configuration changes are properly accounted for. 2719088e9d47Seschrock */ 272099653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2721088e9d47Seschrock 2722fa9e4066Sahrens /* 2723fa9e4066Sahrens * Iterate over all pools to determine the maximum width 2724fa9e4066Sahrens * for the pool / device name column across all pools. 2725fa9e4066Sahrens */ 2726fa9e4066Sahrens cb.cb_namewidth = 0; 272799653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2728fa9e4066Sahrens 272926fd7700SKrishnendu Sadhukhan - Sun Microsystems if (timestamp_fmt != NODATE) 273026fd7700SKrishnendu Sadhukhan - Sun Microsystems print_timestamp(timestamp_fmt); 273126fd7700SKrishnendu Sadhukhan - Sun Microsystems 2732fa9e4066Sahrens /* 2733fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 2734fa9e4066Sahrens */ 2735fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 2736fa9e4066Sahrens print_iostat_header(&cb); 2737fa9e4066Sahrens 273899653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2739fa9e4066Sahrens 2740fa9e4066Sahrens /* 2741fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 2742fa9e4066Sahrens * (which prints a separator for us), then print a separator. 2743fa9e4066Sahrens */ 2744fa9e4066Sahrens if (npools > 1 && !verbose) 2745fa9e4066Sahrens print_iostat_separator(&cb); 2746fa9e4066Sahrens 2747fa9e4066Sahrens if (verbose) 2748fa9e4066Sahrens (void) printf("\n"); 2749fa9e4066Sahrens 275039c23413Seschrock /* 275139c23413Seschrock * Flush the output so that redirection to a file isn't buffered 275239c23413Seschrock * indefinitely. 275339c23413Seschrock */ 275439c23413Seschrock (void) fflush(stdout); 275539c23413Seschrock 2756fa9e4066Sahrens if (interval == 0) 2757fa9e4066Sahrens break; 2758fa9e4066Sahrens 2759fa9e4066Sahrens if (count != 0 && --count == 0) 2760fa9e4066Sahrens break; 2761fa9e4066Sahrens 2762fa9e4066Sahrens (void) sleep(interval); 2763fa9e4066Sahrens } 2764fa9e4066Sahrens 2765fa9e4066Sahrens pool_list_free(list); 2766fa9e4066Sahrens 2767fa9e4066Sahrens return (ret); 2768fa9e4066Sahrens } 2769fa9e4066Sahrens 2770fa9e4066Sahrens typedef struct list_cbdata { 27714263d13fSGeorge Wilson boolean_t cb_verbose; 27724263d13fSGeorge Wilson int cb_namewidth; 277399653d4eSeschrock boolean_t cb_scripted; 2774990b4856Slling zprop_list_t *cb_proplist; 2775c58b3526SAdam Stevko boolean_t cb_literal; 2776fa9e4066Sahrens } list_cbdata_t; 2777fa9e4066Sahrens 2778fa9e4066Sahrens /* 2779fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 2780fa9e4066Sahrens */ 2781990b4856Slling static void 27824263d13fSGeorge Wilson print_header(list_cbdata_t *cb) 2783fa9e4066Sahrens { 27844263d13fSGeorge Wilson zprop_list_t *pl = cb->cb_proplist; 2785ad135b5dSChristopher Siden char headerbuf[ZPOOL_MAXPROPLEN]; 2786990b4856Slling const char *header; 2787990b4856Slling boolean_t first = B_TRUE; 2788990b4856Slling boolean_t right_justify; 27894263d13fSGeorge Wilson size_t width = 0; 2790990b4856Slling 2791990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 27924263d13fSGeorge Wilson width = pl->pl_width; 27934263d13fSGeorge Wilson if (first && cb->cb_verbose) { 27944263d13fSGeorge Wilson /* 27954263d13fSGeorge Wilson * Reset the width to accommodate the verbose listing 27964263d13fSGeorge Wilson * of devices. 27974263d13fSGeorge Wilson */ 27984263d13fSGeorge Wilson width = cb->cb_namewidth; 27994263d13fSGeorge Wilson } 28004263d13fSGeorge Wilson 2801990b4856Slling if (!first) 2802fa9e4066Sahrens (void) printf(" "); 2803fa9e4066Sahrens else 2804990b4856Slling first = B_FALSE; 2805990b4856Slling 2806ad135b5dSChristopher Siden right_justify = B_FALSE; 2807ad135b5dSChristopher Siden if (pl->pl_prop != ZPROP_INVAL) { 2808ad135b5dSChristopher Siden header = zpool_prop_column_name(pl->pl_prop); 2809ad135b5dSChristopher Siden right_justify = zpool_prop_align_right(pl->pl_prop); 2810ad135b5dSChristopher Siden } else { 2811ad135b5dSChristopher Siden int i; 2812ad135b5dSChristopher Siden 2813ad135b5dSChristopher Siden for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2814ad135b5dSChristopher Siden headerbuf[i] = toupper(pl->pl_user_prop[i]); 2815ad135b5dSChristopher Siden headerbuf[i] = '\0'; 2816ad135b5dSChristopher Siden header = headerbuf; 2817ad135b5dSChristopher Siden } 2818fa9e4066Sahrens 2819990b4856Slling if (pl->pl_next == NULL && !right_justify) 2820990b4856Slling (void) printf("%s", header); 2821990b4856Slling else if (right_justify) 28224263d13fSGeorge Wilson (void) printf("%*s", width, header); 2823990b4856Slling else 28244263d13fSGeorge Wilson (void) printf("%-*s", width, header); 28254263d13fSGeorge Wilson 2826fa9e4066Sahrens } 2827fa9e4066Sahrens 2828fa9e4066Sahrens (void) printf("\n"); 2829fa9e4066Sahrens } 2830fa9e4066Sahrens 2831990b4856Slling /* 2832990b4856Slling * Given a pool and a list of properties, print out all the properties according 2833990b4856Slling * to the described layout. 2834990b4856Slling */ 2835990b4856Slling static void 28364263d13fSGeorge Wilson print_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 2837fa9e4066Sahrens { 28384263d13fSGeorge Wilson zprop_list_t *pl = cb->cb_proplist; 2839990b4856Slling boolean_t first = B_TRUE; 2840990b4856Slling char property[ZPOOL_MAXPROPLEN]; 2841990b4856Slling char *propstr; 2842990b4856Slling boolean_t right_justify; 28434263d13fSGeorge Wilson size_t width; 2844990b4856Slling 2845990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 28464263d13fSGeorge Wilson 28474263d13fSGeorge Wilson width = pl->pl_width; 28484263d13fSGeorge Wilson if (first && cb->cb_verbose) { 28494263d13fSGeorge Wilson /* 28504263d13fSGeorge Wilson * Reset the width to accommodate the verbose listing 28514263d13fSGeorge Wilson * of devices. 28524263d13fSGeorge Wilson */ 28534263d13fSGeorge Wilson width = cb->cb_namewidth; 28544263d13fSGeorge Wilson } 28554263d13fSGeorge Wilson 2856990b4856Slling if (!first) { 28574263d13fSGeorge Wilson if (cb->cb_scripted) 2858fa9e4066Sahrens (void) printf("\t"); 2859fa9e4066Sahrens else 2860fa9e4066Sahrens (void) printf(" "); 2861990b4856Slling } else { 2862990b4856Slling first = B_FALSE; 2863fa9e4066Sahrens } 2864fa9e4066Sahrens 2865990b4856Slling right_justify = B_FALSE; 2866990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 28677a09f97bSGeorge Wilson if (zpool_get_prop(zhp, pl->pl_prop, property, 2868c58b3526SAdam Stevko sizeof (property), NULL, cb->cb_literal) != 0) 2869990b4856Slling propstr = "-"; 2870fa9e4066Sahrens else 2871990b4856Slling propstr = property; 2872fa9e4066Sahrens 2873990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2874ad135b5dSChristopher Siden } else if ((zpool_prop_feature(pl->pl_user_prop) || 2875ad135b5dSChristopher Siden zpool_prop_unsupported(pl->pl_user_prop)) && 2876ad135b5dSChristopher Siden zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 2877ad135b5dSChristopher Siden sizeof (property)) == 0) { 2878ad135b5dSChristopher Siden propstr = property; 2879990b4856Slling } else { 2880990b4856Slling propstr = "-"; 2881990b4856Slling } 2882fa9e4066Sahrens 2883fa9e4066Sahrens 2884990b4856Slling /* 2885990b4856Slling * If this is being called in scripted mode, or if this is the 2886990b4856Slling * last column and it is left-justified, don't include a width 2887990b4856Slling * format specifier. 2888990b4856Slling */ 28894263d13fSGeorge Wilson if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 2890990b4856Slling (void) printf("%s", propstr); 2891990b4856Slling else if (right_justify) 2892990b4856Slling (void) printf("%*s", width, propstr); 2893990b4856Slling else 2894990b4856Slling (void) printf("%-*s", width, propstr); 2895990b4856Slling } 2896fa9e4066Sahrens 2897990b4856Slling (void) printf("\n"); 2898990b4856Slling } 2899fa9e4066Sahrens 29004263d13fSGeorge Wilson static void 29017a09f97bSGeorge Wilson print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, 29027a09f97bSGeorge Wilson boolean_t valid) 29034263d13fSGeorge Wilson { 29044263d13fSGeorge Wilson char propval[64]; 29054263d13fSGeorge Wilson boolean_t fixed; 29064263d13fSGeorge Wilson size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 29074263d13fSGeorge Wilson 29087a09f97bSGeorge Wilson switch (prop) { 29097a09f97bSGeorge Wilson case ZPOOL_PROP_EXPANDSZ: 29107a09f97bSGeorge Wilson if (value == 0) 29117a09f97bSGeorge Wilson (void) strlcpy(propval, "-", sizeof (propval)); 29127a09f97bSGeorge Wilson else 29137a09f97bSGeorge Wilson zfs_nicenum(value, propval, sizeof (propval)); 29147a09f97bSGeorge Wilson break; 29157a09f97bSGeorge Wilson case ZPOOL_PROP_FRAGMENTATION: 29167a09f97bSGeorge Wilson if (value == ZFS_FRAG_INVALID) { 29177a09f97bSGeorge Wilson (void) strlcpy(propval, "-", sizeof (propval)); 29187a09f97bSGeorge Wilson } else { 29197a09f97bSGeorge Wilson (void) snprintf(propval, sizeof (propval), "%llu%%", 29207a09f97bSGeorge Wilson value); 29217a09f97bSGeorge Wilson } 29227a09f97bSGeorge Wilson break; 29237a09f97bSGeorge Wilson case ZPOOL_PROP_CAPACITY: 29242e4c9986SGeorge Wilson (void) snprintf(propval, sizeof (propval), "%llu%%", value); 29257a09f97bSGeorge Wilson break; 29267a09f97bSGeorge Wilson default: 29272e4c9986SGeorge Wilson zfs_nicenum(value, propval, sizeof (propval)); 29287a09f97bSGeorge Wilson } 29297a09f97bSGeorge Wilson 29307a09f97bSGeorge Wilson if (!valid) 29317a09f97bSGeorge Wilson (void) strlcpy(propval, "-", sizeof (propval)); 29324263d13fSGeorge Wilson 29334263d13fSGeorge Wilson if (scripted) 29344263d13fSGeorge Wilson (void) printf("\t%s", propval); 29354263d13fSGeorge Wilson else 29364263d13fSGeorge Wilson (void) printf(" %*s", width, propval); 29374263d13fSGeorge Wilson } 29384263d13fSGeorge Wilson 29394263d13fSGeorge Wilson void 29404263d13fSGeorge Wilson print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 29414263d13fSGeorge Wilson list_cbdata_t *cb, int depth) 29424263d13fSGeorge Wilson { 29434263d13fSGeorge Wilson nvlist_t **child; 29444263d13fSGeorge Wilson vdev_stat_t *vs; 29454263d13fSGeorge Wilson uint_t c, children; 29464263d13fSGeorge Wilson char *vname; 29474263d13fSGeorge Wilson boolean_t scripted = cb->cb_scripted; 294852244c09SJohn Wren Kennedy uint64_t islog = B_FALSE; 294952244c09SJohn Wren Kennedy boolean_t haslog = B_FALSE; 295052244c09SJohn Wren Kennedy char *dashes = "%-*s - - - - - -\n"; 29514263d13fSGeorge Wilson 29524263d13fSGeorge Wilson verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 29534263d13fSGeorge Wilson (uint64_t **)&vs, &c) == 0); 29544263d13fSGeorge Wilson 29554263d13fSGeorge Wilson if (name != NULL) { 29567a09f97bSGeorge Wilson boolean_t toplevel = (vs->vs_space != 0); 29577a09f97bSGeorge Wilson uint64_t cap; 29587a09f97bSGeorge Wilson 29594263d13fSGeorge Wilson if (scripted) 29604263d13fSGeorge Wilson (void) printf("\t%s", name); 29614263d13fSGeorge Wilson else if (strlen(name) + depth > cb->cb_namewidth) 29624263d13fSGeorge Wilson (void) printf("%*s%s", depth, "", name); 29634263d13fSGeorge Wilson else 29644263d13fSGeorge Wilson (void) printf("%*s%s%*s", depth, "", name, 29654263d13fSGeorge Wilson (int)(cb->cb_namewidth - strlen(name) - depth), ""); 29664263d13fSGeorge Wilson 29677a09f97bSGeorge Wilson /* 29687a09f97bSGeorge Wilson * Print the properties for the individual vdevs. Some 29697a09f97bSGeorge Wilson * properties are only applicable to toplevel vdevs. The 29707a09f97bSGeorge Wilson * 'toplevel' boolean value is passed to the print_one_column() 29717a09f97bSGeorge Wilson * to indicate that the value is valid. 29727a09f97bSGeorge Wilson */ 29737a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted, 29747a09f97bSGeorge Wilson toplevel); 29757a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted, 29767a09f97bSGeorge Wilson toplevel); 29777a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, 29787a09f97bSGeorge Wilson scripted, toplevel); 29797a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted, 29807a09f97bSGeorge Wilson B_TRUE); 29817a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_FRAGMENTATION, 29827a09f97bSGeorge Wilson vs->vs_fragmentation, scripted, 29837a09f97bSGeorge Wilson (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel)); 29847a09f97bSGeorge Wilson cap = (vs->vs_space == 0) ? 0 : 29857a09f97bSGeorge Wilson (vs->vs_alloc * 100 / vs->vs_space); 29867a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel); 29874263d13fSGeorge Wilson (void) printf("\n"); 29884263d13fSGeorge Wilson } 29894263d13fSGeorge Wilson 29904263d13fSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 29914263d13fSGeorge Wilson &child, &children) != 0) 29924263d13fSGeorge Wilson return; 29934263d13fSGeorge Wilson 29944263d13fSGeorge Wilson for (c = 0; c < children; c++) { 29954263d13fSGeorge Wilson uint64_t ishole = B_FALSE; 29964263d13fSGeorge Wilson 29974263d13fSGeorge Wilson if (nvlist_lookup_uint64(child[c], 29984263d13fSGeorge Wilson ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 29994263d13fSGeorge Wilson continue; 30004263d13fSGeorge Wilson 300152244c09SJohn Wren Kennedy if (nvlist_lookup_uint64(child[c], 300252244c09SJohn Wren Kennedy ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) { 300352244c09SJohn Wren Kennedy haslog = B_TRUE; 300452244c09SJohn Wren Kennedy continue; 300552244c09SJohn Wren Kennedy } 300652244c09SJohn Wren Kennedy 30074263d13fSGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 30084263d13fSGeorge Wilson print_list_stats(zhp, vname, child[c], cb, depth + 2); 30094263d13fSGeorge Wilson free(vname); 30104263d13fSGeorge Wilson } 30114263d13fSGeorge Wilson 301252244c09SJohn Wren Kennedy if (haslog == B_TRUE) { 301352244c09SJohn Wren Kennedy /* LINTED E_SEC_PRINTF_VAR_FMT */ 301452244c09SJohn Wren Kennedy (void) printf(dashes, cb->cb_namewidth, "log"); 301552244c09SJohn Wren Kennedy for (c = 0; c < children; c++) { 301652244c09SJohn Wren Kennedy if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 301752244c09SJohn Wren Kennedy &islog) != 0 || !islog) 301852244c09SJohn Wren Kennedy continue; 301952244c09SJohn Wren Kennedy vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 302052244c09SJohn Wren Kennedy print_list_stats(zhp, vname, child[c], cb, depth + 2); 302152244c09SJohn Wren Kennedy free(vname); 302252244c09SJohn Wren Kennedy } 302352244c09SJohn Wren Kennedy } 302452244c09SJohn Wren Kennedy 30254263d13fSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 302652244c09SJohn Wren Kennedy &child, &children) == 0 && children > 0) { 302752244c09SJohn Wren Kennedy /* LINTED E_SEC_PRINTF_VAR_FMT */ 302852244c09SJohn Wren Kennedy (void) printf(dashes, cb->cb_namewidth, "cache"); 302952244c09SJohn Wren Kennedy for (c = 0; c < children; c++) { 303052244c09SJohn Wren Kennedy vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 303152244c09SJohn Wren Kennedy print_list_stats(zhp, vname, child[c], cb, depth + 2); 303252244c09SJohn Wren Kennedy free(vname); 303352244c09SJohn Wren Kennedy } 303452244c09SJohn Wren Kennedy } 30354263d13fSGeorge Wilson 303652244c09SJohn Wren Kennedy if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child, 303752244c09SJohn Wren Kennedy &children) == 0 && children > 0) { 303852244c09SJohn Wren Kennedy /* LINTED E_SEC_PRINTF_VAR_FMT */ 303952244c09SJohn Wren Kennedy (void) printf(dashes, cb->cb_namewidth, "spare"); 30404263d13fSGeorge Wilson for (c = 0; c < children; c++) { 304152244c09SJohn Wren Kennedy vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 30424263d13fSGeorge Wilson print_list_stats(zhp, vname, child[c], cb, depth + 2); 30434263d13fSGeorge Wilson free(vname); 30444263d13fSGeorge Wilson } 30454263d13fSGeorge Wilson } 30464263d13fSGeorge Wilson } 30474263d13fSGeorge Wilson 30484263d13fSGeorge Wilson 3049990b4856Slling /* 3050990b4856Slling * Generic callback function to list a pool. 3051990b4856Slling */ 3052990b4856Slling int 3053990b4856Slling list_callback(zpool_handle_t *zhp, void *data) 3054990b4856Slling { 3055990b4856Slling list_cbdata_t *cbp = data; 30564263d13fSGeorge Wilson nvlist_t *config; 30574263d13fSGeorge Wilson nvlist_t *nvroot; 3058fa9e4066Sahrens 30594263d13fSGeorge Wilson config = zpool_get_config(zhp, NULL); 3060fa9e4066Sahrens 30614263d13fSGeorge Wilson print_pool(zhp, cbp); 30624263d13fSGeorge Wilson if (!cbp->cb_verbose) 30634263d13fSGeorge Wilson return (0); 30644263d13fSGeorge Wilson 30654263d13fSGeorge Wilson verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 30664263d13fSGeorge Wilson &nvroot) == 0); 30674263d13fSGeorge Wilson print_list_stats(zhp, NULL, nvroot, cbp, 0); 3068fa9e4066Sahrens 3069fa9e4066Sahrens return (0); 3070fa9e4066Sahrens } 3071fa9e4066Sahrens 3072fa9e4066Sahrens /* 3073c58b3526SAdam Stevko * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 3074fa9e4066Sahrens * 3075990b4856Slling * -H Scripted mode. Don't display headers, and separate properties 3076990b4856Slling * by a single tab. 3077990b4856Slling * -o List of properties to display. Defaults to 30787a09f97bSGeorge Wilson * "name,size,allocated,free,expandsize,fragmentation,capacity," 30797a09f97bSGeorge Wilson * "dedupratio,health,altroot" 3080c58b3526SAdam Stevko * -p Diplay values in parsable (exact) format. 30813f9d6ad7SLin Ling * -T Display a timestamp in date(1) or Unix format 3082fa9e4066Sahrens * 3083fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 3084fa9e4066Sahrens * statistics for each one, as well as health status summary. 3085fa9e4066Sahrens */ 3086fa9e4066Sahrens int 3087fa9e4066Sahrens zpool_do_list(int argc, char **argv) 3088fa9e4066Sahrens { 3089fa9e4066Sahrens int c; 3090fa9e4066Sahrens int ret; 3091fa9e4066Sahrens list_cbdata_t cb = { 0 }; 3092990b4856Slling static char default_props[] = 30937a09f97bSGeorge Wilson "name,size,allocated,free,expandsize,fragmentation,capacity," 30942e4c9986SGeorge Wilson "dedupratio,health,altroot"; 3095990b4856Slling char *props = default_props; 30963f9d6ad7SLin Ling unsigned long interval = 0, count = 0; 30974263d13fSGeorge Wilson zpool_list_t *list; 30984263d13fSGeorge Wilson boolean_t first = B_TRUE; 3099fa9e4066Sahrens 3100fa9e4066Sahrens /* check options */ 3101c58b3526SAdam Stevko while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) { 3102fa9e4066Sahrens switch (c) { 3103fa9e4066Sahrens case 'H': 310499653d4eSeschrock cb.cb_scripted = B_TRUE; 3105fa9e4066Sahrens break; 3106fa9e4066Sahrens case 'o': 3107990b4856Slling props = optarg; 3108fa9e4066Sahrens break; 3109c58b3526SAdam Stevko case 'p': 3110c58b3526SAdam Stevko cb.cb_literal = B_TRUE; 3111c58b3526SAdam Stevko break; 31123f9d6ad7SLin Ling case 'T': 31133f9d6ad7SLin Ling get_timestamp_arg(*optarg); 31143f9d6ad7SLin Ling break; 31154263d13fSGeorge Wilson case 'v': 31164263d13fSGeorge Wilson cb.cb_verbose = B_TRUE; 31174263d13fSGeorge Wilson break; 3118fa9e4066Sahrens case ':': 3119fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 3120fa9e4066Sahrens "'%c' option\n"), optopt); 312199653d4eSeschrock usage(B_FALSE); 3122fa9e4066Sahrens break; 3123fa9e4066Sahrens case '?': 3124fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3125fa9e4066Sahrens optopt); 312699653d4eSeschrock usage(B_FALSE); 3127fa9e4066Sahrens } 3128fa9e4066Sahrens } 3129fa9e4066Sahrens 3130fa9e4066Sahrens argc -= optind; 3131fa9e4066Sahrens argv += optind; 3132fa9e4066Sahrens 31333f9d6ad7SLin Ling get_interval_count(&argc, argv, &interval, &count); 31343f9d6ad7SLin Ling 3135990b4856Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3136990b4856Slling usage(B_FALSE); 3137fa9e4066Sahrens 31383f9d6ad7SLin Ling for (;;) { 3139cd67d23dSGeorge Wilson if ((list = pool_list_get(argc, argv, &cb.cb_proplist, 3140cd67d23dSGeorge Wilson &ret)) == NULL) 3141cd67d23dSGeorge Wilson return (1); 31424263d13fSGeorge Wilson 31434263d13fSGeorge Wilson if (pool_list_count(list) == 0) 31444263d13fSGeorge Wilson break; 31454263d13fSGeorge Wilson 31464263d13fSGeorge Wilson cb.cb_namewidth = 0; 31474263d13fSGeorge Wilson (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3148990b4856Slling 31493f9d6ad7SLin Ling if (timestamp_fmt != NODATE) 31503f9d6ad7SLin Ling print_timestamp(timestamp_fmt); 3151fa9e4066Sahrens 31524263d13fSGeorge Wilson if (!cb.cb_scripted && (first || cb.cb_verbose)) { 31534263d13fSGeorge Wilson print_header(&cb); 31544263d13fSGeorge Wilson first = B_FALSE; 31553f9d6ad7SLin Ling } 31564263d13fSGeorge Wilson ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 31573f9d6ad7SLin Ling 31583f9d6ad7SLin Ling if (interval == 0) 31593f9d6ad7SLin Ling break; 31603f9d6ad7SLin Ling 31613f9d6ad7SLin Ling if (count != 0 && --count == 0) 31623f9d6ad7SLin Ling break; 31633f9d6ad7SLin Ling 3164cd67d23dSGeorge Wilson pool_list_free(list); 31653f9d6ad7SLin Ling (void) sleep(interval); 3166fa9e4066Sahrens } 3167fa9e4066Sahrens 3168cd67d23dSGeorge Wilson if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3169cd67d23dSGeorge Wilson (void) printf(gettext("no pools available\n")); 3170cd67d23dSGeorge Wilson ret = 0; 3171cd67d23dSGeorge Wilson } 3172cd67d23dSGeorge Wilson 3173cd67d23dSGeorge Wilson pool_list_free(list); 31743f9d6ad7SLin Ling zprop_free_list(cb.cb_proplist); 3175fa9e4066Sahrens return (ret); 3176fa9e4066Sahrens } 3177fa9e4066Sahrens 3178fa9e4066Sahrens static int 3179fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 3180fa9e4066Sahrens { 318199653d4eSeschrock boolean_t force = B_FALSE; 3182fa9e4066Sahrens int c; 3183fa9e4066Sahrens nvlist_t *nvroot; 3184fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 3185fa9e4066Sahrens zpool_handle_t *zhp; 318699653d4eSeschrock int ret; 3187fa9e4066Sahrens 3188fa9e4066Sahrens /* check options */ 3189fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 3190fa9e4066Sahrens switch (c) { 3191fa9e4066Sahrens case 'f': 319299653d4eSeschrock force = B_TRUE; 3193fa9e4066Sahrens break; 3194fa9e4066Sahrens case '?': 3195fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3196fa9e4066Sahrens optopt); 319799653d4eSeschrock usage(B_FALSE); 3198fa9e4066Sahrens } 3199fa9e4066Sahrens } 3200fa9e4066Sahrens 3201fa9e4066Sahrens argc -= optind; 3202fa9e4066Sahrens argv += optind; 3203fa9e4066Sahrens 3204fa9e4066Sahrens /* get pool name and check number of arguments */ 3205fa9e4066Sahrens if (argc < 1) { 3206fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 320799653d4eSeschrock usage(B_FALSE); 3208fa9e4066Sahrens } 3209fa9e4066Sahrens 3210fa9e4066Sahrens poolname = argv[0]; 3211fa9e4066Sahrens 3212fa9e4066Sahrens if (argc < 2) { 3213fa9e4066Sahrens (void) fprintf(stderr, 3214fa9e4066Sahrens gettext("missing <device> specification\n")); 321599653d4eSeschrock usage(B_FALSE); 3216fa9e4066Sahrens } 3217fa9e4066Sahrens 3218fa9e4066Sahrens old_disk = argv[1]; 3219fa9e4066Sahrens 3220fa9e4066Sahrens if (argc < 3) { 3221fa9e4066Sahrens if (!replacing) { 3222fa9e4066Sahrens (void) fprintf(stderr, 3223fa9e4066Sahrens gettext("missing <new_device> specification\n")); 322499653d4eSeschrock usage(B_FALSE); 3225fa9e4066Sahrens } 3226fa9e4066Sahrens new_disk = old_disk; 3227fa9e4066Sahrens argc -= 1; 3228fa9e4066Sahrens argv += 1; 3229fa9e4066Sahrens } else { 3230fa9e4066Sahrens new_disk = argv[2]; 3231fa9e4066Sahrens argc -= 2; 3232fa9e4066Sahrens argv += 2; 3233fa9e4066Sahrens } 3234fa9e4066Sahrens 3235fa9e4066Sahrens if (argc > 1) { 3236fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 323799653d4eSeschrock usage(B_FALSE); 3238fa9e4066Sahrens } 3239fa9e4066Sahrens 324099653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3241fa9e4066Sahrens return (1); 3242fa9e4066Sahrens 32438488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 3244fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3245fa9e4066Sahrens poolname); 3246fa9e4066Sahrens zpool_close(zhp); 3247fa9e4066Sahrens return (1); 3248fa9e4066Sahrens } 3249fa9e4066Sahrens 3250705040edSEric Taylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3251705040edSEric Taylor argc, argv); 3252fa9e4066Sahrens if (nvroot == NULL) { 3253fa9e4066Sahrens zpool_close(zhp); 3254fa9e4066Sahrens return (1); 3255fa9e4066Sahrens } 3256fa9e4066Sahrens 325799653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 325899653d4eSeschrock 325999653d4eSeschrock nvlist_free(nvroot); 326099653d4eSeschrock zpool_close(zhp); 326199653d4eSeschrock 326299653d4eSeschrock return (ret); 3263fa9e4066Sahrens } 3264fa9e4066Sahrens 3265fa9e4066Sahrens /* 3266fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 3267fa9e4066Sahrens * 3268fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 3269fa9e4066Sahrens * 3270fa9e4066Sahrens * Replace <device> with <new_device>. 3271fa9e4066Sahrens */ 3272fa9e4066Sahrens /* ARGSUSED */ 3273fa9e4066Sahrens int 3274fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 3275fa9e4066Sahrens { 3276fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3277fa9e4066Sahrens } 3278fa9e4066Sahrens 3279fa9e4066Sahrens /* 3280fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 3281fa9e4066Sahrens * 3282fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 3283fa9e4066Sahrens * 3284fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 3285fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 3286fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 3287fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 3288fa9e4066Sahrens */ 3289fa9e4066Sahrens int 3290fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 3291fa9e4066Sahrens { 3292fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3293fa9e4066Sahrens } 3294fa9e4066Sahrens 3295fa9e4066Sahrens /* 3296fa9e4066Sahrens * zpool detach [-f] <pool> <device> 3297fa9e4066Sahrens * 3298fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 3299fa9e4066Sahrens * (not supported yet) 3300fa9e4066Sahrens * 3301fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 3302fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 3303fa9e4066Sahrens * has the only valid copy of some data. 3304fa9e4066Sahrens */ 3305fa9e4066Sahrens /* ARGSUSED */ 3306fa9e4066Sahrens int 3307fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 3308fa9e4066Sahrens { 3309fa9e4066Sahrens int c; 3310fa9e4066Sahrens char *poolname, *path; 3311fa9e4066Sahrens zpool_handle_t *zhp; 331299653d4eSeschrock int ret; 3313fa9e4066Sahrens 3314fa9e4066Sahrens /* check options */ 3315fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 3316fa9e4066Sahrens switch (c) { 3317fa9e4066Sahrens case 'f': 3318fa9e4066Sahrens case '?': 3319fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3320fa9e4066Sahrens optopt); 332199653d4eSeschrock usage(B_FALSE); 3322fa9e4066Sahrens } 3323fa9e4066Sahrens } 3324fa9e4066Sahrens 3325fa9e4066Sahrens argc -= optind; 3326fa9e4066Sahrens argv += optind; 3327fa9e4066Sahrens 3328fa9e4066Sahrens /* get pool name and check number of arguments */ 3329fa9e4066Sahrens if (argc < 1) { 3330fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 333199653d4eSeschrock usage(B_FALSE); 3332fa9e4066Sahrens } 3333fa9e4066Sahrens 3334fa9e4066Sahrens if (argc < 2) { 3335fa9e4066Sahrens (void) fprintf(stderr, 3336fa9e4066Sahrens gettext("missing <device> specification\n")); 333799653d4eSeschrock usage(B_FALSE); 3338fa9e4066Sahrens } 3339fa9e4066Sahrens 3340fa9e4066Sahrens poolname = argv[0]; 3341fa9e4066Sahrens path = argv[1]; 3342fa9e4066Sahrens 334399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3344fa9e4066Sahrens return (1); 3345fa9e4066Sahrens 334699653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 334799653d4eSeschrock 334899653d4eSeschrock zpool_close(zhp); 334999653d4eSeschrock 335099653d4eSeschrock return (ret); 3351fa9e4066Sahrens } 3352fa9e4066Sahrens 33531195e687SMark J Musante /* 33541195e687SMark J Musante * zpool split [-n] [-o prop=val] ... 33551195e687SMark J Musante * [-o mntopt] ... 33561195e687SMark J Musante * [-R altroot] <pool> <newpool> [<device> ...] 33571195e687SMark J Musante * 33581195e687SMark J Musante * -n Do not split the pool, but display the resulting layout if 33591195e687SMark J Musante * it were to be split. 33601195e687SMark J Musante * -o Set property=value, or set mount options. 33611195e687SMark J Musante * -R Mount the split-off pool under an alternate root. 33621195e687SMark J Musante * 33631195e687SMark J Musante * Splits the named pool and gives it the new pool name. Devices to be split 33641195e687SMark J Musante * off may be listed, provided that no more than one device is specified 33651195e687SMark J Musante * per top-level vdev mirror. The newly split pool is left in an exported 33661195e687SMark J Musante * state unless -R is specified. 33671195e687SMark J Musante * 33681195e687SMark J Musante * Restrictions: the top-level of the pool pool must only be made up of 33691195e687SMark J Musante * mirrors; all devices in the pool must be healthy; no device may be 33701195e687SMark J Musante * undergoing a resilvering operation. 33711195e687SMark J Musante */ 33721195e687SMark J Musante int 33731195e687SMark J Musante zpool_do_split(int argc, char **argv) 33741195e687SMark J Musante { 33751195e687SMark J Musante char *srcpool, *newpool, *propval; 33761195e687SMark J Musante char *mntopts = NULL; 33771195e687SMark J Musante splitflags_t flags; 33781195e687SMark J Musante int c, ret = 0; 33791195e687SMark J Musante zpool_handle_t *zhp; 33801195e687SMark J Musante nvlist_t *config, *props = NULL; 33811195e687SMark J Musante 33821195e687SMark J Musante flags.dryrun = B_FALSE; 33831195e687SMark J Musante flags.import = B_FALSE; 33841195e687SMark J Musante 33851195e687SMark J Musante /* check options */ 33861195e687SMark J Musante while ((c = getopt(argc, argv, ":R:no:")) != -1) { 33871195e687SMark J Musante switch (c) { 33881195e687SMark J Musante case 'R': 33891195e687SMark J Musante flags.import = B_TRUE; 33901195e687SMark J Musante if (add_prop_list( 33911195e687SMark J Musante zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 33921195e687SMark J Musante &props, B_TRUE) != 0) { 3393aab83bb8SJosef 'Jeff' Sipek nvlist_free(props); 33941195e687SMark J Musante usage(B_FALSE); 33951195e687SMark J Musante } 33961195e687SMark J Musante break; 33971195e687SMark J Musante case 'n': 33981195e687SMark J Musante flags.dryrun = B_TRUE; 33991195e687SMark J Musante break; 34001195e687SMark J Musante case 'o': 34011195e687SMark J Musante if ((propval = strchr(optarg, '=')) != NULL) { 34021195e687SMark J Musante *propval = '\0'; 34031195e687SMark J Musante propval++; 34041195e687SMark J Musante if (add_prop_list(optarg, propval, 34051195e687SMark J Musante &props, B_TRUE) != 0) { 3406aab83bb8SJosef 'Jeff' Sipek nvlist_free(props); 34071195e687SMark J Musante usage(B_FALSE); 34081195e687SMark J Musante } 34091195e687SMark J Musante } else { 34101195e687SMark J Musante mntopts = optarg; 34111195e687SMark J Musante } 34121195e687SMark J Musante break; 34131195e687SMark J Musante case ':': 34141195e687SMark J Musante (void) fprintf(stderr, gettext("missing argument for " 34151195e687SMark J Musante "'%c' option\n"), optopt); 34161195e687SMark J Musante usage(B_FALSE); 34171195e687SMark J Musante break; 34181195e687SMark J Musante case '?': 34191195e687SMark J Musante (void) fprintf(stderr, gettext("invalid option '%c'\n"), 34201195e687SMark J Musante optopt); 34211195e687SMark J Musante usage(B_FALSE); 34221195e687SMark J Musante break; 34231195e687SMark J Musante } 34241195e687SMark J Musante } 34251195e687SMark J Musante 34261195e687SMark J Musante if (!flags.import && mntopts != NULL) { 34271195e687SMark J Musante (void) fprintf(stderr, gettext("setting mntopts is only " 34281195e687SMark J Musante "valid when importing the pool\n")); 34291195e687SMark J Musante usage(B_FALSE); 34301195e687SMark J Musante } 34311195e687SMark J Musante 34321195e687SMark J Musante argc -= optind; 34331195e687SMark J Musante argv += optind; 34341195e687SMark J Musante 34351195e687SMark J Musante if (argc < 1) { 34361195e687SMark J Musante (void) fprintf(stderr, gettext("Missing pool name\n")); 34371195e687SMark J Musante usage(B_FALSE); 34381195e687SMark J Musante } 34391195e687SMark J Musante if (argc < 2) { 34401195e687SMark J Musante (void) fprintf(stderr, gettext("Missing new pool name\n")); 34411195e687SMark J Musante usage(B_FALSE); 34421195e687SMark J Musante } 34431195e687SMark J Musante 34441195e687SMark J Musante srcpool = argv[0]; 34451195e687SMark J Musante newpool = argv[1]; 34461195e687SMark J Musante 34471195e687SMark J Musante argc -= 2; 34481195e687SMark J Musante argv += 2; 34491195e687SMark J Musante 34501195e687SMark J Musante if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 34511195e687SMark J Musante return (1); 34521195e687SMark J Musante 34531195e687SMark J Musante config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 34541195e687SMark J Musante if (config == NULL) { 34551195e687SMark J Musante ret = 1; 34561195e687SMark J Musante } else { 34571195e687SMark J Musante if (flags.dryrun) { 34581195e687SMark J Musante (void) printf(gettext("would create '%s' with the " 34591195e687SMark J Musante "following layout:\n\n"), newpool); 34601195e687SMark J Musante print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 34611195e687SMark J Musante } 34621195e687SMark J Musante nvlist_free(config); 34631195e687SMark J Musante } 34641195e687SMark J Musante 34651195e687SMark J Musante zpool_close(zhp); 34661195e687SMark J Musante 34671195e687SMark J Musante if (ret != 0 || flags.dryrun || !flags.import) 34681195e687SMark J Musante return (ret); 34691195e687SMark J Musante 34701195e687SMark J Musante /* 34711195e687SMark J Musante * The split was successful. Now we need to open the new 34721195e687SMark J Musante * pool and import it. 34731195e687SMark J Musante */ 34741195e687SMark J Musante if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 34751195e687SMark J Musante return (1); 34761195e687SMark J Musante if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 34771195e687SMark J Musante zpool_enable_datasets(zhp, mntopts, 0) != 0) { 34781195e687SMark J Musante ret = 1; 3479fe7cd8aaSCyril Plisko (void) fprintf(stderr, gettext("Split was successful, but " 34801195e687SMark J Musante "the datasets could not all be mounted\n")); 34811195e687SMark J Musante (void) fprintf(stderr, gettext("Try doing '%s' with a " 34821195e687SMark J Musante "different altroot\n"), "zpool import"); 34831195e687SMark J Musante } 34841195e687SMark J Musante zpool_close(zhp); 34851195e687SMark J Musante 34861195e687SMark J Musante return (ret); 34871195e687SMark J Musante } 34881195e687SMark J Musante 34891195e687SMark J Musante 34901195e687SMark J Musante 3491fa9e4066Sahrens /* 3492441d80aaSlling * zpool online <pool> <device> ... 3493fa9e4066Sahrens */ 3494fa9e4066Sahrens int 3495fa9e4066Sahrens zpool_do_online(int argc, char **argv) 3496fa9e4066Sahrens { 3497fa9e4066Sahrens int c, i; 3498fa9e4066Sahrens char *poolname; 3499fa9e4066Sahrens zpool_handle_t *zhp; 3500fa9e4066Sahrens int ret = 0; 35013d7072f8Seschrock vdev_state_t newstate; 3502573ca77eSGeorge Wilson int flags = 0; 3503fa9e4066Sahrens 3504fa9e4066Sahrens /* check options */ 3505573ca77eSGeorge Wilson while ((c = getopt(argc, argv, "et")) != -1) { 3506fa9e4066Sahrens switch (c) { 3507573ca77eSGeorge Wilson case 'e': 3508573ca77eSGeorge Wilson flags |= ZFS_ONLINE_EXPAND; 3509573ca77eSGeorge Wilson break; 3510fa9e4066Sahrens case 't': 3511fa9e4066Sahrens case '?': 3512fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3513fa9e4066Sahrens optopt); 351499653d4eSeschrock usage(B_FALSE); 3515fa9e4066Sahrens } 3516fa9e4066Sahrens } 3517fa9e4066Sahrens 3518fa9e4066Sahrens argc -= optind; 3519fa9e4066Sahrens argv += optind; 3520fa9e4066Sahrens 3521fa9e4066Sahrens /* get pool name and check number of arguments */ 3522fa9e4066Sahrens if (argc < 1) { 3523fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 352499653d4eSeschrock usage(B_FALSE); 3525fa9e4066Sahrens } 3526fa9e4066Sahrens if (argc < 2) { 3527fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 352899653d4eSeschrock usage(B_FALSE); 3529fa9e4066Sahrens } 3530fa9e4066Sahrens 3531fa9e4066Sahrens poolname = argv[0]; 3532fa9e4066Sahrens 353399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3534fa9e4066Sahrens return (1); 3535fa9e4066Sahrens 35363d7072f8Seschrock for (i = 1; i < argc; i++) { 3537573ca77eSGeorge Wilson if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 35383d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 35393d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 35403d7072f8Seschrock "onlined, but remains in faulted state\n"), 35413d7072f8Seschrock argv[i]); 35423d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 35433d7072f8Seschrock (void) printf(gettext("use 'zpool " 35443d7072f8Seschrock "clear' to restore a faulted " 35453d7072f8Seschrock "device\n")); 35463d7072f8Seschrock else 35473d7072f8Seschrock (void) printf(gettext("use 'zpool " 35483d7072f8Seschrock "replace' to replace devices " 35493d7072f8Seschrock "that are no longer present\n")); 35503d7072f8Seschrock } 35513d7072f8Seschrock } else { 3552fa9e4066Sahrens ret = 1; 35533d7072f8Seschrock } 35543d7072f8Seschrock } 3555fa9e4066Sahrens 355699653d4eSeschrock zpool_close(zhp); 355799653d4eSeschrock 3558fa9e4066Sahrens return (ret); 3559fa9e4066Sahrens } 3560fa9e4066Sahrens 3561fa9e4066Sahrens /* 3562441d80aaSlling * zpool offline [-ft] <pool> <device> ... 3563fa9e4066Sahrens * 3564fa9e4066Sahrens * -f Force the device into the offline state, even if doing 3565fa9e4066Sahrens * so would appear to compromise pool availability. 3566fa9e4066Sahrens * (not supported yet) 3567fa9e4066Sahrens * 3568fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 3569fa9e4066Sahrens * state will not be persistent across reboots. 3570fa9e4066Sahrens */ 3571fa9e4066Sahrens /* ARGSUSED */ 3572fa9e4066Sahrens int 3573fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 3574fa9e4066Sahrens { 3575fa9e4066Sahrens int c, i; 3576fa9e4066Sahrens char *poolname; 3577fa9e4066Sahrens zpool_handle_t *zhp; 357899653d4eSeschrock int ret = 0; 357999653d4eSeschrock boolean_t istmp = B_FALSE; 3580fa9e4066Sahrens 3581fa9e4066Sahrens /* check options */ 3582fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 3583fa9e4066Sahrens switch (c) { 3584fa9e4066Sahrens case 't': 358599653d4eSeschrock istmp = B_TRUE; 3586441d80aaSlling break; 3587441d80aaSlling case 'f': 3588fa9e4066Sahrens case '?': 3589fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3590fa9e4066Sahrens optopt); 359199653d4eSeschrock usage(B_FALSE); 3592fa9e4066Sahrens } 3593fa9e4066Sahrens } 3594fa9e4066Sahrens 3595fa9e4066Sahrens argc -= optind; 3596fa9e4066Sahrens argv += optind; 3597fa9e4066Sahrens 3598fa9e4066Sahrens /* get pool name and check number of arguments */ 3599fa9e4066Sahrens if (argc < 1) { 3600fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 360199653d4eSeschrock usage(B_FALSE); 3602fa9e4066Sahrens } 3603fa9e4066Sahrens if (argc < 2) { 3604fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 360599653d4eSeschrock usage(B_FALSE); 3606fa9e4066Sahrens } 3607fa9e4066Sahrens 3608fa9e4066Sahrens poolname = argv[0]; 3609fa9e4066Sahrens 361099653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3611fa9e4066Sahrens return (1); 3612fa9e4066Sahrens 36133d7072f8Seschrock for (i = 1; i < argc; i++) { 36143d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3615fa9e4066Sahrens ret = 1; 36163d7072f8Seschrock } 3617fa9e4066Sahrens 361899653d4eSeschrock zpool_close(zhp); 361999653d4eSeschrock 3620fa9e4066Sahrens return (ret); 3621fa9e4066Sahrens } 3622fa9e4066Sahrens 3623ea8dc4b6Seschrock /* 3624ea8dc4b6Seschrock * zpool clear <pool> [device] 3625ea8dc4b6Seschrock * 3626ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 3627ea8dc4b6Seschrock */ 3628ea8dc4b6Seschrock int 3629ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 3630ea8dc4b6Seschrock { 3631468c413aSTim Haley int c; 3632ea8dc4b6Seschrock int ret = 0; 3633468c413aSTim Haley boolean_t dryrun = B_FALSE; 3634468c413aSTim Haley boolean_t do_rewind = B_FALSE; 3635468c413aSTim Haley boolean_t xtreme_rewind = B_FALSE; 3636468c413aSTim Haley uint32_t rewind_policy = ZPOOL_NO_REWIND; 3637468c413aSTim Haley nvlist_t *policy = NULL; 3638ea8dc4b6Seschrock zpool_handle_t *zhp; 3639ea8dc4b6Seschrock char *pool, *device; 3640ea8dc4b6Seschrock 3641468c413aSTim Haley /* check options */ 3642468c413aSTim Haley while ((c = getopt(argc, argv, "FnX")) != -1) { 3643468c413aSTim Haley switch (c) { 3644468c413aSTim Haley case 'F': 3645468c413aSTim Haley do_rewind = B_TRUE; 3646468c413aSTim Haley break; 3647468c413aSTim Haley case 'n': 3648468c413aSTim Haley dryrun = B_TRUE; 3649468c413aSTim Haley break; 3650468c413aSTim Haley case 'X': 3651468c413aSTim Haley xtreme_rewind = B_TRUE; 3652468c413aSTim Haley break; 3653468c413aSTim Haley case '?': 3654468c413aSTim Haley (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3655468c413aSTim Haley optopt); 3656468c413aSTim Haley usage(B_FALSE); 3657468c413aSTim Haley } 3658468c413aSTim Haley } 3659468c413aSTim Haley 3660468c413aSTim Haley argc -= optind; 3661468c413aSTim Haley argv += optind; 3662468c413aSTim Haley 3663468c413aSTim Haley if (argc < 1) { 3664ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 366599653d4eSeschrock usage(B_FALSE); 3666ea8dc4b6Seschrock } 3667ea8dc4b6Seschrock 3668468c413aSTim Haley if (argc > 2) { 3669ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 367099653d4eSeschrock usage(B_FALSE); 3671ea8dc4b6Seschrock } 3672ea8dc4b6Seschrock 3673468c413aSTim Haley if ((dryrun || xtreme_rewind) && !do_rewind) { 3674468c413aSTim Haley (void) fprintf(stderr, 3675468c413aSTim Haley gettext("-n or -X only meaningful with -F\n")); 3676468c413aSTim Haley usage(B_FALSE); 3677468c413aSTim Haley } 3678468c413aSTim Haley if (dryrun) 3679468c413aSTim Haley rewind_policy = ZPOOL_TRY_REWIND; 3680468c413aSTim Haley else if (do_rewind) 3681468c413aSTim Haley rewind_policy = ZPOOL_DO_REWIND; 3682468c413aSTim Haley if (xtreme_rewind) 3683468c413aSTim Haley rewind_policy |= ZPOOL_EXTREME_REWIND; 3684468c413aSTim Haley 3685468c413aSTim Haley /* In future, further rewind policy choices can be passed along here */ 3686468c413aSTim Haley if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3687468c413aSTim Haley nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3688468c413aSTim Haley return (1); 3689468c413aSTim Haley 3690468c413aSTim Haley pool = argv[0]; 3691468c413aSTim Haley device = argc == 2 ? argv[1] : NULL; 3692ea8dc4b6Seschrock 3693468c413aSTim Haley if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3694468c413aSTim Haley nvlist_free(policy); 3695ea8dc4b6Seschrock return (1); 3696468c413aSTim Haley } 3697ea8dc4b6Seschrock 3698468c413aSTim Haley if (zpool_clear(zhp, device, policy) != 0) 3699ea8dc4b6Seschrock ret = 1; 3700ea8dc4b6Seschrock 3701ea8dc4b6Seschrock zpool_close(zhp); 3702ea8dc4b6Seschrock 3703468c413aSTim Haley nvlist_free(policy); 3704468c413aSTim Haley 3705ea8dc4b6Seschrock return (ret); 3706ea8dc4b6Seschrock } 3707ea8dc4b6Seschrock 3708e9103aaeSGarrett D'Amore /* 3709e9103aaeSGarrett D'Amore * zpool reguid <pool> 3710e9103aaeSGarrett D'Amore */ 3711e9103aaeSGarrett D'Amore int 3712e9103aaeSGarrett D'Amore zpool_do_reguid(int argc, char **argv) 3713e9103aaeSGarrett D'Amore { 3714e9103aaeSGarrett D'Amore int c; 3715e9103aaeSGarrett D'Amore char *poolname; 3716e9103aaeSGarrett D'Amore zpool_handle_t *zhp; 3717e9103aaeSGarrett D'Amore int ret = 0; 3718e9103aaeSGarrett D'Amore 3719e9103aaeSGarrett D'Amore /* check options */ 3720e9103aaeSGarrett D'Amore while ((c = getopt(argc, argv, "")) != -1) { 3721e9103aaeSGarrett D'Amore switch (c) { 3722e9103aaeSGarrett D'Amore case '?': 3723e9103aaeSGarrett D'Amore (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3724e9103aaeSGarrett D'Amore optopt); 3725e9103aaeSGarrett D'Amore usage(B_FALSE); 3726e9103aaeSGarrett D'Amore } 3727e9103aaeSGarrett D'Amore } 3728e9103aaeSGarrett D'Amore 3729e9103aaeSGarrett D'Amore argc -= optind; 3730e9103aaeSGarrett D'Amore argv += optind; 3731e9103aaeSGarrett D'Amore 3732e9103aaeSGarrett D'Amore /* get pool name and check number of arguments */ 3733e9103aaeSGarrett D'Amore if (argc < 1) { 3734e9103aaeSGarrett D'Amore (void) fprintf(stderr, gettext("missing pool name\n")); 3735e9103aaeSGarrett D'Amore usage(B_FALSE); 3736e9103aaeSGarrett D'Amore } 3737e9103aaeSGarrett D'Amore 3738e9103aaeSGarrett D'Amore if (argc > 1) { 3739e9103aaeSGarrett D'Amore (void) fprintf(stderr, gettext("too many arguments\n")); 3740e9103aaeSGarrett D'Amore usage(B_FALSE); 3741e9103aaeSGarrett D'Amore } 3742e9103aaeSGarrett D'Amore 3743e9103aaeSGarrett D'Amore poolname = argv[0]; 3744e9103aaeSGarrett D'Amore if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3745e9103aaeSGarrett D'Amore return (1); 3746e9103aaeSGarrett D'Amore 3747e9103aaeSGarrett D'Amore ret = zpool_reguid(zhp); 3748e9103aaeSGarrett D'Amore 3749e9103aaeSGarrett D'Amore zpool_close(zhp); 3750e9103aaeSGarrett D'Amore return (ret); 3751e9103aaeSGarrett D'Amore } 3752e9103aaeSGarrett D'Amore 3753e9103aaeSGarrett D'Amore 37544263d13fSGeorge Wilson /* 37554263d13fSGeorge Wilson * zpool reopen <pool> 37564263d13fSGeorge Wilson * 37574263d13fSGeorge Wilson * Reopen the pool so that the kernel can update the sizes of all vdevs. 37584263d13fSGeorge Wilson */ 37594263d13fSGeorge Wilson int 37604263d13fSGeorge Wilson zpool_do_reopen(int argc, char **argv) 37614263d13fSGeorge Wilson { 376231d7e8faSGeorge Wilson int c; 37634263d13fSGeorge Wilson int ret = 0; 37644263d13fSGeorge Wilson zpool_handle_t *zhp; 37654263d13fSGeorge Wilson char *pool; 37664263d13fSGeorge Wilson 376731d7e8faSGeorge Wilson /* check options */ 376831d7e8faSGeorge Wilson while ((c = getopt(argc, argv, "")) != -1) { 376931d7e8faSGeorge Wilson switch (c) { 377031d7e8faSGeorge Wilson case '?': 377131d7e8faSGeorge Wilson (void) fprintf(stderr, gettext("invalid option '%c'\n"), 377231d7e8faSGeorge Wilson optopt); 377331d7e8faSGeorge Wilson usage(B_FALSE); 377431d7e8faSGeorge Wilson } 377531d7e8faSGeorge Wilson } 377631d7e8faSGeorge Wilson 37774263d13fSGeorge Wilson argc--; 37784263d13fSGeorge Wilson argv++; 37794263d13fSGeorge Wilson 378031d7e8faSGeorge Wilson if (argc < 1) { 378131d7e8faSGeorge Wilson (void) fprintf(stderr, gettext("missing pool name\n")); 378231d7e8faSGeorge Wilson usage(B_FALSE); 378331d7e8faSGeorge Wilson } 378431d7e8faSGeorge Wilson 378531d7e8faSGeorge Wilson if (argc > 1) { 378631d7e8faSGeorge Wilson (void) fprintf(stderr, gettext("too many arguments\n")); 378731d7e8faSGeorge Wilson usage(B_FALSE); 378831d7e8faSGeorge Wilson } 37894263d13fSGeorge Wilson 37904263d13fSGeorge Wilson pool = argv[0]; 37914263d13fSGeorge Wilson if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 37924263d13fSGeorge Wilson return (1); 37934263d13fSGeorge Wilson 37944263d13fSGeorge Wilson ret = zpool_reopen(zhp); 37954263d13fSGeorge Wilson zpool_close(zhp); 37964263d13fSGeorge Wilson return (ret); 37974263d13fSGeorge Wilson } 37984263d13fSGeorge Wilson 3799fa9e4066Sahrens typedef struct scrub_cbdata { 3800fa9e4066Sahrens int cb_type; 380106eeb2adSek int cb_argc; 380206eeb2adSek char **cb_argv; 3803fa9e4066Sahrens } scrub_cbdata_t; 3804fa9e4066Sahrens 3805fa9e4066Sahrens int 3806fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 3807fa9e4066Sahrens { 3808fa9e4066Sahrens scrub_cbdata_t *cb = data; 380906eeb2adSek int err; 3810fa9e4066Sahrens 3811ea8dc4b6Seschrock /* 3812ea8dc4b6Seschrock * Ignore faulted pools. 3813ea8dc4b6Seschrock */ 3814ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3815ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3816ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 3817ea8dc4b6Seschrock return (1); 3818ea8dc4b6Seschrock } 3819ea8dc4b6Seschrock 38203f9d6ad7SLin Ling err = zpool_scan(zhp, cb->cb_type); 382106eeb2adSek 382206eeb2adSek return (err != 0); 3823fa9e4066Sahrens } 3824fa9e4066Sahrens 3825fa9e4066Sahrens /* 3826fa9e4066Sahrens * zpool scrub [-s] <pool> ... 3827fa9e4066Sahrens * 3828fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 3829fa9e4066Sahrens */ 3830fa9e4066Sahrens int 3831fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 3832fa9e4066Sahrens { 3833fa9e4066Sahrens int c; 3834fa9e4066Sahrens scrub_cbdata_t cb; 3835fa9e4066Sahrens 38363f9d6ad7SLin Ling cb.cb_type = POOL_SCAN_SCRUB; 3837fa9e4066Sahrens 3838fa9e4066Sahrens /* check options */ 3839fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 3840fa9e4066Sahrens switch (c) { 3841fa9e4066Sahrens case 's': 38423f9d6ad7SLin Ling cb.cb_type = POOL_SCAN_NONE; 3843fa9e4066Sahrens break; 3844fa9e4066Sahrens case '?': 3845fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3846fa9e4066Sahrens optopt); 384799653d4eSeschrock usage(B_FALSE); 3848fa9e4066Sahrens } 3849fa9e4066Sahrens } 3850fa9e4066Sahrens 385106eeb2adSek cb.cb_argc = argc; 385206eeb2adSek cb.cb_argv = argv; 3853fa9e4066Sahrens argc -= optind; 3854fa9e4066Sahrens argv += optind; 3855fa9e4066Sahrens 3856fa9e4066Sahrens if (argc < 1) { 3857fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 385899653d4eSeschrock usage(B_FALSE); 3859fa9e4066Sahrens } 3860fa9e4066Sahrens 3861b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3862fa9e4066Sahrens } 3863fa9e4066Sahrens 3864fa9e4066Sahrens typedef struct status_cbdata { 386599653d4eSeschrock int cb_count; 3866e9dbad6fSeschrock boolean_t cb_allpools; 386799653d4eSeschrock boolean_t cb_verbose; 386899653d4eSeschrock boolean_t cb_explain; 386999653d4eSeschrock boolean_t cb_first; 38709eb19f4dSGeorge Wilson boolean_t cb_dedup_stats; 3871fa9e4066Sahrens } status_cbdata_t; 3872fa9e4066Sahrens 3873fa9e4066Sahrens /* 3874fa9e4066Sahrens * Print out detailed scrub status. 3875fa9e4066Sahrens */ 3876fa9e4066Sahrens void 38773f9d6ad7SLin Ling print_scan_status(pool_scan_stat_t *ps) 3878fa9e4066Sahrens { 38793f9d6ad7SLin Ling time_t start, end; 388073d314ceSLin Ling uint64_t elapsed, mins_left, hours_left; 38813f9d6ad7SLin Ling uint64_t pass_exam, examined, total; 38823f9d6ad7SLin Ling uint_t rate; 3883fa9e4066Sahrens double fraction_done; 38843f9d6ad7SLin Ling char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3885fa9e4066Sahrens 3886ce72e614SYuri Pankov (void) printf(gettext(" scan: ")); 3887fa9e4066Sahrens 38883f9d6ad7SLin Ling /* If there's never been a scan, there's not much to say. */ 38893f9d6ad7SLin Ling if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 38903f9d6ad7SLin Ling ps->pss_func >= POOL_SCAN_FUNCS) { 3891fa9e4066Sahrens (void) printf(gettext("none requested\n")); 3892fa9e4066Sahrens return; 3893fa9e4066Sahrens } 3894fa9e4066Sahrens 38953f9d6ad7SLin Ling start = ps->pss_start_time; 38963f9d6ad7SLin Ling end = ps->pss_end_time; 38973f9d6ad7SLin Ling zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3898fa9e4066Sahrens 38993f9d6ad7SLin Ling assert(ps->pss_func == POOL_SCAN_SCRUB || 39003f9d6ad7SLin Ling ps->pss_func == POOL_SCAN_RESILVER); 39013f9d6ad7SLin Ling /* 39023f9d6ad7SLin Ling * Scan is finished or canceled. 39033f9d6ad7SLin Ling */ 39043f9d6ad7SLin Ling if (ps->pss_state == DSS_FINISHED) { 39053f9d6ad7SLin Ling uint64_t minutes_taken = (end - start) / 60; 3906b327cd3fSIgor Kozhukhov char *fmt = NULL; 39073f9d6ad7SLin Ling 39083f9d6ad7SLin Ling if (ps->pss_func == POOL_SCAN_SCRUB) { 39093f9d6ad7SLin Ling fmt = gettext("scrub repaired %s in %lluh%um with " 39103f9d6ad7SLin Ling "%llu errors on %s"); 39113f9d6ad7SLin Ling } else if (ps->pss_func == POOL_SCAN_RESILVER) { 39123f9d6ad7SLin Ling fmt = gettext("resilvered %s in %lluh%um with " 39133f9d6ad7SLin Ling "%llu errors on %s"); 39143f9d6ad7SLin Ling } 39153f9d6ad7SLin Ling /* LINTED */ 39163f9d6ad7SLin Ling (void) printf(fmt, processed_buf, 391718ce54dfSek (u_longlong_t)(minutes_taken / 60), 391818ce54dfSek (uint_t)(minutes_taken % 60), 39193f9d6ad7SLin Ling (u_longlong_t)ps->pss_errors, 39203f9d6ad7SLin Ling ctime((time_t *)&end)); 39213f9d6ad7SLin Ling return; 39223f9d6ad7SLin Ling } else if (ps->pss_state == DSS_CANCELED) { 39233f9d6ad7SLin Ling if (ps->pss_func == POOL_SCAN_SCRUB) { 39243f9d6ad7SLin Ling (void) printf(gettext("scrub canceled on %s"), 39253f9d6ad7SLin Ling ctime(&end)); 39263f9d6ad7SLin Ling } else if (ps->pss_func == POOL_SCAN_RESILVER) { 39273f9d6ad7SLin Ling (void) printf(gettext("resilver canceled on %s"), 39283f9d6ad7SLin Ling ctime(&end)); 39293f9d6ad7SLin Ling } 3930fa9e4066Sahrens return; 3931fa9e4066Sahrens } 3932fa9e4066Sahrens 39333f9d6ad7SLin Ling assert(ps->pss_state == DSS_SCANNING); 39343f9d6ad7SLin Ling 39353f9d6ad7SLin Ling /* 39363f9d6ad7SLin Ling * Scan is in progress. 39373f9d6ad7SLin Ling */ 39383f9d6ad7SLin Ling if (ps->pss_func == POOL_SCAN_SCRUB) { 39393f9d6ad7SLin Ling (void) printf(gettext("scrub in progress since %s"), 39403f9d6ad7SLin Ling ctime(&start)); 39413f9d6ad7SLin Ling } else if (ps->pss_func == POOL_SCAN_RESILVER) { 39423f9d6ad7SLin Ling (void) printf(gettext("resilver in progress since %s"), 39433f9d6ad7SLin Ling ctime(&start)); 39443f9d6ad7SLin Ling } 3945fa9e4066Sahrens 39463f9d6ad7SLin Ling examined = ps->pss_examined ? ps->pss_examined : 1; 39473f9d6ad7SLin Ling total = ps->pss_to_examine; 3948fa9e4066Sahrens fraction_done = (double)examined / total; 39493f9d6ad7SLin Ling 39503f9d6ad7SLin Ling /* elapsed time for this pass */ 39513f9d6ad7SLin Ling elapsed = time(NULL) - ps->pss_pass_start; 39523f9d6ad7SLin Ling elapsed = elapsed ? elapsed : 1; 39533f9d6ad7SLin Ling pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 39543f9d6ad7SLin Ling rate = pass_exam / elapsed; 39553f9d6ad7SLin Ling rate = rate ? rate : 1; 39563f9d6ad7SLin Ling mins_left = ((total - examined) / rate) / 60; 395773d314ceSLin Ling hours_left = mins_left / 60; 39583f9d6ad7SLin Ling 39593f9d6ad7SLin Ling zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 39603f9d6ad7SLin Ling zfs_nicenum(total, total_buf, sizeof (total_buf)); 39613f9d6ad7SLin Ling zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 39623f9d6ad7SLin Ling 396373d314ceSLin Ling /* 396473d314ceSLin Ling * do not print estimated time if hours_left is more than 30 days 396573d314ceSLin Ling */ 396673d314ceSLin Ling (void) printf(gettext(" %s scanned out of %s at %s/s"), 396773d314ceSLin Ling examined_buf, total_buf, rate_buf); 396873d314ceSLin Ling if (hours_left < (30 * 24)) { 396973d314ceSLin Ling (void) printf(gettext(", %lluh%um to go\n"), 397073d314ceSLin Ling (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 397173d314ceSLin Ling } else { 397273d314ceSLin Ling (void) printf(gettext( 397373d314ceSLin Ling ", (scan is slow, no estimated time)\n")); 397473d314ceSLin Ling } 39753f9d6ad7SLin Ling 39763f9d6ad7SLin Ling if (ps->pss_func == POOL_SCAN_RESILVER) { 39773f9d6ad7SLin Ling (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 39783f9d6ad7SLin Ling processed_buf, 100 * fraction_done); 39793f9d6ad7SLin Ling } else if (ps->pss_func == POOL_SCAN_SCRUB) { 39803f9d6ad7SLin Ling (void) printf(gettext(" %s repaired, %.2f%% done\n"), 39813f9d6ad7SLin Ling processed_buf, 100 * fraction_done); 39823f9d6ad7SLin Ling } 3983fa9e4066Sahrens } 3984fa9e4066Sahrens 3985ea8dc4b6Seschrock static void 3986ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 3987ea8dc4b6Seschrock { 398875519f38Sek nvlist_t *nverrlist = NULL; 398955434c77Sek nvpair_t *elem; 399055434c77Sek char *pathname; 399155434c77Sek size_t len = MAXPATHLEN * 2; 3992ea8dc4b6Seschrock 399355434c77Sek if (zpool_get_errlog(zhp, &nverrlist) != 0) { 3994ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 3995ea8dc4b6Seschrock "(insufficient privileges)\n"); 3996ea8dc4b6Seschrock return; 3997ea8dc4b6Seschrock } 3998ea8dc4b6Seschrock 399955434c77Sek (void) printf("errors: Permanent errors have been " 400055434c77Sek "detected in the following files:\n\n"); 4001ea8dc4b6Seschrock 400255434c77Sek pathname = safe_malloc(len); 400355434c77Sek elem = NULL; 400455434c77Sek while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 400555434c77Sek nvlist_t *nv; 400655434c77Sek uint64_t dsobj, obj; 400755434c77Sek 400855434c77Sek verify(nvpair_value_nvlist(elem, &nv) == 0); 400955434c77Sek verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 401055434c77Sek &dsobj) == 0); 401155434c77Sek verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 401255434c77Sek &obj) == 0); 401355434c77Sek zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 401455434c77Sek (void) printf("%7s %s\n", "", pathname); 401555434c77Sek } 401655434c77Sek free(pathname); 401755434c77Sek nvlist_free(nverrlist); 4018ea8dc4b6Seschrock } 4019ea8dc4b6Seschrock 402099653d4eSeschrock static void 402199653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 402299653d4eSeschrock int namewidth) 402399653d4eSeschrock { 402499653d4eSeschrock uint_t i; 402599653d4eSeschrock char *name; 402699653d4eSeschrock 402799653d4eSeschrock if (nspares == 0) 402899653d4eSeschrock return; 402999653d4eSeschrock 403099653d4eSeschrock (void) printf(gettext("\tspares\n")); 403199653d4eSeschrock 403299653d4eSeschrock for (i = 0; i < nspares; i++) { 403388ecc943SGeorge Wilson name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 403499653d4eSeschrock print_status_config(zhp, name, spares[i], 4035aa8cf21aSNeil Perrin namewidth, 2, B_TRUE); 403699653d4eSeschrock free(name); 403799653d4eSeschrock } 403899653d4eSeschrock } 403999653d4eSeschrock 4040fa94a07fSbrendan static void 4041fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 4042fa94a07fSbrendan int namewidth) 4043fa94a07fSbrendan { 4044fa94a07fSbrendan uint_t i; 4045fa94a07fSbrendan char *name; 4046fa94a07fSbrendan 4047fa94a07fSbrendan if (nl2cache == 0) 4048fa94a07fSbrendan return; 4049fa94a07fSbrendan 4050fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 4051fa94a07fSbrendan 4052fa94a07fSbrendan for (i = 0; i < nl2cache; i++) { 405388ecc943SGeorge Wilson name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 4054fa94a07fSbrendan print_status_config(zhp, name, l2cache[i], 4055aa8cf21aSNeil Perrin namewidth, 2, B_FALSE); 4056aa8cf21aSNeil Perrin free(name); 4057aa8cf21aSNeil Perrin } 4058aa8cf21aSNeil Perrin } 4059aa8cf21aSNeil Perrin 40609eb19f4dSGeorge Wilson static void 40619eb19f4dSGeorge Wilson print_dedup_stats(nvlist_t *config) 40629eb19f4dSGeorge Wilson { 40639eb19f4dSGeorge Wilson ddt_histogram_t *ddh; 40649eb19f4dSGeorge Wilson ddt_stat_t *dds; 40659eb19f4dSGeorge Wilson ddt_object_t *ddo; 40669eb19f4dSGeorge Wilson uint_t c; 40679eb19f4dSGeorge Wilson 40689eb19f4dSGeorge Wilson /* 40699eb19f4dSGeorge Wilson * If the pool was faulted then we may not have been able to 40702384d9f8SGeorge Wilson * obtain the config. Otherwise, if we have anything in the dedup 40719eb19f4dSGeorge Wilson * table continue processing the stats. 40729eb19f4dSGeorge Wilson */ 40739eb19f4dSGeorge Wilson if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 4074ce72e614SYuri Pankov (uint64_t **)&ddo, &c) != 0) 40759eb19f4dSGeorge Wilson return; 40769eb19f4dSGeorge Wilson 40779eb19f4dSGeorge Wilson (void) printf("\n"); 4078ce72e614SYuri Pankov (void) printf(gettext(" dedup: ")); 4079ce72e614SYuri Pankov if (ddo->ddo_count == 0) { 4080ce72e614SYuri Pankov (void) printf(gettext("no DDT entries\n")); 4081ce72e614SYuri Pankov return; 4082ce72e614SYuri Pankov } 4083ce72e614SYuri Pankov 40849eb19f4dSGeorge Wilson (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 40859eb19f4dSGeorge Wilson (u_longlong_t)ddo->ddo_count, 40869eb19f4dSGeorge Wilson (u_longlong_t)ddo->ddo_dspace, 40879eb19f4dSGeorge Wilson (u_longlong_t)ddo->ddo_mspace); 40889eb19f4dSGeorge Wilson 40899eb19f4dSGeorge Wilson verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 40909eb19f4dSGeorge Wilson (uint64_t **)&dds, &c) == 0); 40919eb19f4dSGeorge Wilson verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 40929eb19f4dSGeorge Wilson (uint64_t **)&ddh, &c) == 0); 40939eb19f4dSGeorge Wilson zpool_dump_ddt(dds, ddh); 40949eb19f4dSGeorge Wilson } 40959eb19f4dSGeorge Wilson 4096fa9e4066Sahrens /* 4097fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 4098fa9e4066Sahrens * 4099fa9e4066Sahrens * pool: tank 4100fa9e4066Sahrens * status: DEGRADED 4101fa9e4066Sahrens * reason: One or more devices ... 4102654b400cSJoshua M. Clulow * see: http://illumos.org/msg/ZFS-xxxx-01 4103fa9e4066Sahrens * config: 4104fa9e4066Sahrens * mirror DEGRADED 4105fa9e4066Sahrens * c1t0d0 OK 4106ea8dc4b6Seschrock * c2t0d0 UNAVAIL 4107fa9e4066Sahrens * 4108fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 4109fa9e4066Sahrens * option is specified, then we print out error rate information as well. 4110fa9e4066Sahrens */ 4111fa9e4066Sahrens int 4112fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 4113fa9e4066Sahrens { 4114fa9e4066Sahrens status_cbdata_t *cbp = data; 4115fa9e4066Sahrens nvlist_t *config, *nvroot; 4116fa9e4066Sahrens char *msgid; 4117fa9e4066Sahrens int reason; 411846657f8dSmmusante const char *health; 411946657f8dSmmusante uint_t c; 412046657f8dSmmusante vdev_stat_t *vs; 4121fa9e4066Sahrens 4122088e9d47Seschrock config = zpool_get_config(zhp, NULL); 4123fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 4124fa9e4066Sahrens 4125fa9e4066Sahrens cbp->cb_count++; 4126fa9e4066Sahrens 4127fa9e4066Sahrens /* 4128fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 4129fa9e4066Sahrens * problems. 4130fa9e4066Sahrens */ 4131b3a6f804STim Connors if (cbp->cb_explain && 4132b3a6f804STim Connors (reason == ZPOOL_STATUS_OK || 4133b3a6f804STim Connors reason == ZPOOL_STATUS_VERSION_OLDER || 4134b3a6f804STim Connors reason == ZPOOL_STATUS_FEAT_DISABLED)) { 4135e9dbad6fSeschrock if (!cbp->cb_allpools) { 4136e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 4137e9dbad6fSeschrock zpool_get_name(zhp)); 4138e9dbad6fSeschrock if (cbp->cb_first) 4139e9dbad6fSeschrock cbp->cb_first = B_FALSE; 4140e9dbad6fSeschrock } 4141fa9e4066Sahrens return (0); 4142e9dbad6fSeschrock } 4143fa9e4066Sahrens 4144fa9e4066Sahrens if (cbp->cb_first) 414599653d4eSeschrock cbp->cb_first = B_FALSE; 4146fa9e4066Sahrens else 4147fa9e4066Sahrens (void) printf("\n"); 4148fa9e4066Sahrens 414946657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 415046657f8dSmmusante &nvroot) == 0); 41513f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 415246657f8dSmmusante (uint64_t **)&vs, &c) == 0); 4153990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4154fa9e4066Sahrens 4155fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4156fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 4157fa9e4066Sahrens 4158fa9e4066Sahrens switch (reason) { 4159fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 4160fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 4161fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 4162fa9e4066Sahrens "continue functioning in a degraded state.\n")); 4163fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 4164fa9e4066Sahrens "online it using 'zpool online'.\n")); 4165fa9e4066Sahrens break; 4166fa9e4066Sahrens 4167fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 4168fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 4169fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 4170fa9e4066Sahrens "pool to continue functioning.\n")); 4171fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 4172fa9e4066Sahrens "online it using 'zpool online'.\n")); 4173fa9e4066Sahrens break; 4174fa9e4066Sahrens 4175fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 4176fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 4177fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 4178fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 4179fa9e4066Sahrens "functioning in a degraded state.\n")); 4180fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 4181fa9e4066Sahrens "'zpool replace'.\n")); 4182fa9e4066Sahrens break; 4183fa9e4066Sahrens 4184fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4185fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 4186b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 4187fa9e4066Sahrens "There are insufficient replicas for the pool to " 4188fa9e4066Sahrens "continue\n\tfunctioning.\n")); 4189468c413aSTim Haley zpool_explain_recover(zpool_get_handle(zhp), 4190468c413aSTim Haley zpool_get_name(zhp), reason, config); 4191fa9e4066Sahrens break; 4192fa9e4066Sahrens 4193fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 4194fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 4195fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 4196fa9e4066Sahrens "made to correct the error. Applications are " 4197fa9e4066Sahrens "unaffected.\n")); 4198fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 4199fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 4200ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 4201fa9e4066Sahrens "replace'.\n")); 4202fa9e4066Sahrens break; 4203fa9e4066Sahrens 4204fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 4205fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 4206d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 4207fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 4208fa9e4066Sahrens "a\n\tdegraded state.\n")); 4209fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 4210fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 4211fa9e4066Sahrens "replace'.\n")); 4212fa9e4066Sahrens break; 4213fa9e4066Sahrens 4214c25309d4SGeorge Wilson case ZPOOL_STATUS_REMOVED_DEV: 4215c25309d4SGeorge Wilson (void) printf(gettext("status: One or more devices has " 4216c25309d4SGeorge Wilson "been removed by the administrator.\n\tSufficient " 4217c25309d4SGeorge Wilson "replicas exist for the pool to continue functioning in " 4218c25309d4SGeorge Wilson "a\n\tdegraded state.\n")); 4219c25309d4SGeorge Wilson (void) printf(gettext("action: Online the device using " 4220c25309d4SGeorge Wilson "'zpool online' or replace the device with\n\t'zpool " 4221c25309d4SGeorge Wilson "replace'.\n")); 4222c25309d4SGeorge Wilson break; 4223c25309d4SGeorge Wilson 4224fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 4225fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 4226fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 4227fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 4228fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 4229fa9e4066Sahrens "complete.\n")); 4230fa9e4066Sahrens break; 4231fa9e4066Sahrens 4232ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 4233ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 4234ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 4235ea8dc4b6Seschrock "Applications may be affected.\n")); 4236ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 4237ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 4238ea8dc4b6Seschrock "backup.\n")); 4239ea8dc4b6Seschrock break; 4240ea8dc4b6Seschrock 4241ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 4242ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 4243ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 4244468c413aSTim Haley zpool_explain_recover(zpool_get_handle(zhp), 4245468c413aSTim Haley zpool_get_name(zhp), reason, config); 4246ea8dc4b6Seschrock break; 4247ea8dc4b6Seschrock 4248eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 424957221772SChristopher Siden (void) printf(gettext("status: The pool is formatted using a " 425057221772SChristopher Siden "legacy on-disk format. The pool can\n\tstill be used, " 425157221772SChristopher Siden "but some features are unavailable.\n")); 4252eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 4253eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 425457221772SChristopher Siden "be accessible on software that does not support feature\n" 425557221772SChristopher Siden "\tflags.\n")); 4256eaca9bbdSeschrock break; 4257eaca9bbdSeschrock 4258eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 4259eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 4260eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 4261eaca9bbdSeschrock "be accessed on this system.\n")); 4262eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 4263eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 4264eaca9bbdSeschrock "backup.\n")); 4265eaca9bbdSeschrock break; 4266eaca9bbdSeschrock 426757221772SChristopher Siden case ZPOOL_STATUS_FEAT_DISABLED: 426857221772SChristopher Siden (void) printf(gettext("status: Some supported features are not " 426957221772SChristopher Siden "enabled on the pool. The pool can\n\tstill be used, but " 427057221772SChristopher Siden "some features are unavailable.\n")); 427157221772SChristopher Siden (void) printf(gettext("action: Enable all features using " 427257221772SChristopher Siden "'zpool upgrade'. Once this is done,\n\tthe pool may no " 427357221772SChristopher Siden "longer be accessible by software that does not support\n\t" 427457221772SChristopher Siden "the features. See zpool-features(5) for details.\n")); 427557221772SChristopher Siden break; 427657221772SChristopher Siden 4277ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_READ: 4278ad135b5dSChristopher Siden (void) printf(gettext("status: The pool cannot be accessed on " 4279ad135b5dSChristopher Siden "this system because it uses the\n\tfollowing feature(s) " 4280ad135b5dSChristopher Siden "not supported on this system:\n")); 4281ad135b5dSChristopher Siden zpool_print_unsup_feat(config); 4282ad135b5dSChristopher Siden (void) printf("\n"); 4283ad135b5dSChristopher Siden (void) printf(gettext("action: Access the pool from a system " 4284ad135b5dSChristopher Siden "that supports the required feature(s),\n\tor restore the " 4285ad135b5dSChristopher Siden "pool from backup.\n")); 4286ad135b5dSChristopher Siden break; 4287ad135b5dSChristopher Siden 4288ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4289ad135b5dSChristopher Siden (void) printf(gettext("status: The pool can only be accessed " 4290ad135b5dSChristopher Siden "in read-only mode on this system. It\n\tcannot be " 4291ad135b5dSChristopher Siden "accessed in read-write mode because it uses the " 4292ad135b5dSChristopher Siden "following\n\tfeature(s) not supported on this system:\n")); 4293ad135b5dSChristopher Siden zpool_print_unsup_feat(config); 4294ad135b5dSChristopher Siden (void) printf("\n"); 4295ad135b5dSChristopher Siden (void) printf(gettext("action: The pool cannot be accessed in " 4296ad135b5dSChristopher Siden "read-write mode. Import the pool with\n" 4297ad135b5dSChristopher Siden "\t\"-o readonly=on\", access the pool from a system that " 4298ad135b5dSChristopher Siden "supports the\n\trequired feature(s), or restore the " 4299ad135b5dSChristopher Siden "pool from backup.\n")); 4300ad135b5dSChristopher Siden break; 4301ad135b5dSChristopher Siden 43023d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 43033d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 43043d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 43053d7072f8Seschrock "replicas exist for the pool to continue functioning " 43063d7072f8Seschrock "in a\n\tdegraded state.\n")); 43073d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 43083d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 43093d7072f8Seschrock break; 43103d7072f8Seschrock 43113d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 43123d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 43133d7072f8Seschrock "faulted in response to persistent errors. There are " 43143d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 43153d7072f8Seschrock "functioning.\n")); 43163d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 43173d7072f8Seschrock "from a backup source. Manually marking the device\n" 43183d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 43193d7072f8Seschrock "to be recovered.\n")); 43203d7072f8Seschrock break; 43213d7072f8Seschrock 432232b87932Sek case ZPOOL_STATUS_IO_FAILURE_WAIT: 432332b87932Sek case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 432432b87932Sek (void) printf(gettext("status: One or more devices are " 43258a79c1b5Sek "faulted in response to IO failures.\n")); 432632b87932Sek (void) printf(gettext("action: Make sure the affected devices " 432732b87932Sek "are connected, then run 'zpool clear'.\n")); 432832b87932Sek break; 432932b87932Sek 4330b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 4331b87f3af3Sperrin (void) printf(gettext("status: An intent log record " 4332b87f3af3Sperrin "could not be read.\n" 4333b87f3af3Sperrin "\tWaiting for adminstrator intervention to fix the " 4334b87f3af3Sperrin "faulted pool.\n")); 4335b87f3af3Sperrin (void) printf(gettext("action: Either restore the affected " 4336b87f3af3Sperrin "device(s) and run 'zpool online',\n" 4337b87f3af3Sperrin "\tor ignore the intent log records by running " 4338b87f3af3Sperrin "'zpool clear'.\n")); 4339b87f3af3Sperrin break; 4340b87f3af3Sperrin 4341fa9e4066Sahrens default: 4342fa9e4066Sahrens /* 4343fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 4344fa9e4066Sahrens */ 4345fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 4346fa9e4066Sahrens } 4347fa9e4066Sahrens 4348fa9e4066Sahrens if (msgid != NULL) 4349654b400cSJoshua M. Clulow (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4350fa9e4066Sahrens msgid); 4351fa9e4066Sahrens 4352fa9e4066Sahrens if (config != NULL) { 4353fa9e4066Sahrens int namewidth; 4354ea8dc4b6Seschrock uint64_t nerr; 4355fa94a07fSbrendan nvlist_t **spares, **l2cache; 4356fa94a07fSbrendan uint_t nspares, nl2cache; 43573f9d6ad7SLin Ling pool_scan_stat_t *ps = NULL; 4358fa9e4066Sahrens 43593f9d6ad7SLin Ling (void) nvlist_lookup_uint64_array(nvroot, 43603f9d6ad7SLin Ling ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 43613f9d6ad7SLin Ling print_scan_status(ps); 4362fa9e4066Sahrens 4363c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 4364fa9e4066Sahrens if (namewidth < 10) 4365fa9e4066Sahrens namewidth = 10; 4366fa9e4066Sahrens 4367fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 4368fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4369fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4370c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 4371aa8cf21aSNeil Perrin namewidth, 0, B_FALSE); 437299653d4eSeschrock 43734dea40f0SNeil Perrin if (num_logs(nvroot) > 0) 4374e6ca193dSGeorge Wilson print_logs(zhp, nvroot, namewidth, B_TRUE); 4375fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4376fa94a07fSbrendan &l2cache, &nl2cache) == 0) 4377fa94a07fSbrendan print_l2cache(zhp, l2cache, nl2cache, namewidth); 4378fa94a07fSbrendan 437999653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 438099653d4eSeschrock &spares, &nspares) == 0) 438199653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 4382ea8dc4b6Seschrock 4383ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4384ea8dc4b6Seschrock &nerr) == 0) { 438555434c77Sek nvlist_t *nverrlist = NULL; 438655434c77Sek 4387ea8dc4b6Seschrock /* 4388ea8dc4b6Seschrock * If the approximate error count is small, get a 4389ea8dc4b6Seschrock * precise count by fetching the entire log and 4390ea8dc4b6Seschrock * uniquifying the results. 4391ea8dc4b6Seschrock */ 439275519f38Sek if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 439355434c77Sek zpool_get_errlog(zhp, &nverrlist) == 0) { 439455434c77Sek nvpair_t *elem; 439555434c77Sek 439655434c77Sek elem = NULL; 439755434c77Sek nerr = 0; 439855434c77Sek while ((elem = nvlist_next_nvpair(nverrlist, 439955434c77Sek elem)) != NULL) { 440055434c77Sek nerr++; 440155434c77Sek } 440255434c77Sek } 440355434c77Sek nvlist_free(nverrlist); 4404ea8dc4b6Seschrock 4405ea8dc4b6Seschrock (void) printf("\n"); 440699653d4eSeschrock 4407ea8dc4b6Seschrock if (nerr == 0) 4408ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 4409ea8dc4b6Seschrock "errors\n")); 4410ea8dc4b6Seschrock else if (!cbp->cb_verbose) 4411e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 44125ad82045Snd "errors, use '-v' for a list\n"), 44135ad82045Snd (u_longlong_t)nerr); 4414ea8dc4b6Seschrock else 4415ea8dc4b6Seschrock print_error_log(zhp); 4416ea8dc4b6Seschrock } 44179eb19f4dSGeorge Wilson 44189eb19f4dSGeorge Wilson if (cbp->cb_dedup_stats) 44199eb19f4dSGeorge Wilson print_dedup_stats(config); 4420fa9e4066Sahrens } else { 4421fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 4422fa9e4066Sahrens "determined.\n")); 4423fa9e4066Sahrens } 4424fa9e4066Sahrens 4425fa9e4066Sahrens return (0); 4426fa9e4066Sahrens } 4427fa9e4066Sahrens 4428fa9e4066Sahrens /* 44293f9d6ad7SLin Ling * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4430fa9e4066Sahrens * 4431fa9e4066Sahrens * -v Display complete error logs 4432fa9e4066Sahrens * -x Display only pools with potential problems 44339eb19f4dSGeorge Wilson * -D Display dedup status (undocumented) 44343f9d6ad7SLin Ling * -T Display a timestamp in date(1) or Unix format 4435fa9e4066Sahrens * 4436fa9e4066Sahrens * Describes the health status of all pools or some subset. 4437fa9e4066Sahrens */ 4438fa9e4066Sahrens int 4439fa9e4066Sahrens zpool_do_status(int argc, char **argv) 4440fa9e4066Sahrens { 4441fa9e4066Sahrens int c; 4442fa9e4066Sahrens int ret; 44433f9d6ad7SLin Ling unsigned long interval = 0, count = 0; 4444fa9e4066Sahrens status_cbdata_t cb = { 0 }; 4445fa9e4066Sahrens 4446fa9e4066Sahrens /* check options */ 44473f9d6ad7SLin Ling while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4448fa9e4066Sahrens switch (c) { 4449fa9e4066Sahrens case 'v': 445099653d4eSeschrock cb.cb_verbose = B_TRUE; 4451fa9e4066Sahrens break; 4452fa9e4066Sahrens case 'x': 445399653d4eSeschrock cb.cb_explain = B_TRUE; 4454fa9e4066Sahrens break; 44559eb19f4dSGeorge Wilson case 'D': 44569eb19f4dSGeorge Wilson cb.cb_dedup_stats = B_TRUE; 44579eb19f4dSGeorge Wilson break; 44583f9d6ad7SLin Ling case 'T': 44593f9d6ad7SLin Ling get_timestamp_arg(*optarg); 44603f9d6ad7SLin Ling break; 4461fa9e4066Sahrens case '?': 4462fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4463fa9e4066Sahrens optopt); 446499653d4eSeschrock usage(B_FALSE); 4465fa9e4066Sahrens } 4466fa9e4066Sahrens } 4467fa9e4066Sahrens 4468fa9e4066Sahrens argc -= optind; 4469fa9e4066Sahrens argv += optind; 4470fa9e4066Sahrens 44713f9d6ad7SLin Ling get_interval_count(&argc, argv, &interval, &count); 4472fa9e4066Sahrens 4473e9dbad6fSeschrock if (argc == 0) 4474e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 4475e9dbad6fSeschrock 44763f9d6ad7SLin Ling cb.cb_first = B_TRUE; 4477fa9e4066Sahrens 44783f9d6ad7SLin Ling for (;;) { 44793f9d6ad7SLin Ling if (timestamp_fmt != NODATE) 44803f9d6ad7SLin Ling print_timestamp(timestamp_fmt); 4481fa9e4066Sahrens 44823f9d6ad7SLin Ling ret = for_each_pool(argc, argv, B_TRUE, NULL, 44833f9d6ad7SLin Ling status_callback, &cb); 44843f9d6ad7SLin Ling 44853f9d6ad7SLin Ling if (argc == 0 && cb.cb_count == 0) 44863f9d6ad7SLin Ling (void) printf(gettext("no pools available\n")); 44873f9d6ad7SLin Ling else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 44883f9d6ad7SLin Ling (void) printf(gettext("all pools are healthy\n")); 44893f9d6ad7SLin Ling 44903f9d6ad7SLin Ling if (ret != 0) 44913f9d6ad7SLin Ling return (ret); 44923f9d6ad7SLin Ling 44933f9d6ad7SLin Ling if (interval == 0) 44943f9d6ad7SLin Ling break; 44953f9d6ad7SLin Ling 44963f9d6ad7SLin Ling if (count != 0 && --count == 0) 44973f9d6ad7SLin Ling break; 44983f9d6ad7SLin Ling 44993f9d6ad7SLin Ling (void) sleep(interval); 45003f9d6ad7SLin Ling } 45013f9d6ad7SLin Ling 45023f9d6ad7SLin Ling return (0); 4503fa9e4066Sahrens } 4504fa9e4066Sahrens 4505eaca9bbdSeschrock typedef struct upgrade_cbdata { 4506eaca9bbdSeschrock int cb_first; 450706eeb2adSek int cb_argc; 4508990b4856Slling uint64_t cb_version; 450906eeb2adSek char **cb_argv; 4510eaca9bbdSeschrock } upgrade_cbdata_t; 4511eaca9bbdSeschrock 451257221772SChristopher Siden static int 451357221772SChristopher Siden upgrade_version(zpool_handle_t *zhp, uint64_t version) 451457221772SChristopher Siden { 451557221772SChristopher Siden int ret; 451657221772SChristopher Siden nvlist_t *config; 451757221772SChristopher Siden uint64_t oldversion; 451857221772SChristopher Siden 451957221772SChristopher Siden config = zpool_get_config(zhp, NULL); 452057221772SChristopher Siden verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 452157221772SChristopher Siden &oldversion) == 0); 452257221772SChristopher Siden 452357221772SChristopher Siden assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 452457221772SChristopher Siden assert(oldversion < version); 452557221772SChristopher Siden 452657221772SChristopher Siden ret = zpool_upgrade(zhp, version); 452757221772SChristopher Siden if (ret != 0) 452857221772SChristopher Siden return (ret); 452957221772SChristopher Siden 453057221772SChristopher Siden if (version >= SPA_VERSION_FEATURES) { 453157221772SChristopher Siden (void) printf(gettext("Successfully upgraded " 453257221772SChristopher Siden "'%s' from version %llu to feature flags.\n"), 453357221772SChristopher Siden zpool_get_name(zhp), oldversion); 453457221772SChristopher Siden } else { 453557221772SChristopher Siden (void) printf(gettext("Successfully upgraded " 453657221772SChristopher Siden "'%s' from version %llu to version %llu.\n"), 453757221772SChristopher Siden zpool_get_name(zhp), oldversion, version); 453857221772SChristopher Siden } 453957221772SChristopher Siden 454057221772SChristopher Siden return (0); 454157221772SChristopher Siden } 454257221772SChristopher Siden 454357221772SChristopher Siden static int 454457221772SChristopher Siden upgrade_enable_all(zpool_handle_t *zhp, int *countp) 454557221772SChristopher Siden { 454657221772SChristopher Siden int i, ret, count; 454757221772SChristopher Siden boolean_t firstff = B_TRUE; 454857221772SChristopher Siden nvlist_t *enabled = zpool_get_features(zhp); 454957221772SChristopher Siden 455057221772SChristopher Siden count = 0; 455157221772SChristopher Siden for (i = 0; i < SPA_FEATURES; i++) { 455257221772SChristopher Siden const char *fname = spa_feature_table[i].fi_uname; 455357221772SChristopher Siden const char *fguid = spa_feature_table[i].fi_guid; 455457221772SChristopher Siden if (!nvlist_exists(enabled, fguid)) { 455557221772SChristopher Siden char *propname; 455657221772SChristopher Siden verify(-1 != asprintf(&propname, "feature@%s", fname)); 455757221772SChristopher Siden ret = zpool_set_prop(zhp, propname, 455857221772SChristopher Siden ZFS_FEATURE_ENABLED); 455957221772SChristopher Siden if (ret != 0) { 456057221772SChristopher Siden free(propname); 456157221772SChristopher Siden return (ret); 456257221772SChristopher Siden } 456357221772SChristopher Siden count++; 456457221772SChristopher Siden 456557221772SChristopher Siden if (firstff) { 456657221772SChristopher Siden (void) printf(gettext("Enabled the " 456757221772SChristopher Siden "following features on '%s':\n"), 456857221772SChristopher Siden zpool_get_name(zhp)); 456957221772SChristopher Siden firstff = B_FALSE; 457057221772SChristopher Siden } 457157221772SChristopher Siden (void) printf(gettext(" %s\n"), fname); 457257221772SChristopher Siden free(propname); 457357221772SChristopher Siden } 457457221772SChristopher Siden } 457557221772SChristopher Siden 457657221772SChristopher Siden if (countp != NULL) 457757221772SChristopher Siden *countp = count; 457857221772SChristopher Siden return (0); 457957221772SChristopher Siden } 458057221772SChristopher Siden 4581eaca9bbdSeschrock static int 4582eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 4583eaca9bbdSeschrock { 4584eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 4585eaca9bbdSeschrock nvlist_t *config; 4586eaca9bbdSeschrock uint64_t version; 458757221772SChristopher Siden boolean_t printnl = B_FALSE; 458857221772SChristopher Siden int ret; 4589eaca9bbdSeschrock 4590eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 4591eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4592eaca9bbdSeschrock &version) == 0); 4593eaca9bbdSeschrock 459457221772SChristopher Siden assert(SPA_VERSION_IS_SUPPORTED(version)); 4595eaca9bbdSeschrock 459657221772SChristopher Siden if (version < cbp->cb_version) { 459757221772SChristopher Siden cbp->cb_first = B_FALSE; 459857221772SChristopher Siden ret = upgrade_version(zhp, cbp->cb_version); 459957221772SChristopher Siden if (ret != 0) 460057221772SChristopher Siden return (ret); 460157221772SChristopher Siden printnl = B_TRUE; 460257221772SChristopher Siden 460357221772SChristopher Siden /* 460457221772SChristopher Siden * If they did "zpool upgrade -a", then we could 460557221772SChristopher Siden * be doing ioctls to different pools. We need 460657221772SChristopher Siden * to log this history once to each pool, and bypass 460757221772SChristopher Siden * the normal history logging that happens in main(). 460857221772SChristopher Siden */ 460957221772SChristopher Siden (void) zpool_log_history(g_zfs, history_str); 461057221772SChristopher Siden log_history = B_FALSE; 461157221772SChristopher Siden } 461257221772SChristopher Siden 461357221772SChristopher Siden if (cbp->cb_version >= SPA_VERSION_FEATURES) { 461457221772SChristopher Siden int count; 461557221772SChristopher Siden ret = upgrade_enable_all(zhp, &count); 461657221772SChristopher Siden if (ret != 0) 461757221772SChristopher Siden return (ret); 461857221772SChristopher Siden 461957221772SChristopher Siden if (count > 0) { 462099653d4eSeschrock cbp->cb_first = B_FALSE; 462157221772SChristopher Siden printnl = B_TRUE; 4622eaca9bbdSeschrock } 462357221772SChristopher Siden } 4624eaca9bbdSeschrock 462557221772SChristopher Siden if (printnl) { 462657221772SChristopher Siden (void) printf(gettext("\n")); 462757221772SChristopher Siden } 462857221772SChristopher Siden 462957221772SChristopher Siden return (0); 463057221772SChristopher Siden } 463157221772SChristopher Siden 463257221772SChristopher Siden static int 463357221772SChristopher Siden upgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 463457221772SChristopher Siden { 463557221772SChristopher Siden upgrade_cbdata_t *cbp = arg; 463657221772SChristopher Siden nvlist_t *config; 463757221772SChristopher Siden uint64_t version; 463857221772SChristopher Siden 463957221772SChristopher Siden config = zpool_get_config(zhp, NULL); 464057221772SChristopher Siden verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 464157221772SChristopher Siden &version) == 0); 464257221772SChristopher Siden 464357221772SChristopher Siden assert(SPA_VERSION_IS_SUPPORTED(version)); 464457221772SChristopher Siden 464557221772SChristopher Siden if (version < SPA_VERSION_FEATURES) { 4646eaca9bbdSeschrock if (cbp->cb_first) { 4647eaca9bbdSeschrock (void) printf(gettext("The following pools are " 464857221772SChristopher Siden "formatted with legacy version numbers and can\n" 464957221772SChristopher Siden "be upgraded to use feature flags. After " 465057221772SChristopher Siden "being upgraded, these pools\nwill no " 465157221772SChristopher Siden "longer be accessible by software that does not " 465257221772SChristopher Siden "support feature\nflags.\n\n")); 4653eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 4654eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 465599653d4eSeschrock cbp->cb_first = B_FALSE; 4656eaca9bbdSeschrock } 4657eaca9bbdSeschrock 46585ad82045Snd (void) printf("%2llu %s\n", (u_longlong_t)version, 4659eaca9bbdSeschrock zpool_get_name(zhp)); 4660eaca9bbdSeschrock } 4661eaca9bbdSeschrock 466257221772SChristopher Siden return (0); 466357221772SChristopher Siden } 466457221772SChristopher Siden 466557221772SChristopher Siden static int 466657221772SChristopher Siden upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 466757221772SChristopher Siden { 466857221772SChristopher Siden upgrade_cbdata_t *cbp = arg; 466957221772SChristopher Siden nvlist_t *config; 467057221772SChristopher Siden uint64_t version; 467157221772SChristopher Siden 467257221772SChristopher Siden config = zpool_get_config(zhp, NULL); 467357221772SChristopher Siden verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 467457221772SChristopher Siden &version) == 0); 467557221772SChristopher Siden 467657221772SChristopher Siden if (version >= SPA_VERSION_FEATURES) { 467757221772SChristopher Siden int i; 467857221772SChristopher Siden boolean_t poolfirst = B_TRUE; 467957221772SChristopher Siden nvlist_t *enabled = zpool_get_features(zhp); 468057221772SChristopher Siden 468157221772SChristopher Siden for (i = 0; i < SPA_FEATURES; i++) { 468257221772SChristopher Siden const char *fguid = spa_feature_table[i].fi_guid; 468357221772SChristopher Siden const char *fname = spa_feature_table[i].fi_uname; 468457221772SChristopher Siden if (!nvlist_exists(enabled, fguid)) { 468557221772SChristopher Siden if (cbp->cb_first) { 468657221772SChristopher Siden (void) printf(gettext("\nSome " 468757221772SChristopher Siden "supported features are not " 468857221772SChristopher Siden "enabled on the following pools. " 468957221772SChristopher Siden "Once a\nfeature is enabled the " 469057221772SChristopher Siden "pool may become incompatible with " 469157221772SChristopher Siden "software\nthat does not support " 469257221772SChristopher Siden "the feature. See " 469357221772SChristopher Siden "zpool-features(5) for " 469457221772SChristopher Siden "details.\n\n")); 469557221772SChristopher Siden (void) printf(gettext("POOL " 469657221772SChristopher Siden "FEATURE\n")); 469757221772SChristopher Siden (void) printf(gettext("------" 469857221772SChristopher Siden "---------\n")); 469957221772SChristopher Siden cbp->cb_first = B_FALSE; 470057221772SChristopher Siden } 470157221772SChristopher Siden 470257221772SChristopher Siden if (poolfirst) { 470357221772SChristopher Siden (void) printf(gettext("%s\n"), 470457221772SChristopher Siden zpool_get_name(zhp)); 470557221772SChristopher Siden poolfirst = B_FALSE; 470657221772SChristopher Siden } 470757221772SChristopher Siden 470857221772SChristopher Siden (void) printf(gettext(" %s\n"), fname); 470957221772SChristopher Siden } 471057221772SChristopher Siden } 471157221772SChristopher Siden } 471257221772SChristopher Siden 471357221772SChristopher Siden return (0); 4714eaca9bbdSeschrock } 4715eaca9bbdSeschrock 4716eaca9bbdSeschrock /* ARGSUSED */ 4717eaca9bbdSeschrock static int 471806eeb2adSek upgrade_one(zpool_handle_t *zhp, void *data) 4719eaca9bbdSeschrock { 472057221772SChristopher Siden boolean_t printnl = B_FALSE; 4721990b4856Slling upgrade_cbdata_t *cbp = data; 4722990b4856Slling uint64_t cur_version; 4723eaca9bbdSeschrock int ret; 4724eaca9bbdSeschrock 47258654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 47268654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 47278654d025Sperrin "Pool 'log' must be renamed using export and import" 47288654d025Sperrin " to upgrade.\n")); 47298654d025Sperrin return (1); 47308654d025Sperrin } 4731990b4856Slling 4732990b4856Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4733e6c728e1Sbrendan if (cur_version > cbp->cb_version) { 4734eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 473557221772SChristopher Siden "using more current version '%llu'.\n\n"), 4736e6c728e1Sbrendan zpool_get_name(zhp), cur_version); 4737e6c728e1Sbrendan return (0); 4738e6c728e1Sbrendan } 473957221772SChristopher Siden 474057221772SChristopher Siden if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 4741e6c728e1Sbrendan (void) printf(gettext("Pool '%s' is already formatted " 474257221772SChristopher Siden "using version %llu.\n\n"), zpool_get_name(zhp), 474357221772SChristopher Siden cbp->cb_version); 4744eaca9bbdSeschrock return (0); 4745eaca9bbdSeschrock } 4746eaca9bbdSeschrock 474757221772SChristopher Siden if (cur_version != cbp->cb_version) { 474857221772SChristopher Siden printnl = B_TRUE; 474957221772SChristopher Siden ret = upgrade_version(zhp, cbp->cb_version); 475057221772SChristopher Siden if (ret != 0) 475157221772SChristopher Siden return (ret); 475257221772SChristopher Siden } 475306eeb2adSek 475457221772SChristopher Siden if (cbp->cb_version >= SPA_VERSION_FEATURES) { 475557221772SChristopher Siden int count = 0; 475657221772SChristopher Siden ret = upgrade_enable_all(zhp, &count); 475757221772SChristopher Siden if (ret != 0) 475857221772SChristopher Siden return (ret); 475957221772SChristopher Siden 476057221772SChristopher Siden if (count != 0) { 476157221772SChristopher Siden printnl = B_TRUE; 476257221772SChristopher Siden } else if (cur_version == SPA_VERSION) { 476357221772SChristopher Siden (void) printf(gettext("Pool '%s' already has all " 476457221772SChristopher Siden "supported features enabled.\n"), 476557221772SChristopher Siden zpool_get_name(zhp)); 476657221772SChristopher Siden } 476757221772SChristopher Siden } 476857221772SChristopher Siden 476957221772SChristopher Siden if (printnl) { 477057221772SChristopher Siden (void) printf(gettext("\n")); 477106eeb2adSek } 4772eaca9bbdSeschrock 477357221772SChristopher Siden return (0); 4774eaca9bbdSeschrock } 4775eaca9bbdSeschrock 4776eaca9bbdSeschrock /* 4777eaca9bbdSeschrock * zpool upgrade 4778eaca9bbdSeschrock * zpool upgrade -v 4779990b4856Slling * zpool upgrade [-V version] <-a | pool ...> 4780eaca9bbdSeschrock * 4781eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 4782eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 4783eaca9bbdSeschrock * upgrade all pools. 4784eaca9bbdSeschrock */ 4785eaca9bbdSeschrock int 4786eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 4787eaca9bbdSeschrock { 4788eaca9bbdSeschrock int c; 4789eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 4790eaca9bbdSeschrock int ret = 0; 4791eaca9bbdSeschrock boolean_t showversions = B_FALSE; 479257221772SChristopher Siden boolean_t upgradeall = B_FALSE; 4793990b4856Slling char *end; 4794990b4856Slling 4795eaca9bbdSeschrock 4796eaca9bbdSeschrock /* check options */ 4797478ed9adSEric Taylor while ((c = getopt(argc, argv, ":avV:")) != -1) { 4798eaca9bbdSeschrock switch (c) { 4799eaca9bbdSeschrock case 'a': 480057221772SChristopher Siden upgradeall = B_TRUE; 4801eaca9bbdSeschrock break; 4802eaca9bbdSeschrock case 'v': 4803eaca9bbdSeschrock showversions = B_TRUE; 4804eaca9bbdSeschrock break; 4805990b4856Slling case 'V': 4806990b4856Slling cb.cb_version = strtoll(optarg, &end, 10); 4807ad135b5dSChristopher Siden if (*end != '\0' || 4808ad135b5dSChristopher Siden !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 4809990b4856Slling (void) fprintf(stderr, 4810990b4856Slling gettext("invalid version '%s'\n"), optarg); 4811990b4856Slling usage(B_FALSE); 4812990b4856Slling } 4813990b4856Slling break; 4814478ed9adSEric Taylor case ':': 4815478ed9adSEric Taylor (void) fprintf(stderr, gettext("missing argument for " 4816478ed9adSEric Taylor "'%c' option\n"), optopt); 4817478ed9adSEric Taylor usage(B_FALSE); 4818478ed9adSEric Taylor break; 4819eaca9bbdSeschrock case '?': 4820eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4821eaca9bbdSeschrock optopt); 482299653d4eSeschrock usage(B_FALSE); 4823eaca9bbdSeschrock } 4824eaca9bbdSeschrock } 4825eaca9bbdSeschrock 482606eeb2adSek cb.cb_argc = argc; 482706eeb2adSek cb.cb_argv = argv; 4828eaca9bbdSeschrock argc -= optind; 4829eaca9bbdSeschrock argv += optind; 4830eaca9bbdSeschrock 4831351420b3Slling if (cb.cb_version == 0) { 4832351420b3Slling cb.cb_version = SPA_VERSION; 483357221772SChristopher Siden } else if (!upgradeall && argc == 0) { 4834351420b3Slling (void) fprintf(stderr, gettext("-V option is " 4835351420b3Slling "incompatible with other arguments\n")); 4836351420b3Slling usage(B_FALSE); 4837351420b3Slling } 4838351420b3Slling 4839eaca9bbdSeschrock if (showversions) { 484057221772SChristopher Siden if (upgradeall || argc != 0) { 4841eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 4842eaca9bbdSeschrock "incompatible with other arguments\n")); 484399653d4eSeschrock usage(B_FALSE); 4844eaca9bbdSeschrock } 484557221772SChristopher Siden } else if (upgradeall) { 4846eaca9bbdSeschrock if (argc != 0) { 4847351420b3Slling (void) fprintf(stderr, gettext("-a option should not " 4848351420b3Slling "be used along with a pool name\n")); 484999653d4eSeschrock usage(B_FALSE); 4850eaca9bbdSeschrock } 4851eaca9bbdSeschrock } 4852eaca9bbdSeschrock 4853ad135b5dSChristopher Siden (void) printf(gettext("This system supports ZFS pool feature " 4854ad135b5dSChristopher Siden "flags.\n\n")); 4855eaca9bbdSeschrock if (showversions) { 485657221772SChristopher Siden int i; 485757221772SChristopher Siden 485857221772SChristopher Siden (void) printf(gettext("The following features are " 485957221772SChristopher Siden "supported:\n\n")); 486057221772SChristopher Siden (void) printf(gettext("FEAT DESCRIPTION\n")); 486157221772SChristopher Siden (void) printf("----------------------------------------------" 486257221772SChristopher Siden "---------------\n"); 486357221772SChristopher Siden for (i = 0; i < SPA_FEATURES; i++) { 486457221772SChristopher Siden zfeature_info_t *fi = &spa_feature_table[i]; 4865ca0cc391SMatthew Ahrens const char *ro = 4866ca0cc391SMatthew Ahrens (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ? 486757221772SChristopher Siden " (read-only compatible)" : ""; 486857221772SChristopher Siden 486957221772SChristopher Siden (void) printf("%-37s%s\n", fi->fi_uname, ro); 487057221772SChristopher Siden (void) printf(" %s\n", fi->fi_desc); 487157221772SChristopher Siden } 487257221772SChristopher Siden (void) printf("\n"); 487357221772SChristopher Siden 487457221772SChristopher Siden (void) printf(gettext("The following legacy versions are also " 4875d7d4af51Smmusante "supported:\n\n")); 4876eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 4877eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 4878eaca9bbdSeschrock "---------------\n"); 487999653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 488044cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 488144cd46caSbillm "(replicated metadata)\n")); 488299653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 488399653d4eSeschrock "RAID-Z\n")); 4884d7306b64Sek (void) printf(gettext(" 4 zpool history\n")); 4885c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 4886c9431fa1Sahl "algorithm\n")); 4887990b4856Slling (void) printf(gettext(" 6 bootfs pool property\n")); 48888654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 4889ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 48908eed72d4Sck (void) printf(gettext(" 9 refquota and refreservation " 4891a9799022Sck "properties\n")); 4892fa94a07fSbrendan (void) printf(gettext(" 10 Cache devices\n")); 4893088f3894Sahrens (void) printf(gettext(" 11 Improved scrub performance\n")); 4894bb0ade09Sahrens (void) printf(gettext(" 12 Snapshot properties\n")); 489574e7dc98SMatthew Ahrens (void) printf(gettext(" 13 snapused property\n")); 489614843421SMatthew Ahrens (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 489714843421SMatthew Ahrens (void) printf(gettext(" 15 user/group space accounting\n")); 4898478ed9adSEric Taylor (void) printf(gettext(" 16 stmf property support\n")); 48997aeab329SAdam Leventhal (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 4900b24ab676SJeff Bonwick (void) printf(gettext(" 18 Snapshot user holds\n")); 490188ecc943SGeorge Wilson (void) printf(gettext(" 19 Log device removal\n")); 4902b24ab676SJeff Bonwick (void) printf(gettext(" 20 Compression using zle " 4903b24ab676SJeff Bonwick "(zero-length encoding)\n")); 4904b24ab676SJeff Bonwick (void) printf(gettext(" 21 Deduplication\n")); 490592241e0bSTom Erickson (void) printf(gettext(" 22 Received properties\n")); 49066e1f5caaSNeil Perrin (void) printf(gettext(" 23 Slim ZIL\n")); 49070a586ceaSMark Shellenbaum (void) printf(gettext(" 24 System attributes\n")); 49083f9d6ad7SLin Ling (void) printf(gettext(" 25 Improved scrub stats\n")); 4909cde58dbcSMatthew Ahrens (void) printf(gettext(" 26 Improved snapshot deletion " 4910cde58dbcSMatthew Ahrens "performance\n")); 49116e0cbcaaSMatthew Ahrens (void) printf(gettext(" 27 Improved snapshot creation " 49126e0cbcaaSMatthew Ahrens "performance\n")); 4913cb04b873SMark J Musante (void) printf(gettext(" 28 Multiple vdev replacements\n")); 4914b24ab676SJeff Bonwick (void) printf(gettext("\nFor more information on a particular " 49159a8685acSstephanie scheffler "version, including supported releases,\n")); 49169a8685acSstephanie scheffler (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 491757221772SChristopher Siden } else if (argc == 0 && upgradeall) { 491857221772SChristopher Siden cb.cb_first = B_TRUE; 491999653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 492057221772SChristopher Siden if (ret == 0 && cb.cb_first) { 492157221772SChristopher Siden if (cb.cb_version == SPA_VERSION) { 492257221772SChristopher Siden (void) printf(gettext("All pools are already " 492357221772SChristopher Siden "formatted using feature flags.\n\n")); 492457221772SChristopher Siden (void) printf(gettext("Every feature flags " 492557221772SChristopher Siden "pool already has all supported features " 492657221772SChristopher Siden "enabled.\n")); 492757221772SChristopher Siden } else { 492857221772SChristopher Siden (void) printf(gettext("All pools are already " 492957221772SChristopher Siden "formatted with version %llu or higher.\n"), 493057221772SChristopher Siden cb.cb_version); 4931eaca9bbdSeschrock } 4932eaca9bbdSeschrock } 493357221772SChristopher Siden } else if (argc == 0) { 493457221772SChristopher Siden cb.cb_first = B_TRUE; 493557221772SChristopher Siden ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 493657221772SChristopher Siden assert(ret == 0); 4937eaca9bbdSeschrock 493857221772SChristopher Siden if (cb.cb_first) { 493957221772SChristopher Siden (void) printf(gettext("All pools are formatted " 494057221772SChristopher Siden "using feature flags.\n\n")); 494157221772SChristopher Siden } else { 494257221772SChristopher Siden (void) printf(gettext("\nUse 'zpool upgrade -v' " 494357221772SChristopher Siden "for a list of available legacy versions.\n")); 494457221772SChristopher Siden } 494557221772SChristopher Siden 494657221772SChristopher Siden cb.cb_first = B_TRUE; 494757221772SChristopher Siden ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 494857221772SChristopher Siden assert(ret == 0); 494957221772SChristopher Siden 495057221772SChristopher Siden if (cb.cb_first) { 495157221772SChristopher Siden (void) printf(gettext("Every feature flags pool has " 495257221772SChristopher Siden "all supported features enabled.\n")); 495357221772SChristopher Siden } else { 495457221772SChristopher Siden (void) printf(gettext("\n")); 4955eaca9bbdSeschrock } 4956eaca9bbdSeschrock } else { 4957b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 4958b1b8ab34Slling upgrade_one, &cb); 495906eeb2adSek } 496006eeb2adSek 496106eeb2adSek return (ret); 496206eeb2adSek } 496306eeb2adSek 4964ecd6cf80Smarks typedef struct hist_cbdata { 4965ecd6cf80Smarks boolean_t first; 49664445fffbSMatthew Ahrens boolean_t longfmt; 49674445fffbSMatthew Ahrens boolean_t internal; 4968ecd6cf80Smarks } hist_cbdata_t; 4969ecd6cf80Smarks 497006eeb2adSek /* 497106eeb2adSek * Print out the command history for a specific pool. 497206eeb2adSek */ 497306eeb2adSek static int 497406eeb2adSek get_history_one(zpool_handle_t *zhp, void *data) 497506eeb2adSek { 497606eeb2adSek nvlist_t *nvhis; 497706eeb2adSek nvlist_t **records; 497806eeb2adSek uint_t numrecords; 497906eeb2adSek int ret, i; 4980ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 498106eeb2adSek 4982ecd6cf80Smarks cb->first = B_FALSE; 498306eeb2adSek 498406eeb2adSek (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 498506eeb2adSek 498606eeb2adSek if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 498706eeb2adSek return (ret); 498806eeb2adSek 498906eeb2adSek verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 499006eeb2adSek &records, &numrecords) == 0); 499106eeb2adSek for (i = 0; i < numrecords; i++) { 49924445fffbSMatthew Ahrens nvlist_t *rec = records[i]; 49934445fffbSMatthew Ahrens char tbuf[30] = ""; 4994ecd6cf80Smarks 49954445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_TIME)) { 49964445fffbSMatthew Ahrens time_t tsec; 49974445fffbSMatthew Ahrens struct tm t; 49984445fffbSMatthew Ahrens 49994445fffbSMatthew Ahrens tsec = fnvlist_lookup_uint64(records[i], 50004445fffbSMatthew Ahrens ZPOOL_HIST_TIME); 50014445fffbSMatthew Ahrens (void) localtime_r(&tsec, &t); 50024445fffbSMatthew Ahrens (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 50034445fffbSMatthew Ahrens } 5004ecd6cf80Smarks 50054445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_CMD)) { 50064445fffbSMatthew Ahrens (void) printf("%s %s", tbuf, 50074445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_CMD)); 50084445fffbSMatthew Ahrens } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) { 50094445fffbSMatthew Ahrens int ievent = 50104445fffbSMatthew Ahrens fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT); 50114445fffbSMatthew Ahrens if (!cb->internal) 50124445fffbSMatthew Ahrens continue; 50134445fffbSMatthew Ahrens if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) { 50144445fffbSMatthew Ahrens (void) printf("%s unrecognized record:\n", 50154445fffbSMatthew Ahrens tbuf); 50164445fffbSMatthew Ahrens dump_nvlist(rec, 4); 50174445fffbSMatthew Ahrens continue; 50184445fffbSMatthew Ahrens } 50194445fffbSMatthew Ahrens (void) printf("%s [internal %s txg:%lld] %s", tbuf, 50204445fffbSMatthew Ahrens zfs_history_event_names[ievent], 50214445fffbSMatthew Ahrens fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 50224445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR)); 50234445fffbSMatthew Ahrens } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) { 50244445fffbSMatthew Ahrens if (!cb->internal) 5025ecd6cf80Smarks continue; 50264445fffbSMatthew Ahrens (void) printf("%s [txg:%lld] %s", tbuf, 50274445fffbSMatthew Ahrens fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 50284445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME)); 50294445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) { 50304445fffbSMatthew Ahrens (void) printf(" %s (%llu)", 50314445fffbSMatthew Ahrens fnvlist_lookup_string(rec, 50324445fffbSMatthew Ahrens ZPOOL_HIST_DSNAME), 50334445fffbSMatthew Ahrens fnvlist_lookup_uint64(rec, 50344445fffbSMatthew Ahrens ZPOOL_HIST_DSID)); 50354445fffbSMatthew Ahrens } 50364445fffbSMatthew Ahrens (void) printf(" %s", fnvlist_lookup_string(rec, 50374445fffbSMatthew Ahrens ZPOOL_HIST_INT_STR)); 50384445fffbSMatthew Ahrens } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) { 50394445fffbSMatthew Ahrens if (!cb->internal) 50404445fffbSMatthew Ahrens continue; 50414445fffbSMatthew Ahrens (void) printf("%s ioctl %s\n", tbuf, 50424445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL)); 50434445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) { 50444445fffbSMatthew Ahrens (void) printf(" input:\n"); 50454445fffbSMatthew Ahrens dump_nvlist(fnvlist_lookup_nvlist(rec, 50464445fffbSMatthew Ahrens ZPOOL_HIST_INPUT_NVL), 8); 50474445fffbSMatthew Ahrens } 50484445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) { 50494445fffbSMatthew Ahrens (void) printf(" output:\n"); 50504445fffbSMatthew Ahrens dump_nvlist(fnvlist_lookup_nvlist(rec, 50514445fffbSMatthew Ahrens ZPOOL_HIST_OUTPUT_NVL), 8); 50524445fffbSMatthew Ahrens } 50534445fffbSMatthew Ahrens } else { 50544445fffbSMatthew Ahrens if (!cb->internal) 5055ecd6cf80Smarks continue; 50564445fffbSMatthew Ahrens (void) printf("%s unrecognized record:\n", tbuf); 50574445fffbSMatthew Ahrens dump_nvlist(rec, 4); 505806eeb2adSek } 5059ecd6cf80Smarks 5060ecd6cf80Smarks if (!cb->longfmt) { 5061ecd6cf80Smarks (void) printf("\n"); 5062ecd6cf80Smarks continue; 5063ecd6cf80Smarks } 5064ecd6cf80Smarks (void) printf(" ["); 50654445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_WHO)) { 50664445fffbSMatthew Ahrens uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO); 50674445fffbSMatthew Ahrens struct passwd *pwd = getpwuid(who); 50684445fffbSMatthew Ahrens (void) printf("user %d ", (int)who); 50694445fffbSMatthew Ahrens if (pwd != NULL) 50704445fffbSMatthew Ahrens (void) printf("(%s) ", pwd->pw_name); 5071ecd6cf80Smarks } 50724445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_HOST)) { 50734445fffbSMatthew Ahrens (void) printf("on %s", 50744445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_HOST)); 5075ecd6cf80Smarks } 50764445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) { 50774445fffbSMatthew Ahrens (void) printf(":%s", 50784445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE)); 5079ecd6cf80Smarks } 5080ecd6cf80Smarks (void) printf("]"); 5081ecd6cf80Smarks (void) printf("\n"); 508206eeb2adSek } 508306eeb2adSek (void) printf("\n"); 508406eeb2adSek nvlist_free(nvhis); 508506eeb2adSek 508606eeb2adSek return (ret); 508706eeb2adSek } 508806eeb2adSek 508906eeb2adSek /* 509006eeb2adSek * zpool history <pool> 509106eeb2adSek * 509206eeb2adSek * Displays the history of commands that modified pools. 509306eeb2adSek */ 509406eeb2adSek int 509506eeb2adSek zpool_do_history(int argc, char **argv) 509606eeb2adSek { 5097ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 509806eeb2adSek int ret; 5099ecd6cf80Smarks int c; 510006eeb2adSek 5101ecd6cf80Smarks cbdata.first = B_TRUE; 5102ecd6cf80Smarks /* check options */ 5103ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 5104ecd6cf80Smarks switch (c) { 5105ecd6cf80Smarks case 'l': 51064445fffbSMatthew Ahrens cbdata.longfmt = B_TRUE; 5107ecd6cf80Smarks break; 5108ecd6cf80Smarks case 'i': 51094445fffbSMatthew Ahrens cbdata.internal = B_TRUE; 5110ecd6cf80Smarks break; 5111ecd6cf80Smarks case '?': 5112ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5113ecd6cf80Smarks optopt); 5114ecd6cf80Smarks usage(B_FALSE); 5115ecd6cf80Smarks } 5116ecd6cf80Smarks } 511706eeb2adSek argc -= optind; 511806eeb2adSek argv += optind; 511906eeb2adSek 5120b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 5121ecd6cf80Smarks &cbdata); 512206eeb2adSek 5123ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 512406eeb2adSek (void) printf(gettext("no pools available\n")); 512506eeb2adSek return (0); 5126eaca9bbdSeschrock } 5127eaca9bbdSeschrock 5128eaca9bbdSeschrock return (ret); 5129eaca9bbdSeschrock } 5130eaca9bbdSeschrock 5131b1b8ab34Slling static int 5132b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 5133b1b8ab34Slling { 5134990b4856Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 5135b1b8ab34Slling char value[MAXNAMELEN]; 5136990b4856Slling zprop_source_t srctype; 5137990b4856Slling zprop_list_t *pl; 5138b1b8ab34Slling 5139b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 5140b1b8ab34Slling 5141b1b8ab34Slling /* 5142990b4856Slling * Skip the special fake placeholder. This will also skip 5143990b4856Slling * over the name property when 'all' is specified. 5144b1b8ab34Slling */ 5145990b4856Slling if (pl->pl_prop == ZPOOL_PROP_NAME && 5146b1b8ab34Slling pl == cbp->cb_proplist) 5147b1b8ab34Slling continue; 5148b1b8ab34Slling 5149ad135b5dSChristopher Siden if (pl->pl_prop == ZPROP_INVAL && 5150ad135b5dSChristopher Siden (zpool_prop_feature(pl->pl_user_prop) || 5151ad135b5dSChristopher Siden zpool_prop_unsupported(pl->pl_user_prop))) { 5152ad135b5dSChristopher Siden srctype = ZPROP_SRC_LOCAL; 5153b1b8ab34Slling 5154ad135b5dSChristopher Siden if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 5155ad135b5dSChristopher Siden value, sizeof (value)) == 0) { 5156ad135b5dSChristopher Siden zprop_print_one_property(zpool_get_name(zhp), 5157ad135b5dSChristopher Siden cbp, pl->pl_user_prop, value, srctype, 5158ad135b5dSChristopher Siden NULL, NULL); 5159ad135b5dSChristopher Siden } 5160ad135b5dSChristopher Siden } else { 5161ad135b5dSChristopher Siden if (zpool_get_prop(zhp, pl->pl_prop, value, 5162c58b3526SAdam Stevko sizeof (value), &srctype, cbp->cb_literal) != 0) 5163ad135b5dSChristopher Siden continue; 5164ad135b5dSChristopher Siden 5165ad135b5dSChristopher Siden zprop_print_one_property(zpool_get_name(zhp), cbp, 5166ad135b5dSChristopher Siden zpool_prop_to_name(pl->pl_prop), value, srctype, 5167ad135b5dSChristopher Siden NULL, NULL); 5168ad135b5dSChristopher Siden } 5169b1b8ab34Slling } 5170b1b8ab34Slling return (0); 5171b1b8ab34Slling } 5172b1b8ab34Slling 5173c58b3526SAdam Stevko /* 5174c58b3526SAdam Stevko * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ... 5175c58b3526SAdam Stevko * 5176c58b3526SAdam Stevko * -H Scripted mode. Don't display headers, and separate properties 5177c58b3526SAdam Stevko * by a single tab. 5178c58b3526SAdam Stevko * -o List of columns to display. Defaults to 5179c58b3526SAdam Stevko * "name,property,value,source". 5180c58b3526SAdam Stevko * -p Diplay values in parsable (exact) format. 5181c58b3526SAdam Stevko * 5182c58b3526SAdam Stevko * Get properties of pools in the system. Output space statistics 5183c58b3526SAdam Stevko * for each one as well as other attributes. 5184c58b3526SAdam Stevko */ 5185b1b8ab34Slling int 5186b1b8ab34Slling zpool_do_get(int argc, char **argv) 5187b1b8ab34Slling { 5188990b4856Slling zprop_get_cbdata_t cb = { 0 }; 5189990b4856Slling zprop_list_t fake_name = { 0 }; 5190b1b8ab34Slling int ret; 5191c58b3526SAdam Stevko int c, i; 5192c58b3526SAdam Stevko char *value; 5193b1b8ab34Slling 5194b1b8ab34Slling cb.cb_first = B_TRUE; 5195c58b3526SAdam Stevko 5196c58b3526SAdam Stevko /* 5197c58b3526SAdam Stevko * Set up default columns and sources. 5198c58b3526SAdam Stevko */ 5199990b4856Slling cb.cb_sources = ZPROP_SRC_ALL; 5200b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 5201b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 5202b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 5203b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 5204990b4856Slling cb.cb_type = ZFS_TYPE_POOL; 5205b1b8ab34Slling 5206c58b3526SAdam Stevko /* check options */ 5207c58b3526SAdam Stevko while ((c = getopt(argc, argv, ":Hpo:")) != -1) { 5208c58b3526SAdam Stevko switch (c) { 5209c58b3526SAdam Stevko case 'p': 5210c58b3526SAdam Stevko cb.cb_literal = B_TRUE; 5211c58b3526SAdam Stevko break; 5212c58b3526SAdam Stevko case 'H': 5213c58b3526SAdam Stevko cb.cb_scripted = B_TRUE; 5214c58b3526SAdam Stevko break; 5215c58b3526SAdam Stevko case 'o': 5216c58b3526SAdam Stevko bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 5217c58b3526SAdam Stevko i = 0; 5218c58b3526SAdam Stevko while (*optarg != '\0') { 5219c58b3526SAdam Stevko static char *col_subopts[] = 5220c58b3526SAdam Stevko { "name", "property", "value", "source", 5221c58b3526SAdam Stevko "all", NULL }; 5222c58b3526SAdam Stevko 5223c58b3526SAdam Stevko if (i == ZFS_GET_NCOLS) { 5224c58b3526SAdam Stevko (void) fprintf(stderr, gettext("too " 5225c58b3526SAdam Stevko "many fields given to -o " 5226c58b3526SAdam Stevko "option\n")); 5227c58b3526SAdam Stevko usage(B_FALSE); 5228c58b3526SAdam Stevko } 5229c58b3526SAdam Stevko 5230c58b3526SAdam Stevko switch (getsubopt(&optarg, col_subopts, 5231c58b3526SAdam Stevko &value)) { 5232c58b3526SAdam Stevko case 0: 5233c58b3526SAdam Stevko cb.cb_columns[i++] = GET_COL_NAME; 5234c58b3526SAdam Stevko break; 5235c58b3526SAdam Stevko case 1: 5236c58b3526SAdam Stevko cb.cb_columns[i++] = GET_COL_PROPERTY; 5237c58b3526SAdam Stevko break; 5238c58b3526SAdam Stevko case 2: 5239c58b3526SAdam Stevko cb.cb_columns[i++] = GET_COL_VALUE; 5240c58b3526SAdam Stevko break; 5241c58b3526SAdam Stevko case 3: 5242c58b3526SAdam Stevko cb.cb_columns[i++] = GET_COL_SOURCE; 5243c58b3526SAdam Stevko break; 5244c58b3526SAdam Stevko case 4: 5245c58b3526SAdam Stevko if (i > 0) { 5246c58b3526SAdam Stevko (void) fprintf(stderr, 5247c58b3526SAdam Stevko gettext("\"all\" conflicts " 5248c58b3526SAdam Stevko "with specific fields " 5249c58b3526SAdam Stevko "given to -o option\n")); 5250c58b3526SAdam Stevko usage(B_FALSE); 5251c58b3526SAdam Stevko } 5252c58b3526SAdam Stevko cb.cb_columns[0] = GET_COL_NAME; 5253c58b3526SAdam Stevko cb.cb_columns[1] = GET_COL_PROPERTY; 5254c58b3526SAdam Stevko cb.cb_columns[2] = GET_COL_VALUE; 5255c58b3526SAdam Stevko cb.cb_columns[3] = GET_COL_SOURCE; 5256c58b3526SAdam Stevko i = ZFS_GET_NCOLS; 5257c58b3526SAdam Stevko break; 5258c58b3526SAdam Stevko default: 5259c58b3526SAdam Stevko (void) fprintf(stderr, 5260c58b3526SAdam Stevko gettext("invalid column name " 5261c58b3526SAdam Stevko "'%s'\n"), value); 5262c58b3526SAdam Stevko usage(B_FALSE); 5263c58b3526SAdam Stevko } 5264c58b3526SAdam Stevko } 5265c58b3526SAdam Stevko break; 5266c58b3526SAdam Stevko case '?': 5267c58b3526SAdam Stevko (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5268c58b3526SAdam Stevko optopt); 5269c58b3526SAdam Stevko usage(B_FALSE); 5270c58b3526SAdam Stevko } 5271c58b3526SAdam Stevko } 5272c58b3526SAdam Stevko 5273c58b3526SAdam Stevko argc -= optind; 5274c58b3526SAdam Stevko argv += optind; 5275c58b3526SAdam Stevko 5276c58b3526SAdam Stevko if (argc < 1) { 5277c58b3526SAdam Stevko (void) fprintf(stderr, gettext("missing property " 5278c58b3526SAdam Stevko "argument\n")); 5279c58b3526SAdam Stevko usage(B_FALSE); 5280c58b3526SAdam Stevko } 5281c58b3526SAdam Stevko 5282c58b3526SAdam Stevko if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, 5283990b4856Slling ZFS_TYPE_POOL) != 0) 5284b1b8ab34Slling usage(B_FALSE); 5285b1b8ab34Slling 5286c58b3526SAdam Stevko argc--; 5287c58b3526SAdam Stevko argv++; 5288c58b3526SAdam Stevko 5289b1b8ab34Slling if (cb.cb_proplist != NULL) { 5290990b4856Slling fake_name.pl_prop = ZPOOL_PROP_NAME; 5291b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 5292b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 5293b1b8ab34Slling cb.cb_proplist = &fake_name; 5294b1b8ab34Slling } 5295b1b8ab34Slling 5296c58b3526SAdam Stevko ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 5297b1b8ab34Slling get_callback, &cb); 5298b1b8ab34Slling 5299b1b8ab34Slling if (cb.cb_proplist == &fake_name) 5300990b4856Slling zprop_free_list(fake_name.pl_next); 5301b1b8ab34Slling else 5302990b4856Slling zprop_free_list(cb.cb_proplist); 5303b1b8ab34Slling 5304b1b8ab34Slling return (ret); 5305b1b8ab34Slling } 5306b1b8ab34Slling 5307b1b8ab34Slling typedef struct set_cbdata { 5308b1b8ab34Slling char *cb_propname; 5309b1b8ab34Slling char *cb_value; 5310b1b8ab34Slling boolean_t cb_any_successful; 5311b1b8ab34Slling } set_cbdata_t; 5312b1b8ab34Slling 5313b1b8ab34Slling int 5314b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 5315b1b8ab34Slling { 5316b1b8ab34Slling int error; 5317b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 5318b1b8ab34Slling 5319b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 5320b1b8ab34Slling 5321b1b8ab34Slling if (!error) 5322b1b8ab34Slling cb->cb_any_successful = B_TRUE; 5323b1b8ab34Slling 5324b1b8ab34Slling return (error); 5325b1b8ab34Slling } 5326b1b8ab34Slling 5327b1b8ab34Slling int 5328b1b8ab34Slling zpool_do_set(int argc, char **argv) 5329b1b8ab34Slling { 5330b1b8ab34Slling set_cbdata_t cb = { 0 }; 5331b1b8ab34Slling int error; 5332b1b8ab34Slling 5333b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 5334b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5335b1b8ab34Slling argv[1][1]); 5336b1b8ab34Slling usage(B_FALSE); 5337b1b8ab34Slling } 5338b1b8ab34Slling 5339b1b8ab34Slling if (argc < 2) { 5340b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 5341b1b8ab34Slling "argument\n")); 5342b1b8ab34Slling usage(B_FALSE); 5343b1b8ab34Slling } 5344b1b8ab34Slling 5345b1b8ab34Slling if (argc < 3) { 5346b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 5347b1b8ab34Slling usage(B_FALSE); 5348b1b8ab34Slling } 5349b1b8ab34Slling 5350b1b8ab34Slling if (argc > 3) { 5351b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 5352b1b8ab34Slling usage(B_FALSE); 5353b1b8ab34Slling } 5354b1b8ab34Slling 5355b1b8ab34Slling cb.cb_propname = argv[1]; 5356b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 5357b1b8ab34Slling if (cb.cb_value == NULL) { 5358b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 5359b1b8ab34Slling "property=value argument\n")); 5360b1b8ab34Slling usage(B_FALSE); 5361b1b8ab34Slling } 5362b1b8ab34Slling 5363b1b8ab34Slling *(cb.cb_value) = '\0'; 5364b1b8ab34Slling cb.cb_value++; 5365b1b8ab34Slling 5366b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 5367b1b8ab34Slling set_callback, &cb); 5368b1b8ab34Slling 5369b1b8ab34Slling return (error); 5370b1b8ab34Slling } 5371b1b8ab34Slling 5372b1b8ab34Slling static int 5373b1b8ab34Slling find_command_idx(char *command, int *idx) 5374b1b8ab34Slling { 5375b1b8ab34Slling int i; 5376b1b8ab34Slling 5377b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 5378b1b8ab34Slling if (command_table[i].name == NULL) 5379b1b8ab34Slling continue; 5380b1b8ab34Slling 5381b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 5382b1b8ab34Slling *idx = i; 5383b1b8ab34Slling return (0); 5384b1b8ab34Slling } 5385b1b8ab34Slling } 5386b1b8ab34Slling return (1); 5387b1b8ab34Slling } 5388b1b8ab34Slling 5389fa9e4066Sahrens int 5390fa9e4066Sahrens main(int argc, char **argv) 5391fa9e4066Sahrens { 5392b327cd3fSIgor Kozhukhov int ret = 0; 5393fa9e4066Sahrens int i; 5394fa9e4066Sahrens char *cmdname; 5395fa9e4066Sahrens 5396fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 5397fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 5398fa9e4066Sahrens 539999653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 540099653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 5401203a47d8Snd "initialize ZFS library\n")); 540299653d4eSeschrock return (1); 540399653d4eSeschrock } 540499653d4eSeschrock 540599653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 540699653d4eSeschrock 5407fa9e4066Sahrens opterr = 0; 5408fa9e4066Sahrens 5409fa9e4066Sahrens /* 5410fa9e4066Sahrens * Make sure the user has specified some command. 5411fa9e4066Sahrens */ 5412fa9e4066Sahrens if (argc < 2) { 5413fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 541499653d4eSeschrock usage(B_FALSE); 5415fa9e4066Sahrens } 5416fa9e4066Sahrens 5417fa9e4066Sahrens cmdname = argv[1]; 5418fa9e4066Sahrens 5419fa9e4066Sahrens /* 5420fa9e4066Sahrens * Special case '-?' 5421fa9e4066Sahrens */ 5422fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 542399653d4eSeschrock usage(B_TRUE); 5424fa9e4066Sahrens 54254445fffbSMatthew Ahrens zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); 54262a6b87f0Sek 5427fa9e4066Sahrens /* 5428fa9e4066Sahrens * Run the appropriate command. 5429fa9e4066Sahrens */ 5430b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 5431b1b8ab34Slling current_command = &command_table[i]; 5432b1b8ab34Slling ret = command_table[i].func(argc - 1, argv + 1); 543391ebeef5Sahrens } else if (strchr(cmdname, '=')) { 543491ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 543591ebeef5Sahrens current_command = &command_table[i]; 543691ebeef5Sahrens ret = command_table[i].func(argc, argv); 543791ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 543891ebeef5Sahrens /* 543991ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 544091ebeef5Sahrens * it as such. 544191ebeef5Sahrens */ 5442ea8dc4b6Seschrock char buf[16384]; 5443ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 5444fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 5445fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 544691ebeef5Sahrens } else { 5447fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 5448fa9e4066Sahrens "command '%s'\n"), cmdname); 544999653d4eSeschrock usage(B_FALSE); 5450fa9e4066Sahrens } 5451fa9e4066Sahrens 54524445fffbSMatthew Ahrens if (ret == 0 && log_history) 54534445fffbSMatthew Ahrens (void) zpool_log_history(g_zfs, history_str); 54544445fffbSMatthew Ahrens 545599653d4eSeschrock libzfs_fini(g_zfs); 545699653d4eSeschrock 5457fa9e4066Sahrens /* 5458fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 5459fa9e4066Sahrens * for the purposes of running ::findleaks. 5460fa9e4066Sahrens */ 5461fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 5462fa9e4066Sahrens (void) printf("dumping core by request\n"); 5463fa9e4066Sahrens abort(); 5464fa9e4066Sahrens } 5465fa9e4066Sahrens 5466fa9e4066Sahrens return (ret); 5467fa9e4066Sahrens } 5468