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. 24dfc11533SChris Williamson * Copyright (c) 2011, 2016 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>. 286401734dSWill Andrews * Copyright 2016 Nexenta Systems, Inc. 29*1702cce7SAlek Pinchuk * Copyright (c) 2017 Datto Inc. 30fa9e4066Sahrens */ 31fa9e4066Sahrens 32fa9e4066Sahrens #include <assert.h> 33fa9e4066Sahrens #include <ctype.h> 34fa9e4066Sahrens #include <dirent.h> 35fa9e4066Sahrens #include <errno.h> 36fa9e4066Sahrens #include <fcntl.h> 37fa9e4066Sahrens #include <libgen.h> 38fa9e4066Sahrens #include <libintl.h> 39fa9e4066Sahrens #include <libuutil.h> 40fa9e4066Sahrens #include <locale.h> 41fa9e4066Sahrens #include <stdio.h> 42fa9e4066Sahrens #include <stdlib.h> 43fa9e4066Sahrens #include <string.h> 44fa9e4066Sahrens #include <strings.h> 45fa9e4066Sahrens #include <unistd.h> 46fa9e4066Sahrens #include <priv.h> 47ecd6cf80Smarks #include <pwd.h> 48ecd6cf80Smarks #include <zone.h> 494263d13fSGeorge Wilson #include <zfs_prop.h> 50b1b8ab34Slling #include <sys/fs/zfs.h> 51fa9e4066Sahrens #include <sys/stat.h> 52fa9e4066Sahrens 53fa9e4066Sahrens #include <libzfs.h> 54fa9e4066Sahrens 55fa9e4066Sahrens #include "zpool_util.h" 56b7b97454Sperrin #include "zfs_comutil.h" 57ad135b5dSChristopher Siden #include "zfeature_common.h" 58fa9e4066Sahrens 5926fd7700SKrishnendu Sadhukhan - Sun Microsystems #include "statcommon.h" 6026fd7700SKrishnendu Sadhukhan - Sun Microsystems 61fa9e4066Sahrens static int zpool_do_create(int, char **); 62fa9e4066Sahrens static int zpool_do_destroy(int, char **); 63fa9e4066Sahrens 64fa9e4066Sahrens static int zpool_do_add(int, char **); 6599653d4eSeschrock static int zpool_do_remove(int, char **); 666401734dSWill Andrews static int zpool_do_labelclear(int, char **); 67fa9e4066Sahrens 68fa9e4066Sahrens static int zpool_do_list(int, char **); 69fa9e4066Sahrens static int zpool_do_iostat(int, char **); 70fa9e4066Sahrens static int zpool_do_status(int, char **); 71fa9e4066Sahrens 72fa9e4066Sahrens static int zpool_do_online(int, char **); 73fa9e4066Sahrens static int zpool_do_offline(int, char **); 74ea8dc4b6Seschrock static int zpool_do_clear(int, char **); 754263d13fSGeorge Wilson static int zpool_do_reopen(int, char **); 76fa9e4066Sahrens 77e9103aaeSGarrett D'Amore static int zpool_do_reguid(int, char **); 78e9103aaeSGarrett D'Amore 79fa9e4066Sahrens static int zpool_do_attach(int, char **); 80fa9e4066Sahrens static int zpool_do_detach(int, char **); 81fa9e4066Sahrens static int zpool_do_replace(int, char **); 821195e687SMark J Musante static int zpool_do_split(int, char **); 83fa9e4066Sahrens 84fa9e4066Sahrens static int zpool_do_scrub(int, char **); 85fa9e4066Sahrens 86fa9e4066Sahrens static int zpool_do_import(int, char **); 87fa9e4066Sahrens static int zpool_do_export(int, char **); 88fa9e4066Sahrens 89eaca9bbdSeschrock static int zpool_do_upgrade(int, char **); 90eaca9bbdSeschrock 9106eeb2adSek static int zpool_do_history(int, char **); 9206eeb2adSek 93b1b8ab34Slling static int zpool_do_get(int, char **); 94b1b8ab34Slling static int zpool_do_set(int, char **); 95b1b8ab34Slling 96fa9e4066Sahrens /* 97fa9e4066Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 98fa9e4066Sahrens * debugging facilities. 99fa9e4066Sahrens */ 10029ab75c9Srm 10129ab75c9Srm #ifdef DEBUG 102fa9e4066Sahrens const char * 10399653d4eSeschrock _umem_debug_init(void) 104fa9e4066Sahrens { 105fa9e4066Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 106fa9e4066Sahrens } 107fa9e4066Sahrens 108fa9e4066Sahrens const char * 109fa9e4066Sahrens _umem_logging_init(void) 110fa9e4066Sahrens { 111fa9e4066Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 112fa9e4066Sahrens } 11329ab75c9Srm #endif 114fa9e4066Sahrens 11565cd9f28Seschrock typedef enum { 11665cd9f28Seschrock HELP_ADD, 11765cd9f28Seschrock HELP_ATTACH, 118ea8dc4b6Seschrock HELP_CLEAR, 11965cd9f28Seschrock HELP_CREATE, 12065cd9f28Seschrock HELP_DESTROY, 12165cd9f28Seschrock HELP_DETACH, 12265cd9f28Seschrock HELP_EXPORT, 12306eeb2adSek HELP_HISTORY, 12465cd9f28Seschrock HELP_IMPORT, 12565cd9f28Seschrock HELP_IOSTAT, 1266401734dSWill Andrews HELP_LABELCLEAR, 12765cd9f28Seschrock HELP_LIST, 12865cd9f28Seschrock HELP_OFFLINE, 12965cd9f28Seschrock HELP_ONLINE, 13065cd9f28Seschrock HELP_REPLACE, 13199653d4eSeschrock HELP_REMOVE, 13265cd9f28Seschrock HELP_SCRUB, 133eaca9bbdSeschrock HELP_STATUS, 134b1b8ab34Slling HELP_UPGRADE, 135b1b8ab34Slling HELP_GET, 1361195e687SMark J Musante HELP_SET, 137e9103aaeSGarrett D'Amore HELP_SPLIT, 1384263d13fSGeorge Wilson HELP_REGUID, 1394263d13fSGeorge Wilson HELP_REOPEN 14065cd9f28Seschrock } zpool_help_t; 14165cd9f28Seschrock 14265cd9f28Seschrock 143fa9e4066Sahrens typedef struct zpool_command { 144fa9e4066Sahrens const char *name; 145fa9e4066Sahrens int (*func)(int, char **); 14665cd9f28Seschrock zpool_help_t usage; 147fa9e4066Sahrens } zpool_command_t; 148fa9e4066Sahrens 149fa9e4066Sahrens /* 150fa9e4066Sahrens * Master command table. Each ZFS command has a name, associated function, and 151ea8dc4b6Seschrock * usage message. The usage messages need to be internationalized, so we have 152ea8dc4b6Seschrock * to have a function to return the usage message based on a command index. 15365cd9f28Seschrock * 15465cd9f28Seschrock * These commands are organized according to how they are displayed in the usage 15565cd9f28Seschrock * message. An empty command (one with a NULL name) indicates an empty line in 15665cd9f28Seschrock * the generic usage message. 157fa9e4066Sahrens */ 158fa9e4066Sahrens static zpool_command_t command_table[] = { 15965cd9f28Seschrock { "create", zpool_do_create, HELP_CREATE }, 16065cd9f28Seschrock { "destroy", zpool_do_destroy, HELP_DESTROY }, 161fa9e4066Sahrens { NULL }, 16265cd9f28Seschrock { "add", zpool_do_add, HELP_ADD }, 16399653d4eSeschrock { "remove", zpool_do_remove, HELP_REMOVE }, 164fa9e4066Sahrens { NULL }, 1656401734dSWill Andrews { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 1666401734dSWill Andrews { NULL }, 16765cd9f28Seschrock { "list", zpool_do_list, HELP_LIST }, 16865cd9f28Seschrock { "iostat", zpool_do_iostat, HELP_IOSTAT }, 16965cd9f28Seschrock { "status", zpool_do_status, HELP_STATUS }, 170fa9e4066Sahrens { NULL }, 17165cd9f28Seschrock { "online", zpool_do_online, HELP_ONLINE }, 17265cd9f28Seschrock { "offline", zpool_do_offline, HELP_OFFLINE }, 173ea8dc4b6Seschrock { "clear", zpool_do_clear, HELP_CLEAR }, 1744263d13fSGeorge Wilson { "reopen", zpool_do_reopen, HELP_REOPEN }, 175fa9e4066Sahrens { NULL }, 17665cd9f28Seschrock { "attach", zpool_do_attach, HELP_ATTACH }, 17765cd9f28Seschrock { "detach", zpool_do_detach, HELP_DETACH }, 17865cd9f28Seschrock { "replace", zpool_do_replace, HELP_REPLACE }, 1791195e687SMark J Musante { "split", zpool_do_split, HELP_SPLIT }, 180fa9e4066Sahrens { NULL }, 18165cd9f28Seschrock { "scrub", zpool_do_scrub, HELP_SCRUB }, 182fa9e4066Sahrens { NULL }, 18365cd9f28Seschrock { "import", zpool_do_import, HELP_IMPORT }, 18465cd9f28Seschrock { "export", zpool_do_export, HELP_EXPORT }, 18506eeb2adSek { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 186e9103aaeSGarrett D'Amore { "reguid", zpool_do_reguid, HELP_REGUID }, 18706eeb2adSek { NULL }, 188b1b8ab34Slling { "history", zpool_do_history, HELP_HISTORY }, 189b1b8ab34Slling { "get", zpool_do_get, HELP_GET }, 190b1b8ab34Slling { "set", zpool_do_set, HELP_SET }, 191fa9e4066Sahrens }; 192fa9e4066Sahrens 193fa9e4066Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 194fa9e4066Sahrens 1954445fffbSMatthew Ahrens static zpool_command_t *current_command; 1962a6b87f0Sek static char history_str[HIS_MAX_RECORD_LEN]; 1974445fffbSMatthew Ahrens static boolean_t log_history = B_TRUE; 19826fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE; 19926fd7700SKrishnendu Sadhukhan - Sun Microsystems 20065cd9f28Seschrock static const char * 2019a686fbcSPaul Dagnelie get_usage(zpool_help_t idx) 2029a686fbcSPaul Dagnelie { 20365cd9f28Seschrock switch (idx) { 20465cd9f28Seschrock case HELP_ADD: 20565cd9f28Seschrock return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 20665cd9f28Seschrock case HELP_ATTACH: 20765cd9f28Seschrock return (gettext("\tattach [-f] <pool> <device> " 208e45ce728Sahrens "<new-device>\n")); 209ea8dc4b6Seschrock case HELP_CLEAR: 210468c413aSTim Haley return (gettext("\tclear [-nF] <pool> [device]\n")); 21165cd9f28Seschrock case HELP_CREATE: 2127855d95bSToomas Soome return (gettext("\tcreate [-fnd] [-B] " 2137855d95bSToomas Soome "[-o property=value] ... \n" 2140a48a24eStimh "\t [-O file-system-property=value] ... \n" 215990b4856Slling "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 21665cd9f28Seschrock case HELP_DESTROY: 21765cd9f28Seschrock return (gettext("\tdestroy [-f] <pool>\n")); 21865cd9f28Seschrock case HELP_DETACH: 21965cd9f28Seschrock return (gettext("\tdetach <pool> <device>\n")); 22065cd9f28Seschrock case HELP_EXPORT: 22165cd9f28Seschrock return (gettext("\texport [-f] <pool> ...\n")); 22206eeb2adSek case HELP_HISTORY: 223ecd6cf80Smarks return (gettext("\thistory [-il] [<pool>] ...\n")); 22465cd9f28Seschrock case HELP_IMPORT: 2254c58d714Sdarrenm return (gettext("\timport [-d dir] [-D]\n" 226f9af39baSGeorge Wilson "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 2272f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 228f9af39baSGeorge Wilson "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 229f9af39baSGeorge Wilson "[-R root] [-F [-n]] -a\n" 2302f8aaab3Seschrock "\timport [-o mntopts] [-o property=value] ... \n" 231f9af39baSGeorge Wilson "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 232f9af39baSGeorge Wilson "[-R root] [-F [-n]]\n" 233f9af39baSGeorge Wilson "\t <pool | id> [newpool]\n")); 23465cd9f28Seschrock case HELP_IOSTAT: 23526fd7700SKrishnendu Sadhukhan - Sun Microsystems return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 23665cd9f28Seschrock "[count]]\n")); 2376401734dSWill Andrews case HELP_LABELCLEAR: 2386401734dSWill Andrews return (gettext("\tlabelclear [-f] <vdev>\n")); 23965cd9f28Seschrock case HELP_LIST: 240c58b3526SAdam Stevko return (gettext("\tlist [-Hp] [-o property[,...]] " 2413f9d6ad7SLin Ling "[-T d|u] [pool] ... [interval [count]]\n")); 24265cd9f28Seschrock case HELP_OFFLINE: 243441d80aaSlling return (gettext("\toffline [-t] <pool> <device> ...\n")); 24465cd9f28Seschrock case HELP_ONLINE: 245441d80aaSlling return (gettext("\tonline <pool> <device> ...\n")); 24665cd9f28Seschrock case HELP_REPLACE: 24765cd9f28Seschrock return (gettext("\treplace [-f] <pool> <device> " 248e45ce728Sahrens "[new-device]\n")); 24999653d4eSeschrock case HELP_REMOVE: 250fa94a07fSbrendan return (gettext("\tremove <pool> <device> ...\n")); 2514263d13fSGeorge Wilson case HELP_REOPEN: 25231d7e8faSGeorge Wilson return (gettext("\treopen <pool>\n")); 25365cd9f28Seschrock case HELP_SCRUB: 254*1702cce7SAlek Pinchuk return (gettext("\tscrub [-s | -p] <pool> ...\n")); 25565cd9f28Seschrock case HELP_STATUS: 2563f9d6ad7SLin Ling return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 2573f9d6ad7SLin Ling "[count]]\n")); 258eaca9bbdSeschrock case HELP_UPGRADE: 259eaca9bbdSeschrock return (gettext("\tupgrade\n" 260eaca9bbdSeschrock "\tupgrade -v\n" 261990b4856Slling "\tupgrade [-V version] <-a | pool ...>\n")); 262b1b8ab34Slling case HELP_GET: 263c58b3526SAdam Stevko return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] " 264c58b3526SAdam Stevko "<\"all\" | property[,...]> <pool> ...\n")); 265b1b8ab34Slling case HELP_SET: 266b1b8ab34Slling return (gettext("\tset <property=value> <pool> \n")); 2671195e687SMark J Musante case HELP_SPLIT: 2681195e687SMark J Musante return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 2691195e687SMark J Musante "\t [-o property=value] <pool> <newpool> " 2701195e687SMark J Musante "[<device> ...]\n")); 271e9103aaeSGarrett D'Amore case HELP_REGUID: 272e9103aaeSGarrett D'Amore return (gettext("\treguid <pool>\n")); 27365cd9f28Seschrock } 27465cd9f28Seschrock 27565cd9f28Seschrock abort(); 27665cd9f28Seschrock /* NOTREACHED */ 27765cd9f28Seschrock } 27865cd9f28Seschrock 279fa9e4066Sahrens 280b1b8ab34Slling /* 281b1b8ab34Slling * Callback routine that will print out a pool property value. 282b1b8ab34Slling */ 283990b4856Slling static int 284990b4856Slling print_prop_cb(int prop, void *cb) 285b1b8ab34Slling { 286b1b8ab34Slling FILE *fp = cb; 287b1b8ab34Slling 288b24ab676SJeff Bonwick (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 289b1b8ab34Slling 290990b4856Slling if (zpool_prop_readonly(prop)) 291990b4856Slling (void) fprintf(fp, " NO "); 292990b4856Slling else 293b24ab676SJeff Bonwick (void) fprintf(fp, " YES "); 294990b4856Slling 295b1b8ab34Slling if (zpool_prop_values(prop) == NULL) 296b1b8ab34Slling (void) fprintf(fp, "-\n"); 297b1b8ab34Slling else 298b1b8ab34Slling (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 299b1b8ab34Slling 300990b4856Slling return (ZPROP_CONT); 301b1b8ab34Slling } 302b1b8ab34Slling 303fa9e4066Sahrens /* 304fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 305fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 306fa9e4066Sahrens * a complete usage message. 307fa9e4066Sahrens */ 308fa9e4066Sahrens void 30999653d4eSeschrock usage(boolean_t requested) 310fa9e4066Sahrens { 311fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 312fa9e4066Sahrens 313fa9e4066Sahrens if (current_command == NULL) { 314fa9e4066Sahrens int i; 315fa9e4066Sahrens 316fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 317fa9e4066Sahrens (void) fprintf(fp, 318fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 319fa9e4066Sahrens 320fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 321fa9e4066Sahrens if (command_table[i].name == NULL) 322fa9e4066Sahrens (void) fprintf(fp, "\n"); 323fa9e4066Sahrens else 324fa9e4066Sahrens (void) fprintf(fp, "%s", 32565cd9f28Seschrock get_usage(command_table[i].usage)); 326fa9e4066Sahrens } 327fa9e4066Sahrens } else { 328fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 32965cd9f28Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 330fa9e4066Sahrens } 331fa9e4066Sahrens 332b1b8ab34Slling if (current_command != NULL && 333b1b8ab34Slling ((strcmp(current_command->name, "set") == 0) || 334990b4856Slling (strcmp(current_command->name, "get") == 0) || 335990b4856Slling (strcmp(current_command->name, "list") == 0))) { 336b1b8ab34Slling 337b1b8ab34Slling (void) fprintf(fp, 338b1b8ab34Slling gettext("\nthe following properties are supported:\n")); 339b1b8ab34Slling 340b24ab676SJeff Bonwick (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 341990b4856Slling "PROPERTY", "EDIT", "VALUES"); 342b1b8ab34Slling 343b1b8ab34Slling /* Iterate over all properties */ 344990b4856Slling (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 345990b4856Slling ZFS_TYPE_POOL); 346ad135b5dSChristopher Siden 347ad135b5dSChristopher Siden (void) fprintf(fp, "\t%-15s ", "feature@..."); 348ad135b5dSChristopher Siden (void) fprintf(fp, "YES disabled | enabled | active\n"); 349ad135b5dSChristopher Siden 350ad135b5dSChristopher Siden (void) fprintf(fp, gettext("\nThe feature@ properties must be " 351ad135b5dSChristopher Siden "appended with a feature name.\nSee zpool-features(5).\n")); 352b1b8ab34Slling } 353b1b8ab34Slling 354e9dbad6fSeschrock /* 355e9dbad6fSeschrock * See comments at end of main(). 356e9dbad6fSeschrock */ 357e9dbad6fSeschrock if (getenv("ZFS_ABORT") != NULL) { 358e9dbad6fSeschrock (void) printf("dumping core by request\n"); 359e9dbad6fSeschrock abort(); 360e9dbad6fSeschrock } 361e9dbad6fSeschrock 362fa9e4066Sahrens exit(requested ? 0 : 2); 363fa9e4066Sahrens } 364fa9e4066Sahrens 365fa9e4066Sahrens void 3668654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 3678654d025Sperrin boolean_t print_logs) 368fa9e4066Sahrens { 369fa9e4066Sahrens nvlist_t **child; 370fa9e4066Sahrens uint_t c, children; 371afefbcddSeschrock char *vname; 372fa9e4066Sahrens 373fa9e4066Sahrens if (name != NULL) 374fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 375fa9e4066Sahrens 376fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 377fa9e4066Sahrens &child, &children) != 0) 378fa9e4066Sahrens return; 379fa9e4066Sahrens 380afefbcddSeschrock for (c = 0; c < children; c++) { 3818654d025Sperrin uint64_t is_log = B_FALSE; 3828654d025Sperrin 3838654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3848654d025Sperrin &is_log); 3858654d025Sperrin if ((is_log && !print_logs) || (!is_log && print_logs)) 3868654d025Sperrin continue; 3878654d025Sperrin 38888ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3898654d025Sperrin print_vdev_tree(zhp, vname, child[c], indent + 2, 3908654d025Sperrin B_FALSE); 391afefbcddSeschrock free(vname); 392afefbcddSeschrock } 393fa9e4066Sahrens } 394fa9e4066Sahrens 39557221772SChristopher Siden static boolean_t 39657221772SChristopher Siden prop_list_contains_feature(nvlist_t *proplist) 39757221772SChristopher Siden { 39857221772SChristopher Siden nvpair_t *nvp; 39957221772SChristopher Siden for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; 40057221772SChristopher Siden nvp = nvlist_next_nvpair(proplist, nvp)) { 40157221772SChristopher Siden if (zpool_prop_feature(nvpair_name(nvp))) 40257221772SChristopher Siden return (B_TRUE); 40357221772SChristopher Siden } 40457221772SChristopher Siden return (B_FALSE); 40557221772SChristopher Siden } 40657221772SChristopher Siden 407990b4856Slling /* 408990b4856Slling * Add a property pair (name, string-value) into a property nvlist. 409990b4856Slling */ 410990b4856Slling static int 4110a48a24eStimh add_prop_list(const char *propname, char *propval, nvlist_t **props, 4120a48a24eStimh boolean_t poolprop) 413990b4856Slling { 4140a48a24eStimh zpool_prop_t prop = ZPROP_INVAL; 4150a48a24eStimh zfs_prop_t fprop; 416990b4856Slling nvlist_t *proplist; 4170a48a24eStimh const char *normnm; 4180a48a24eStimh char *strval; 419990b4856Slling 420990b4856Slling if (*props == NULL && 421990b4856Slling nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 422990b4856Slling (void) fprintf(stderr, 423990b4856Slling gettext("internal error: out of memory\n")); 424990b4856Slling return (1); 425990b4856Slling } 426990b4856Slling 427990b4856Slling proplist = *props; 428990b4856Slling 4290a48a24eStimh if (poolprop) { 43057221772SChristopher Siden const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); 43157221772SChristopher Siden 432ad135b5dSChristopher Siden if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 433ad135b5dSChristopher Siden !zpool_prop_feature(propname)) { 4340a48a24eStimh (void) fprintf(stderr, gettext("property '%s' is " 4350a48a24eStimh "not a valid pool property\n"), propname); 4360a48a24eStimh return (2); 4370a48a24eStimh } 43857221772SChristopher Siden 43957221772SChristopher Siden /* 44057221772SChristopher Siden * feature@ properties and version should not be specified 44157221772SChristopher Siden * at the same time. 44257221772SChristopher Siden */ 44357221772SChristopher Siden if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && 44457221772SChristopher Siden nvlist_exists(proplist, vname)) || 44557221772SChristopher Siden (prop == ZPOOL_PROP_VERSION && 44657221772SChristopher Siden prop_list_contains_feature(proplist))) { 44757221772SChristopher Siden (void) fprintf(stderr, gettext("'feature@' and " 44857221772SChristopher Siden "'version' properties cannot be specified " 44957221772SChristopher Siden "together\n")); 45057221772SChristopher Siden return (2); 45157221772SChristopher Siden } 45257221772SChristopher Siden 45357221772SChristopher Siden 454ad135b5dSChristopher Siden if (zpool_prop_feature(propname)) 455ad135b5dSChristopher Siden normnm = propname; 456ad135b5dSChristopher Siden else 457ad135b5dSChristopher Siden normnm = zpool_prop_to_name(prop); 4580a48a24eStimh } else { 45914843421SMatthew Ahrens if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 46014843421SMatthew Ahrens normnm = zfs_prop_to_name(fprop); 46114843421SMatthew Ahrens } else { 46214843421SMatthew Ahrens normnm = propname; 4630a48a24eStimh } 464990b4856Slling } 465990b4856Slling 4660a48a24eStimh if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 4670a48a24eStimh prop != ZPOOL_PROP_CACHEFILE) { 468990b4856Slling (void) fprintf(stderr, gettext("property '%s' " 469990b4856Slling "specified multiple times\n"), propname); 470990b4856Slling return (2); 471990b4856Slling } 472990b4856Slling 4730a48a24eStimh if (nvlist_add_string(proplist, normnm, propval) != 0) { 474990b4856Slling (void) fprintf(stderr, gettext("internal " 475990b4856Slling "error: out of memory\n")); 476990b4856Slling return (1); 477990b4856Slling } 478990b4856Slling 479990b4856Slling return (0); 480990b4856Slling } 481990b4856Slling 482fa9e4066Sahrens /* 483fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 484fa9e4066Sahrens * 485fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 486fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 487fa9e4066Sahrens * they were to be added. 488fa9e4066Sahrens * 489fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 490fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 491fa9e4066Sahrens * libzfs. 492fa9e4066Sahrens */ 493fa9e4066Sahrens int 494fa9e4066Sahrens zpool_do_add(int argc, char **argv) 495fa9e4066Sahrens { 49699653d4eSeschrock boolean_t force = B_FALSE; 49799653d4eSeschrock boolean_t dryrun = B_FALSE; 498fa9e4066Sahrens int c; 499fa9e4066Sahrens nvlist_t *nvroot; 500fa9e4066Sahrens char *poolname; 5017855d95bSToomas Soome zpool_boot_label_t boot_type; 5027855d95bSToomas Soome uint64_t boot_size; 503fa9e4066Sahrens int ret; 504fa9e4066Sahrens zpool_handle_t *zhp; 505fa9e4066Sahrens nvlist_t *config; 506fa9e4066Sahrens 507fa9e4066Sahrens /* check options */ 508fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 509fa9e4066Sahrens switch (c) { 510fa9e4066Sahrens case 'f': 51199653d4eSeschrock force = B_TRUE; 512fa9e4066Sahrens break; 513fa9e4066Sahrens case 'n': 51499653d4eSeschrock dryrun = B_TRUE; 515fa9e4066Sahrens break; 516fa9e4066Sahrens case '?': 517fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 518fa9e4066Sahrens optopt); 51999653d4eSeschrock usage(B_FALSE); 520fa9e4066Sahrens } 521fa9e4066Sahrens } 522fa9e4066Sahrens 523fa9e4066Sahrens argc -= optind; 524fa9e4066Sahrens argv += optind; 525fa9e4066Sahrens 526fa9e4066Sahrens /* get pool name and check number of arguments */ 527fa9e4066Sahrens if (argc < 1) { 528fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 52999653d4eSeschrock usage(B_FALSE); 530fa9e4066Sahrens } 531fa9e4066Sahrens if (argc < 2) { 532fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 53399653d4eSeschrock usage(B_FALSE); 534fa9e4066Sahrens } 535fa9e4066Sahrens 536fa9e4066Sahrens poolname = argv[0]; 537fa9e4066Sahrens 538fa9e4066Sahrens argc--; 539fa9e4066Sahrens argv++; 540fa9e4066Sahrens 54199653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 542fa9e4066Sahrens return (1); 543fa9e4066Sahrens 544088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) == NULL) { 545fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 546fa9e4066Sahrens poolname); 547fa9e4066Sahrens zpool_close(zhp); 548fa9e4066Sahrens return (1); 549fa9e4066Sahrens } 550fa9e4066Sahrens 5517855d95bSToomas Soome if (zpool_is_bootable(zhp)) 5527855d95bSToomas Soome boot_type = ZPOOL_COPY_BOOT_LABEL; 5537855d95bSToomas Soome else 5547855d95bSToomas Soome boot_type = ZPOOL_NO_BOOT_LABEL; 5557855d95bSToomas Soome 556fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 5577855d95bSToomas Soome boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL); 558705040edSEric Taylor nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 5597855d95bSToomas Soome boot_type, boot_size, argc, argv); 560fa9e4066Sahrens if (nvroot == NULL) { 561fa9e4066Sahrens zpool_close(zhp); 562fa9e4066Sahrens return (1); 563fa9e4066Sahrens } 564fa9e4066Sahrens 565fa9e4066Sahrens if (dryrun) { 566fa9e4066Sahrens nvlist_t *poolnvroot; 567fa9e4066Sahrens 568fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 569fa9e4066Sahrens &poolnvroot) == 0); 570fa9e4066Sahrens 571fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 572fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 573fa9e4066Sahrens 5748654d025Sperrin /* print original main pool and new tree */ 5758654d025Sperrin print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 5768654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 5778654d025Sperrin 5788654d025Sperrin /* Do the same for the logs */ 5798654d025Sperrin if (num_logs(poolnvroot) > 0) { 5808654d025Sperrin print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 5818654d025Sperrin print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 5828654d025Sperrin } else if (num_logs(nvroot) > 0) { 5838654d025Sperrin print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 5848654d025Sperrin } 585fa9e4066Sahrens 586fa9e4066Sahrens ret = 0; 587fa9e4066Sahrens } else { 588fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 589fa9e4066Sahrens } 590fa9e4066Sahrens 59199653d4eSeschrock nvlist_free(nvroot); 59299653d4eSeschrock zpool_close(zhp); 59399653d4eSeschrock 59499653d4eSeschrock return (ret); 59599653d4eSeschrock } 59699653d4eSeschrock 59799653d4eSeschrock /* 5983f9d6ad7SLin Ling * zpool remove <pool> <vdev> ... 59999653d4eSeschrock * 6003f9d6ad7SLin Ling * Removes the given vdev from the pool. Currently, this supports removing 6013f9d6ad7SLin Ling * spares, cache, and log devices from the pool. 60299653d4eSeschrock */ 60399653d4eSeschrock int 60499653d4eSeschrock zpool_do_remove(int argc, char **argv) 60599653d4eSeschrock { 60699653d4eSeschrock char *poolname; 607fa94a07fSbrendan int i, ret = 0; 60899653d4eSeschrock zpool_handle_t *zhp; 60999653d4eSeschrock 61099653d4eSeschrock argc--; 61199653d4eSeschrock argv++; 61299653d4eSeschrock 61399653d4eSeschrock /* get pool name and check number of arguments */ 61499653d4eSeschrock if (argc < 1) { 61599653d4eSeschrock (void) fprintf(stderr, gettext("missing pool name argument\n")); 61699653d4eSeschrock usage(B_FALSE); 61799653d4eSeschrock } 61899653d4eSeschrock if (argc < 2) { 61999653d4eSeschrock (void) fprintf(stderr, gettext("missing device\n")); 62099653d4eSeschrock usage(B_FALSE); 62199653d4eSeschrock } 62299653d4eSeschrock 62399653d4eSeschrock poolname = argv[0]; 62499653d4eSeschrock 62599653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 62699653d4eSeschrock return (1); 62799653d4eSeschrock 628fa94a07fSbrendan for (i = 1; i < argc; i++) { 629fa94a07fSbrendan if (zpool_vdev_remove(zhp, argv[i]) != 0) 630fa94a07fSbrendan ret = 1; 631fa94a07fSbrendan } 63299653d4eSeschrock 633fa9e4066Sahrens return (ret); 634fa9e4066Sahrens } 635fa9e4066Sahrens 6366401734dSWill Andrews /* 6376401734dSWill Andrews * zpool labelclear [-f] <vdev> 6386401734dSWill Andrews * 6396401734dSWill Andrews * -f Force clearing the label for the vdevs which are members of 6406401734dSWill Andrews * the exported or foreign pools. 6416401734dSWill Andrews * 6426401734dSWill Andrews * Verifies that the vdev is not active and zeros out the label information 6436401734dSWill Andrews * on the device. 6446401734dSWill Andrews */ 6456401734dSWill Andrews int 6466401734dSWill Andrews zpool_do_labelclear(int argc, char **argv) 6476401734dSWill Andrews { 6486401734dSWill Andrews char vdev[MAXPATHLEN]; 6496401734dSWill Andrews char *name = NULL; 6506401734dSWill Andrews struct stat st; 6516401734dSWill Andrews int c, fd, ret = 0; 6526401734dSWill Andrews nvlist_t *config; 6536401734dSWill Andrews pool_state_t state; 6546401734dSWill Andrews boolean_t inuse = B_FALSE; 6556401734dSWill Andrews boolean_t force = B_FALSE; 6566401734dSWill Andrews 6576401734dSWill Andrews /* check options */ 6586401734dSWill Andrews while ((c = getopt(argc, argv, "f")) != -1) { 6596401734dSWill Andrews switch (c) { 6606401734dSWill Andrews case 'f': 6616401734dSWill Andrews force = B_TRUE; 6626401734dSWill Andrews break; 6636401734dSWill Andrews default: 6646401734dSWill Andrews (void) fprintf(stderr, gettext("invalid option '%c'\n"), 6656401734dSWill Andrews optopt); 6666401734dSWill Andrews usage(B_FALSE); 6676401734dSWill Andrews } 6686401734dSWill Andrews } 6696401734dSWill Andrews 6706401734dSWill Andrews argc -= optind; 6716401734dSWill Andrews argv += optind; 6726401734dSWill Andrews 6736401734dSWill Andrews /* get vdev name */ 6746401734dSWill Andrews if (argc < 1) { 6756401734dSWill Andrews (void) fprintf(stderr, gettext("missing vdev name\n")); 6766401734dSWill Andrews usage(B_FALSE); 6776401734dSWill Andrews } 6786401734dSWill Andrews if (argc > 1) { 6796401734dSWill Andrews (void) fprintf(stderr, gettext("too many arguments\n")); 6806401734dSWill Andrews usage(B_FALSE); 6816401734dSWill Andrews } 6826401734dSWill Andrews 6836401734dSWill Andrews /* 6846401734dSWill Andrews * Check if we were given absolute path and use it as is. 6856401734dSWill Andrews * Otherwise if the provided vdev name doesn't point to a file, 6866401734dSWill Andrews * try prepending dsk path and appending s0. 6876401734dSWill Andrews */ 6886401734dSWill Andrews (void) strlcpy(vdev, argv[0], sizeof (vdev)); 6896401734dSWill Andrews if (vdev[0] != '/' && stat(vdev, &st) != 0) { 6906401734dSWill Andrews char *s; 6916401734dSWill Andrews 6926401734dSWill Andrews (void) snprintf(vdev, sizeof (vdev), "%s/%s", 6936401734dSWill Andrews ZFS_DISK_ROOT, argv[0]); 6946401734dSWill Andrews if ((s = strrchr(argv[0], 's')) == NULL || 6956401734dSWill Andrews !isdigit(*(s + 1))) 6966401734dSWill Andrews (void) strlcat(vdev, "s0", sizeof (vdev)); 6976401734dSWill Andrews if (stat(vdev, &st) != 0) { 6986401734dSWill Andrews (void) fprintf(stderr, gettext( 6996401734dSWill Andrews "failed to find device %s, try specifying absolute " 7006401734dSWill Andrews "path instead\n"), argv[0]); 7016401734dSWill Andrews return (1); 7026401734dSWill Andrews } 7036401734dSWill Andrews } 7046401734dSWill Andrews 7056401734dSWill Andrews if ((fd = open(vdev, O_RDWR)) < 0) { 7066401734dSWill Andrews (void) fprintf(stderr, gettext("failed to open %s: %s\n"), 7076401734dSWill Andrews vdev, strerror(errno)); 7086401734dSWill Andrews return (1); 7096401734dSWill Andrews } 7106401734dSWill Andrews 7116401734dSWill Andrews if (zpool_read_label(fd, &config) != 0 || config == NULL) { 7126401734dSWill Andrews (void) fprintf(stderr, 7136401734dSWill Andrews gettext("failed to read label from %s\n"), vdev); 7146401734dSWill Andrews return (1); 7156401734dSWill Andrews } 7166401734dSWill Andrews nvlist_free(config); 7176401734dSWill Andrews 7186401734dSWill Andrews ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse); 7196401734dSWill Andrews if (ret != 0) { 7206401734dSWill Andrews (void) fprintf(stderr, 7216401734dSWill Andrews gettext("failed to check state for %s\n"), vdev); 7226401734dSWill Andrews return (1); 7236401734dSWill Andrews } 7246401734dSWill Andrews 7256401734dSWill Andrews if (!inuse) 7266401734dSWill Andrews goto wipe_label; 7276401734dSWill Andrews 7286401734dSWill Andrews switch (state) { 7296401734dSWill Andrews default: 7306401734dSWill Andrews case POOL_STATE_ACTIVE: 7316401734dSWill Andrews case POOL_STATE_SPARE: 7326401734dSWill Andrews case POOL_STATE_L2CACHE: 7336401734dSWill Andrews (void) fprintf(stderr, gettext( 7346401734dSWill Andrews "%s is a member (%s) of pool \"%s\"\n"), 7356401734dSWill Andrews vdev, zpool_pool_state_to_name(state), name); 7366401734dSWill Andrews ret = 1; 7376401734dSWill Andrews goto errout; 7386401734dSWill Andrews 7396401734dSWill Andrews case POOL_STATE_EXPORTED: 7406401734dSWill Andrews if (force) 7416401734dSWill Andrews break; 7426401734dSWill Andrews (void) fprintf(stderr, gettext( 7436401734dSWill Andrews "use '-f' to override the following error:\n" 7446401734dSWill Andrews "%s is a member of exported pool \"%s\"\n"), 7456401734dSWill Andrews vdev, name); 7466401734dSWill Andrews ret = 1; 7476401734dSWill Andrews goto errout; 7486401734dSWill Andrews 7496401734dSWill Andrews case POOL_STATE_POTENTIALLY_ACTIVE: 7506401734dSWill Andrews if (force) 7516401734dSWill Andrews break; 7526401734dSWill Andrews (void) fprintf(stderr, gettext( 7536401734dSWill Andrews "use '-f' to override the following error:\n" 7546401734dSWill Andrews "%s is a member of potentially active pool \"%s\"\n"), 7556401734dSWill Andrews vdev, name); 7566401734dSWill Andrews ret = 1; 7576401734dSWill Andrews goto errout; 7586401734dSWill Andrews 7596401734dSWill Andrews case POOL_STATE_DESTROYED: 7606401734dSWill Andrews /* inuse should never be set for a destroyed pool */ 7616401734dSWill Andrews assert(0); 7626401734dSWill Andrews break; 7636401734dSWill Andrews } 7646401734dSWill Andrews 7656401734dSWill Andrews wipe_label: 7666401734dSWill Andrews ret = zpool_clear_label(fd); 7676401734dSWill Andrews if (ret != 0) { 7686401734dSWill Andrews (void) fprintf(stderr, 7696401734dSWill Andrews gettext("failed to clear label for %s\n"), vdev); 7706401734dSWill Andrews } 7716401734dSWill Andrews 7726401734dSWill Andrews errout: 7736401734dSWill Andrews free(name); 7746401734dSWill Andrews (void) close(fd); 7756401734dSWill Andrews 7766401734dSWill Andrews return (ret); 7776401734dSWill Andrews } 7786401734dSWill Andrews 779fa9e4066Sahrens /* 7807855d95bSToomas Soome * zpool create [-fnd] [-B] [-o property=value] ... 7810a48a24eStimh * [-O file-system-property=value] ... 7820a48a24eStimh * [-R root] [-m mountpoint] <pool> <dev> ... 783fa9e4066Sahrens * 7847855d95bSToomas Soome * -B Create boot partition. 785fa9e4066Sahrens * -f Force creation, even if devices appear in use 786fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 787fa9e4066Sahrens * were to be created. 788fa9e4066Sahrens * -R Create a pool under an alternate root 789fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 790ad135b5dSChristopher Siden * '/<pool>' 791990b4856Slling * -o Set property=value. 792ad135b5dSChristopher Siden * -d Don't automatically enable all supported pool features 793ad135b5dSChristopher Siden * (individual features can be enabled with -o). 7940a48a24eStimh * -O Set fsproperty=value in the pool's root file system 795fa9e4066Sahrens * 796b1b8ab34Slling * Creates the named pool according to the given vdev specification. The 797fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 798fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 799fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 800fa9e4066Sahrens */ 8017855d95bSToomas Soome 8027855d95bSToomas Soome #define SYSTEM256 (256 * 1024 * 1024) 803fa9e4066Sahrens int 804fa9e4066Sahrens zpool_do_create(int argc, char **argv) 805fa9e4066Sahrens { 80699653d4eSeschrock boolean_t force = B_FALSE; 80799653d4eSeschrock boolean_t dryrun = B_FALSE; 808ad135b5dSChristopher Siden boolean_t enable_all_pool_feat = B_TRUE; 8097855d95bSToomas Soome zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL; 8107855d95bSToomas Soome uint64_t boot_size = 0; 811fa9e4066Sahrens int c; 812990b4856Slling nvlist_t *nvroot = NULL; 813fa9e4066Sahrens char *poolname; 814990b4856Slling int ret = 1; 815fa9e4066Sahrens char *altroot = NULL; 816fa9e4066Sahrens char *mountpoint = NULL; 8170a48a24eStimh nvlist_t *fsprops = NULL; 818990b4856Slling nvlist_t *props = NULL; 8192f8aaab3Seschrock char *propval; 820fa9e4066Sahrens 821fa9e4066Sahrens /* check options */ 8227855d95bSToomas Soome while ((c = getopt(argc, argv, ":fndBR:m:o:O:")) != -1) { 823fa9e4066Sahrens switch (c) { 824fa9e4066Sahrens case 'f': 82599653d4eSeschrock force = B_TRUE; 826fa9e4066Sahrens break; 827fa9e4066Sahrens case 'n': 82899653d4eSeschrock dryrun = B_TRUE; 829fa9e4066Sahrens break; 830ad135b5dSChristopher Siden case 'd': 831ad135b5dSChristopher Siden enable_all_pool_feat = B_FALSE; 832ad135b5dSChristopher Siden break; 8337855d95bSToomas Soome case 'B': 8347855d95bSToomas Soome /* 8357855d95bSToomas Soome * We should create the system partition. 8367855d95bSToomas Soome * Also make sure the size is set. 8377855d95bSToomas Soome */ 8387855d95bSToomas Soome boot_type = ZPOOL_CREATE_BOOT_LABEL; 8397855d95bSToomas Soome if (boot_size == 0) 8407855d95bSToomas Soome boot_size = SYSTEM256; 8417855d95bSToomas Soome break; 842fa9e4066Sahrens case 'R': 843fa9e4066Sahrens altroot = optarg; 844990b4856Slling if (add_prop_list(zpool_prop_to_name( 8450a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 846990b4856Slling goto errout; 8472f8aaab3Seschrock if (nvlist_lookup_string(props, 8482f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 8492f8aaab3Seschrock &propval) == 0) 8502f8aaab3Seschrock break; 851990b4856Slling if (add_prop_list(zpool_prop_to_name( 8520a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 853990b4856Slling goto errout; 854fa9e4066Sahrens break; 855fa9e4066Sahrens case 'm': 8568b713775SWill Andrews /* Equivalent to -O mountpoint=optarg */ 857fa9e4066Sahrens mountpoint = optarg; 858fa9e4066Sahrens break; 859990b4856Slling case 'o': 860990b4856Slling if ((propval = strchr(optarg, '=')) == NULL) { 861990b4856Slling (void) fprintf(stderr, gettext("missing " 862990b4856Slling "'=' for -o option\n")); 863990b4856Slling goto errout; 864990b4856Slling } 865990b4856Slling *propval = '\0'; 866990b4856Slling propval++; 867990b4856Slling 8680a48a24eStimh if (add_prop_list(optarg, propval, &props, B_TRUE)) 8690a48a24eStimh goto errout; 870ad135b5dSChristopher Siden 8717855d95bSToomas Soome /* 8727855d95bSToomas Soome * Get bootsize value for make_root_vdev(). 8737855d95bSToomas Soome */ 8747855d95bSToomas Soome if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) { 8757855d95bSToomas Soome if (zfs_nicestrtonum(g_zfs, propval, 8767855d95bSToomas Soome &boot_size) < 0 || boot_size == 0) { 8777855d95bSToomas Soome (void) fprintf(stderr, 8787855d95bSToomas Soome gettext("bad boot partition size " 8797855d95bSToomas Soome "'%s': %s\n"), propval, 8807855d95bSToomas Soome libzfs_error_description(g_zfs)); 8817855d95bSToomas Soome goto errout; 8827855d95bSToomas Soome } 8837855d95bSToomas Soome } 8847855d95bSToomas Soome 885ad135b5dSChristopher Siden /* 886ad135b5dSChristopher Siden * If the user is creating a pool that doesn't support 887ad135b5dSChristopher Siden * feature flags, don't enable any features. 888ad135b5dSChristopher Siden */ 889ad135b5dSChristopher Siden if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 890ad135b5dSChristopher Siden char *end; 891ad135b5dSChristopher Siden u_longlong_t ver; 892ad135b5dSChristopher Siden 893ad135b5dSChristopher Siden ver = strtoull(propval, &end, 10); 894ad135b5dSChristopher Siden if (*end == '\0' && 895ad135b5dSChristopher Siden ver < SPA_VERSION_FEATURES) { 896ad135b5dSChristopher Siden enable_all_pool_feat = B_FALSE; 897ad135b5dSChristopher Siden } 898ad135b5dSChristopher Siden } 899c423721fSXin Li if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) 900c423721fSXin Li altroot = propval; 9010a48a24eStimh break; 9020a48a24eStimh case 'O': 9030a48a24eStimh if ((propval = strchr(optarg, '=')) == NULL) { 9040a48a24eStimh (void) fprintf(stderr, gettext("missing " 9050a48a24eStimh "'=' for -O option\n")); 9060a48a24eStimh goto errout; 9070a48a24eStimh } 9080a48a24eStimh *propval = '\0'; 9090a48a24eStimh propval++; 9100a48a24eStimh 9118b713775SWill Andrews /* 9128b713775SWill Andrews * Mountpoints are checked and then added later. 9138b713775SWill Andrews * Uniquely among properties, they can be specified 9148b713775SWill Andrews * more than once, to avoid conflict with -m. 9158b713775SWill Andrews */ 9168b713775SWill Andrews if (0 == strcmp(optarg, 9178b713775SWill Andrews zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) { 9188b713775SWill Andrews mountpoint = propval; 9198b713775SWill Andrews } else if (add_prop_list(optarg, propval, &fsprops, 9208b713775SWill Andrews B_FALSE)) { 921990b4856Slling goto errout; 9228b713775SWill Andrews } 923990b4856Slling break; 924fa9e4066Sahrens case ':': 925fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 926fa9e4066Sahrens "'%c' option\n"), optopt); 927990b4856Slling goto badusage; 928fa9e4066Sahrens case '?': 929fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 930fa9e4066Sahrens optopt); 931990b4856Slling goto badusage; 932fa9e4066Sahrens } 933fa9e4066Sahrens } 934fa9e4066Sahrens 935fa9e4066Sahrens argc -= optind; 936fa9e4066Sahrens argv += optind; 937fa9e4066Sahrens 938fa9e4066Sahrens /* get pool name and check number of arguments */ 939fa9e4066Sahrens if (argc < 1) { 940fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 941990b4856Slling goto badusage; 942fa9e4066Sahrens } 943fa9e4066Sahrens if (argc < 2) { 944fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 945990b4856Slling goto badusage; 946fa9e4066Sahrens } 947fa9e4066Sahrens 948fa9e4066Sahrens poolname = argv[0]; 949fa9e4066Sahrens 950fa9e4066Sahrens /* 951fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 952fa9e4066Sahrens * user to use 'zfs create' instead. 953fa9e4066Sahrens */ 954fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 955fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 956fa9e4066Sahrens "character '/' in pool name\n"), poolname); 957fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 958fa9e4066Sahrens "create a dataset\n")); 959990b4856Slling goto errout; 960fa9e4066Sahrens } 961fa9e4066Sahrens 9627855d95bSToomas Soome /* 9637855d95bSToomas Soome * Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used, 9647855d95bSToomas Soome * and not set otherwise. 9657855d95bSToomas Soome */ 9667855d95bSToomas Soome if (boot_type == ZPOOL_CREATE_BOOT_LABEL) { 9677855d95bSToomas Soome const char *propname; 9687855d95bSToomas Soome char *strptr, *buf = NULL; 9697855d95bSToomas Soome int rv; 9707855d95bSToomas Soome 9717855d95bSToomas Soome propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE); 9727855d95bSToomas Soome if (nvlist_lookup_string(props, propname, &strptr) != 0) { 9737855d95bSToomas Soome (void) asprintf(&buf, "%" PRIu64, boot_size); 9747855d95bSToomas Soome if (buf == NULL) { 9757855d95bSToomas Soome (void) fprintf(stderr, 9767855d95bSToomas Soome gettext("internal error: out of memory\n")); 9777855d95bSToomas Soome goto errout; 9787855d95bSToomas Soome } 9797855d95bSToomas Soome rv = add_prop_list(propname, buf, &props, B_TRUE); 9807855d95bSToomas Soome free(buf); 9817855d95bSToomas Soome if (rv != 0) 9827855d95bSToomas Soome goto errout; 9837855d95bSToomas Soome } 9847855d95bSToomas Soome } else { 9857855d95bSToomas Soome const char *propname; 9867855d95bSToomas Soome char *strptr; 9877855d95bSToomas Soome 9887855d95bSToomas Soome propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE); 9897855d95bSToomas Soome if (nvlist_lookup_string(props, propname, &strptr) == 0) { 9907855d95bSToomas Soome (void) fprintf(stderr, gettext("error: setting boot " 9917855d95bSToomas Soome "partition size requires option '-B'\n")); 9927855d95bSToomas Soome goto errout; 9937855d95bSToomas Soome } 9947855d95bSToomas Soome } 9957855d95bSToomas Soome 996fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 997705040edSEric Taylor nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 9987855d95bSToomas Soome boot_type, boot_size, argc - 1, argv + 1); 999fa9e4066Sahrens if (nvroot == NULL) 10000a48a24eStimh goto errout; 1001fa9e4066Sahrens 100299653d4eSeschrock /* make_root_vdev() allows 0 toplevel children if there are spares */ 1003b7b97454Sperrin if (!zfs_allocatable_devs(nvroot)) { 100499653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 100599653d4eSeschrock "specification: at least one toplevel vdev must be " 100699653d4eSeschrock "specified\n")); 1007990b4856Slling goto errout; 100899653d4eSeschrock } 100999653d4eSeschrock 1010fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 1011fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 1012e9dbad6fSeschrock "must be an absolute path\n"), altroot); 1013990b4856Slling goto errout; 1014fa9e4066Sahrens } 1015fa9e4066Sahrens 1016fa9e4066Sahrens /* 1017fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 1018fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 1019fa9e4066Sahrens */ 1020fa9e4066Sahrens if (mountpoint == NULL || 1021fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 1022fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 1023fa9e4066Sahrens char buf[MAXPATHLEN]; 102411022c7cStimh DIR *dirp; 1025fa9e4066Sahrens 1026fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 1027fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 1028fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 1029fa9e4066Sahrens "'none'\n"), mountpoint); 1030990b4856Slling goto errout; 1031fa9e4066Sahrens } 1032fa9e4066Sahrens 1033fa9e4066Sahrens if (mountpoint == NULL) { 1034fa9e4066Sahrens if (altroot != NULL) 1035fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 1036fa9e4066Sahrens altroot, poolname); 1037fa9e4066Sahrens else 1038fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 1039fa9e4066Sahrens poolname); 1040fa9e4066Sahrens } else { 1041fa9e4066Sahrens if (altroot != NULL) 1042fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 1043fa9e4066Sahrens altroot, mountpoint); 1044fa9e4066Sahrens else 1045fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 1046fa9e4066Sahrens mountpoint); 1047fa9e4066Sahrens } 1048fa9e4066Sahrens 104911022c7cStimh if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 105011022c7cStimh (void) fprintf(stderr, gettext("mountpoint '%s' : " 105111022c7cStimh "%s\n"), buf, strerror(errno)); 1052fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 1053fa9e4066Sahrens "option to provide a different default\n")); 1054990b4856Slling goto errout; 105511022c7cStimh } else if (dirp) { 105611022c7cStimh int count = 0; 105711022c7cStimh 105811022c7cStimh while (count < 3 && readdir(dirp) != NULL) 105911022c7cStimh count++; 106011022c7cStimh (void) closedir(dirp); 106111022c7cStimh 106211022c7cStimh if (count > 2) { 106311022c7cStimh (void) fprintf(stderr, gettext("mountpoint " 106411022c7cStimh "'%s' exists and is not empty\n"), buf); 106511022c7cStimh (void) fprintf(stderr, gettext("use '-m' " 106611022c7cStimh "option to provide a " 106711022c7cStimh "different default\n")); 106811022c7cStimh goto errout; 106911022c7cStimh } 1070fa9e4066Sahrens } 1071fa9e4066Sahrens } 1072fa9e4066Sahrens 10738b713775SWill Andrews /* 10748b713775SWill Andrews * Now that the mountpoint's validity has been checked, ensure that 10758b713775SWill Andrews * the property is set appropriately prior to creating the pool. 10768b713775SWill Andrews */ 10778b713775SWill Andrews if (mountpoint != NULL) { 10788b713775SWill Andrews ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 10798b713775SWill Andrews mountpoint, &fsprops, B_FALSE); 10808b713775SWill Andrews if (ret != 0) 10818b713775SWill Andrews goto errout; 10828b713775SWill Andrews } 10838b713775SWill Andrews 10848b713775SWill Andrews ret = 1; 1085fa9e4066Sahrens if (dryrun) { 1086fa9e4066Sahrens /* 1087fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 1088fa9e4066Sahrens * through all the vdevs in the list and print out in an 1089fa9e4066Sahrens * appropriate hierarchy. 1090fa9e4066Sahrens */ 1091fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 1092fa9e4066Sahrens "following layout:\n\n"), poolname); 1093fa9e4066Sahrens 10948654d025Sperrin print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 10958654d025Sperrin if (num_logs(nvroot) > 0) 10968654d025Sperrin print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 1097fa9e4066Sahrens 1098fa9e4066Sahrens ret = 0; 1099fa9e4066Sahrens } else { 1100fa9e4066Sahrens /* 1101fa9e4066Sahrens * Hand off to libzfs. 1102fa9e4066Sahrens */ 1103ad135b5dSChristopher Siden if (enable_all_pool_feat) { 11042acef22dSMatthew Ahrens spa_feature_t i; 1105ad135b5dSChristopher Siden for (i = 0; i < SPA_FEATURES; i++) { 1106ad135b5dSChristopher Siden char propname[MAXPATHLEN]; 1107ad135b5dSChristopher Siden zfeature_info_t *feat = &spa_feature_table[i]; 1108ad135b5dSChristopher Siden 1109ad135b5dSChristopher Siden (void) snprintf(propname, sizeof (propname), 1110ad135b5dSChristopher Siden "feature@%s", feat->fi_uname); 1111ad135b5dSChristopher Siden 1112ad135b5dSChristopher Siden /* 1113ad135b5dSChristopher Siden * Skip feature if user specified it manually 1114ad135b5dSChristopher Siden * on the command line. 1115ad135b5dSChristopher Siden */ 1116ad135b5dSChristopher Siden if (nvlist_exists(props, propname)) 1117ad135b5dSChristopher Siden continue; 1118ad135b5dSChristopher Siden 11198b713775SWill Andrews ret = add_prop_list(propname, 11208b713775SWill Andrews ZFS_FEATURE_ENABLED, &props, B_TRUE); 11218b713775SWill Andrews if (ret != 0) 1122ad135b5dSChristopher Siden goto errout; 1123ad135b5dSChristopher Siden } 1124ad135b5dSChristopher Siden } 11258b713775SWill Andrews 11268b713775SWill Andrews ret = 1; 11270a48a24eStimh if (zpool_create(g_zfs, poolname, 11280a48a24eStimh nvroot, props, fsprops) == 0) { 112999653d4eSeschrock zfs_handle_t *pool = zfs_open(g_zfs, poolname, 1130fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 1131fa9e4066Sahrens if (pool != NULL) { 1132fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 1133da6c28aaSamw ret = zfs_shareall(pool); 1134fa9e4066Sahrens zfs_close(pool); 1135fa9e4066Sahrens } 113699653d4eSeschrock } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 113799653d4eSeschrock (void) fprintf(stderr, gettext("pool name may have " 113899653d4eSeschrock "been omitted\n")); 1139fa9e4066Sahrens } 1140fa9e4066Sahrens } 1141fa9e4066Sahrens 1142990b4856Slling errout: 11432f8aaab3Seschrock nvlist_free(nvroot); 11440a48a24eStimh nvlist_free(fsprops); 11452f8aaab3Seschrock nvlist_free(props); 1146fa9e4066Sahrens return (ret); 1147990b4856Slling badusage: 11480a48a24eStimh nvlist_free(fsprops); 1149990b4856Slling nvlist_free(props); 1150990b4856Slling usage(B_FALSE); 1151990b4856Slling return (2); 1152fa9e4066Sahrens } 1153fa9e4066Sahrens 1154fa9e4066Sahrens /* 1155fa9e4066Sahrens * zpool destroy <pool> 1156fa9e4066Sahrens * 1157fa9e4066Sahrens * -f Forcefully unmount any datasets 1158fa9e4066Sahrens * 1159fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 1160fa9e4066Sahrens */ 1161fa9e4066Sahrens int 1162fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 1163fa9e4066Sahrens { 116499653d4eSeschrock boolean_t force = B_FALSE; 1165fa9e4066Sahrens int c; 1166fa9e4066Sahrens char *pool; 1167fa9e4066Sahrens zpool_handle_t *zhp; 1168fa9e4066Sahrens int ret; 1169fa9e4066Sahrens 1170fa9e4066Sahrens /* check options */ 1171fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 1172fa9e4066Sahrens switch (c) { 1173fa9e4066Sahrens case 'f': 117499653d4eSeschrock force = B_TRUE; 1175fa9e4066Sahrens break; 1176fa9e4066Sahrens case '?': 1177fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1178fa9e4066Sahrens optopt); 117999653d4eSeschrock usage(B_FALSE); 1180fa9e4066Sahrens } 1181fa9e4066Sahrens } 1182fa9e4066Sahrens 1183fa9e4066Sahrens argc -= optind; 1184fa9e4066Sahrens argv += optind; 1185fa9e4066Sahrens 1186fa9e4066Sahrens /* check arguments */ 1187fa9e4066Sahrens if (argc < 1) { 1188fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 118999653d4eSeschrock usage(B_FALSE); 1190fa9e4066Sahrens } 1191fa9e4066Sahrens if (argc > 1) { 1192fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 119399653d4eSeschrock usage(B_FALSE); 1194fa9e4066Sahrens } 1195fa9e4066Sahrens 1196fa9e4066Sahrens pool = argv[0]; 1197fa9e4066Sahrens 119899653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1199fa9e4066Sahrens /* 1200fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 1201fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 1202fa9e4066Sahrens */ 1203fa9e4066Sahrens if (strchr(pool, '/') != NULL) 1204fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1205fa9e4066Sahrens "destroy a dataset\n")); 1206fa9e4066Sahrens return (1); 1207fa9e4066Sahrens } 1208fa9e4066Sahrens 1209f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 1210fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 1211fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 1212fa9e4066Sahrens return (1); 1213fa9e4066Sahrens } 1214fa9e4066Sahrens 12154445fffbSMatthew Ahrens /* The history must be logged as part of the export */ 12164445fffbSMatthew Ahrens log_history = B_FALSE; 12174445fffbSMatthew Ahrens 12184445fffbSMatthew Ahrens ret = (zpool_destroy(zhp, history_str) != 0); 1219fa9e4066Sahrens 1220fa9e4066Sahrens zpool_close(zhp); 1221fa9e4066Sahrens 1222fa9e4066Sahrens return (ret); 1223fa9e4066Sahrens } 1224fa9e4066Sahrens 1225fa9e4066Sahrens /* 1226fa9e4066Sahrens * zpool export [-f] <pool> ... 1227fa9e4066Sahrens * 1228fa9e4066Sahrens * -f Forcefully unmount datasets 1229fa9e4066Sahrens * 1230b1b8ab34Slling * Export the given pools. By default, the command will attempt to cleanly 1231fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 1232fa9e4066Sahrens * then the datasets will be forcefully unmounted. 1233fa9e4066Sahrens */ 1234fa9e4066Sahrens int 1235fa9e4066Sahrens zpool_do_export(int argc, char **argv) 1236fa9e4066Sahrens { 123799653d4eSeschrock boolean_t force = B_FALSE; 1238394ab0cbSGeorge Wilson boolean_t hardforce = B_FALSE; 1239fa9e4066Sahrens int c; 1240fa9e4066Sahrens zpool_handle_t *zhp; 1241fa9e4066Sahrens int ret; 1242fa9e4066Sahrens int i; 1243fa9e4066Sahrens 1244fa9e4066Sahrens /* check options */ 1245394ab0cbSGeorge Wilson while ((c = getopt(argc, argv, "fF")) != -1) { 1246fa9e4066Sahrens switch (c) { 1247fa9e4066Sahrens case 'f': 124899653d4eSeschrock force = B_TRUE; 1249fa9e4066Sahrens break; 1250394ab0cbSGeorge Wilson case 'F': 1251394ab0cbSGeorge Wilson hardforce = B_TRUE; 1252394ab0cbSGeorge Wilson break; 1253fa9e4066Sahrens case '?': 1254fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1255fa9e4066Sahrens optopt); 125699653d4eSeschrock usage(B_FALSE); 1257fa9e4066Sahrens } 1258fa9e4066Sahrens } 1259fa9e4066Sahrens 1260fa9e4066Sahrens argc -= optind; 1261fa9e4066Sahrens argv += optind; 1262fa9e4066Sahrens 1263fa9e4066Sahrens /* check arguments */ 1264fa9e4066Sahrens if (argc < 1) { 1265fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 126699653d4eSeschrock usage(B_FALSE); 1267fa9e4066Sahrens } 1268fa9e4066Sahrens 1269fa9e4066Sahrens ret = 0; 1270fa9e4066Sahrens for (i = 0; i < argc; i++) { 127199653d4eSeschrock if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1272fa9e4066Sahrens ret = 1; 1273fa9e4066Sahrens continue; 1274fa9e4066Sahrens } 1275fa9e4066Sahrens 1276f3861e1aSahl if (zpool_disable_datasets(zhp, force) != 0) { 1277fa9e4066Sahrens ret = 1; 1278fa9e4066Sahrens zpool_close(zhp); 1279fa9e4066Sahrens continue; 1280fa9e4066Sahrens } 1281fa9e4066Sahrens 12824445fffbSMatthew Ahrens /* The history must be logged as part of the export */ 12834445fffbSMatthew Ahrens log_history = B_FALSE; 12844445fffbSMatthew Ahrens 1285394ab0cbSGeorge Wilson if (hardforce) { 12864445fffbSMatthew Ahrens if (zpool_export_force(zhp, history_str) != 0) 1287394ab0cbSGeorge Wilson ret = 1; 12884445fffbSMatthew Ahrens } else if (zpool_export(zhp, force, history_str) != 0) { 1289fa9e4066Sahrens ret = 1; 1290394ab0cbSGeorge Wilson } 1291fa9e4066Sahrens 1292fa9e4066Sahrens zpool_close(zhp); 1293fa9e4066Sahrens } 1294fa9e4066Sahrens 1295fa9e4066Sahrens return (ret); 1296fa9e4066Sahrens } 1297fa9e4066Sahrens 1298fa9e4066Sahrens /* 1299fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 1300fa9e4066Sahrens * name column. 1301fa9e4066Sahrens */ 1302fa9e4066Sahrens static int 1303c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1304fa9e4066Sahrens { 130588ecc943SGeorge Wilson char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1306fa9e4066Sahrens nvlist_t **child; 1307fa9e4066Sahrens uint_t c, children; 1308fa9e4066Sahrens int ret; 1309fa9e4066Sahrens 1310fa9e4066Sahrens if (strlen(name) + depth > max) 1311fa9e4066Sahrens max = strlen(name) + depth; 1312fa9e4066Sahrens 1313afefbcddSeschrock free(name); 1314afefbcddSeschrock 131599653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 131699653d4eSeschrock &child, &children) == 0) { 131799653d4eSeschrock for (c = 0; c < children; c++) 131899653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 131999653d4eSeschrock max)) > max) 132099653d4eSeschrock max = ret; 132199653d4eSeschrock } 132299653d4eSeschrock 1323fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1324fa94a07fSbrendan &child, &children) == 0) { 1325fa94a07fSbrendan for (c = 0; c < children; c++) 1326fa94a07fSbrendan if ((ret = max_width(zhp, child[c], depth + 2, 1327fa94a07fSbrendan max)) > max) 1328fa94a07fSbrendan max = ret; 1329fa94a07fSbrendan } 1330fa94a07fSbrendan 1331fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 133299653d4eSeschrock &child, &children) == 0) { 133399653d4eSeschrock for (c = 0; c < children; c++) 133499653d4eSeschrock if ((ret = max_width(zhp, child[c], depth + 2, 133599653d4eSeschrock max)) > max) 133699653d4eSeschrock max = ret; 133799653d4eSeschrock } 1338fa9e4066Sahrens 1339fa9e4066Sahrens 1340fa9e4066Sahrens return (max); 1341fa9e4066Sahrens } 1342fa9e4066Sahrens 1343e6ca193dSGeorge Wilson typedef struct spare_cbdata { 1344e6ca193dSGeorge Wilson uint64_t cb_guid; 1345e6ca193dSGeorge Wilson zpool_handle_t *cb_zhp; 1346e6ca193dSGeorge Wilson } spare_cbdata_t; 1347e6ca193dSGeorge Wilson 1348e6ca193dSGeorge Wilson static boolean_t 1349e6ca193dSGeorge Wilson find_vdev(nvlist_t *nv, uint64_t search) 1350e6ca193dSGeorge Wilson { 1351e6ca193dSGeorge Wilson uint64_t guid; 1352e6ca193dSGeorge Wilson nvlist_t **child; 1353e6ca193dSGeorge Wilson uint_t c, children; 1354e6ca193dSGeorge Wilson 1355e6ca193dSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1356e6ca193dSGeorge Wilson search == guid) 1357e6ca193dSGeorge Wilson return (B_TRUE); 1358e6ca193dSGeorge Wilson 1359e6ca193dSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1360e6ca193dSGeorge Wilson &child, &children) == 0) { 1361e6ca193dSGeorge Wilson for (c = 0; c < children; c++) 1362e6ca193dSGeorge Wilson if (find_vdev(child[c], search)) 1363e6ca193dSGeorge Wilson return (B_TRUE); 1364e6ca193dSGeorge Wilson } 1365e6ca193dSGeorge Wilson 1366e6ca193dSGeorge Wilson return (B_FALSE); 1367e6ca193dSGeorge Wilson } 1368e6ca193dSGeorge Wilson 1369e6ca193dSGeorge Wilson static int 1370e6ca193dSGeorge Wilson find_spare(zpool_handle_t *zhp, void *data) 1371e6ca193dSGeorge Wilson { 1372e6ca193dSGeorge Wilson spare_cbdata_t *cbp = data; 1373e6ca193dSGeorge Wilson nvlist_t *config, *nvroot; 1374e6ca193dSGeorge Wilson 1375e6ca193dSGeorge Wilson config = zpool_get_config(zhp, NULL); 1376e6ca193dSGeorge Wilson verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1377e6ca193dSGeorge Wilson &nvroot) == 0); 1378e6ca193dSGeorge Wilson 1379e6ca193dSGeorge Wilson if (find_vdev(nvroot, cbp->cb_guid)) { 1380e6ca193dSGeorge Wilson cbp->cb_zhp = zhp; 1381e6ca193dSGeorge Wilson return (1); 1382e6ca193dSGeorge Wilson } 1383e6ca193dSGeorge Wilson 1384e6ca193dSGeorge Wilson zpool_close(zhp); 1385e6ca193dSGeorge Wilson return (0); 1386e6ca193dSGeorge Wilson } 1387e6ca193dSGeorge Wilson 1388e6ca193dSGeorge Wilson /* 1389e6ca193dSGeorge Wilson * Print out configuration state as requested by status_callback. 1390e6ca193dSGeorge Wilson */ 1391e6ca193dSGeorge Wilson void 1392e6ca193dSGeorge Wilson print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1393e6ca193dSGeorge Wilson int namewidth, int depth, boolean_t isspare) 1394e6ca193dSGeorge Wilson { 1395e6ca193dSGeorge Wilson nvlist_t **child; 1396e6ca193dSGeorge Wilson uint_t c, children; 13973f9d6ad7SLin Ling pool_scan_stat_t *ps = NULL; 1398e6ca193dSGeorge Wilson vdev_stat_t *vs; 13993f9d6ad7SLin Ling char rbuf[6], wbuf[6], cbuf[6]; 1400e6ca193dSGeorge Wilson char *vname; 1401e6ca193dSGeorge Wilson uint64_t notpresent; 1402e6ca193dSGeorge Wilson spare_cbdata_t cb; 14036401734dSWill Andrews const char *state; 1404e6ca193dSGeorge Wilson 1405e6ca193dSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1406e6ca193dSGeorge Wilson &child, &children) != 0) 1407e6ca193dSGeorge Wilson children = 0; 1408e6ca193dSGeorge Wilson 14093f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 14103f9d6ad7SLin Ling (uint64_t **)&vs, &c) == 0); 14113f9d6ad7SLin Ling 1412e6ca193dSGeorge Wilson state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1413e6ca193dSGeorge Wilson if (isspare) { 1414e6ca193dSGeorge Wilson /* 1415e6ca193dSGeorge Wilson * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1416e6ca193dSGeorge Wilson * online drives. 1417e6ca193dSGeorge Wilson */ 1418e6ca193dSGeorge Wilson if (vs->vs_aux == VDEV_AUX_SPARED) 1419e6ca193dSGeorge Wilson state = "INUSE"; 1420e6ca193dSGeorge Wilson else if (vs->vs_state == VDEV_STATE_HEALTHY) 1421e6ca193dSGeorge Wilson state = "AVAIL"; 1422e6ca193dSGeorge Wilson } 1423e6ca193dSGeorge Wilson 1424e6ca193dSGeorge Wilson (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1425e6ca193dSGeorge Wilson name, state); 1426e6ca193dSGeorge Wilson 1427e6ca193dSGeorge Wilson if (!isspare) { 1428e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1429e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1430e6ca193dSGeorge Wilson zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1431e6ca193dSGeorge Wilson (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1432e6ca193dSGeorge Wilson } 1433e6ca193dSGeorge Wilson 1434e6ca193dSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1435e6ca193dSGeorge Wilson ¬present) == 0) { 1436e6ca193dSGeorge Wilson char *path; 1437e6ca193dSGeorge Wilson verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 1438e6ca193dSGeorge Wilson (void) printf(" was %s", path); 1439e6ca193dSGeorge Wilson } else if (vs->vs_aux != 0) { 1440e6ca193dSGeorge Wilson (void) printf(" "); 1441e6ca193dSGeorge Wilson 1442e6ca193dSGeorge Wilson switch (vs->vs_aux) { 1443e6ca193dSGeorge Wilson case VDEV_AUX_OPEN_FAILED: 1444e6ca193dSGeorge Wilson (void) printf(gettext("cannot open")); 1445e6ca193dSGeorge Wilson break; 1446e6ca193dSGeorge Wilson 1447e6ca193dSGeorge Wilson case VDEV_AUX_BAD_GUID_SUM: 1448e6ca193dSGeorge Wilson (void) printf(gettext("missing device")); 1449e6ca193dSGeorge Wilson break; 1450e6ca193dSGeorge Wilson 1451e6ca193dSGeorge Wilson case VDEV_AUX_NO_REPLICAS: 1452e6ca193dSGeorge Wilson (void) printf(gettext("insufficient replicas")); 1453e6ca193dSGeorge Wilson break; 1454e6ca193dSGeorge Wilson 1455e6ca193dSGeorge Wilson case VDEV_AUX_VERSION_NEWER: 1456e6ca193dSGeorge Wilson (void) printf(gettext("newer version")); 1457e6ca193dSGeorge Wilson break; 1458e6ca193dSGeorge Wilson 1459ad135b5dSChristopher Siden case VDEV_AUX_UNSUP_FEAT: 1460ad135b5dSChristopher Siden (void) printf(gettext("unsupported feature(s)")); 1461ad135b5dSChristopher Siden break; 1462ad135b5dSChristopher Siden 1463e6ca193dSGeorge Wilson case VDEV_AUX_SPARED: 1464e6ca193dSGeorge Wilson verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1465e6ca193dSGeorge Wilson &cb.cb_guid) == 0); 1466e6ca193dSGeorge Wilson if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1467e6ca193dSGeorge Wilson if (strcmp(zpool_get_name(cb.cb_zhp), 1468e6ca193dSGeorge Wilson zpool_get_name(zhp)) == 0) 1469e6ca193dSGeorge Wilson (void) printf(gettext("currently in " 1470e6ca193dSGeorge Wilson "use")); 1471e6ca193dSGeorge Wilson else 1472e6ca193dSGeorge Wilson (void) printf(gettext("in use by " 1473e6ca193dSGeorge Wilson "pool '%s'"), 1474e6ca193dSGeorge Wilson zpool_get_name(cb.cb_zhp)); 1475e6ca193dSGeorge Wilson zpool_close(cb.cb_zhp); 1476e6ca193dSGeorge Wilson } else { 1477e6ca193dSGeorge Wilson (void) printf(gettext("currently in use")); 1478e6ca193dSGeorge Wilson } 1479e6ca193dSGeorge Wilson break; 1480e6ca193dSGeorge Wilson 1481e6ca193dSGeorge Wilson case VDEV_AUX_ERR_EXCEEDED: 1482e6ca193dSGeorge Wilson (void) printf(gettext("too many errors")); 1483e6ca193dSGeorge Wilson break; 1484e6ca193dSGeorge Wilson 1485e6ca193dSGeorge Wilson case VDEV_AUX_IO_FAILURE: 1486e6ca193dSGeorge Wilson (void) printf(gettext("experienced I/O failures")); 1487e6ca193dSGeorge Wilson break; 1488e6ca193dSGeorge Wilson 1489e6ca193dSGeorge Wilson case VDEV_AUX_BAD_LOG: 1490e6ca193dSGeorge Wilson (void) printf(gettext("bad intent log")); 1491e6ca193dSGeorge Wilson break; 1492e6ca193dSGeorge Wilson 1493069f55e2SEric Schrock case VDEV_AUX_EXTERNAL: 1494069f55e2SEric Schrock (void) printf(gettext("external device fault")); 1495069f55e2SEric Schrock break; 1496069f55e2SEric Schrock 14971195e687SMark J Musante case VDEV_AUX_SPLIT_POOL: 14981195e687SMark J Musante (void) printf(gettext("split into new pool")); 14991195e687SMark J Musante break; 15001195e687SMark J Musante 1501e6ca193dSGeorge Wilson default: 1502e6ca193dSGeorge Wilson (void) printf(gettext("corrupted data")); 1503e6ca193dSGeorge Wilson break; 1504e6ca193dSGeorge Wilson } 15053f9d6ad7SLin Ling } 15063f9d6ad7SLin Ling 15073f9d6ad7SLin Ling (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 15083f9d6ad7SLin Ling (uint64_t **)&ps, &c); 15093f9d6ad7SLin Ling 15103f9d6ad7SLin Ling if (ps && ps->pss_state == DSS_SCANNING && 15113f9d6ad7SLin Ling vs->vs_scan_processed != 0 && children == 0) { 15123f9d6ad7SLin Ling (void) printf(gettext(" (%s)"), 15133f9d6ad7SLin Ling (ps->pss_func == POOL_SCAN_RESILVER) ? 15143f9d6ad7SLin Ling "resilvering" : "repairing"); 1515e6ca193dSGeorge Wilson } 1516e6ca193dSGeorge Wilson 1517e6ca193dSGeorge Wilson (void) printf("\n"); 1518e6ca193dSGeorge Wilson 1519e6ca193dSGeorge Wilson for (c = 0; c < children; c++) { 152088ecc943SGeorge Wilson uint64_t islog = B_FALSE, ishole = B_FALSE; 1521e6ca193dSGeorge Wilson 152288ecc943SGeorge Wilson /* Don't print logs or holes here */ 1523e6ca193dSGeorge Wilson (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 152488ecc943SGeorge Wilson &islog); 152588ecc943SGeorge Wilson (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 152688ecc943SGeorge Wilson &ishole); 152788ecc943SGeorge Wilson if (islog || ishole) 1528e6ca193dSGeorge Wilson continue; 152988ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1530e6ca193dSGeorge Wilson print_status_config(zhp, vname, child[c], 1531e6ca193dSGeorge Wilson namewidth, depth + 2, isspare); 1532e6ca193dSGeorge Wilson free(vname); 1533e6ca193dSGeorge Wilson } 1534e6ca193dSGeorge Wilson } 1535e6ca193dSGeorge Wilson 1536fa9e4066Sahrens 1537fa9e4066Sahrens /* 1538fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 1539fa9e4066Sahrens * pool, printing out the name and status for each one. 1540fa9e4066Sahrens */ 1541fa9e4066Sahrens void 1542e6ca193dSGeorge Wilson print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1543fa9e4066Sahrens { 1544fa9e4066Sahrens nvlist_t **child; 1545fa9e4066Sahrens uint_t c, children; 1546fa9e4066Sahrens vdev_stat_t *vs; 1547afefbcddSeschrock char *type, *vname; 1548fa9e4066Sahrens 1549fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 155088ecc943SGeorge Wilson if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 155188ecc943SGeorge Wilson strcmp(type, VDEV_TYPE_HOLE) == 0) 1552fa9e4066Sahrens return; 1553fa9e4066Sahrens 15543f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1555fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 1556fa9e4066Sahrens 1557fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1558990b4856Slling (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1559fa9e4066Sahrens 1560fa9e4066Sahrens if (vs->vs_aux != 0) { 15613d7072f8Seschrock (void) printf(" "); 1562fa9e4066Sahrens 1563fa9e4066Sahrens switch (vs->vs_aux) { 1564fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 1565fa9e4066Sahrens (void) printf(gettext("cannot open")); 1566fa9e4066Sahrens break; 1567fa9e4066Sahrens 1568fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 1569fa9e4066Sahrens (void) printf(gettext("missing device")); 1570fa9e4066Sahrens break; 1571fa9e4066Sahrens 1572fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 1573fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 1574fa9e4066Sahrens break; 1575fa9e4066Sahrens 1576eaca9bbdSeschrock case VDEV_AUX_VERSION_NEWER: 1577eaca9bbdSeschrock (void) printf(gettext("newer version")); 1578eaca9bbdSeschrock break; 1579eaca9bbdSeschrock 1580ad135b5dSChristopher Siden case VDEV_AUX_UNSUP_FEAT: 1581ad135b5dSChristopher Siden (void) printf(gettext("unsupported feature(s)")); 1582ad135b5dSChristopher Siden break; 1583ad135b5dSChristopher Siden 15843d7072f8Seschrock case VDEV_AUX_ERR_EXCEEDED: 15853d7072f8Seschrock (void) printf(gettext("too many errors")); 15863d7072f8Seschrock break; 15873d7072f8Seschrock 1588fa9e4066Sahrens default: 1589fa9e4066Sahrens (void) printf(gettext("corrupted data")); 1590fa9e4066Sahrens break; 1591fa9e4066Sahrens } 1592fa9e4066Sahrens } 1593fa9e4066Sahrens (void) printf("\n"); 1594fa9e4066Sahrens 1595fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1596fa9e4066Sahrens &child, &children) != 0) 1597fa9e4066Sahrens return; 1598fa9e4066Sahrens 1599afefbcddSeschrock for (c = 0; c < children; c++) { 16008654d025Sperrin uint64_t is_log = B_FALSE; 16018654d025Sperrin 16028654d025Sperrin (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 16038654d025Sperrin &is_log); 1604e6ca193dSGeorge Wilson if (is_log) 16058654d025Sperrin continue; 16068654d025Sperrin 160788ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1608e6ca193dSGeorge Wilson print_import_config(vname, child[c], namewidth, depth + 2); 1609afefbcddSeschrock free(vname); 1610afefbcddSeschrock } 161199653d4eSeschrock 1612fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1613fa94a07fSbrendan &child, &children) == 0) { 1614fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 1615fa94a07fSbrendan for (c = 0; c < children; c++) { 161688ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1617fa94a07fSbrendan (void) printf("\t %s\n", vname); 1618fa94a07fSbrendan free(vname); 1619fa94a07fSbrendan } 1620fa94a07fSbrendan } 162199653d4eSeschrock 1622fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1623fa94a07fSbrendan &child, &children) == 0) { 1624fa94a07fSbrendan (void) printf(gettext("\tspares\n")); 1625fa94a07fSbrendan for (c = 0; c < children; c++) { 162688ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1627fa94a07fSbrendan (void) printf("\t %s\n", vname); 1628fa94a07fSbrendan free(vname); 1629fa94a07fSbrendan } 163099653d4eSeschrock } 1631fa9e4066Sahrens } 1632fa9e4066Sahrens 1633e6ca193dSGeorge Wilson /* 1634e6ca193dSGeorge Wilson * Print log vdevs. 1635e6ca193dSGeorge Wilson * Logs are recorded as top level vdevs in the main pool child array 1636e6ca193dSGeorge Wilson * but with "is_log" set to 1. We use either print_status_config() or 1637e6ca193dSGeorge Wilson * print_import_config() to print the top level logs then any log 1638e6ca193dSGeorge Wilson * children (eg mirrored slogs) are printed recursively - which 1639e6ca193dSGeorge Wilson * works because only the top level vdev is marked "is_log" 1640e6ca193dSGeorge Wilson */ 1641e6ca193dSGeorge Wilson static void 1642e6ca193dSGeorge Wilson print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1643e6ca193dSGeorge Wilson { 1644e6ca193dSGeorge Wilson uint_t c, children; 1645e6ca193dSGeorge Wilson nvlist_t **child; 1646e6ca193dSGeorge Wilson 1647e6ca193dSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1648e6ca193dSGeorge Wilson &children) != 0) 1649e6ca193dSGeorge Wilson return; 1650e6ca193dSGeorge Wilson 1651e6ca193dSGeorge Wilson (void) printf(gettext("\tlogs\n")); 1652e6ca193dSGeorge Wilson 1653e6ca193dSGeorge Wilson for (c = 0; c < children; c++) { 1654e6ca193dSGeorge Wilson uint64_t is_log = B_FALSE; 1655e6ca193dSGeorge Wilson char *name; 1656e6ca193dSGeorge Wilson 1657e6ca193dSGeorge Wilson (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1658e6ca193dSGeorge Wilson &is_log); 1659e6ca193dSGeorge Wilson if (!is_log) 1660e6ca193dSGeorge Wilson continue; 166188ecc943SGeorge Wilson name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1662e6ca193dSGeorge Wilson if (verbose) 1663e6ca193dSGeorge Wilson print_status_config(zhp, name, child[c], namewidth, 1664e6ca193dSGeorge Wilson 2, B_FALSE); 1665e6ca193dSGeorge Wilson else 1666e6ca193dSGeorge Wilson print_import_config(name, child[c], namewidth, 2); 1667e6ca193dSGeorge Wilson free(name); 1668e6ca193dSGeorge Wilson } 1669e6ca193dSGeorge Wilson } 1670468c413aSTim Haley 1671fa9e4066Sahrens /* 1672fa9e4066Sahrens * Display the status for the given pool. 1673fa9e4066Sahrens */ 1674fa9e4066Sahrens static void 1675fa9e4066Sahrens show_import(nvlist_t *config) 1676fa9e4066Sahrens { 1677fa9e4066Sahrens uint64_t pool_state; 1678fa9e4066Sahrens vdev_stat_t *vs; 1679fa9e4066Sahrens char *name; 1680fa9e4066Sahrens uint64_t guid; 1681fa9e4066Sahrens char *msgid; 1682fa9e4066Sahrens nvlist_t *nvroot; 1683fa9e4066Sahrens int reason; 168446657f8dSmmusante const char *health; 1685fa9e4066Sahrens uint_t vsc; 1686fa9e4066Sahrens int namewidth; 16878704186eSDan McDonald char *comment; 1688fa9e4066Sahrens 1689fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1690fa9e4066Sahrens &name) == 0); 1691fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1692fa9e4066Sahrens &guid) == 0); 1693fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1694fa9e4066Sahrens &pool_state) == 0); 1695fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1696fa9e4066Sahrens &nvroot) == 0); 1697fa9e4066Sahrens 16983f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1699fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 1700990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1701fa9e4066Sahrens 1702fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 1703fa9e4066Sahrens 17048704186eSDan McDonald (void) printf(gettext(" pool: %s\n"), name); 17058704186eSDan McDonald (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 17068704186eSDan McDonald (void) printf(gettext(" state: %s"), health); 17074c58d714Sdarrenm if (pool_state == POOL_STATE_DESTROYED) 1708b1b8ab34Slling (void) printf(gettext(" (DESTROYED)")); 17094c58d714Sdarrenm (void) printf("\n"); 1710fa9e4066Sahrens 1711fa9e4066Sahrens switch (reason) { 1712fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 1713fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 1714fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 17158704186eSDan McDonald (void) printf(gettext(" status: One or more devices are " 17168704186eSDan McDonald "missing from the system.\n")); 1717fa9e4066Sahrens break; 1718fa9e4066Sahrens 1719fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 1720fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 17218704186eSDan McDonald (void) printf(gettext(" status: One or more devices contains " 1722fa9e4066Sahrens "corrupted data.\n")); 1723fa9e4066Sahrens break; 1724fa9e4066Sahrens 1725fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 17268704186eSDan McDonald (void) printf( 17278704186eSDan McDonald gettext(" status: The pool data is corrupted.\n")); 1728fa9e4066Sahrens break; 1729fa9e4066Sahrens 1730441d80aaSlling case ZPOOL_STATUS_OFFLINE_DEV: 17318704186eSDan McDonald (void) printf(gettext(" status: One or more devices " 1732441d80aaSlling "are offlined.\n")); 1733441d80aaSlling break; 1734441d80aaSlling 1735ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 17368704186eSDan McDonald (void) printf(gettext(" status: The pool metadata is " 1737ea8dc4b6Seschrock "corrupted.\n")); 1738ea8dc4b6Seschrock break; 1739ea8dc4b6Seschrock 1740eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 174157221772SChristopher Siden (void) printf(gettext(" status: The pool is formatted using a " 174257221772SChristopher Siden "legacy on-disk version.\n")); 1743eaca9bbdSeschrock break; 1744eaca9bbdSeschrock 1745eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 17468704186eSDan McDonald (void) printf(gettext(" status: The pool is formatted using an " 1747eaca9bbdSeschrock "incompatible version.\n")); 1748eaca9bbdSeschrock break; 1749b87f3af3Sperrin 175057221772SChristopher Siden case ZPOOL_STATUS_FEAT_DISABLED: 175157221772SChristopher Siden (void) printf(gettext(" status: Some supported features are " 175257221772SChristopher Siden "not enabled on the pool.\n")); 175357221772SChristopher Siden break; 175457221772SChristopher Siden 1755ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_READ: 1756ad135b5dSChristopher Siden (void) printf(gettext("status: The pool uses the following " 1757ad135b5dSChristopher Siden "feature(s) not supported on this sytem:\n")); 1758ad135b5dSChristopher Siden zpool_print_unsup_feat(config); 1759ad135b5dSChristopher Siden break; 1760ad135b5dSChristopher Siden 1761ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1762ad135b5dSChristopher Siden (void) printf(gettext("status: The pool can only be accessed " 1763ad135b5dSChristopher Siden "in read-only mode on this system. It\n\tcannot be " 1764ad135b5dSChristopher Siden "accessed in read-write mode because it uses the " 1765ad135b5dSChristopher Siden "following\n\tfeature(s) not supported on this system:\n")); 1766ad135b5dSChristopher Siden zpool_print_unsup_feat(config); 1767ad135b5dSChristopher Siden break; 1768ad135b5dSChristopher Siden 176995173954Sek case ZPOOL_STATUS_HOSTID_MISMATCH: 17708704186eSDan McDonald (void) printf(gettext(" status: The pool was last accessed by " 177195173954Sek "another system.\n")); 177295173954Sek break; 1773b87f3af3Sperrin 17743d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 17753d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 17768704186eSDan McDonald (void) printf(gettext(" status: One or more devices are " 17773d7072f8Seschrock "faulted.\n")); 17783d7072f8Seschrock break; 17793d7072f8Seschrock 1780b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 17818704186eSDan McDonald (void) printf(gettext(" status: An intent log record cannot be " 1782b87f3af3Sperrin "read.\n")); 1783b87f3af3Sperrin break; 1784b87f3af3Sperrin 17853f9d6ad7SLin Ling case ZPOOL_STATUS_RESILVERING: 17868704186eSDan McDonald (void) printf(gettext(" status: One or more devices were being " 17873f9d6ad7SLin Ling "resilvered.\n")); 17883f9d6ad7SLin Ling break; 17893f9d6ad7SLin Ling 1790fa9e4066Sahrens default: 1791fa9e4066Sahrens /* 1792fa9e4066Sahrens * No other status can be seen when importing pools. 1793fa9e4066Sahrens */ 1794fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 1795fa9e4066Sahrens } 1796fa9e4066Sahrens 1797fa9e4066Sahrens /* 1798fa9e4066Sahrens * Print out an action according to the overall state of the pool. 1799fa9e4066Sahrens */ 180046657f8dSmmusante if (vs->vs_state == VDEV_STATE_HEALTHY) { 180157221772SChristopher Siden if (reason == ZPOOL_STATUS_VERSION_OLDER || 180257221772SChristopher Siden reason == ZPOOL_STATUS_FEAT_DISABLED) { 18038704186eSDan McDonald (void) printf(gettext(" action: The pool can be " 1804eaca9bbdSeschrock "imported using its name or numeric identifier, " 1805eaca9bbdSeschrock "though\n\tsome features will not be available " 1806eaca9bbdSeschrock "without an explicit 'zpool upgrade'.\n")); 180757221772SChristopher Siden } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 18088704186eSDan McDonald (void) printf(gettext(" action: The pool can be " 180995173954Sek "imported using its name or numeric " 181095173954Sek "identifier and\n\tthe '-f' flag.\n")); 181157221772SChristopher Siden } else { 18128704186eSDan McDonald (void) printf(gettext(" action: The pool can be " 1813eaca9bbdSeschrock "imported using its name or numeric " 1814eaca9bbdSeschrock "identifier.\n")); 181557221772SChristopher Siden } 181646657f8dSmmusante } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 18178704186eSDan McDonald (void) printf(gettext(" action: The pool can be imported " 1818fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 1819eaca9bbdSeschrock "tolerance of the pool may be compromised if imported.\n")); 1820fa9e4066Sahrens } else { 1821eaca9bbdSeschrock switch (reason) { 1822eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 18238704186eSDan McDonald (void) printf(gettext(" action: The pool cannot be " 1824eaca9bbdSeschrock "imported. Access the pool on a system running " 1825eaca9bbdSeschrock "newer\n\tsoftware, or recreate the pool from " 1826eaca9bbdSeschrock "backup.\n")); 1827eaca9bbdSeschrock break; 1828ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_READ: 1829ad135b5dSChristopher Siden (void) printf(gettext("action: The pool cannot be " 1830ad135b5dSChristopher Siden "imported. Access the pool on a system that " 1831ad135b5dSChristopher Siden "supports\n\tthe required feature(s), or recreate " 1832ad135b5dSChristopher Siden "the pool from backup.\n")); 1833ad135b5dSChristopher Siden break; 1834ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1835ad135b5dSChristopher Siden (void) printf(gettext("action: The pool cannot be " 1836ad135b5dSChristopher Siden "imported in read-write mode. Import the pool " 1837ad135b5dSChristopher Siden "with\n" 1838ad135b5dSChristopher Siden "\t\"-o readonly=on\", access the pool on a system " 1839ad135b5dSChristopher Siden "that supports the\n\trequired feature(s), or " 1840ad135b5dSChristopher Siden "recreate the pool from backup.\n")); 1841ad135b5dSChristopher Siden break; 1842eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_R: 1843eaca9bbdSeschrock case ZPOOL_STATUS_MISSING_DEV_NR: 1844eaca9bbdSeschrock case ZPOOL_STATUS_BAD_GUID_SUM: 18458704186eSDan McDonald (void) printf(gettext(" action: The pool cannot be " 1846fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 1847fa9e4066Sahrens "again.\n")); 1848eaca9bbdSeschrock break; 1849eaca9bbdSeschrock default: 18508704186eSDan McDonald (void) printf(gettext(" action: The pool cannot be " 1851fa9e4066Sahrens "imported due to damaged devices or data.\n")); 1852eaca9bbdSeschrock } 1853eaca9bbdSeschrock } 1854eaca9bbdSeschrock 18558704186eSDan McDonald /* Print the comment attached to the pool. */ 18568704186eSDan McDonald if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 18578704186eSDan McDonald (void) printf(gettext("comment: %s\n"), comment); 18588704186eSDan McDonald 185946657f8dSmmusante /* 186046657f8dSmmusante * If the state is "closed" or "can't open", and the aux state 186146657f8dSmmusante * is "corrupt data": 186246657f8dSmmusante */ 186346657f8dSmmusante if (((vs->vs_state == VDEV_STATE_CLOSED) || 186446657f8dSmmusante (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 186546657f8dSmmusante (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1866eaca9bbdSeschrock if (pool_state == POOL_STATE_DESTROYED) 1867eaca9bbdSeschrock (void) printf(gettext("\tThe pool was destroyed, " 1868eaca9bbdSeschrock "but can be imported using the '-Df' flags.\n")); 1869eaca9bbdSeschrock else if (pool_state != POOL_STATE_EXPORTED) 1870eaca9bbdSeschrock (void) printf(gettext("\tThe pool may be active on " 187118ce54dfSek "another system, but can be imported using\n\t" 1872eaca9bbdSeschrock "the '-f' flag.\n")); 1873fa9e4066Sahrens } 1874fa9e4066Sahrens 1875fa9e4066Sahrens if (msgid != NULL) 1876654b400cSJoshua M. Clulow (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1877fa9e4066Sahrens msgid); 1878fa9e4066Sahrens 18798704186eSDan McDonald (void) printf(gettext(" config:\n\n")); 1880fa9e4066Sahrens 1881c67d9675Seschrock namewidth = max_width(NULL, nvroot, 0, 0); 1882fa9e4066Sahrens if (namewidth < 10) 1883fa9e4066Sahrens namewidth = 10; 18848654d025Sperrin 1885e6ca193dSGeorge Wilson print_import_config(name, nvroot, namewidth, 0); 1886e6ca193dSGeorge Wilson if (num_logs(nvroot) > 0) 1887e6ca193dSGeorge Wilson print_logs(NULL, nvroot, namewidth, B_FALSE); 1888fa9e4066Sahrens 1889fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 189046657f8dSmmusante (void) printf(gettext("\n\tAdditional devices are known to " 1891fa9e4066Sahrens "be part of this pool, though their\n\texact " 189246657f8dSmmusante "configuration cannot be determined.\n")); 1893fa9e4066Sahrens } 1894fa9e4066Sahrens } 1895fa9e4066Sahrens 1896fa9e4066Sahrens /* 1897fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 1898990b4856Slling * lifting off to zpool_import_props(), and then mounts the datasets contained 1899990b4856Slling * within the pool. 1900fa9e4066Sahrens */ 1901fa9e4066Sahrens static int 1902fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 19034b964adaSGeorge Wilson nvlist_t *props, int flags) 1904fa9e4066Sahrens { 1905fa9e4066Sahrens zpool_handle_t *zhp; 1906fa9e4066Sahrens char *name; 1907fa9e4066Sahrens uint64_t state; 1908eaca9bbdSeschrock uint64_t version; 1909fa9e4066Sahrens 1910fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1911fa9e4066Sahrens &name) == 0); 1912fa9e4066Sahrens 1913fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1914fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1915eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, 1916eaca9bbdSeschrock ZPOOL_CONFIG_VERSION, &version) == 0); 1917ad135b5dSChristopher Siden if (!SPA_VERSION_IS_SUPPORTED(version)) { 1918eaca9bbdSeschrock (void) fprintf(stderr, gettext("cannot import '%s': pool " 1919ad135b5dSChristopher Siden "is formatted using an unsupported ZFS version\n"), name); 1920eaca9bbdSeschrock return (1); 19214b964adaSGeorge Wilson } else if (state != POOL_STATE_EXPORTED && 19224b964adaSGeorge Wilson !(flags & ZFS_IMPORT_ANY_HOST)) { 192395173954Sek uint64_t hostid; 192495173954Sek 192595173954Sek if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 192695173954Sek &hostid) == 0) { 192795173954Sek if ((unsigned long)hostid != gethostid()) { 192895173954Sek char *hostname; 192995173954Sek uint64_t timestamp; 193095173954Sek time_t t; 193195173954Sek 193295173954Sek verify(nvlist_lookup_string(config, 193395173954Sek ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 193495173954Sek verify(nvlist_lookup_uint64(config, 193595173954Sek ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 193695173954Sek t = timestamp; 193795173954Sek (void) fprintf(stderr, gettext("cannot import " 193895173954Sek "'%s': pool may be in use from other " 193995173954Sek "system, it was last accessed by %s " 194095173954Sek "(hostid: 0x%lx) on %s"), name, hostname, 194195173954Sek (unsigned long)hostid, 194295173954Sek asctime(localtime(&t))); 194395173954Sek (void) fprintf(stderr, gettext("use '-f' to " 194495173954Sek "import anyway\n")); 194595173954Sek return (1); 194695173954Sek } 194795173954Sek } else { 194895173954Sek (void) fprintf(stderr, gettext("cannot import '%s': " 194995173954Sek "pool may be in use from other system\n"), name); 195095173954Sek (void) fprintf(stderr, gettext("use '-f' to import " 195195173954Sek "anyway\n")); 195295173954Sek return (1); 195395173954Sek } 1954fa9e4066Sahrens } 1955fa9e4066Sahrens 19564b964adaSGeorge Wilson if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1957fa9e4066Sahrens return (1); 1958fa9e4066Sahrens 1959fa9e4066Sahrens if (newname != NULL) 1960fa9e4066Sahrens name = (char *)newname; 1961fa9e4066Sahrens 19624f0f5e5bSVictor Latushkin if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 19634f0f5e5bSVictor Latushkin return (1); 1964fa9e4066Sahrens 1965379c004dSEric Schrock if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1966f9af39baSGeorge Wilson !(flags & ZFS_IMPORT_ONLY) && 1967379c004dSEric Schrock zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1968fa9e4066Sahrens zpool_close(zhp); 1969fa9e4066Sahrens return (1); 1970fa9e4066Sahrens } 1971fa9e4066Sahrens 1972fa9e4066Sahrens zpool_close(zhp); 1973468c413aSTim Haley return (0); 1974fa9e4066Sahrens } 1975fa9e4066Sahrens 1976fa9e4066Sahrens /* 19774c58d714Sdarrenm * zpool import [-d dir] [-D] 19782f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 19792f8aaab3Seschrock * [-d dir | -c cachefile] [-f] -a 19802f8aaab3Seschrock * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1981468c413aSTim Haley * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 19822f8aaab3Seschrock * 19832f8aaab3Seschrock * -c Read pool information from a cachefile instead of searching 19842f8aaab3Seschrock * devices. 1985fa9e4066Sahrens * 1986fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 1987fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 1988fa9e4066Sahrens * 19894c58d714Sdarrenm * -D Scan for previously destroyed pools or import all or only 19904c58d714Sdarrenm * specified destroyed pools. 19914c58d714Sdarrenm * 1992fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 1993fa9e4066Sahrens * the given root. The pool will remain exported when the machine 1994fa9e4066Sahrens * is rebooted. 1995fa9e4066Sahrens * 1996468c413aSTim Haley * -V Import even in the presence of faulted vdevs. This is an 1997c5904d13Seschrock * intentionally undocumented option for testing purposes, and 1998c5904d13Seschrock * treats the pool configuration as complete, leaving any bad 19994f0f5e5bSVictor Latushkin * vdevs in the FAULTED state. In other words, it does verbatim 20004f0f5e5bSVictor Latushkin * import. 2001c5904d13Seschrock * 2002468c413aSTim Haley * -f Force import, even if it appears that the pool is active. 2003468c413aSTim Haley * 2004468c413aSTim Haley * -F Attempt rewind if necessary. 2005468c413aSTim Haley * 2006468c413aSTim Haley * -n See if rewind would work, but don't actually rewind. 2007468c413aSTim Haley * 2008f9af39baSGeorge Wilson * -N Import the pool but don't mount datasets. 2009f9af39baSGeorge Wilson * 2010f9af39baSGeorge Wilson * -T Specify a starting txg to use for import. This option is 2011f9af39baSGeorge Wilson * intentionally undocumented option for testing purposes. 2012f9af39baSGeorge Wilson * 2013fa9e4066Sahrens * -a Import all pools found. 2014fa9e4066Sahrens * 2015990b4856Slling * -o Set property=value and/or temporary mount options (without '='). 2016ecd6cf80Smarks * 2017fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 2018fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 2019fa9e4066Sahrens */ 2020fa9e4066Sahrens int 2021fa9e4066Sahrens zpool_do_import(int argc, char **argv) 2022fa9e4066Sahrens { 2023fa9e4066Sahrens char **searchdirs = NULL; 2024fa9e4066Sahrens int nsearch = 0; 2025fa9e4066Sahrens int c; 2026d41c4376SMark J Musante int err = 0; 20272f8aaab3Seschrock nvlist_t *pools = NULL; 202899653d4eSeschrock boolean_t do_all = B_FALSE; 202999653d4eSeschrock boolean_t do_destroyed = B_FALSE; 2030fa9e4066Sahrens char *mntopts = NULL; 2031fa9e4066Sahrens nvpair_t *elem; 2032fa9e4066Sahrens nvlist_t *config; 203324e697d4Sck uint64_t searchguid = 0; 203424e697d4Sck char *searchname = NULL; 2035990b4856Slling char *propval; 2036fa9e4066Sahrens nvlist_t *found_config; 2037468c413aSTim Haley nvlist_t *policy = NULL; 2038ecd6cf80Smarks nvlist_t *props = NULL; 203999653d4eSeschrock boolean_t first; 20404b964adaSGeorge Wilson int flags = ZFS_IMPORT_NORMAL; 2041468c413aSTim Haley uint32_t rewind_policy = ZPOOL_NO_REWIND; 2042468c413aSTim Haley boolean_t dryrun = B_FALSE; 2043468c413aSTim Haley boolean_t do_rewind = B_FALSE; 2044468c413aSTim Haley boolean_t xtreme_rewind = B_FALSE; 2045f9af39baSGeorge Wilson uint64_t pool_state, txg = -1ULL; 20462f8aaab3Seschrock char *cachefile = NULL; 2047d41c4376SMark J Musante importargs_t idata = { 0 }; 2048f9af39baSGeorge Wilson char *endptr; 2049fa9e4066Sahrens 2050fa9e4066Sahrens /* check options */ 2051f9af39baSGeorge Wilson while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) { 2052fa9e4066Sahrens switch (c) { 2053fa9e4066Sahrens case 'a': 205499653d4eSeschrock do_all = B_TRUE; 2055fa9e4066Sahrens break; 20562f8aaab3Seschrock case 'c': 20572f8aaab3Seschrock cachefile = optarg; 20582f8aaab3Seschrock break; 2059fa9e4066Sahrens case 'd': 2060fa9e4066Sahrens if (searchdirs == NULL) { 2061fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 2062fa9e4066Sahrens } else { 2063fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 2064fa9e4066Sahrens sizeof (char *)); 2065fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 2066fa9e4066Sahrens sizeof (char *)); 2067fa9e4066Sahrens free(searchdirs); 2068fa9e4066Sahrens searchdirs = tmp; 2069fa9e4066Sahrens } 2070fa9e4066Sahrens searchdirs[nsearch++] = optarg; 2071fa9e4066Sahrens break; 20724c58d714Sdarrenm case 'D': 207399653d4eSeschrock do_destroyed = B_TRUE; 20744c58d714Sdarrenm break; 2075fa9e4066Sahrens case 'f': 20764b964adaSGeorge Wilson flags |= ZFS_IMPORT_ANY_HOST; 2077fa9e4066Sahrens break; 2078c5904d13Seschrock case 'F': 2079468c413aSTim Haley do_rewind = B_TRUE; 2080468c413aSTim Haley break; 20814b964adaSGeorge Wilson case 'm': 20824b964adaSGeorge Wilson flags |= ZFS_IMPORT_MISSING_LOG; 20834b964adaSGeorge Wilson break; 2084468c413aSTim Haley case 'n': 2085468c413aSTim Haley dryrun = B_TRUE; 2086c5904d13Seschrock break; 2087f9af39baSGeorge Wilson case 'N': 2088f9af39baSGeorge Wilson flags |= ZFS_IMPORT_ONLY; 2089f9af39baSGeorge Wilson break; 2090fa9e4066Sahrens case 'o': 2091990b4856Slling if ((propval = strchr(optarg, '=')) != NULL) { 2092990b4856Slling *propval = '\0'; 2093990b4856Slling propval++; 20940a48a24eStimh if (add_prop_list(optarg, propval, 20950a48a24eStimh &props, B_TRUE)) 2096990b4856Slling goto error; 2097990b4856Slling } else { 2098990b4856Slling mntopts = optarg; 2099990b4856Slling } 2100fa9e4066Sahrens break; 2101fa9e4066Sahrens case 'R': 2102990b4856Slling if (add_prop_list(zpool_prop_to_name( 21030a48a24eStimh ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 2104990b4856Slling goto error; 21052f8aaab3Seschrock if (nvlist_lookup_string(props, 21062f8aaab3Seschrock zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 21072f8aaab3Seschrock &propval) == 0) 21082f8aaab3Seschrock break; 2109990b4856Slling if (add_prop_list(zpool_prop_to_name( 21100a48a24eStimh ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2111990b4856Slling goto error; 2112fa9e4066Sahrens break; 2113f9af39baSGeorge Wilson case 'T': 2114f9af39baSGeorge Wilson errno = 0; 2115e42d2059SMatthew Ahrens txg = strtoull(optarg, &endptr, 0); 2116f9af39baSGeorge Wilson if (errno != 0 || *endptr != '\0') { 2117f9af39baSGeorge Wilson (void) fprintf(stderr, 2118f9af39baSGeorge Wilson gettext("invalid txg value\n")); 2119f9af39baSGeorge Wilson usage(B_FALSE); 2120f9af39baSGeorge Wilson } 2121f9af39baSGeorge Wilson rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 2122f9af39baSGeorge Wilson break; 2123468c413aSTim Haley case 'V': 21244b964adaSGeorge Wilson flags |= ZFS_IMPORT_VERBATIM; 2125468c413aSTim Haley break; 2126468c413aSTim Haley case 'X': 2127468c413aSTim Haley xtreme_rewind = B_TRUE; 2128468c413aSTim Haley break; 2129fa9e4066Sahrens case ':': 2130fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 2131fa9e4066Sahrens "'%c' option\n"), optopt); 213299653d4eSeschrock usage(B_FALSE); 2133fa9e4066Sahrens break; 2134fa9e4066Sahrens case '?': 2135fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2136fa9e4066Sahrens optopt); 213799653d4eSeschrock usage(B_FALSE); 2138fa9e4066Sahrens } 2139fa9e4066Sahrens } 2140fa9e4066Sahrens 2141fa9e4066Sahrens argc -= optind; 2142fa9e4066Sahrens argv += optind; 2143fa9e4066Sahrens 21442f8aaab3Seschrock if (cachefile && nsearch != 0) { 21452f8aaab3Seschrock (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 21462f8aaab3Seschrock usage(B_FALSE); 21472f8aaab3Seschrock } 21482f8aaab3Seschrock 2149468c413aSTim Haley if ((dryrun || xtreme_rewind) && !do_rewind) { 2150468c413aSTim Haley (void) fprintf(stderr, 2151468c413aSTim Haley gettext("-n or -X only meaningful with -F\n")); 2152468c413aSTim Haley usage(B_FALSE); 2153468c413aSTim Haley } 2154468c413aSTim Haley if (dryrun) 2155468c413aSTim Haley rewind_policy = ZPOOL_TRY_REWIND; 2156468c413aSTim Haley else if (do_rewind) 2157468c413aSTim Haley rewind_policy = ZPOOL_DO_REWIND; 2158468c413aSTim Haley if (xtreme_rewind) 2159468c413aSTim Haley rewind_policy |= ZPOOL_EXTREME_REWIND; 2160468c413aSTim Haley 2161468c413aSTim Haley /* In the future, we can capture further policy and include it here */ 2162468c413aSTim Haley if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2163f9af39baSGeorge Wilson nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 2164468c413aSTim Haley nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 2165468c413aSTim Haley goto error; 2166468c413aSTim Haley 2167fa9e4066Sahrens if (searchdirs == NULL) { 2168fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 21696401734dSWill Andrews searchdirs[0] = ZFS_DISK_ROOT; 2170fa9e4066Sahrens nsearch = 1; 2171fa9e4066Sahrens } 2172fa9e4066Sahrens 2173fa9e4066Sahrens /* check argument count */ 2174fa9e4066Sahrens if (do_all) { 2175fa9e4066Sahrens if (argc != 0) { 2176fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 217799653d4eSeschrock usage(B_FALSE); 2178fa9e4066Sahrens } 2179fa9e4066Sahrens } else { 2180fa9e4066Sahrens if (argc > 2) { 2181fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 218299653d4eSeschrock usage(B_FALSE); 2183fa9e4066Sahrens } 2184fa9e4066Sahrens 2185fa9e4066Sahrens /* 2186fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 2187fa9e4066Sahrens * here because otherwise any attempt to discover pools will 2188fa9e4066Sahrens * silently fail. 2189fa9e4066Sahrens */ 2190fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2191fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 2192fa9e4066Sahrens "discover pools: permission denied\n")); 219399653d4eSeschrock free(searchdirs); 2194468c413aSTim Haley nvlist_free(policy); 2195fa9e4066Sahrens return (1); 2196fa9e4066Sahrens } 2197fa9e4066Sahrens } 2198fa9e4066Sahrens 2199fa9e4066Sahrens /* 2200fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 2201fa9e4066Sahrens * 2202fa9e4066Sahrens * <none> Iterate through all pools and display information about 2203fa9e4066Sahrens * each one. 2204fa9e4066Sahrens * 2205fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 2206fa9e4066Sahrens * 2207fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 2208fa9e4066Sahrens * name and import that one. 22094c58d714Sdarrenm * 22104c58d714Sdarrenm * -D Above options applies only to destroyed pools. 2211fa9e4066Sahrens */ 2212fa9e4066Sahrens if (argc != 0) { 2213fa9e4066Sahrens char *endptr; 2214fa9e4066Sahrens 2215fa9e4066Sahrens errno = 0; 2216fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 22179edf9ebdSPrasad Joshi if (errno != 0 || *endptr != '\0') { 2218fa9e4066Sahrens searchname = argv[0]; 22199edf9ebdSPrasad Joshi searchguid = 0; 22209edf9ebdSPrasad Joshi } 2221fa9e4066Sahrens found_config = NULL; 2222fa9e4066Sahrens 222324e697d4Sck /* 2224d41c4376SMark J Musante * User specified a name or guid. Ensure it's unique. 222524e697d4Sck */ 2226d41c4376SMark J Musante idata.unique = B_TRUE; 222724e697d4Sck } 222824e697d4Sck 2229d41c4376SMark J Musante 2230d41c4376SMark J Musante idata.path = searchdirs; 2231d41c4376SMark J Musante idata.paths = nsearch; 2232d41c4376SMark J Musante idata.poolname = searchname; 2233d41c4376SMark J Musante idata.guid = searchguid; 2234d41c4376SMark J Musante idata.cachefile = cachefile; 2235d41c4376SMark J Musante 2236d41c4376SMark J Musante pools = zpool_search_import(g_zfs, &idata); 2237d41c4376SMark J Musante 2238d41c4376SMark J Musante if (pools != NULL && idata.exists && 2239d41c4376SMark J Musante (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2240d41c4376SMark J Musante (void) fprintf(stderr, gettext("cannot import '%s': " 2241d41c4376SMark J Musante "a pool with that name already exists\n"), 2242d41c4376SMark J Musante argv[0]); 2243d41c4376SMark J Musante (void) fprintf(stderr, gettext("use the form '%s " 2244d41c4376SMark J Musante "<pool | id> <newpool>' to give it a new name\n"), 2245d41c4376SMark J Musante "zpool import"); 2246d41c4376SMark J Musante err = 1; 2247d41c4376SMark J Musante } else if (pools == NULL && idata.exists) { 2248d41c4376SMark J Musante (void) fprintf(stderr, gettext("cannot import '%s': " 2249d41c4376SMark J Musante "a pool with that name is already created/imported,\n"), 2250d41c4376SMark J Musante argv[0]); 2251d41c4376SMark J Musante (void) fprintf(stderr, gettext("and no additional pools " 2252d41c4376SMark J Musante "with that name were found\n")); 2253d41c4376SMark J Musante err = 1; 2254d41c4376SMark J Musante } else if (pools == NULL) { 225524e697d4Sck if (argc != 0) { 225624e697d4Sck (void) fprintf(stderr, gettext("cannot import '%s': " 225724e697d4Sck "no such pool available\n"), argv[0]); 225824e697d4Sck } 2259d41c4376SMark J Musante err = 1; 2260d41c4376SMark J Musante } 2261d41c4376SMark J Musante 2262d41c4376SMark J Musante if (err == 1) { 226324e697d4Sck free(searchdirs); 2264468c413aSTim Haley nvlist_free(policy); 226524e697d4Sck return (1); 226624e697d4Sck } 226724e697d4Sck 226824e697d4Sck /* 226924e697d4Sck * At this point we have a list of import candidate configs. Even if 227024e697d4Sck * we were searching by pool name or guid, we still need to 227124e697d4Sck * post-process the list to deal with pool state and possible 227224e697d4Sck * duplicate names. 227324e697d4Sck */ 2274fa9e4066Sahrens err = 0; 2275fa9e4066Sahrens elem = NULL; 227699653d4eSeschrock first = B_TRUE; 2277fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2278fa9e4066Sahrens 2279fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 2280fa9e4066Sahrens 22814c58d714Sdarrenm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 22824c58d714Sdarrenm &pool_state) == 0); 22834c58d714Sdarrenm if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 22844c58d714Sdarrenm continue; 22854c58d714Sdarrenm if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 22864c58d714Sdarrenm continue; 22874c58d714Sdarrenm 2288468c413aSTim Haley verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2289468c413aSTim Haley policy) == 0); 2290468c413aSTim Haley 2291fa9e4066Sahrens if (argc == 0) { 2292fa9e4066Sahrens if (first) 229399653d4eSeschrock first = B_FALSE; 22943bb79becSeschrock else if (!do_all) 2295fa9e4066Sahrens (void) printf("\n"); 2296fa9e4066Sahrens 2297468c413aSTim Haley if (do_all) { 2298fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 22994b964adaSGeorge Wilson props, flags); 2300468c413aSTim Haley } else { 2301fa9e4066Sahrens show_import(config); 2302468c413aSTim Haley } 2303fa9e4066Sahrens } else if (searchname != NULL) { 2304fa9e4066Sahrens char *name; 2305fa9e4066Sahrens 2306fa9e4066Sahrens /* 2307fa9e4066Sahrens * We are searching for a pool based on name. 2308fa9e4066Sahrens */ 2309fa9e4066Sahrens verify(nvlist_lookup_string(config, 2310fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2311fa9e4066Sahrens 2312fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 2313fa9e4066Sahrens if (found_config != NULL) { 2314fa9e4066Sahrens (void) fprintf(stderr, gettext( 2315fa9e4066Sahrens "cannot import '%s': more than " 2316fa9e4066Sahrens "one matching pool\n"), searchname); 2317fa9e4066Sahrens (void) fprintf(stderr, gettext( 2318fa9e4066Sahrens "import by numeric ID instead\n")); 231999653d4eSeschrock err = B_TRUE; 2320fa9e4066Sahrens } 2321fa9e4066Sahrens found_config = config; 2322fa9e4066Sahrens } 2323fa9e4066Sahrens } else { 2324fa9e4066Sahrens uint64_t guid; 2325fa9e4066Sahrens 2326fa9e4066Sahrens /* 2327fa9e4066Sahrens * Search for a pool by guid. 2328fa9e4066Sahrens */ 2329fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 2330fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2331fa9e4066Sahrens 2332fa9e4066Sahrens if (guid == searchguid) 2333fa9e4066Sahrens found_config = config; 2334fa9e4066Sahrens } 2335fa9e4066Sahrens } 2336fa9e4066Sahrens 2337fa9e4066Sahrens /* 2338fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 2339fa9e4066Sahrens * pool, and then do the import. 2340fa9e4066Sahrens */ 2341fa9e4066Sahrens if (argc != 0 && err == 0) { 2342fa9e4066Sahrens if (found_config == NULL) { 2343fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 2344fa9e4066Sahrens "no such pool available\n"), argv[0]); 234599653d4eSeschrock err = B_TRUE; 2346fa9e4066Sahrens } else { 2347fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 23484b964adaSGeorge Wilson argv[1], mntopts, props, flags); 2349fa9e4066Sahrens } 2350fa9e4066Sahrens } 2351fa9e4066Sahrens 2352fa9e4066Sahrens /* 2353fa9e4066Sahrens * If we were just looking for pools, report an error if none were 2354fa9e4066Sahrens * found. 2355fa9e4066Sahrens */ 2356fa9e4066Sahrens if (argc == 0 && first) 2357fa9e4066Sahrens (void) fprintf(stderr, 2358fa9e4066Sahrens gettext("no pools available to import\n")); 2359fa9e4066Sahrens 2360ecd6cf80Smarks error: 23612f8aaab3Seschrock nvlist_free(props); 2362fa9e4066Sahrens nvlist_free(pools); 2363468c413aSTim Haley nvlist_free(policy); 236499653d4eSeschrock free(searchdirs); 2365fa9e4066Sahrens 2366fa9e4066Sahrens return (err ? 1 : 0); 2367fa9e4066Sahrens } 2368fa9e4066Sahrens 2369fa9e4066Sahrens typedef struct iostat_cbdata { 23704263d13fSGeorge Wilson boolean_t cb_verbose; 2371fa9e4066Sahrens int cb_namewidth; 23724263d13fSGeorge Wilson int cb_iteration; 23734263d13fSGeorge Wilson zpool_list_t *cb_list; 2374fa9e4066Sahrens } iostat_cbdata_t; 2375fa9e4066Sahrens 2376fa9e4066Sahrens static void 2377fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 2378fa9e4066Sahrens { 2379fa9e4066Sahrens int i = 0; 2380fa9e4066Sahrens 2381fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 2382fa9e4066Sahrens (void) printf("-"); 2383fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2384fa9e4066Sahrens } 2385fa9e4066Sahrens 2386fa9e4066Sahrens static void 2387fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 2388fa9e4066Sahrens { 2389fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 2390fa9e4066Sahrens cb->cb_namewidth, ""); 2391485bbbf5SGeorge Wilson (void) printf("%-*s alloc free read write read write\n", 2392fa9e4066Sahrens cb->cb_namewidth, "pool"); 2393fa9e4066Sahrens print_iostat_separator(cb); 2394fa9e4066Sahrens } 2395fa9e4066Sahrens 2396fa9e4066Sahrens /* 2397fa9e4066Sahrens * Display a single statistic. 2398fa9e4066Sahrens */ 2399990b4856Slling static void 2400fa9e4066Sahrens print_one_stat(uint64_t value) 2401fa9e4066Sahrens { 2402fa9e4066Sahrens char buf[64]; 2403fa9e4066Sahrens 2404fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 2405fa9e4066Sahrens (void) printf(" %5s", buf); 2406fa9e4066Sahrens } 2407fa9e4066Sahrens 2408fa9e4066Sahrens /* 2409fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 2410fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 2411fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 2412fa9e4066Sahrens */ 2413fa9e4066Sahrens void 2414c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2415c67d9675Seschrock nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2416fa9e4066Sahrens { 2417fa9e4066Sahrens nvlist_t **oldchild, **newchild; 2418fa9e4066Sahrens uint_t c, children; 2419fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 2420fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 2421fa9e4066Sahrens uint64_t tdelta; 2422fa9e4066Sahrens double scale; 2423afefbcddSeschrock char *vname; 2424fa9e4066Sahrens 2425fa9e4066Sahrens if (oldnv != NULL) { 24263f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(oldnv, 24273f9d6ad7SLin Ling ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2428fa9e4066Sahrens } else { 2429fa9e4066Sahrens oldvs = &zerovs; 2430fa9e4066Sahrens } 2431fa9e4066Sahrens 24323f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2433fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 2434fa9e4066Sahrens 2435fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 2436fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 2437fa9e4066Sahrens else 2438fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 2439fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2440fa9e4066Sahrens 2441fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2442fa9e4066Sahrens 2443fa9e4066Sahrens if (tdelta == 0) 2444fa9e4066Sahrens scale = 1.0; 2445fa9e4066Sahrens else 2446fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 2447fa9e4066Sahrens 2448fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 2449fa9e4066Sahrens if (newvs->vs_space == 0) { 2450fa9e4066Sahrens (void) printf(" - -"); 2451fa9e4066Sahrens } else { 2452fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 2453fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 2454fa9e4066Sahrens } 2455fa9e4066Sahrens 2456fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2457fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 2458fa9e4066Sahrens 2459fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2460fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2461fa9e4066Sahrens 2462fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2463fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 2464fa9e4066Sahrens 2465fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2466fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2467fa9e4066Sahrens 2468fa9e4066Sahrens (void) printf("\n"); 2469fa9e4066Sahrens 2470fa9e4066Sahrens if (!cb->cb_verbose) 2471fa9e4066Sahrens return; 2472fa9e4066Sahrens 2473fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2474fa9e4066Sahrens &newchild, &children) != 0) 2475fa9e4066Sahrens return; 2476fa9e4066Sahrens 2477fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2478fa9e4066Sahrens &oldchild, &c) != 0) 2479fa9e4066Sahrens return; 2480fa9e4066Sahrens 2481afefbcddSeschrock for (c = 0; c < children; c++) { 24829d439f90SMike Harsch uint64_t ishole = B_FALSE, islog = B_FALSE; 24833f9d6ad7SLin Ling 24849d439f90SMike Harsch (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 24859d439f90SMike Harsch &ishole); 24869d439f90SMike Harsch 24879d439f90SMike Harsch (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 24889d439f90SMike Harsch &islog); 24899d439f90SMike Harsch 24909d439f90SMike Harsch if (ishole || islog) 24913f9d6ad7SLin Ling continue; 24923f9d6ad7SLin Ling 249388ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2494c67d9675Seschrock print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2495afefbcddSeschrock newchild[c], cb, depth + 2); 2496afefbcddSeschrock free(vname); 2497afefbcddSeschrock } 2498fa94a07fSbrendan 24999d439f90SMike Harsch /* 25009d439f90SMike Harsch * Log device section 25019d439f90SMike Harsch */ 25029d439f90SMike Harsch 25039d439f90SMike Harsch if (num_logs(newnv) > 0) { 25049d439f90SMike Harsch (void) printf("%-*s - - - - - " 25059d439f90SMike Harsch "-\n", cb->cb_namewidth, "logs"); 25069d439f90SMike Harsch 25079d439f90SMike Harsch for (c = 0; c < children; c++) { 25089d439f90SMike Harsch uint64_t islog = B_FALSE; 25099d439f90SMike Harsch (void) nvlist_lookup_uint64(newchild[c], 25109d439f90SMike Harsch ZPOOL_CONFIG_IS_LOG, &islog); 25119d439f90SMike Harsch 25129d439f90SMike Harsch if (islog) { 25139d439f90SMike Harsch vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 25149d439f90SMike Harsch B_FALSE); 25159d439f90SMike Harsch print_vdev_stats(zhp, vname, oldnv ? 25169d439f90SMike Harsch oldchild[c] : NULL, newchild[c], 25179d439f90SMike Harsch cb, depth + 2); 25189d439f90SMike Harsch free(vname); 25199d439f90SMike Harsch } 25209d439f90SMike Harsch } 25219d439f90SMike Harsch 25229d439f90SMike Harsch } 25239d439f90SMike Harsch 2524fa94a07fSbrendan /* 2525fa94a07fSbrendan * Include level 2 ARC devices in iostat output 2526fa94a07fSbrendan */ 2527fa94a07fSbrendan if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2528fa94a07fSbrendan &newchild, &children) != 0) 2529fa94a07fSbrendan return; 2530fa94a07fSbrendan 2531fa94a07fSbrendan if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2532fa94a07fSbrendan &oldchild, &c) != 0) 2533fa94a07fSbrendan return; 2534fa94a07fSbrendan 2535fa94a07fSbrendan if (children > 0) { 2536fa94a07fSbrendan (void) printf("%-*s - - - - - " 2537fa94a07fSbrendan "-\n", cb->cb_namewidth, "cache"); 2538fa94a07fSbrendan for (c = 0; c < children; c++) { 253988ecc943SGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 254088ecc943SGeorge Wilson B_FALSE); 2541fa94a07fSbrendan print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2542fa94a07fSbrendan newchild[c], cb, depth + 2); 2543fa94a07fSbrendan free(vname); 2544fa94a07fSbrendan } 2545fa94a07fSbrendan } 2546fa9e4066Sahrens } 2547fa9e4066Sahrens 2548088e9d47Seschrock static int 2549088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data) 2550088e9d47Seschrock { 2551088e9d47Seschrock iostat_cbdata_t *cb = data; 255294de1d4cSeschrock boolean_t missing; 2553088e9d47Seschrock 2554088e9d47Seschrock /* 2555088e9d47Seschrock * If the pool has disappeared, remove it from the list and continue. 2556088e9d47Seschrock */ 255794de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) 255894de1d4cSeschrock return (-1); 255994de1d4cSeschrock 256094de1d4cSeschrock if (missing) 2561088e9d47Seschrock pool_list_remove(cb->cb_list, zhp); 2562088e9d47Seschrock 2563088e9d47Seschrock return (0); 2564088e9d47Seschrock } 2565088e9d47Seschrock 2566fa9e4066Sahrens /* 2567fa9e4066Sahrens * Callback to print out the iostats for the given pool. 2568fa9e4066Sahrens */ 2569fa9e4066Sahrens int 2570fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 2571fa9e4066Sahrens { 2572fa9e4066Sahrens iostat_cbdata_t *cb = data; 2573fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 2574fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 2575fa9e4066Sahrens 2576088e9d47Seschrock newconfig = zpool_get_config(zhp, &oldconfig); 2577fa9e4066Sahrens 2578088e9d47Seschrock if (cb->cb_iteration == 1) 2579fa9e4066Sahrens oldconfig = NULL; 2580fa9e4066Sahrens 2581fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2582fa9e4066Sahrens &newnvroot) == 0); 2583fa9e4066Sahrens 2584088e9d47Seschrock if (oldconfig == NULL) 2585fa9e4066Sahrens oldnvroot = NULL; 2586088e9d47Seschrock else 2587088e9d47Seschrock verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2588088e9d47Seschrock &oldnvroot) == 0); 2589fa9e4066Sahrens 2590fa9e4066Sahrens /* 2591fa9e4066Sahrens * Print out the statistics for the pool. 2592fa9e4066Sahrens */ 2593c67d9675Seschrock print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2594fa9e4066Sahrens 2595fa9e4066Sahrens if (cb->cb_verbose) 2596fa9e4066Sahrens print_iostat_separator(cb); 2597fa9e4066Sahrens 2598fa9e4066Sahrens return (0); 2599fa9e4066Sahrens } 2600fa9e4066Sahrens 2601fa9e4066Sahrens int 2602fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 2603fa9e4066Sahrens { 2604fa9e4066Sahrens iostat_cbdata_t *cb = data; 2605fa9e4066Sahrens nvlist_t *config, *nvroot; 2606fa9e4066Sahrens 2607088e9d47Seschrock if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2608fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2609fa9e4066Sahrens &nvroot) == 0); 2610fa9e4066Sahrens if (!cb->cb_verbose) 2611fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2612fa9e4066Sahrens else 2613e1d5e507SFrederik Wessels cb->cb_namewidth = max_width(zhp, nvroot, 0, 2614e1d5e507SFrederik Wessels cb->cb_namewidth); 2615fa9e4066Sahrens } 2616fa9e4066Sahrens 2617fa9e4066Sahrens /* 2618fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 2619fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 2620fa9e4066Sahrens */ 2621fa9e4066Sahrens if (cb->cb_namewidth < 10) 2622fa9e4066Sahrens cb->cb_namewidth = 10; 2623fa9e4066Sahrens if (cb->cb_namewidth > 38) 2624fa9e4066Sahrens cb->cb_namewidth = 38; 2625fa9e4066Sahrens 2626fa9e4066Sahrens return (0); 2627fa9e4066Sahrens } 2628fa9e4066Sahrens 2629fa9e4066Sahrens /* 26303f9d6ad7SLin Ling * Parse the input string, get the 'interval' and 'count' value if there is one. 2631fa9e4066Sahrens */ 26323f9d6ad7SLin Ling static void 26333f9d6ad7SLin Ling get_interval_count(int *argcp, char **argv, unsigned long *iv, 26343f9d6ad7SLin Ling unsigned long *cnt) 2635fa9e4066Sahrens { 2636fa9e4066Sahrens unsigned long interval = 0, count = 0; 26373f9d6ad7SLin Ling int argc = *argcp, errno; 2638fa9e4066Sahrens 2639fa9e4066Sahrens /* 2640fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 2641fa9e4066Sahrens */ 2642fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 2643fa9e4066Sahrens char *end; 2644fa9e4066Sahrens 2645fa9e4066Sahrens errno = 0; 2646fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 2647fa9e4066Sahrens 2648fa9e4066Sahrens if (*end == '\0' && errno == 0) { 2649fa9e4066Sahrens if (interval == 0) { 2650fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 2651fa9e4066Sahrens "cannot be zero\n")); 265299653d4eSeschrock usage(B_FALSE); 2653fa9e4066Sahrens } 2654fa9e4066Sahrens /* 2655fa9e4066Sahrens * Ignore the last parameter 2656fa9e4066Sahrens */ 2657fa9e4066Sahrens argc--; 2658fa9e4066Sahrens } else { 2659fa9e4066Sahrens /* 2660fa9e4066Sahrens * If this is not a valid number, just plow on. The 2661fa9e4066Sahrens * user will get a more informative error message later 2662fa9e4066Sahrens * on. 2663fa9e4066Sahrens */ 2664fa9e4066Sahrens interval = 0; 2665fa9e4066Sahrens } 2666fa9e4066Sahrens } 2667fa9e4066Sahrens 2668fa9e4066Sahrens /* 2669fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 26703f9d6ad7SLin Ling * and an interval. 2671fa9e4066Sahrens */ 2672fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 2673fa9e4066Sahrens char *end; 2674fa9e4066Sahrens 2675fa9e4066Sahrens errno = 0; 2676fa9e4066Sahrens count = interval; 2677fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 2678fa9e4066Sahrens 2679fa9e4066Sahrens if (*end == '\0' && errno == 0) { 2680fa9e4066Sahrens if (interval == 0) { 2681fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 2682fa9e4066Sahrens "cannot be zero\n")); 268399653d4eSeschrock usage(B_FALSE); 2684fa9e4066Sahrens } 2685fa9e4066Sahrens 2686fa9e4066Sahrens /* 2687fa9e4066Sahrens * Ignore the last parameter 2688fa9e4066Sahrens */ 2689fa9e4066Sahrens argc--; 2690fa9e4066Sahrens } else { 2691fa9e4066Sahrens interval = 0; 2692fa9e4066Sahrens } 2693fa9e4066Sahrens } 2694fa9e4066Sahrens 26953f9d6ad7SLin Ling *iv = interval; 26963f9d6ad7SLin Ling *cnt = count; 26973f9d6ad7SLin Ling *argcp = argc; 26983f9d6ad7SLin Ling } 26993f9d6ad7SLin Ling 27003f9d6ad7SLin Ling static void 27013f9d6ad7SLin Ling get_timestamp_arg(char c) 27023f9d6ad7SLin Ling { 27033f9d6ad7SLin Ling if (c == 'u') 27043f9d6ad7SLin Ling timestamp_fmt = UDATE; 27053f9d6ad7SLin Ling else if (c == 'd') 27063f9d6ad7SLin Ling timestamp_fmt = DDATE; 27073f9d6ad7SLin Ling else 27083f9d6ad7SLin Ling usage(B_FALSE); 27093f9d6ad7SLin Ling } 27103f9d6ad7SLin Ling 27113f9d6ad7SLin Ling /* 27123f9d6ad7SLin Ling * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 27133f9d6ad7SLin Ling * 27143f9d6ad7SLin Ling * -v Display statistics for individual vdevs 27153f9d6ad7SLin Ling * -T Display a timestamp in date(1) or Unix format 27163f9d6ad7SLin Ling * 27173f9d6ad7SLin Ling * This command can be tricky because we want to be able to deal with pool 27183f9d6ad7SLin Ling * creation/destruction as well as vdev configuration changes. The bulk of this 27193f9d6ad7SLin Ling * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 27203f9d6ad7SLin Ling * on pool_list_update() to detect the addition of new pools. Configuration 27213f9d6ad7SLin Ling * changes are all handled within libzfs. 27223f9d6ad7SLin Ling */ 27233f9d6ad7SLin Ling int 27243f9d6ad7SLin Ling zpool_do_iostat(int argc, char **argv) 27253f9d6ad7SLin Ling { 27263f9d6ad7SLin Ling int c; 27273f9d6ad7SLin Ling int ret; 27283f9d6ad7SLin Ling int npools; 27293f9d6ad7SLin Ling unsigned long interval = 0, count = 0; 27303f9d6ad7SLin Ling zpool_list_t *list; 27313f9d6ad7SLin Ling boolean_t verbose = B_FALSE; 27323f9d6ad7SLin Ling iostat_cbdata_t cb; 27333f9d6ad7SLin Ling 27343f9d6ad7SLin Ling /* check options */ 27353f9d6ad7SLin Ling while ((c = getopt(argc, argv, "T:v")) != -1) { 27363f9d6ad7SLin Ling switch (c) { 27373f9d6ad7SLin Ling case 'T': 27383f9d6ad7SLin Ling get_timestamp_arg(*optarg); 27393f9d6ad7SLin Ling break; 27403f9d6ad7SLin Ling case 'v': 27413f9d6ad7SLin Ling verbose = B_TRUE; 27423f9d6ad7SLin Ling break; 27433f9d6ad7SLin Ling case '?': 27443f9d6ad7SLin Ling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 27453f9d6ad7SLin Ling optopt); 27463f9d6ad7SLin Ling usage(B_FALSE); 27473f9d6ad7SLin Ling } 27483f9d6ad7SLin Ling } 27493f9d6ad7SLin Ling 27503f9d6ad7SLin Ling argc -= optind; 27513f9d6ad7SLin Ling argv += optind; 27523f9d6ad7SLin Ling 27533f9d6ad7SLin Ling get_interval_count(&argc, argv, &interval, &count); 27543f9d6ad7SLin Ling 2755fa9e4066Sahrens /* 2756fa9e4066Sahrens * Construct the list of all interesting pools. 2757fa9e4066Sahrens */ 2758fa9e4066Sahrens ret = 0; 2759b1b8ab34Slling if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2760fa9e4066Sahrens return (1); 2761fa9e4066Sahrens 276299653d4eSeschrock if (pool_list_count(list) == 0 && argc != 0) { 276399653d4eSeschrock pool_list_free(list); 2764fa9e4066Sahrens return (1); 276599653d4eSeschrock } 2766fa9e4066Sahrens 2767fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 276899653d4eSeschrock pool_list_free(list); 2769fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 2770fa9e4066Sahrens return (1); 2771fa9e4066Sahrens } 2772fa9e4066Sahrens 2773fa9e4066Sahrens /* 2774fa9e4066Sahrens * Enter the main iostat loop. 2775fa9e4066Sahrens */ 2776fa9e4066Sahrens cb.cb_list = list; 2777fa9e4066Sahrens cb.cb_verbose = verbose; 2778fa9e4066Sahrens cb.cb_iteration = 0; 2779fa9e4066Sahrens cb.cb_namewidth = 0; 2780fa9e4066Sahrens 2781fa9e4066Sahrens for (;;) { 2782fa9e4066Sahrens pool_list_update(list); 2783fa9e4066Sahrens 2784fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 2785fa9e4066Sahrens break; 2786fa9e4066Sahrens 2787088e9d47Seschrock /* 2788088e9d47Seschrock * Refresh all statistics. This is done as an explicit step 2789088e9d47Seschrock * before calculating the maximum name width, so that any 2790088e9d47Seschrock * configuration changes are properly accounted for. 2791088e9d47Seschrock */ 279299653d4eSeschrock (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2793088e9d47Seschrock 2794fa9e4066Sahrens /* 2795fa9e4066Sahrens * Iterate over all pools to determine the maximum width 2796fa9e4066Sahrens * for the pool / device name column across all pools. 2797fa9e4066Sahrens */ 2798fa9e4066Sahrens cb.cb_namewidth = 0; 279999653d4eSeschrock (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2800fa9e4066Sahrens 280126fd7700SKrishnendu Sadhukhan - Sun Microsystems if (timestamp_fmt != NODATE) 280226fd7700SKrishnendu Sadhukhan - Sun Microsystems print_timestamp(timestamp_fmt); 280326fd7700SKrishnendu Sadhukhan - Sun Microsystems 2804fa9e4066Sahrens /* 2805fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 2806fa9e4066Sahrens */ 2807fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 2808fa9e4066Sahrens print_iostat_header(&cb); 2809fa9e4066Sahrens 281099653d4eSeschrock (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2811fa9e4066Sahrens 2812fa9e4066Sahrens /* 2813fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 2814fa9e4066Sahrens * (which prints a separator for us), then print a separator. 2815fa9e4066Sahrens */ 2816fa9e4066Sahrens if (npools > 1 && !verbose) 2817fa9e4066Sahrens print_iostat_separator(&cb); 2818fa9e4066Sahrens 2819fa9e4066Sahrens if (verbose) 2820fa9e4066Sahrens (void) printf("\n"); 2821fa9e4066Sahrens 282239c23413Seschrock /* 282339c23413Seschrock * Flush the output so that redirection to a file isn't buffered 282439c23413Seschrock * indefinitely. 282539c23413Seschrock */ 282639c23413Seschrock (void) fflush(stdout); 282739c23413Seschrock 2828fa9e4066Sahrens if (interval == 0) 2829fa9e4066Sahrens break; 2830fa9e4066Sahrens 2831fa9e4066Sahrens if (count != 0 && --count == 0) 2832fa9e4066Sahrens break; 2833fa9e4066Sahrens 2834fa9e4066Sahrens (void) sleep(interval); 2835fa9e4066Sahrens } 2836fa9e4066Sahrens 2837fa9e4066Sahrens pool_list_free(list); 2838fa9e4066Sahrens 2839fa9e4066Sahrens return (ret); 2840fa9e4066Sahrens } 2841fa9e4066Sahrens 2842fa9e4066Sahrens typedef struct list_cbdata { 28434263d13fSGeorge Wilson boolean_t cb_verbose; 28444263d13fSGeorge Wilson int cb_namewidth; 284599653d4eSeschrock boolean_t cb_scripted; 2846990b4856Slling zprop_list_t *cb_proplist; 2847c58b3526SAdam Stevko boolean_t cb_literal; 2848fa9e4066Sahrens } list_cbdata_t; 2849fa9e4066Sahrens 2850fa9e4066Sahrens /* 2851fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 2852fa9e4066Sahrens */ 2853990b4856Slling static void 28544263d13fSGeorge Wilson print_header(list_cbdata_t *cb) 2855fa9e4066Sahrens { 28564263d13fSGeorge Wilson zprop_list_t *pl = cb->cb_proplist; 2857ad135b5dSChristopher Siden char headerbuf[ZPOOL_MAXPROPLEN]; 2858990b4856Slling const char *header; 2859990b4856Slling boolean_t first = B_TRUE; 2860990b4856Slling boolean_t right_justify; 28614263d13fSGeorge Wilson size_t width = 0; 2862990b4856Slling 2863990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 28644263d13fSGeorge Wilson width = pl->pl_width; 28654263d13fSGeorge Wilson if (first && cb->cb_verbose) { 28664263d13fSGeorge Wilson /* 28674263d13fSGeorge Wilson * Reset the width to accommodate the verbose listing 28684263d13fSGeorge Wilson * of devices. 28694263d13fSGeorge Wilson */ 28704263d13fSGeorge Wilson width = cb->cb_namewidth; 28714263d13fSGeorge Wilson } 28724263d13fSGeorge Wilson 2873990b4856Slling if (!first) 2874fa9e4066Sahrens (void) printf(" "); 2875fa9e4066Sahrens else 2876990b4856Slling first = B_FALSE; 2877990b4856Slling 2878ad135b5dSChristopher Siden right_justify = B_FALSE; 2879ad135b5dSChristopher Siden if (pl->pl_prop != ZPROP_INVAL) { 2880ad135b5dSChristopher Siden header = zpool_prop_column_name(pl->pl_prop); 2881ad135b5dSChristopher Siden right_justify = zpool_prop_align_right(pl->pl_prop); 2882ad135b5dSChristopher Siden } else { 2883ad135b5dSChristopher Siden int i; 2884ad135b5dSChristopher Siden 2885ad135b5dSChristopher Siden for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2886ad135b5dSChristopher Siden headerbuf[i] = toupper(pl->pl_user_prop[i]); 2887ad135b5dSChristopher Siden headerbuf[i] = '\0'; 2888ad135b5dSChristopher Siden header = headerbuf; 2889ad135b5dSChristopher Siden } 2890fa9e4066Sahrens 2891990b4856Slling if (pl->pl_next == NULL && !right_justify) 2892990b4856Slling (void) printf("%s", header); 2893990b4856Slling else if (right_justify) 28944263d13fSGeorge Wilson (void) printf("%*s", width, header); 2895990b4856Slling else 28964263d13fSGeorge Wilson (void) printf("%-*s", width, header); 28974263d13fSGeorge Wilson 2898fa9e4066Sahrens } 2899fa9e4066Sahrens 2900fa9e4066Sahrens (void) printf("\n"); 2901fa9e4066Sahrens } 2902fa9e4066Sahrens 2903990b4856Slling /* 2904990b4856Slling * Given a pool and a list of properties, print out all the properties according 2905990b4856Slling * to the described layout. 2906990b4856Slling */ 2907990b4856Slling static void 29084263d13fSGeorge Wilson print_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 2909fa9e4066Sahrens { 29104263d13fSGeorge Wilson zprop_list_t *pl = cb->cb_proplist; 2911990b4856Slling boolean_t first = B_TRUE; 2912990b4856Slling char property[ZPOOL_MAXPROPLEN]; 2913990b4856Slling char *propstr; 2914990b4856Slling boolean_t right_justify; 29154263d13fSGeorge Wilson size_t width; 2916990b4856Slling 2917990b4856Slling for (; pl != NULL; pl = pl->pl_next) { 29184263d13fSGeorge Wilson 29194263d13fSGeorge Wilson width = pl->pl_width; 29204263d13fSGeorge Wilson if (first && cb->cb_verbose) { 29214263d13fSGeorge Wilson /* 29224263d13fSGeorge Wilson * Reset the width to accommodate the verbose listing 29234263d13fSGeorge Wilson * of devices. 29244263d13fSGeorge Wilson */ 29254263d13fSGeorge Wilson width = cb->cb_namewidth; 29264263d13fSGeorge Wilson } 29274263d13fSGeorge Wilson 2928990b4856Slling if (!first) { 29294263d13fSGeorge Wilson if (cb->cb_scripted) 2930fa9e4066Sahrens (void) printf("\t"); 2931fa9e4066Sahrens else 2932fa9e4066Sahrens (void) printf(" "); 2933990b4856Slling } else { 2934990b4856Slling first = B_FALSE; 2935fa9e4066Sahrens } 2936fa9e4066Sahrens 2937990b4856Slling right_justify = B_FALSE; 2938990b4856Slling if (pl->pl_prop != ZPROP_INVAL) { 29397a09f97bSGeorge Wilson if (zpool_get_prop(zhp, pl->pl_prop, property, 2940c58b3526SAdam Stevko sizeof (property), NULL, cb->cb_literal) != 0) 2941990b4856Slling propstr = "-"; 2942fa9e4066Sahrens else 2943990b4856Slling propstr = property; 2944fa9e4066Sahrens 2945990b4856Slling right_justify = zpool_prop_align_right(pl->pl_prop); 2946ad135b5dSChristopher Siden } else if ((zpool_prop_feature(pl->pl_user_prop) || 2947ad135b5dSChristopher Siden zpool_prop_unsupported(pl->pl_user_prop)) && 2948ad135b5dSChristopher Siden zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 2949ad135b5dSChristopher Siden sizeof (property)) == 0) { 2950ad135b5dSChristopher Siden propstr = property; 2951990b4856Slling } else { 2952990b4856Slling propstr = "-"; 2953990b4856Slling } 2954fa9e4066Sahrens 2955fa9e4066Sahrens 2956990b4856Slling /* 2957990b4856Slling * If this is being called in scripted mode, or if this is the 2958990b4856Slling * last column and it is left-justified, don't include a width 2959990b4856Slling * format specifier. 2960990b4856Slling */ 29614263d13fSGeorge Wilson if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 2962990b4856Slling (void) printf("%s", propstr); 2963990b4856Slling else if (right_justify) 2964990b4856Slling (void) printf("%*s", width, propstr); 2965990b4856Slling else 2966990b4856Slling (void) printf("%-*s", width, propstr); 2967990b4856Slling } 2968fa9e4066Sahrens 2969990b4856Slling (void) printf("\n"); 2970990b4856Slling } 2971fa9e4066Sahrens 29724263d13fSGeorge Wilson static void 29737a09f97bSGeorge Wilson print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, 29747a09f97bSGeorge Wilson boolean_t valid) 29754263d13fSGeorge Wilson { 29764263d13fSGeorge Wilson char propval[64]; 29774263d13fSGeorge Wilson boolean_t fixed; 29784263d13fSGeorge Wilson size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 29794263d13fSGeorge Wilson 29807a09f97bSGeorge Wilson switch (prop) { 29817a09f97bSGeorge Wilson case ZPOOL_PROP_EXPANDSZ: 29827a09f97bSGeorge Wilson if (value == 0) 29837a09f97bSGeorge Wilson (void) strlcpy(propval, "-", sizeof (propval)); 29847a09f97bSGeorge Wilson else 29857a09f97bSGeorge Wilson zfs_nicenum(value, propval, sizeof (propval)); 29867a09f97bSGeorge Wilson break; 29877a09f97bSGeorge Wilson case ZPOOL_PROP_FRAGMENTATION: 29887a09f97bSGeorge Wilson if (value == ZFS_FRAG_INVALID) { 29897a09f97bSGeorge Wilson (void) strlcpy(propval, "-", sizeof (propval)); 29907a09f97bSGeorge Wilson } else { 29917a09f97bSGeorge Wilson (void) snprintf(propval, sizeof (propval), "%llu%%", 29927a09f97bSGeorge Wilson value); 29937a09f97bSGeorge Wilson } 29947a09f97bSGeorge Wilson break; 29957a09f97bSGeorge Wilson case ZPOOL_PROP_CAPACITY: 29962e4c9986SGeorge Wilson (void) snprintf(propval, sizeof (propval), "%llu%%", value); 29977a09f97bSGeorge Wilson break; 29987a09f97bSGeorge Wilson default: 29992e4c9986SGeorge Wilson zfs_nicenum(value, propval, sizeof (propval)); 30007a09f97bSGeorge Wilson } 30017a09f97bSGeorge Wilson 30027a09f97bSGeorge Wilson if (!valid) 30037a09f97bSGeorge Wilson (void) strlcpy(propval, "-", sizeof (propval)); 30044263d13fSGeorge Wilson 30054263d13fSGeorge Wilson if (scripted) 30064263d13fSGeorge Wilson (void) printf("\t%s", propval); 30074263d13fSGeorge Wilson else 30084263d13fSGeorge Wilson (void) printf(" %*s", width, propval); 30094263d13fSGeorge Wilson } 30104263d13fSGeorge Wilson 30114263d13fSGeorge Wilson void 30124263d13fSGeorge Wilson print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 30134263d13fSGeorge Wilson list_cbdata_t *cb, int depth) 30144263d13fSGeorge Wilson { 30154263d13fSGeorge Wilson nvlist_t **child; 30164263d13fSGeorge Wilson vdev_stat_t *vs; 30174263d13fSGeorge Wilson uint_t c, children; 30184263d13fSGeorge Wilson char *vname; 30194263d13fSGeorge Wilson boolean_t scripted = cb->cb_scripted; 302052244c09SJohn Wren Kennedy uint64_t islog = B_FALSE; 302152244c09SJohn Wren Kennedy boolean_t haslog = B_FALSE; 302252244c09SJohn Wren Kennedy char *dashes = "%-*s - - - - - -\n"; 30234263d13fSGeorge Wilson 30244263d13fSGeorge Wilson verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 30254263d13fSGeorge Wilson (uint64_t **)&vs, &c) == 0); 30264263d13fSGeorge Wilson 30274263d13fSGeorge Wilson if (name != NULL) { 30287a09f97bSGeorge Wilson boolean_t toplevel = (vs->vs_space != 0); 30297a09f97bSGeorge Wilson uint64_t cap; 30307a09f97bSGeorge Wilson 30314263d13fSGeorge Wilson if (scripted) 30324263d13fSGeorge Wilson (void) printf("\t%s", name); 30334263d13fSGeorge Wilson else if (strlen(name) + depth > cb->cb_namewidth) 30344263d13fSGeorge Wilson (void) printf("%*s%s", depth, "", name); 30354263d13fSGeorge Wilson else 30364263d13fSGeorge Wilson (void) printf("%*s%s%*s", depth, "", name, 30374263d13fSGeorge Wilson (int)(cb->cb_namewidth - strlen(name) - depth), ""); 30384263d13fSGeorge Wilson 30397a09f97bSGeorge Wilson /* 30407a09f97bSGeorge Wilson * Print the properties for the individual vdevs. Some 30417a09f97bSGeorge Wilson * properties are only applicable to toplevel vdevs. The 30427a09f97bSGeorge Wilson * 'toplevel' boolean value is passed to the print_one_column() 30437a09f97bSGeorge Wilson * to indicate that the value is valid. 30447a09f97bSGeorge Wilson */ 30457a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted, 30467a09f97bSGeorge Wilson toplevel); 30477a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted, 30487a09f97bSGeorge Wilson toplevel); 30497a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, 30507a09f97bSGeorge Wilson scripted, toplevel); 30517a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted, 30527a09f97bSGeorge Wilson B_TRUE); 30537a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_FRAGMENTATION, 30547a09f97bSGeorge Wilson vs->vs_fragmentation, scripted, 30557a09f97bSGeorge Wilson (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel)); 30567a09f97bSGeorge Wilson cap = (vs->vs_space == 0) ? 0 : 30577a09f97bSGeorge Wilson (vs->vs_alloc * 100 / vs->vs_space); 30587a09f97bSGeorge Wilson print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel); 30594263d13fSGeorge Wilson (void) printf("\n"); 30604263d13fSGeorge Wilson } 30614263d13fSGeorge Wilson 30624263d13fSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 30634263d13fSGeorge Wilson &child, &children) != 0) 30644263d13fSGeorge Wilson return; 30654263d13fSGeorge Wilson 30664263d13fSGeorge Wilson for (c = 0; c < children; c++) { 30674263d13fSGeorge Wilson uint64_t ishole = B_FALSE; 30684263d13fSGeorge Wilson 30694263d13fSGeorge Wilson if (nvlist_lookup_uint64(child[c], 30704263d13fSGeorge Wilson ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 30714263d13fSGeorge Wilson continue; 30724263d13fSGeorge Wilson 307352244c09SJohn Wren Kennedy if (nvlist_lookup_uint64(child[c], 307452244c09SJohn Wren Kennedy ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) { 307552244c09SJohn Wren Kennedy haslog = B_TRUE; 307652244c09SJohn Wren Kennedy continue; 307752244c09SJohn Wren Kennedy } 307852244c09SJohn Wren Kennedy 30794263d13fSGeorge Wilson vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 30804263d13fSGeorge Wilson print_list_stats(zhp, vname, child[c], cb, depth + 2); 30814263d13fSGeorge Wilson free(vname); 30824263d13fSGeorge Wilson } 30834263d13fSGeorge Wilson 308452244c09SJohn Wren Kennedy if (haslog == B_TRUE) { 308552244c09SJohn Wren Kennedy /* LINTED E_SEC_PRINTF_VAR_FMT */ 308652244c09SJohn Wren Kennedy (void) printf(dashes, cb->cb_namewidth, "log"); 308752244c09SJohn Wren Kennedy for (c = 0; c < children; c++) { 308852244c09SJohn Wren Kennedy if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 308952244c09SJohn Wren Kennedy &islog) != 0 || !islog) 309052244c09SJohn Wren Kennedy continue; 309152244c09SJohn Wren Kennedy vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 309252244c09SJohn Wren Kennedy print_list_stats(zhp, vname, child[c], cb, depth + 2); 309352244c09SJohn Wren Kennedy free(vname); 309452244c09SJohn Wren Kennedy } 309552244c09SJohn Wren Kennedy } 309652244c09SJohn Wren Kennedy 30974263d13fSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 309852244c09SJohn Wren Kennedy &child, &children) == 0 && children > 0) { 309952244c09SJohn Wren Kennedy /* LINTED E_SEC_PRINTF_VAR_FMT */ 310052244c09SJohn Wren Kennedy (void) printf(dashes, cb->cb_namewidth, "cache"); 310152244c09SJohn Wren Kennedy for (c = 0; c < children; c++) { 310252244c09SJohn Wren Kennedy vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 310352244c09SJohn Wren Kennedy print_list_stats(zhp, vname, child[c], cb, depth + 2); 310452244c09SJohn Wren Kennedy free(vname); 310552244c09SJohn Wren Kennedy } 310652244c09SJohn Wren Kennedy } 31074263d13fSGeorge Wilson 310852244c09SJohn Wren Kennedy if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child, 310952244c09SJohn Wren Kennedy &children) == 0 && children > 0) { 311052244c09SJohn Wren Kennedy /* LINTED E_SEC_PRINTF_VAR_FMT */ 311152244c09SJohn Wren Kennedy (void) printf(dashes, cb->cb_namewidth, "spare"); 31124263d13fSGeorge Wilson for (c = 0; c < children; c++) { 311352244c09SJohn Wren Kennedy vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 31144263d13fSGeorge Wilson print_list_stats(zhp, vname, child[c], cb, depth + 2); 31154263d13fSGeorge Wilson free(vname); 31164263d13fSGeorge Wilson } 31174263d13fSGeorge Wilson } 31184263d13fSGeorge Wilson } 31194263d13fSGeorge Wilson 31204263d13fSGeorge Wilson 3121990b4856Slling /* 3122990b4856Slling * Generic callback function to list a pool. 3123990b4856Slling */ 3124990b4856Slling int 3125990b4856Slling list_callback(zpool_handle_t *zhp, void *data) 3126990b4856Slling { 3127990b4856Slling list_cbdata_t *cbp = data; 31284263d13fSGeorge Wilson nvlist_t *config; 31294263d13fSGeorge Wilson nvlist_t *nvroot; 3130fa9e4066Sahrens 31314263d13fSGeorge Wilson config = zpool_get_config(zhp, NULL); 3132fa9e4066Sahrens 31334263d13fSGeorge Wilson print_pool(zhp, cbp); 31344263d13fSGeorge Wilson if (!cbp->cb_verbose) 31354263d13fSGeorge Wilson return (0); 31364263d13fSGeorge Wilson 31374263d13fSGeorge Wilson verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 31384263d13fSGeorge Wilson &nvroot) == 0); 31394263d13fSGeorge Wilson print_list_stats(zhp, NULL, nvroot, cbp, 0); 3140fa9e4066Sahrens 3141fa9e4066Sahrens return (0); 3142fa9e4066Sahrens } 3143fa9e4066Sahrens 3144fa9e4066Sahrens /* 3145c58b3526SAdam Stevko * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 3146fa9e4066Sahrens * 3147990b4856Slling * -H Scripted mode. Don't display headers, and separate properties 3148990b4856Slling * by a single tab. 3149990b4856Slling * -o List of properties to display. Defaults to 31507a09f97bSGeorge Wilson * "name,size,allocated,free,expandsize,fragmentation,capacity," 31517a09f97bSGeorge Wilson * "dedupratio,health,altroot" 3152c58b3526SAdam Stevko * -p Diplay values in parsable (exact) format. 31533f9d6ad7SLin Ling * -T Display a timestamp in date(1) or Unix format 3154fa9e4066Sahrens * 3155fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 3156fa9e4066Sahrens * statistics for each one, as well as health status summary. 3157fa9e4066Sahrens */ 3158fa9e4066Sahrens int 3159fa9e4066Sahrens zpool_do_list(int argc, char **argv) 3160fa9e4066Sahrens { 3161fa9e4066Sahrens int c; 3162fa9e4066Sahrens int ret; 3163fa9e4066Sahrens list_cbdata_t cb = { 0 }; 3164990b4856Slling static char default_props[] = 31657a09f97bSGeorge Wilson "name,size,allocated,free,expandsize,fragmentation,capacity," 31662e4c9986SGeorge Wilson "dedupratio,health,altroot"; 3167990b4856Slling char *props = default_props; 31683f9d6ad7SLin Ling unsigned long interval = 0, count = 0; 31694263d13fSGeorge Wilson zpool_list_t *list; 31704263d13fSGeorge Wilson boolean_t first = B_TRUE; 3171fa9e4066Sahrens 3172fa9e4066Sahrens /* check options */ 3173c58b3526SAdam Stevko while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) { 3174fa9e4066Sahrens switch (c) { 3175fa9e4066Sahrens case 'H': 317699653d4eSeschrock cb.cb_scripted = B_TRUE; 3177fa9e4066Sahrens break; 3178fa9e4066Sahrens case 'o': 3179990b4856Slling props = optarg; 3180fa9e4066Sahrens break; 3181c58b3526SAdam Stevko case 'p': 3182c58b3526SAdam Stevko cb.cb_literal = B_TRUE; 3183c58b3526SAdam Stevko break; 31843f9d6ad7SLin Ling case 'T': 31853f9d6ad7SLin Ling get_timestamp_arg(*optarg); 31863f9d6ad7SLin Ling break; 31874263d13fSGeorge Wilson case 'v': 31884263d13fSGeorge Wilson cb.cb_verbose = B_TRUE; 31894263d13fSGeorge Wilson break; 3190fa9e4066Sahrens case ':': 3191fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 3192fa9e4066Sahrens "'%c' option\n"), optopt); 319399653d4eSeschrock usage(B_FALSE); 3194fa9e4066Sahrens break; 3195fa9e4066Sahrens case '?': 3196fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3197fa9e4066Sahrens optopt); 319899653d4eSeschrock usage(B_FALSE); 3199fa9e4066Sahrens } 3200fa9e4066Sahrens } 3201fa9e4066Sahrens 3202fa9e4066Sahrens argc -= optind; 3203fa9e4066Sahrens argv += optind; 3204fa9e4066Sahrens 32053f9d6ad7SLin Ling get_interval_count(&argc, argv, &interval, &count); 32063f9d6ad7SLin Ling 3207990b4856Slling if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3208990b4856Slling usage(B_FALSE); 3209fa9e4066Sahrens 32103f9d6ad7SLin Ling for (;;) { 3211cd67d23dSGeorge Wilson if ((list = pool_list_get(argc, argv, &cb.cb_proplist, 3212cd67d23dSGeorge Wilson &ret)) == NULL) 3213cd67d23dSGeorge Wilson return (1); 32144263d13fSGeorge Wilson 32154263d13fSGeorge Wilson if (pool_list_count(list) == 0) 32164263d13fSGeorge Wilson break; 32174263d13fSGeorge Wilson 32184263d13fSGeorge Wilson cb.cb_namewidth = 0; 32194263d13fSGeorge Wilson (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3220990b4856Slling 32213f9d6ad7SLin Ling if (timestamp_fmt != NODATE) 32223f9d6ad7SLin Ling print_timestamp(timestamp_fmt); 3223fa9e4066Sahrens 32244263d13fSGeorge Wilson if (!cb.cb_scripted && (first || cb.cb_verbose)) { 32254263d13fSGeorge Wilson print_header(&cb); 32264263d13fSGeorge Wilson first = B_FALSE; 32273f9d6ad7SLin Ling } 32284263d13fSGeorge Wilson ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 32293f9d6ad7SLin Ling 32303f9d6ad7SLin Ling if (interval == 0) 32313f9d6ad7SLin Ling break; 32323f9d6ad7SLin Ling 32333f9d6ad7SLin Ling if (count != 0 && --count == 0) 32343f9d6ad7SLin Ling break; 32353f9d6ad7SLin Ling 3236cd67d23dSGeorge Wilson pool_list_free(list); 32373f9d6ad7SLin Ling (void) sleep(interval); 3238fa9e4066Sahrens } 3239fa9e4066Sahrens 3240cd67d23dSGeorge Wilson if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3241cd67d23dSGeorge Wilson (void) printf(gettext("no pools available\n")); 3242cd67d23dSGeorge Wilson ret = 0; 3243cd67d23dSGeorge Wilson } 3244cd67d23dSGeorge Wilson 3245cd67d23dSGeorge Wilson pool_list_free(list); 32463f9d6ad7SLin Ling zprop_free_list(cb.cb_proplist); 3247fa9e4066Sahrens return (ret); 3248fa9e4066Sahrens } 3249fa9e4066Sahrens 3250fa9e4066Sahrens static int 3251fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 3252fa9e4066Sahrens { 325399653d4eSeschrock boolean_t force = B_FALSE; 3254fa9e4066Sahrens int c; 3255fa9e4066Sahrens nvlist_t *nvroot; 3256fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 3257fa9e4066Sahrens zpool_handle_t *zhp; 32587855d95bSToomas Soome zpool_boot_label_t boot_type; 32597855d95bSToomas Soome uint64_t boot_size; 326099653d4eSeschrock int ret; 3261fa9e4066Sahrens 3262fa9e4066Sahrens /* check options */ 3263fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 3264fa9e4066Sahrens switch (c) { 3265fa9e4066Sahrens case 'f': 326699653d4eSeschrock force = B_TRUE; 3267fa9e4066Sahrens break; 3268fa9e4066Sahrens case '?': 3269fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3270fa9e4066Sahrens optopt); 327199653d4eSeschrock usage(B_FALSE); 3272fa9e4066Sahrens } 3273fa9e4066Sahrens } 3274fa9e4066Sahrens 3275fa9e4066Sahrens argc -= optind; 3276fa9e4066Sahrens argv += optind; 3277fa9e4066Sahrens 3278fa9e4066Sahrens /* get pool name and check number of arguments */ 3279fa9e4066Sahrens if (argc < 1) { 3280fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 328199653d4eSeschrock usage(B_FALSE); 3282fa9e4066Sahrens } 3283fa9e4066Sahrens 3284fa9e4066Sahrens poolname = argv[0]; 3285fa9e4066Sahrens 3286fa9e4066Sahrens if (argc < 2) { 3287fa9e4066Sahrens (void) fprintf(stderr, 3288fa9e4066Sahrens gettext("missing <device> specification\n")); 328999653d4eSeschrock usage(B_FALSE); 3290fa9e4066Sahrens } 3291fa9e4066Sahrens 3292fa9e4066Sahrens old_disk = argv[1]; 3293fa9e4066Sahrens 3294fa9e4066Sahrens if (argc < 3) { 3295fa9e4066Sahrens if (!replacing) { 3296fa9e4066Sahrens (void) fprintf(stderr, 3297fa9e4066Sahrens gettext("missing <new_device> specification\n")); 329899653d4eSeschrock usage(B_FALSE); 3299fa9e4066Sahrens } 3300fa9e4066Sahrens new_disk = old_disk; 3301fa9e4066Sahrens argc -= 1; 3302fa9e4066Sahrens argv += 1; 3303fa9e4066Sahrens } else { 3304fa9e4066Sahrens new_disk = argv[2]; 3305fa9e4066Sahrens argc -= 2; 3306fa9e4066Sahrens argv += 2; 3307fa9e4066Sahrens } 3308fa9e4066Sahrens 3309fa9e4066Sahrens if (argc > 1) { 3310fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 331199653d4eSeschrock usage(B_FALSE); 3312fa9e4066Sahrens } 3313fa9e4066Sahrens 331499653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3315fa9e4066Sahrens return (1); 3316fa9e4066Sahrens 33178488aeb5Staylor if (zpool_get_config(zhp, NULL) == NULL) { 3318fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3319fa9e4066Sahrens poolname); 3320fa9e4066Sahrens zpool_close(zhp); 3321fa9e4066Sahrens return (1); 3322fa9e4066Sahrens } 3323fa9e4066Sahrens 33247855d95bSToomas Soome if (zpool_is_bootable(zhp)) 33257855d95bSToomas Soome boot_type = ZPOOL_COPY_BOOT_LABEL; 33267855d95bSToomas Soome else 33277855d95bSToomas Soome boot_type = ZPOOL_NO_BOOT_LABEL; 33287855d95bSToomas Soome 33297855d95bSToomas Soome boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL); 3330705040edSEric Taylor nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 33317855d95bSToomas Soome boot_type, boot_size, argc, argv); 3332fa9e4066Sahrens if (nvroot == NULL) { 3333fa9e4066Sahrens zpool_close(zhp); 3334fa9e4066Sahrens return (1); 3335fa9e4066Sahrens } 3336fa9e4066Sahrens 333799653d4eSeschrock ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 333899653d4eSeschrock 333999653d4eSeschrock nvlist_free(nvroot); 334099653d4eSeschrock zpool_close(zhp); 334199653d4eSeschrock 334299653d4eSeschrock return (ret); 3343fa9e4066Sahrens } 3344fa9e4066Sahrens 3345fa9e4066Sahrens /* 3346fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 3347fa9e4066Sahrens * 3348fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 3349fa9e4066Sahrens * 3350fa9e4066Sahrens * Replace <device> with <new_device>. 3351fa9e4066Sahrens */ 3352fa9e4066Sahrens /* ARGSUSED */ 3353fa9e4066Sahrens int 3354fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 3355fa9e4066Sahrens { 3356fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3357fa9e4066Sahrens } 3358fa9e4066Sahrens 3359fa9e4066Sahrens /* 3360fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 3361fa9e4066Sahrens * 3362fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 3363fa9e4066Sahrens * 3364fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 3365fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 3366fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 3367fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 3368fa9e4066Sahrens */ 3369fa9e4066Sahrens int 3370fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 3371fa9e4066Sahrens { 3372fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3373fa9e4066Sahrens } 3374fa9e4066Sahrens 3375fa9e4066Sahrens /* 3376fa9e4066Sahrens * zpool detach [-f] <pool> <device> 3377fa9e4066Sahrens * 3378fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 3379fa9e4066Sahrens * (not supported yet) 3380fa9e4066Sahrens * 3381fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 3382fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 3383fa9e4066Sahrens * has the only valid copy of some data. 3384fa9e4066Sahrens */ 3385fa9e4066Sahrens /* ARGSUSED */ 3386fa9e4066Sahrens int 3387fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 3388fa9e4066Sahrens { 3389fa9e4066Sahrens int c; 3390fa9e4066Sahrens char *poolname, *path; 3391fa9e4066Sahrens zpool_handle_t *zhp; 339299653d4eSeschrock int ret; 3393fa9e4066Sahrens 3394fa9e4066Sahrens /* check options */ 3395fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 3396fa9e4066Sahrens switch (c) { 3397fa9e4066Sahrens case 'f': 3398fa9e4066Sahrens case '?': 3399fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3400fa9e4066Sahrens optopt); 340199653d4eSeschrock usage(B_FALSE); 3402fa9e4066Sahrens } 3403fa9e4066Sahrens } 3404fa9e4066Sahrens 3405fa9e4066Sahrens argc -= optind; 3406fa9e4066Sahrens argv += optind; 3407fa9e4066Sahrens 3408fa9e4066Sahrens /* get pool name and check number of arguments */ 3409fa9e4066Sahrens if (argc < 1) { 3410fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 341199653d4eSeschrock usage(B_FALSE); 3412fa9e4066Sahrens } 3413fa9e4066Sahrens 3414fa9e4066Sahrens if (argc < 2) { 3415fa9e4066Sahrens (void) fprintf(stderr, 3416fa9e4066Sahrens gettext("missing <device> specification\n")); 341799653d4eSeschrock usage(B_FALSE); 3418fa9e4066Sahrens } 3419fa9e4066Sahrens 3420fa9e4066Sahrens poolname = argv[0]; 3421fa9e4066Sahrens path = argv[1]; 3422fa9e4066Sahrens 342399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3424fa9e4066Sahrens return (1); 3425fa9e4066Sahrens 342699653d4eSeschrock ret = zpool_vdev_detach(zhp, path); 342799653d4eSeschrock 342899653d4eSeschrock zpool_close(zhp); 342999653d4eSeschrock 343099653d4eSeschrock return (ret); 3431fa9e4066Sahrens } 3432fa9e4066Sahrens 34331195e687SMark J Musante /* 34341195e687SMark J Musante * zpool split [-n] [-o prop=val] ... 34351195e687SMark J Musante * [-o mntopt] ... 34361195e687SMark J Musante * [-R altroot] <pool> <newpool> [<device> ...] 34371195e687SMark J Musante * 34381195e687SMark J Musante * -n Do not split the pool, but display the resulting layout if 34391195e687SMark J Musante * it were to be split. 34401195e687SMark J Musante * -o Set property=value, or set mount options. 34411195e687SMark J Musante * -R Mount the split-off pool under an alternate root. 34421195e687SMark J Musante * 34431195e687SMark J Musante * Splits the named pool and gives it the new pool name. Devices to be split 34441195e687SMark J Musante * off may be listed, provided that no more than one device is specified 34451195e687SMark J Musante * per top-level vdev mirror. The newly split pool is left in an exported 34461195e687SMark J Musante * state unless -R is specified. 34471195e687SMark J Musante * 34481195e687SMark J Musante * Restrictions: the top-level of the pool pool must only be made up of 34491195e687SMark J Musante * mirrors; all devices in the pool must be healthy; no device may be 34501195e687SMark J Musante * undergoing a resilvering operation. 34511195e687SMark J Musante */ 34521195e687SMark J Musante int 34531195e687SMark J Musante zpool_do_split(int argc, char **argv) 34541195e687SMark J Musante { 34551195e687SMark J Musante char *srcpool, *newpool, *propval; 34561195e687SMark J Musante char *mntopts = NULL; 34571195e687SMark J Musante splitflags_t flags; 34581195e687SMark J Musante int c, ret = 0; 34591195e687SMark J Musante zpool_handle_t *zhp; 34601195e687SMark J Musante nvlist_t *config, *props = NULL; 34611195e687SMark J Musante 34621195e687SMark J Musante flags.dryrun = B_FALSE; 34631195e687SMark J Musante flags.import = B_FALSE; 34641195e687SMark J Musante 34651195e687SMark J Musante /* check options */ 34661195e687SMark J Musante while ((c = getopt(argc, argv, ":R:no:")) != -1) { 34671195e687SMark J Musante switch (c) { 34681195e687SMark J Musante case 'R': 34691195e687SMark J Musante flags.import = B_TRUE; 34701195e687SMark J Musante if (add_prop_list( 34711195e687SMark J Musante zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 34721195e687SMark J Musante &props, B_TRUE) != 0) { 3473aab83bb8SJosef 'Jeff' Sipek nvlist_free(props); 34741195e687SMark J Musante usage(B_FALSE); 34751195e687SMark J Musante } 34761195e687SMark J Musante break; 34771195e687SMark J Musante case 'n': 34781195e687SMark J Musante flags.dryrun = B_TRUE; 34791195e687SMark J Musante break; 34801195e687SMark J Musante case 'o': 34811195e687SMark J Musante if ((propval = strchr(optarg, '=')) != NULL) { 34821195e687SMark J Musante *propval = '\0'; 34831195e687SMark J Musante propval++; 34841195e687SMark J Musante if (add_prop_list(optarg, propval, 34851195e687SMark J Musante &props, B_TRUE) != 0) { 3486aab83bb8SJosef 'Jeff' Sipek nvlist_free(props); 34871195e687SMark J Musante usage(B_FALSE); 34881195e687SMark J Musante } 34891195e687SMark J Musante } else { 34901195e687SMark J Musante mntopts = optarg; 34911195e687SMark J Musante } 34921195e687SMark J Musante break; 34931195e687SMark J Musante case ':': 34941195e687SMark J Musante (void) fprintf(stderr, gettext("missing argument for " 34951195e687SMark J Musante "'%c' option\n"), optopt); 34961195e687SMark J Musante usage(B_FALSE); 34971195e687SMark J Musante break; 34981195e687SMark J Musante case '?': 34991195e687SMark J Musante (void) fprintf(stderr, gettext("invalid option '%c'\n"), 35001195e687SMark J Musante optopt); 35011195e687SMark J Musante usage(B_FALSE); 35021195e687SMark J Musante break; 35031195e687SMark J Musante } 35041195e687SMark J Musante } 35051195e687SMark J Musante 35061195e687SMark J Musante if (!flags.import && mntopts != NULL) { 35071195e687SMark J Musante (void) fprintf(stderr, gettext("setting mntopts is only " 35081195e687SMark J Musante "valid when importing the pool\n")); 35091195e687SMark J Musante usage(B_FALSE); 35101195e687SMark J Musante } 35111195e687SMark J Musante 35121195e687SMark J Musante argc -= optind; 35131195e687SMark J Musante argv += optind; 35141195e687SMark J Musante 35151195e687SMark J Musante if (argc < 1) { 35161195e687SMark J Musante (void) fprintf(stderr, gettext("Missing pool name\n")); 35171195e687SMark J Musante usage(B_FALSE); 35181195e687SMark J Musante } 35191195e687SMark J Musante if (argc < 2) { 35201195e687SMark J Musante (void) fprintf(stderr, gettext("Missing new pool name\n")); 35211195e687SMark J Musante usage(B_FALSE); 35221195e687SMark J Musante } 35231195e687SMark J Musante 35241195e687SMark J Musante srcpool = argv[0]; 35251195e687SMark J Musante newpool = argv[1]; 35261195e687SMark J Musante 35271195e687SMark J Musante argc -= 2; 35281195e687SMark J Musante argv += 2; 35291195e687SMark J Musante 35301195e687SMark J Musante if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 35311195e687SMark J Musante return (1); 35321195e687SMark J Musante 35331195e687SMark J Musante config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 35341195e687SMark J Musante if (config == NULL) { 35351195e687SMark J Musante ret = 1; 35361195e687SMark J Musante } else { 35371195e687SMark J Musante if (flags.dryrun) { 35381195e687SMark J Musante (void) printf(gettext("would create '%s' with the " 35391195e687SMark J Musante "following layout:\n\n"), newpool); 35401195e687SMark J Musante print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 35411195e687SMark J Musante } 35421195e687SMark J Musante nvlist_free(config); 35431195e687SMark J Musante } 35441195e687SMark J Musante 35451195e687SMark J Musante zpool_close(zhp); 35461195e687SMark J Musante 35471195e687SMark J Musante if (ret != 0 || flags.dryrun || !flags.import) 35481195e687SMark J Musante return (ret); 35491195e687SMark J Musante 35501195e687SMark J Musante /* 35511195e687SMark J Musante * The split was successful. Now we need to open the new 35521195e687SMark J Musante * pool and import it. 35531195e687SMark J Musante */ 35541195e687SMark J Musante if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 35551195e687SMark J Musante return (1); 35561195e687SMark J Musante if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 35571195e687SMark J Musante zpool_enable_datasets(zhp, mntopts, 0) != 0) { 35581195e687SMark J Musante ret = 1; 3559fe7cd8aaSCyril Plisko (void) fprintf(stderr, gettext("Split was successful, but " 35601195e687SMark J Musante "the datasets could not all be mounted\n")); 35611195e687SMark J Musante (void) fprintf(stderr, gettext("Try doing '%s' with a " 35621195e687SMark J Musante "different altroot\n"), "zpool import"); 35631195e687SMark J Musante } 35641195e687SMark J Musante zpool_close(zhp); 35651195e687SMark J Musante 35661195e687SMark J Musante return (ret); 35671195e687SMark J Musante } 35681195e687SMark J Musante 35691195e687SMark J Musante 35701195e687SMark J Musante 3571fa9e4066Sahrens /* 3572441d80aaSlling * zpool online <pool> <device> ... 3573fa9e4066Sahrens */ 3574fa9e4066Sahrens int 3575fa9e4066Sahrens zpool_do_online(int argc, char **argv) 3576fa9e4066Sahrens { 3577fa9e4066Sahrens int c, i; 3578fa9e4066Sahrens char *poolname; 3579fa9e4066Sahrens zpool_handle_t *zhp; 3580fa9e4066Sahrens int ret = 0; 35813d7072f8Seschrock vdev_state_t newstate; 3582573ca77eSGeorge Wilson int flags = 0; 3583fa9e4066Sahrens 3584fa9e4066Sahrens /* check options */ 3585573ca77eSGeorge Wilson while ((c = getopt(argc, argv, "et")) != -1) { 3586fa9e4066Sahrens switch (c) { 3587573ca77eSGeorge Wilson case 'e': 3588573ca77eSGeorge Wilson flags |= ZFS_ONLINE_EXPAND; 3589573ca77eSGeorge Wilson break; 3590fa9e4066Sahrens case 't': 3591fa9e4066Sahrens case '?': 3592fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3593fa9e4066Sahrens optopt); 359499653d4eSeschrock usage(B_FALSE); 3595fa9e4066Sahrens } 3596fa9e4066Sahrens } 3597fa9e4066Sahrens 3598fa9e4066Sahrens argc -= optind; 3599fa9e4066Sahrens argv += optind; 3600fa9e4066Sahrens 3601fa9e4066Sahrens /* get pool name and check number of arguments */ 3602fa9e4066Sahrens if (argc < 1) { 3603fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 360499653d4eSeschrock usage(B_FALSE); 3605fa9e4066Sahrens } 3606fa9e4066Sahrens if (argc < 2) { 3607fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 360899653d4eSeschrock usage(B_FALSE); 3609fa9e4066Sahrens } 3610fa9e4066Sahrens 3611fa9e4066Sahrens poolname = argv[0]; 3612fa9e4066Sahrens 361399653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3614fa9e4066Sahrens return (1); 3615fa9e4066Sahrens 36163d7072f8Seschrock for (i = 1; i < argc; i++) { 3617573ca77eSGeorge Wilson if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 36183d7072f8Seschrock if (newstate != VDEV_STATE_HEALTHY) { 36193d7072f8Seschrock (void) printf(gettext("warning: device '%s' " 36203d7072f8Seschrock "onlined, but remains in faulted state\n"), 36213d7072f8Seschrock argv[i]); 36223d7072f8Seschrock if (newstate == VDEV_STATE_FAULTED) 36233d7072f8Seschrock (void) printf(gettext("use 'zpool " 36243d7072f8Seschrock "clear' to restore a faulted " 36253d7072f8Seschrock "device\n")); 36263d7072f8Seschrock else 36273d7072f8Seschrock (void) printf(gettext("use 'zpool " 36283d7072f8Seschrock "replace' to replace devices " 36293d7072f8Seschrock "that are no longer present\n")); 36303d7072f8Seschrock } 36313d7072f8Seschrock } else { 3632fa9e4066Sahrens ret = 1; 36333d7072f8Seschrock } 36343d7072f8Seschrock } 3635fa9e4066Sahrens 363699653d4eSeschrock zpool_close(zhp); 363799653d4eSeschrock 3638fa9e4066Sahrens return (ret); 3639fa9e4066Sahrens } 3640fa9e4066Sahrens 3641fa9e4066Sahrens /* 3642441d80aaSlling * zpool offline [-ft] <pool> <device> ... 3643fa9e4066Sahrens * 3644fa9e4066Sahrens * -f Force the device into the offline state, even if doing 3645fa9e4066Sahrens * so would appear to compromise pool availability. 3646fa9e4066Sahrens * (not supported yet) 3647fa9e4066Sahrens * 3648fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 3649fa9e4066Sahrens * state will not be persistent across reboots. 3650fa9e4066Sahrens */ 3651fa9e4066Sahrens /* ARGSUSED */ 3652fa9e4066Sahrens int 3653fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 3654fa9e4066Sahrens { 3655fa9e4066Sahrens int c, i; 3656fa9e4066Sahrens char *poolname; 3657fa9e4066Sahrens zpool_handle_t *zhp; 365899653d4eSeschrock int ret = 0; 365999653d4eSeschrock boolean_t istmp = B_FALSE; 3660fa9e4066Sahrens 3661fa9e4066Sahrens /* check options */ 3662fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 3663fa9e4066Sahrens switch (c) { 3664fa9e4066Sahrens case 't': 366599653d4eSeschrock istmp = B_TRUE; 3666441d80aaSlling break; 3667441d80aaSlling case 'f': 3668fa9e4066Sahrens case '?': 3669fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3670fa9e4066Sahrens optopt); 367199653d4eSeschrock usage(B_FALSE); 3672fa9e4066Sahrens } 3673fa9e4066Sahrens } 3674fa9e4066Sahrens 3675fa9e4066Sahrens argc -= optind; 3676fa9e4066Sahrens argv += optind; 3677fa9e4066Sahrens 3678fa9e4066Sahrens /* get pool name and check number of arguments */ 3679fa9e4066Sahrens if (argc < 1) { 3680fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 368199653d4eSeschrock usage(B_FALSE); 3682fa9e4066Sahrens } 3683fa9e4066Sahrens if (argc < 2) { 3684fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 368599653d4eSeschrock usage(B_FALSE); 3686fa9e4066Sahrens } 3687fa9e4066Sahrens 3688fa9e4066Sahrens poolname = argv[0]; 3689fa9e4066Sahrens 369099653d4eSeschrock if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3691fa9e4066Sahrens return (1); 3692fa9e4066Sahrens 36933d7072f8Seschrock for (i = 1; i < argc; i++) { 36943d7072f8Seschrock if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3695fa9e4066Sahrens ret = 1; 36963d7072f8Seschrock } 3697fa9e4066Sahrens 369899653d4eSeschrock zpool_close(zhp); 369999653d4eSeschrock 3700fa9e4066Sahrens return (ret); 3701fa9e4066Sahrens } 3702fa9e4066Sahrens 3703ea8dc4b6Seschrock /* 3704ea8dc4b6Seschrock * zpool clear <pool> [device] 3705ea8dc4b6Seschrock * 3706ea8dc4b6Seschrock * Clear all errors associated with a pool or a particular device. 3707ea8dc4b6Seschrock */ 3708ea8dc4b6Seschrock int 3709ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv) 3710ea8dc4b6Seschrock { 3711468c413aSTim Haley int c; 3712ea8dc4b6Seschrock int ret = 0; 3713468c413aSTim Haley boolean_t dryrun = B_FALSE; 3714468c413aSTim Haley boolean_t do_rewind = B_FALSE; 3715468c413aSTim Haley boolean_t xtreme_rewind = B_FALSE; 3716468c413aSTim Haley uint32_t rewind_policy = ZPOOL_NO_REWIND; 3717468c413aSTim Haley nvlist_t *policy = NULL; 3718ea8dc4b6Seschrock zpool_handle_t *zhp; 3719ea8dc4b6Seschrock char *pool, *device; 3720ea8dc4b6Seschrock 3721468c413aSTim Haley /* check options */ 3722468c413aSTim Haley while ((c = getopt(argc, argv, "FnX")) != -1) { 3723468c413aSTim Haley switch (c) { 3724468c413aSTim Haley case 'F': 3725468c413aSTim Haley do_rewind = B_TRUE; 3726468c413aSTim Haley break; 3727468c413aSTim Haley case 'n': 3728468c413aSTim Haley dryrun = B_TRUE; 3729468c413aSTim Haley break; 3730468c413aSTim Haley case 'X': 3731468c413aSTim Haley xtreme_rewind = B_TRUE; 3732468c413aSTim Haley break; 3733468c413aSTim Haley case '?': 3734468c413aSTim Haley (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3735468c413aSTim Haley optopt); 3736468c413aSTim Haley usage(B_FALSE); 3737468c413aSTim Haley } 3738468c413aSTim Haley } 3739468c413aSTim Haley 3740468c413aSTim Haley argc -= optind; 3741468c413aSTim Haley argv += optind; 3742468c413aSTim Haley 3743468c413aSTim Haley if (argc < 1) { 3744ea8dc4b6Seschrock (void) fprintf(stderr, gettext("missing pool name\n")); 374599653d4eSeschrock usage(B_FALSE); 3746ea8dc4b6Seschrock } 3747ea8dc4b6Seschrock 3748468c413aSTim Haley if (argc > 2) { 3749ea8dc4b6Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 375099653d4eSeschrock usage(B_FALSE); 3751ea8dc4b6Seschrock } 3752ea8dc4b6Seschrock 3753468c413aSTim Haley if ((dryrun || xtreme_rewind) && !do_rewind) { 3754468c413aSTim Haley (void) fprintf(stderr, 3755468c413aSTim Haley gettext("-n or -X only meaningful with -F\n")); 3756468c413aSTim Haley usage(B_FALSE); 3757468c413aSTim Haley } 3758468c413aSTim Haley if (dryrun) 3759468c413aSTim Haley rewind_policy = ZPOOL_TRY_REWIND; 3760468c413aSTim Haley else if (do_rewind) 3761468c413aSTim Haley rewind_policy = ZPOOL_DO_REWIND; 3762468c413aSTim Haley if (xtreme_rewind) 3763468c413aSTim Haley rewind_policy |= ZPOOL_EXTREME_REWIND; 3764468c413aSTim Haley 3765468c413aSTim Haley /* In future, further rewind policy choices can be passed along here */ 3766468c413aSTim Haley if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3767468c413aSTim Haley nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3768468c413aSTim Haley return (1); 3769468c413aSTim Haley 3770468c413aSTim Haley pool = argv[0]; 3771468c413aSTim Haley device = argc == 2 ? argv[1] : NULL; 3772ea8dc4b6Seschrock 3773468c413aSTim Haley if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3774468c413aSTim Haley nvlist_free(policy); 3775ea8dc4b6Seschrock return (1); 3776468c413aSTim Haley } 3777ea8dc4b6Seschrock 3778468c413aSTim Haley if (zpool_clear(zhp, device, policy) != 0) 3779ea8dc4b6Seschrock ret = 1; 3780ea8dc4b6Seschrock 3781ea8dc4b6Seschrock zpool_close(zhp); 3782ea8dc4b6Seschrock 3783468c413aSTim Haley nvlist_free(policy); 3784468c413aSTim Haley 3785ea8dc4b6Seschrock return (ret); 3786ea8dc4b6Seschrock } 3787ea8dc4b6Seschrock 3788e9103aaeSGarrett D'Amore /* 3789e9103aaeSGarrett D'Amore * zpool reguid <pool> 3790e9103aaeSGarrett D'Amore */ 3791e9103aaeSGarrett D'Amore int 3792e9103aaeSGarrett D'Amore zpool_do_reguid(int argc, char **argv) 3793e9103aaeSGarrett D'Amore { 3794e9103aaeSGarrett D'Amore int c; 3795e9103aaeSGarrett D'Amore char *poolname; 3796e9103aaeSGarrett D'Amore zpool_handle_t *zhp; 3797e9103aaeSGarrett D'Amore int ret = 0; 3798e9103aaeSGarrett D'Amore 3799e9103aaeSGarrett D'Amore /* check options */ 3800e9103aaeSGarrett D'Amore while ((c = getopt(argc, argv, "")) != -1) { 3801e9103aaeSGarrett D'Amore switch (c) { 3802e9103aaeSGarrett D'Amore case '?': 3803e9103aaeSGarrett D'Amore (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3804e9103aaeSGarrett D'Amore optopt); 3805e9103aaeSGarrett D'Amore usage(B_FALSE); 3806e9103aaeSGarrett D'Amore } 3807e9103aaeSGarrett D'Amore } 3808e9103aaeSGarrett D'Amore 3809e9103aaeSGarrett D'Amore argc -= optind; 3810e9103aaeSGarrett D'Amore argv += optind; 3811e9103aaeSGarrett D'Amore 3812e9103aaeSGarrett D'Amore /* get pool name and check number of arguments */ 3813e9103aaeSGarrett D'Amore if (argc < 1) { 3814e9103aaeSGarrett D'Amore (void) fprintf(stderr, gettext("missing pool name\n")); 3815e9103aaeSGarrett D'Amore usage(B_FALSE); 3816e9103aaeSGarrett D'Amore } 3817e9103aaeSGarrett D'Amore 3818e9103aaeSGarrett D'Amore if (argc > 1) { 3819e9103aaeSGarrett D'Amore (void) fprintf(stderr, gettext("too many arguments\n")); 3820e9103aaeSGarrett D'Amore usage(B_FALSE); 3821e9103aaeSGarrett D'Amore } 3822e9103aaeSGarrett D'Amore 3823e9103aaeSGarrett D'Amore poolname = argv[0]; 3824e9103aaeSGarrett D'Amore if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3825e9103aaeSGarrett D'Amore return (1); 3826e9103aaeSGarrett D'Amore 3827e9103aaeSGarrett D'Amore ret = zpool_reguid(zhp); 3828e9103aaeSGarrett D'Amore 3829e9103aaeSGarrett D'Amore zpool_close(zhp); 3830e9103aaeSGarrett D'Amore return (ret); 3831e9103aaeSGarrett D'Amore } 3832e9103aaeSGarrett D'Amore 3833e9103aaeSGarrett D'Amore 38344263d13fSGeorge Wilson /* 38354263d13fSGeorge Wilson * zpool reopen <pool> 38364263d13fSGeorge Wilson * 38374263d13fSGeorge Wilson * Reopen the pool so that the kernel can update the sizes of all vdevs. 38384263d13fSGeorge Wilson */ 38394263d13fSGeorge Wilson int 38404263d13fSGeorge Wilson zpool_do_reopen(int argc, char **argv) 38414263d13fSGeorge Wilson { 384231d7e8faSGeorge Wilson int c; 38434263d13fSGeorge Wilson int ret = 0; 38444263d13fSGeorge Wilson zpool_handle_t *zhp; 38454263d13fSGeorge Wilson char *pool; 38464263d13fSGeorge Wilson 384731d7e8faSGeorge Wilson /* check options */ 384831d7e8faSGeorge Wilson while ((c = getopt(argc, argv, "")) != -1) { 384931d7e8faSGeorge Wilson switch (c) { 385031d7e8faSGeorge Wilson case '?': 385131d7e8faSGeorge Wilson (void) fprintf(stderr, gettext("invalid option '%c'\n"), 385231d7e8faSGeorge Wilson optopt); 385331d7e8faSGeorge Wilson usage(B_FALSE); 385431d7e8faSGeorge Wilson } 385531d7e8faSGeorge Wilson } 385631d7e8faSGeorge Wilson 38574263d13fSGeorge Wilson argc--; 38584263d13fSGeorge Wilson argv++; 38594263d13fSGeorge Wilson 386031d7e8faSGeorge Wilson if (argc < 1) { 386131d7e8faSGeorge Wilson (void) fprintf(stderr, gettext("missing pool name\n")); 386231d7e8faSGeorge Wilson usage(B_FALSE); 386331d7e8faSGeorge Wilson } 386431d7e8faSGeorge Wilson 386531d7e8faSGeorge Wilson if (argc > 1) { 386631d7e8faSGeorge Wilson (void) fprintf(stderr, gettext("too many arguments\n")); 386731d7e8faSGeorge Wilson usage(B_FALSE); 386831d7e8faSGeorge Wilson } 38694263d13fSGeorge Wilson 38704263d13fSGeorge Wilson pool = argv[0]; 38714263d13fSGeorge Wilson if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 38724263d13fSGeorge Wilson return (1); 38734263d13fSGeorge Wilson 38744263d13fSGeorge Wilson ret = zpool_reopen(zhp); 38754263d13fSGeorge Wilson zpool_close(zhp); 38764263d13fSGeorge Wilson return (ret); 38774263d13fSGeorge Wilson } 38784263d13fSGeorge Wilson 3879fa9e4066Sahrens typedef struct scrub_cbdata { 3880fa9e4066Sahrens int cb_type; 388106eeb2adSek int cb_argc; 388206eeb2adSek char **cb_argv; 3883*1702cce7SAlek Pinchuk pool_scrub_cmd_t cb_scrub_cmd; 3884fa9e4066Sahrens } scrub_cbdata_t; 3885fa9e4066Sahrens 3886fa9e4066Sahrens int 3887fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 3888fa9e4066Sahrens { 3889fa9e4066Sahrens scrub_cbdata_t *cb = data; 389006eeb2adSek int err; 3891fa9e4066Sahrens 3892ea8dc4b6Seschrock /* 3893ea8dc4b6Seschrock * Ignore faulted pools. 3894ea8dc4b6Seschrock */ 3895ea8dc4b6Seschrock if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3896ea8dc4b6Seschrock (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3897ea8dc4b6Seschrock "currently unavailable\n"), zpool_get_name(zhp)); 3898ea8dc4b6Seschrock return (1); 3899ea8dc4b6Seschrock } 3900ea8dc4b6Seschrock 3901*1702cce7SAlek Pinchuk err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd); 390206eeb2adSek 390306eeb2adSek return (err != 0); 3904fa9e4066Sahrens } 3905fa9e4066Sahrens 3906fa9e4066Sahrens /* 3907*1702cce7SAlek Pinchuk * zpool scrub [-s | -p] <pool> ... 3908fa9e4066Sahrens * 3909fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 3910*1702cce7SAlek Pinchuk * -p Pause. Pause in-progress scrub. 3911fa9e4066Sahrens */ 3912fa9e4066Sahrens int 3913fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 3914fa9e4066Sahrens { 3915fa9e4066Sahrens int c; 3916fa9e4066Sahrens scrub_cbdata_t cb; 3917fa9e4066Sahrens 39183f9d6ad7SLin Ling cb.cb_type = POOL_SCAN_SCRUB; 3919*1702cce7SAlek Pinchuk cb.cb_scrub_cmd = POOL_SCRUB_NORMAL; 3920fa9e4066Sahrens 3921fa9e4066Sahrens /* check options */ 3922*1702cce7SAlek Pinchuk while ((c = getopt(argc, argv, "sp")) != -1) { 3923fa9e4066Sahrens switch (c) { 3924fa9e4066Sahrens case 's': 39253f9d6ad7SLin Ling cb.cb_type = POOL_SCAN_NONE; 3926fa9e4066Sahrens break; 3927*1702cce7SAlek Pinchuk case 'p': 3928*1702cce7SAlek Pinchuk cb.cb_scrub_cmd = POOL_SCRUB_PAUSE; 3929*1702cce7SAlek Pinchuk break; 3930fa9e4066Sahrens case '?': 3931fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3932fa9e4066Sahrens optopt); 393399653d4eSeschrock usage(B_FALSE); 3934fa9e4066Sahrens } 3935fa9e4066Sahrens } 3936fa9e4066Sahrens 3937*1702cce7SAlek Pinchuk if (cb.cb_type == POOL_SCAN_NONE && 3938*1702cce7SAlek Pinchuk cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) { 3939*1702cce7SAlek Pinchuk (void) fprintf(stderr, gettext("invalid option combination: " 3940*1702cce7SAlek Pinchuk "-s and -p are mutually exclusive\n")); 3941*1702cce7SAlek Pinchuk usage(B_FALSE); 3942*1702cce7SAlek Pinchuk } 3943*1702cce7SAlek Pinchuk 394406eeb2adSek cb.cb_argc = argc; 394506eeb2adSek cb.cb_argv = argv; 3946fa9e4066Sahrens argc -= optind; 3947fa9e4066Sahrens argv += optind; 3948fa9e4066Sahrens 3949fa9e4066Sahrens if (argc < 1) { 3950fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 395199653d4eSeschrock usage(B_FALSE); 3952fa9e4066Sahrens } 3953fa9e4066Sahrens 3954b1b8ab34Slling return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3955fa9e4066Sahrens } 3956fa9e4066Sahrens 3957fa9e4066Sahrens typedef struct status_cbdata { 395899653d4eSeschrock int cb_count; 3959e9dbad6fSeschrock boolean_t cb_allpools; 396099653d4eSeschrock boolean_t cb_verbose; 396199653d4eSeschrock boolean_t cb_explain; 396299653d4eSeschrock boolean_t cb_first; 39639eb19f4dSGeorge Wilson boolean_t cb_dedup_stats; 3964fa9e4066Sahrens } status_cbdata_t; 3965fa9e4066Sahrens 3966fa9e4066Sahrens /* 3967fa9e4066Sahrens * Print out detailed scrub status. 3968fa9e4066Sahrens */ 3969fa9e4066Sahrens void 39703f9d6ad7SLin Ling print_scan_status(pool_scan_stat_t *ps) 3971fa9e4066Sahrens { 3972*1702cce7SAlek Pinchuk time_t start, end, pause; 397373d314ceSLin Ling uint64_t elapsed, mins_left, hours_left; 39743f9d6ad7SLin Ling uint64_t pass_exam, examined, total; 39753f9d6ad7SLin Ling uint_t rate; 3976fa9e4066Sahrens double fraction_done; 39773f9d6ad7SLin Ling char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3978fa9e4066Sahrens 3979ce72e614SYuri Pankov (void) printf(gettext(" scan: ")); 3980fa9e4066Sahrens 39813f9d6ad7SLin Ling /* If there's never been a scan, there's not much to say. */ 39823f9d6ad7SLin Ling if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 39833f9d6ad7SLin Ling ps->pss_func >= POOL_SCAN_FUNCS) { 3984fa9e4066Sahrens (void) printf(gettext("none requested\n")); 3985fa9e4066Sahrens return; 3986fa9e4066Sahrens } 3987fa9e4066Sahrens 39883f9d6ad7SLin Ling start = ps->pss_start_time; 39893f9d6ad7SLin Ling end = ps->pss_end_time; 3990*1702cce7SAlek Pinchuk pause = ps->pss_pass_scrub_pause; 39913f9d6ad7SLin Ling zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3992fa9e4066Sahrens 39933f9d6ad7SLin Ling assert(ps->pss_func == POOL_SCAN_SCRUB || 39943f9d6ad7SLin Ling ps->pss_func == POOL_SCAN_RESILVER); 39953f9d6ad7SLin Ling /* 39963f9d6ad7SLin Ling * Scan is finished or canceled. 39973f9d6ad7SLin Ling */ 39983f9d6ad7SLin Ling if (ps->pss_state == DSS_FINISHED) { 39993f9d6ad7SLin Ling uint64_t minutes_taken = (end - start) / 60; 4000b327cd3fSIgor Kozhukhov char *fmt = NULL; 40013f9d6ad7SLin Ling 40023f9d6ad7SLin Ling if (ps->pss_func == POOL_SCAN_SCRUB) { 40033f9d6ad7SLin Ling fmt = gettext("scrub repaired %s in %lluh%um with " 40043f9d6ad7SLin Ling "%llu errors on %s"); 40053f9d6ad7SLin Ling } else if (ps->pss_func == POOL_SCAN_RESILVER) { 40063f9d6ad7SLin Ling fmt = gettext("resilvered %s in %lluh%um with " 40073f9d6ad7SLin Ling "%llu errors on %s"); 40083f9d6ad7SLin Ling } 40093f9d6ad7SLin Ling /* LINTED */ 40103f9d6ad7SLin Ling (void) printf(fmt, processed_buf, 401118ce54dfSek (u_longlong_t)(minutes_taken / 60), 401218ce54dfSek (uint_t)(minutes_taken % 60), 40133f9d6ad7SLin Ling (u_longlong_t)ps->pss_errors, 40143f9d6ad7SLin Ling ctime((time_t *)&end)); 40153f9d6ad7SLin Ling return; 40163f9d6ad7SLin Ling } else if (ps->pss_state == DSS_CANCELED) { 40173f9d6ad7SLin Ling if (ps->pss_func == POOL_SCAN_SCRUB) { 40183f9d6ad7SLin Ling (void) printf(gettext("scrub canceled on %s"), 40193f9d6ad7SLin Ling ctime(&end)); 40203f9d6ad7SLin Ling } else if (ps->pss_func == POOL_SCAN_RESILVER) { 40213f9d6ad7SLin Ling (void) printf(gettext("resilver canceled on %s"), 40223f9d6ad7SLin Ling ctime(&end)); 40233f9d6ad7SLin Ling } 4024fa9e4066Sahrens return; 4025fa9e4066Sahrens } 4026fa9e4066Sahrens 40273f9d6ad7SLin Ling assert(ps->pss_state == DSS_SCANNING); 40283f9d6ad7SLin Ling 40293f9d6ad7SLin Ling /* 40303f9d6ad7SLin Ling * Scan is in progress. 40313f9d6ad7SLin Ling */ 40323f9d6ad7SLin Ling if (ps->pss_func == POOL_SCAN_SCRUB) { 4033*1702cce7SAlek Pinchuk if (pause == 0) { 4034*1702cce7SAlek Pinchuk (void) printf(gettext("scrub in progress since %s"), 4035*1702cce7SAlek Pinchuk ctime(&start)); 4036*1702cce7SAlek Pinchuk } else { 4037*1702cce7SAlek Pinchuk char buf[32]; 4038*1702cce7SAlek Pinchuk struct tm *p = localtime(&pause); 4039*1702cce7SAlek Pinchuk (void) strftime(buf, sizeof (buf), "%a %b %e %T %Y", p); 4040*1702cce7SAlek Pinchuk (void) printf(gettext("scrub paused since %s\n"), buf); 4041*1702cce7SAlek Pinchuk (void) printf(gettext("\tscrub started on %s"), 4042*1702cce7SAlek Pinchuk ctime(&start)); 4043*1702cce7SAlek Pinchuk } 40443f9d6ad7SLin Ling } else if (ps->pss_func == POOL_SCAN_RESILVER) { 40453f9d6ad7SLin Ling (void) printf(gettext("resilver in progress since %s"), 40463f9d6ad7SLin Ling ctime(&start)); 40473f9d6ad7SLin Ling } 4048fa9e4066Sahrens 40493f9d6ad7SLin Ling examined = ps->pss_examined ? ps->pss_examined : 1; 40503f9d6ad7SLin Ling total = ps->pss_to_examine; 4051fa9e4066Sahrens fraction_done = (double)examined / total; 40523f9d6ad7SLin Ling 40533f9d6ad7SLin Ling /* elapsed time for this pass */ 40543f9d6ad7SLin Ling elapsed = time(NULL) - ps->pss_pass_start; 4055*1702cce7SAlek Pinchuk elapsed -= ps->pss_pass_scrub_spent_paused; 40563f9d6ad7SLin Ling elapsed = elapsed ? elapsed : 1; 40573f9d6ad7SLin Ling pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 40583f9d6ad7SLin Ling rate = pass_exam / elapsed; 40593f9d6ad7SLin Ling rate = rate ? rate : 1; 40603f9d6ad7SLin Ling mins_left = ((total - examined) / rate) / 60; 406173d314ceSLin Ling hours_left = mins_left / 60; 40623f9d6ad7SLin Ling 40633f9d6ad7SLin Ling zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 40643f9d6ad7SLin Ling zfs_nicenum(total, total_buf, sizeof (total_buf)); 40653f9d6ad7SLin Ling 406673d314ceSLin Ling /* 406773d314ceSLin Ling * do not print estimated time if hours_left is more than 30 days 4068*1702cce7SAlek Pinchuk * or we have a paused scrub 406973d314ceSLin Ling */ 4070*1702cce7SAlek Pinchuk if (pause == 0) { 4071*1702cce7SAlek Pinchuk zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 4072*1702cce7SAlek Pinchuk (void) printf(gettext("\t%s scanned out of %s at %s/s"), 4073*1702cce7SAlek Pinchuk examined_buf, total_buf, rate_buf); 4074*1702cce7SAlek Pinchuk if (hours_left < (30 * 24)) { 4075*1702cce7SAlek Pinchuk (void) printf(gettext(", %lluh%um to go\n"), 4076*1702cce7SAlek Pinchuk (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 4077*1702cce7SAlek Pinchuk } else { 4078*1702cce7SAlek Pinchuk (void) printf(gettext( 4079*1702cce7SAlek Pinchuk ", (scan is slow, no estimated time)\n")); 4080*1702cce7SAlek Pinchuk } 408173d314ceSLin Ling } else { 4082*1702cce7SAlek Pinchuk (void) printf(gettext("\t%s scanned out of %s\n"), 4083*1702cce7SAlek Pinchuk examined_buf, total_buf); 408473d314ceSLin Ling } 40853f9d6ad7SLin Ling 40863f9d6ad7SLin Ling if (ps->pss_func == POOL_SCAN_RESILVER) { 40873f9d6ad7SLin Ling (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 40883f9d6ad7SLin Ling processed_buf, 100 * fraction_done); 40893f9d6ad7SLin Ling } else if (ps->pss_func == POOL_SCAN_SCRUB) { 40903f9d6ad7SLin Ling (void) printf(gettext(" %s repaired, %.2f%% done\n"), 40913f9d6ad7SLin Ling processed_buf, 100 * fraction_done); 40923f9d6ad7SLin Ling } 4093fa9e4066Sahrens } 4094fa9e4066Sahrens 4095ea8dc4b6Seschrock static void 4096ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp) 4097ea8dc4b6Seschrock { 409875519f38Sek nvlist_t *nverrlist = NULL; 409955434c77Sek nvpair_t *elem; 410055434c77Sek char *pathname; 410155434c77Sek size_t len = MAXPATHLEN * 2; 4102ea8dc4b6Seschrock 410355434c77Sek if (zpool_get_errlog(zhp, &nverrlist) != 0) { 4104ea8dc4b6Seschrock (void) printf("errors: List of errors unavailable " 4105ea8dc4b6Seschrock "(insufficient privileges)\n"); 4106ea8dc4b6Seschrock return; 4107ea8dc4b6Seschrock } 4108ea8dc4b6Seschrock 410955434c77Sek (void) printf("errors: Permanent errors have been " 411055434c77Sek "detected in the following files:\n\n"); 4111ea8dc4b6Seschrock 411255434c77Sek pathname = safe_malloc(len); 411355434c77Sek elem = NULL; 411455434c77Sek while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 411555434c77Sek nvlist_t *nv; 411655434c77Sek uint64_t dsobj, obj; 411755434c77Sek 411855434c77Sek verify(nvpair_value_nvlist(elem, &nv) == 0); 411955434c77Sek verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 412055434c77Sek &dsobj) == 0); 412155434c77Sek verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 412255434c77Sek &obj) == 0); 412355434c77Sek zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 412455434c77Sek (void) printf("%7s %s\n", "", pathname); 412555434c77Sek } 412655434c77Sek free(pathname); 412755434c77Sek nvlist_free(nverrlist); 4128ea8dc4b6Seschrock } 4129ea8dc4b6Seschrock 413099653d4eSeschrock static void 413199653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 413299653d4eSeschrock int namewidth) 413399653d4eSeschrock { 413499653d4eSeschrock uint_t i; 413599653d4eSeschrock char *name; 413699653d4eSeschrock 413799653d4eSeschrock if (nspares == 0) 413899653d4eSeschrock return; 413999653d4eSeschrock 414099653d4eSeschrock (void) printf(gettext("\tspares\n")); 414199653d4eSeschrock 414299653d4eSeschrock for (i = 0; i < nspares; i++) { 414388ecc943SGeorge Wilson name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 414499653d4eSeschrock print_status_config(zhp, name, spares[i], 4145aa8cf21aSNeil Perrin namewidth, 2, B_TRUE); 414699653d4eSeschrock free(name); 414799653d4eSeschrock } 414899653d4eSeschrock } 414999653d4eSeschrock 4150fa94a07fSbrendan static void 4151fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 4152fa94a07fSbrendan int namewidth) 4153fa94a07fSbrendan { 4154fa94a07fSbrendan uint_t i; 4155fa94a07fSbrendan char *name; 4156fa94a07fSbrendan 4157fa94a07fSbrendan if (nl2cache == 0) 4158fa94a07fSbrendan return; 4159fa94a07fSbrendan 4160fa94a07fSbrendan (void) printf(gettext("\tcache\n")); 4161fa94a07fSbrendan 4162fa94a07fSbrendan for (i = 0; i < nl2cache; i++) { 416388ecc943SGeorge Wilson name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 4164fa94a07fSbrendan print_status_config(zhp, name, l2cache[i], 4165aa8cf21aSNeil Perrin namewidth, 2, B_FALSE); 4166aa8cf21aSNeil Perrin free(name); 4167aa8cf21aSNeil Perrin } 4168aa8cf21aSNeil Perrin } 4169aa8cf21aSNeil Perrin 41709eb19f4dSGeorge Wilson static void 41719eb19f4dSGeorge Wilson print_dedup_stats(nvlist_t *config) 41729eb19f4dSGeorge Wilson { 41739eb19f4dSGeorge Wilson ddt_histogram_t *ddh; 41749eb19f4dSGeorge Wilson ddt_stat_t *dds; 41759eb19f4dSGeorge Wilson ddt_object_t *ddo; 41769eb19f4dSGeorge Wilson uint_t c; 41779eb19f4dSGeorge Wilson 41789eb19f4dSGeorge Wilson /* 41799eb19f4dSGeorge Wilson * If the pool was faulted then we may not have been able to 41802384d9f8SGeorge Wilson * obtain the config. Otherwise, if we have anything in the dedup 41819eb19f4dSGeorge Wilson * table continue processing the stats. 41829eb19f4dSGeorge Wilson */ 41839eb19f4dSGeorge Wilson if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 4184ce72e614SYuri Pankov (uint64_t **)&ddo, &c) != 0) 41859eb19f4dSGeorge Wilson return; 41869eb19f4dSGeorge Wilson 41879eb19f4dSGeorge Wilson (void) printf("\n"); 4188ce72e614SYuri Pankov (void) printf(gettext(" dedup: ")); 4189ce72e614SYuri Pankov if (ddo->ddo_count == 0) { 4190ce72e614SYuri Pankov (void) printf(gettext("no DDT entries\n")); 4191ce72e614SYuri Pankov return; 4192ce72e614SYuri Pankov } 4193ce72e614SYuri Pankov 41949eb19f4dSGeorge Wilson (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 41959eb19f4dSGeorge Wilson (u_longlong_t)ddo->ddo_count, 41969eb19f4dSGeorge Wilson (u_longlong_t)ddo->ddo_dspace, 41979eb19f4dSGeorge Wilson (u_longlong_t)ddo->ddo_mspace); 41989eb19f4dSGeorge Wilson 41999eb19f4dSGeorge Wilson verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 42009eb19f4dSGeorge Wilson (uint64_t **)&dds, &c) == 0); 42019eb19f4dSGeorge Wilson verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 42029eb19f4dSGeorge Wilson (uint64_t **)&ddh, &c) == 0); 42039eb19f4dSGeorge Wilson zpool_dump_ddt(dds, ddh); 42049eb19f4dSGeorge Wilson } 42059eb19f4dSGeorge Wilson 4206fa9e4066Sahrens /* 4207fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 4208fa9e4066Sahrens * 4209fa9e4066Sahrens * pool: tank 4210fa9e4066Sahrens * status: DEGRADED 4211fa9e4066Sahrens * reason: One or more devices ... 4212654b400cSJoshua M. Clulow * see: http://illumos.org/msg/ZFS-xxxx-01 4213fa9e4066Sahrens * config: 4214fa9e4066Sahrens * mirror DEGRADED 4215fa9e4066Sahrens * c1t0d0 OK 4216ea8dc4b6Seschrock * c2t0d0 UNAVAIL 4217fa9e4066Sahrens * 4218fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 4219fa9e4066Sahrens * option is specified, then we print out error rate information as well. 4220fa9e4066Sahrens */ 4221fa9e4066Sahrens int 4222fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 4223fa9e4066Sahrens { 4224fa9e4066Sahrens status_cbdata_t *cbp = data; 4225fa9e4066Sahrens nvlist_t *config, *nvroot; 4226fa9e4066Sahrens char *msgid; 4227fa9e4066Sahrens int reason; 422846657f8dSmmusante const char *health; 422946657f8dSmmusante uint_t c; 423046657f8dSmmusante vdev_stat_t *vs; 4231fa9e4066Sahrens 4232088e9d47Seschrock config = zpool_get_config(zhp, NULL); 4233fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 4234fa9e4066Sahrens 4235fa9e4066Sahrens cbp->cb_count++; 4236fa9e4066Sahrens 4237fa9e4066Sahrens /* 4238fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 4239fa9e4066Sahrens * problems. 4240fa9e4066Sahrens */ 4241b3a6f804STim Connors if (cbp->cb_explain && 4242b3a6f804STim Connors (reason == ZPOOL_STATUS_OK || 4243b3a6f804STim Connors reason == ZPOOL_STATUS_VERSION_OLDER || 4244b3a6f804STim Connors reason == ZPOOL_STATUS_FEAT_DISABLED)) { 4245e9dbad6fSeschrock if (!cbp->cb_allpools) { 4246e9dbad6fSeschrock (void) printf(gettext("pool '%s' is healthy\n"), 4247e9dbad6fSeschrock zpool_get_name(zhp)); 4248e9dbad6fSeschrock if (cbp->cb_first) 4249e9dbad6fSeschrock cbp->cb_first = B_FALSE; 4250e9dbad6fSeschrock } 4251fa9e4066Sahrens return (0); 4252e9dbad6fSeschrock } 4253fa9e4066Sahrens 4254fa9e4066Sahrens if (cbp->cb_first) 425599653d4eSeschrock cbp->cb_first = B_FALSE; 4256fa9e4066Sahrens else 4257fa9e4066Sahrens (void) printf("\n"); 4258fa9e4066Sahrens 425946657f8dSmmusante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 426046657f8dSmmusante &nvroot) == 0); 42613f9d6ad7SLin Ling verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 426246657f8dSmmusante (uint64_t **)&vs, &c) == 0); 4263990b4856Slling health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4264fa9e4066Sahrens 4265fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4266fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 4267fa9e4066Sahrens 4268fa9e4066Sahrens switch (reason) { 4269fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 4270fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 4271fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 4272fa9e4066Sahrens "continue functioning in a degraded state.\n")); 4273fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 4274fa9e4066Sahrens "online it using 'zpool online'.\n")); 4275fa9e4066Sahrens break; 4276fa9e4066Sahrens 4277fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 4278fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 4279fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 4280fa9e4066Sahrens "pool to continue functioning.\n")); 4281fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 4282fa9e4066Sahrens "online it using 'zpool online'.\n")); 4283fa9e4066Sahrens break; 4284fa9e4066Sahrens 4285fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 4286fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 4287fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 4288fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 4289fa9e4066Sahrens "functioning in a degraded state.\n")); 4290fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 4291fa9e4066Sahrens "'zpool replace'.\n")); 4292fa9e4066Sahrens break; 4293fa9e4066Sahrens 4294fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4295fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 4296b1b8ab34Slling "be used because the label is missing \n\tor invalid. " 4297fa9e4066Sahrens "There are insufficient replicas for the pool to " 4298fa9e4066Sahrens "continue\n\tfunctioning.\n")); 4299468c413aSTim Haley zpool_explain_recover(zpool_get_handle(zhp), 4300468c413aSTim Haley zpool_get_name(zhp), reason, config); 4301fa9e4066Sahrens break; 4302fa9e4066Sahrens 4303fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 4304fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 4305fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 4306fa9e4066Sahrens "made to correct the error. Applications are " 4307fa9e4066Sahrens "unaffected.\n")); 4308fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 4309fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 4310ea8dc4b6Seschrock "'zpool clear' or replace the device with 'zpool " 4311fa9e4066Sahrens "replace'.\n")); 4312fa9e4066Sahrens break; 4313fa9e4066Sahrens 4314fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 4315fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 4316d7d4af51Smmusante "been taken offline by the administrator.\n\tSufficient " 4317fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 4318fa9e4066Sahrens "a\n\tdegraded state.\n")); 4319fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 4320fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 4321fa9e4066Sahrens "replace'.\n")); 4322fa9e4066Sahrens break; 4323fa9e4066Sahrens 4324c25309d4SGeorge Wilson case ZPOOL_STATUS_REMOVED_DEV: 4325c25309d4SGeorge Wilson (void) printf(gettext("status: One or more devices has " 4326c25309d4SGeorge Wilson "been removed by the administrator.\n\tSufficient " 4327c25309d4SGeorge Wilson "replicas exist for the pool to continue functioning in " 4328c25309d4SGeorge Wilson "a\n\tdegraded state.\n")); 4329c25309d4SGeorge Wilson (void) printf(gettext("action: Online the device using " 4330c25309d4SGeorge Wilson "'zpool online' or replace the device with\n\t'zpool " 4331c25309d4SGeorge Wilson "replace'.\n")); 4332c25309d4SGeorge Wilson break; 4333c25309d4SGeorge Wilson 4334fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 4335fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 4336fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 4337fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 4338fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 4339fa9e4066Sahrens "complete.\n")); 4340fa9e4066Sahrens break; 4341fa9e4066Sahrens 4342ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_DATA: 4343ea8dc4b6Seschrock (void) printf(gettext("status: One or more devices has " 4344ea8dc4b6Seschrock "experienced an error resulting in data\n\tcorruption. " 4345ea8dc4b6Seschrock "Applications may be affected.\n")); 4346ea8dc4b6Seschrock (void) printf(gettext("action: Restore the file in question " 4347ea8dc4b6Seschrock "if possible. Otherwise restore the\n\tentire pool from " 4348ea8dc4b6Seschrock "backup.\n")); 4349ea8dc4b6Seschrock break; 4350ea8dc4b6Seschrock 4351ea8dc4b6Seschrock case ZPOOL_STATUS_CORRUPT_POOL: 4352ea8dc4b6Seschrock (void) printf(gettext("status: The pool metadata is corrupted " 4353ea8dc4b6Seschrock "and the pool cannot be opened.\n")); 4354468c413aSTim Haley zpool_explain_recover(zpool_get_handle(zhp), 4355468c413aSTim Haley zpool_get_name(zhp), reason, config); 4356ea8dc4b6Seschrock break; 4357ea8dc4b6Seschrock 4358eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_OLDER: 435957221772SChristopher Siden (void) printf(gettext("status: The pool is formatted using a " 436057221772SChristopher Siden "legacy on-disk format. The pool can\n\tstill be used, " 436157221772SChristopher Siden "but some features are unavailable.\n")); 4362eaca9bbdSeschrock (void) printf(gettext("action: Upgrade the pool using 'zpool " 4363eaca9bbdSeschrock "upgrade'. Once this is done, the\n\tpool will no longer " 436457221772SChristopher Siden "be accessible on software that does not support feature\n" 436557221772SChristopher Siden "\tflags.\n")); 4366eaca9bbdSeschrock break; 4367eaca9bbdSeschrock 4368eaca9bbdSeschrock case ZPOOL_STATUS_VERSION_NEWER: 4369eaca9bbdSeschrock (void) printf(gettext("status: The pool has been upgraded to a " 4370eaca9bbdSeschrock "newer, incompatible on-disk version.\n\tThe pool cannot " 4371eaca9bbdSeschrock "be accessed on this system.\n")); 4372eaca9bbdSeschrock (void) printf(gettext("action: Access the pool from a system " 4373eaca9bbdSeschrock "running more recent software, or\n\trestore the pool from " 4374eaca9bbdSeschrock "backup.\n")); 4375eaca9bbdSeschrock break; 4376eaca9bbdSeschrock 437757221772SChristopher Siden case ZPOOL_STATUS_FEAT_DISABLED: 437857221772SChristopher Siden (void) printf(gettext("status: Some supported features are not " 437957221772SChristopher Siden "enabled on the pool. The pool can\n\tstill be used, but " 438057221772SChristopher Siden "some features are unavailable.\n")); 438157221772SChristopher Siden (void) printf(gettext("action: Enable all features using " 438257221772SChristopher Siden "'zpool upgrade'. Once this is done,\n\tthe pool may no " 438357221772SChristopher Siden "longer be accessible by software that does not support\n\t" 438457221772SChristopher Siden "the features. See zpool-features(5) for details.\n")); 438557221772SChristopher Siden break; 438657221772SChristopher Siden 4387ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_READ: 4388ad135b5dSChristopher Siden (void) printf(gettext("status: The pool cannot be accessed on " 4389ad135b5dSChristopher Siden "this system because it uses the\n\tfollowing feature(s) " 4390ad135b5dSChristopher Siden "not supported on this system:\n")); 4391ad135b5dSChristopher Siden zpool_print_unsup_feat(config); 4392ad135b5dSChristopher Siden (void) printf("\n"); 4393ad135b5dSChristopher Siden (void) printf(gettext("action: Access the pool from a system " 4394ad135b5dSChristopher Siden "that supports the required feature(s),\n\tor restore the " 4395ad135b5dSChristopher Siden "pool from backup.\n")); 4396ad135b5dSChristopher Siden break; 4397ad135b5dSChristopher Siden 4398ad135b5dSChristopher Siden case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4399ad135b5dSChristopher Siden (void) printf(gettext("status: The pool can only be accessed " 4400ad135b5dSChristopher Siden "in read-only mode on this system. It\n\tcannot be " 4401ad135b5dSChristopher Siden "accessed in read-write mode because it uses the " 4402ad135b5dSChristopher Siden "following\n\tfeature(s) not supported on this system:\n")); 4403ad135b5dSChristopher Siden zpool_print_unsup_feat(config); 4404ad135b5dSChristopher Siden (void) printf("\n"); 4405ad135b5dSChristopher Siden (void) printf(gettext("action: The pool cannot be accessed in " 4406ad135b5dSChristopher Siden "read-write mode. Import the pool with\n" 4407ad135b5dSChristopher Siden "\t\"-o readonly=on\", access the pool from a system that " 4408ad135b5dSChristopher Siden "supports the\n\trequired feature(s), or restore the " 4409ad135b5dSChristopher Siden "pool from backup.\n")); 4410ad135b5dSChristopher Siden break; 4411ad135b5dSChristopher Siden 44123d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_R: 44133d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 44143d7072f8Seschrock "faulted in response to persistent errors.\n\tSufficient " 44153d7072f8Seschrock "replicas exist for the pool to continue functioning " 44163d7072f8Seschrock "in a\n\tdegraded state.\n")); 44173d7072f8Seschrock (void) printf(gettext("action: Replace the faulted device, " 44183d7072f8Seschrock "or use 'zpool clear' to mark the device\n\trepaired.\n")); 44193d7072f8Seschrock break; 44203d7072f8Seschrock 44213d7072f8Seschrock case ZPOOL_STATUS_FAULTED_DEV_NR: 44223d7072f8Seschrock (void) printf(gettext("status: One or more devices are " 44233d7072f8Seschrock "faulted in response to persistent errors. There are " 44243d7072f8Seschrock "insufficient replicas for the pool to\n\tcontinue " 44253d7072f8Seschrock "functioning.\n")); 44263d7072f8Seschrock (void) printf(gettext("action: Destroy and re-create the pool " 44273d7072f8Seschrock "from a backup source. Manually marking the device\n" 44283d7072f8Seschrock "\trepaired using 'zpool clear' may allow some data " 44293d7072f8Seschrock "to be recovered.\n")); 44303d7072f8Seschrock break; 44313d7072f8Seschrock 443232b87932Sek case ZPOOL_STATUS_IO_FAILURE_WAIT: 443332b87932Sek case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 443432b87932Sek (void) printf(gettext("status: One or more devices are " 44358a79c1b5Sek "faulted in response to IO failures.\n")); 443632b87932Sek (void) printf(gettext("action: Make sure the affected devices " 443732b87932Sek "are connected, then run 'zpool clear'.\n")); 443832b87932Sek break; 443932b87932Sek 4440b87f3af3Sperrin case ZPOOL_STATUS_BAD_LOG: 4441b87f3af3Sperrin (void) printf(gettext("status: An intent log record " 4442b87f3af3Sperrin "could not be read.\n" 4443b87f3af3Sperrin "\tWaiting for adminstrator intervention to fix the " 4444b87f3af3Sperrin "faulted pool.\n")); 4445b87f3af3Sperrin (void) printf(gettext("action: Either restore the affected " 4446b87f3af3Sperrin "device(s) and run 'zpool online',\n" 4447b87f3af3Sperrin "\tor ignore the intent log records by running " 4448b87f3af3Sperrin "'zpool clear'.\n")); 4449b87f3af3Sperrin break; 4450b87f3af3Sperrin 4451fa9e4066Sahrens default: 4452fa9e4066Sahrens /* 4453fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 4454fa9e4066Sahrens */ 4455fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 4456fa9e4066Sahrens } 4457fa9e4066Sahrens 4458fa9e4066Sahrens if (msgid != NULL) 4459654b400cSJoshua M. Clulow (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4460fa9e4066Sahrens msgid); 4461fa9e4066Sahrens 4462fa9e4066Sahrens if (config != NULL) { 4463fa9e4066Sahrens int namewidth; 4464ea8dc4b6Seschrock uint64_t nerr; 4465fa94a07fSbrendan nvlist_t **spares, **l2cache; 4466fa94a07fSbrendan uint_t nspares, nl2cache; 44673f9d6ad7SLin Ling pool_scan_stat_t *ps = NULL; 4468fa9e4066Sahrens 44693f9d6ad7SLin Ling (void) nvlist_lookup_uint64_array(nvroot, 44703f9d6ad7SLin Ling ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 44713f9d6ad7SLin Ling print_scan_status(ps); 4472fa9e4066Sahrens 4473c67d9675Seschrock namewidth = max_width(zhp, nvroot, 0, 0); 4474fa9e4066Sahrens if (namewidth < 10) 4475fa9e4066Sahrens namewidth = 10; 4476fa9e4066Sahrens 4477fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 4478fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4479fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4480c67d9675Seschrock print_status_config(zhp, zpool_get_name(zhp), nvroot, 4481aa8cf21aSNeil Perrin namewidth, 0, B_FALSE); 448299653d4eSeschrock 44834dea40f0SNeil Perrin if (num_logs(nvroot) > 0) 4484e6ca193dSGeorge Wilson print_logs(zhp, nvroot, namewidth, B_TRUE); 4485fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4486fa94a07fSbrendan &l2cache, &nl2cache) == 0) 4487fa94a07fSbrendan print_l2cache(zhp, l2cache, nl2cache, namewidth); 4488fa94a07fSbrendan 448999653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 449099653d4eSeschrock &spares, &nspares) == 0) 449199653d4eSeschrock print_spares(zhp, spares, nspares, namewidth); 4492ea8dc4b6Seschrock 4493ea8dc4b6Seschrock if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4494ea8dc4b6Seschrock &nerr) == 0) { 449555434c77Sek nvlist_t *nverrlist = NULL; 449655434c77Sek 4497ea8dc4b6Seschrock /* 4498ea8dc4b6Seschrock * If the approximate error count is small, get a 4499ea8dc4b6Seschrock * precise count by fetching the entire log and 4500ea8dc4b6Seschrock * uniquifying the results. 4501ea8dc4b6Seschrock */ 450275519f38Sek if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 450355434c77Sek zpool_get_errlog(zhp, &nverrlist) == 0) { 450455434c77Sek nvpair_t *elem; 450555434c77Sek 450655434c77Sek elem = NULL; 450755434c77Sek nerr = 0; 450855434c77Sek while ((elem = nvlist_next_nvpair(nverrlist, 450955434c77Sek elem)) != NULL) { 451055434c77Sek nerr++; 451155434c77Sek } 451255434c77Sek } 451355434c77Sek nvlist_free(nverrlist); 4514ea8dc4b6Seschrock 4515ea8dc4b6Seschrock (void) printf("\n"); 451699653d4eSeschrock 4517ea8dc4b6Seschrock if (nerr == 0) 4518ea8dc4b6Seschrock (void) printf(gettext("errors: No known data " 4519ea8dc4b6Seschrock "errors\n")); 4520ea8dc4b6Seschrock else if (!cbp->cb_verbose) 4521e9dbad6fSeschrock (void) printf(gettext("errors: %llu data " 45225ad82045Snd "errors, use '-v' for a list\n"), 45235ad82045Snd (u_longlong_t)nerr); 4524ea8dc4b6Seschrock else 4525ea8dc4b6Seschrock print_error_log(zhp); 4526ea8dc4b6Seschrock } 45279eb19f4dSGeorge Wilson 45289eb19f4dSGeorge Wilson if (cbp->cb_dedup_stats) 45299eb19f4dSGeorge Wilson print_dedup_stats(config); 4530fa9e4066Sahrens } else { 4531fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 4532fa9e4066Sahrens "determined.\n")); 4533fa9e4066Sahrens } 4534fa9e4066Sahrens 4535fa9e4066Sahrens return (0); 4536fa9e4066Sahrens } 4537fa9e4066Sahrens 4538fa9e4066Sahrens /* 45393f9d6ad7SLin Ling * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4540fa9e4066Sahrens * 4541fa9e4066Sahrens * -v Display complete error logs 4542fa9e4066Sahrens * -x Display only pools with potential problems 45439eb19f4dSGeorge Wilson * -D Display dedup status (undocumented) 45443f9d6ad7SLin Ling * -T Display a timestamp in date(1) or Unix format 4545fa9e4066Sahrens * 4546fa9e4066Sahrens * Describes the health status of all pools or some subset. 4547fa9e4066Sahrens */ 4548fa9e4066Sahrens int 4549fa9e4066Sahrens zpool_do_status(int argc, char **argv) 4550fa9e4066Sahrens { 4551fa9e4066Sahrens int c; 4552fa9e4066Sahrens int ret; 45533f9d6ad7SLin Ling unsigned long interval = 0, count = 0; 4554fa9e4066Sahrens status_cbdata_t cb = { 0 }; 4555fa9e4066Sahrens 4556fa9e4066Sahrens /* check options */ 45573f9d6ad7SLin Ling while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4558fa9e4066Sahrens switch (c) { 4559fa9e4066Sahrens case 'v': 456099653d4eSeschrock cb.cb_verbose = B_TRUE; 4561fa9e4066Sahrens break; 4562fa9e4066Sahrens case 'x': 456399653d4eSeschrock cb.cb_explain = B_TRUE; 4564fa9e4066Sahrens break; 45659eb19f4dSGeorge Wilson case 'D': 45669eb19f4dSGeorge Wilson cb.cb_dedup_stats = B_TRUE; 45679eb19f4dSGeorge Wilson break; 45683f9d6ad7SLin Ling case 'T': 45693f9d6ad7SLin Ling get_timestamp_arg(*optarg); 45703f9d6ad7SLin Ling break; 4571fa9e4066Sahrens case '?': 4572fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4573fa9e4066Sahrens optopt); 457499653d4eSeschrock usage(B_FALSE); 4575fa9e4066Sahrens } 4576fa9e4066Sahrens } 4577fa9e4066Sahrens 4578fa9e4066Sahrens argc -= optind; 4579fa9e4066Sahrens argv += optind; 4580fa9e4066Sahrens 45813f9d6ad7SLin Ling get_interval_count(&argc, argv, &interval, &count); 4582fa9e4066Sahrens 4583e9dbad6fSeschrock if (argc == 0) 4584e9dbad6fSeschrock cb.cb_allpools = B_TRUE; 4585e9dbad6fSeschrock 45863f9d6ad7SLin Ling cb.cb_first = B_TRUE; 4587fa9e4066Sahrens 45883f9d6ad7SLin Ling for (;;) { 45893f9d6ad7SLin Ling if (timestamp_fmt != NODATE) 45903f9d6ad7SLin Ling print_timestamp(timestamp_fmt); 4591fa9e4066Sahrens 45923f9d6ad7SLin Ling ret = for_each_pool(argc, argv, B_TRUE, NULL, 45933f9d6ad7SLin Ling status_callback, &cb); 45943f9d6ad7SLin Ling 45953f9d6ad7SLin Ling if (argc == 0 && cb.cb_count == 0) 45963f9d6ad7SLin Ling (void) printf(gettext("no pools available\n")); 45973f9d6ad7SLin Ling else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 45983f9d6ad7SLin Ling (void) printf(gettext("all pools are healthy\n")); 45993f9d6ad7SLin Ling 46003f9d6ad7SLin Ling if (ret != 0) 46013f9d6ad7SLin Ling return (ret); 46023f9d6ad7SLin Ling 46033f9d6ad7SLin Ling if (interval == 0) 46043f9d6ad7SLin Ling break; 46053f9d6ad7SLin Ling 46063f9d6ad7SLin Ling if (count != 0 && --count == 0) 46073f9d6ad7SLin Ling break; 46083f9d6ad7SLin Ling 46093f9d6ad7SLin Ling (void) sleep(interval); 46103f9d6ad7SLin Ling } 46113f9d6ad7SLin Ling 46123f9d6ad7SLin Ling return (0); 4613fa9e4066Sahrens } 4614fa9e4066Sahrens 4615eaca9bbdSeschrock typedef struct upgrade_cbdata { 4616eaca9bbdSeschrock int cb_first; 461706eeb2adSek int cb_argc; 4618990b4856Slling uint64_t cb_version; 461906eeb2adSek char **cb_argv; 4620eaca9bbdSeschrock } upgrade_cbdata_t; 4621eaca9bbdSeschrock 462257221772SChristopher Siden static int 462357221772SChristopher Siden upgrade_version(zpool_handle_t *zhp, uint64_t version) 462457221772SChristopher Siden { 462557221772SChristopher Siden int ret; 462657221772SChristopher Siden nvlist_t *config; 462757221772SChristopher Siden uint64_t oldversion; 462857221772SChristopher Siden 462957221772SChristopher Siden config = zpool_get_config(zhp, NULL); 463057221772SChristopher Siden verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 463157221772SChristopher Siden &oldversion) == 0); 463257221772SChristopher Siden 463357221772SChristopher Siden assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 463457221772SChristopher Siden assert(oldversion < version); 463557221772SChristopher Siden 463657221772SChristopher Siden ret = zpool_upgrade(zhp, version); 463757221772SChristopher Siden if (ret != 0) 463857221772SChristopher Siden return (ret); 463957221772SChristopher Siden 464057221772SChristopher Siden if (version >= SPA_VERSION_FEATURES) { 464157221772SChristopher Siden (void) printf(gettext("Successfully upgraded " 464257221772SChristopher Siden "'%s' from version %llu to feature flags.\n"), 464357221772SChristopher Siden zpool_get_name(zhp), oldversion); 464457221772SChristopher Siden } else { 464557221772SChristopher Siden (void) printf(gettext("Successfully upgraded " 464657221772SChristopher Siden "'%s' from version %llu to version %llu.\n"), 464757221772SChristopher Siden zpool_get_name(zhp), oldversion, version); 464857221772SChristopher Siden } 464957221772SChristopher Siden 465057221772SChristopher Siden return (0); 465157221772SChristopher Siden } 465257221772SChristopher Siden 465357221772SChristopher Siden static int 465457221772SChristopher Siden upgrade_enable_all(zpool_handle_t *zhp, int *countp) 465557221772SChristopher Siden { 465657221772SChristopher Siden int i, ret, count; 465757221772SChristopher Siden boolean_t firstff = B_TRUE; 465857221772SChristopher Siden nvlist_t *enabled = zpool_get_features(zhp); 465957221772SChristopher Siden 466057221772SChristopher Siden count = 0; 466157221772SChristopher Siden for (i = 0; i < SPA_FEATURES; i++) { 466257221772SChristopher Siden const char *fname = spa_feature_table[i].fi_uname; 466357221772SChristopher Siden const char *fguid = spa_feature_table[i].fi_guid; 466457221772SChristopher Siden if (!nvlist_exists(enabled, fguid)) { 466557221772SChristopher Siden char *propname; 466657221772SChristopher Siden verify(-1 != asprintf(&propname, "feature@%s", fname)); 466757221772SChristopher Siden ret = zpool_set_prop(zhp, propname, 466857221772SChristopher Siden ZFS_FEATURE_ENABLED); 466957221772SChristopher Siden if (ret != 0) { 467057221772SChristopher Siden free(propname); 467157221772SChristopher Siden return (ret); 467257221772SChristopher Siden } 467357221772SChristopher Siden count++; 467457221772SChristopher Siden 467557221772SChristopher Siden if (firstff) { 467657221772SChristopher Siden (void) printf(gettext("Enabled the " 467757221772SChristopher Siden "following features on '%s':\n"), 467857221772SChristopher Siden zpool_get_name(zhp)); 467957221772SChristopher Siden firstff = B_FALSE; 468057221772SChristopher Siden } 468157221772SChristopher Siden (void) printf(gettext(" %s\n"), fname); 468257221772SChristopher Siden free(propname); 468357221772SChristopher Siden } 468457221772SChristopher Siden } 468557221772SChristopher Siden 468657221772SChristopher Siden if (countp != NULL) 468757221772SChristopher Siden *countp = count; 468857221772SChristopher Siden return (0); 468957221772SChristopher Siden } 469057221772SChristopher Siden 4691eaca9bbdSeschrock static int 4692eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg) 4693eaca9bbdSeschrock { 4694eaca9bbdSeschrock upgrade_cbdata_t *cbp = arg; 4695eaca9bbdSeschrock nvlist_t *config; 4696eaca9bbdSeschrock uint64_t version; 469757221772SChristopher Siden boolean_t printnl = B_FALSE; 469857221772SChristopher Siden int ret; 4699eaca9bbdSeschrock 4700eaca9bbdSeschrock config = zpool_get_config(zhp, NULL); 4701eaca9bbdSeschrock verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4702eaca9bbdSeschrock &version) == 0); 4703eaca9bbdSeschrock 470457221772SChristopher Siden assert(SPA_VERSION_IS_SUPPORTED(version)); 4705eaca9bbdSeschrock 470657221772SChristopher Siden if (version < cbp->cb_version) { 470757221772SChristopher Siden cbp->cb_first = B_FALSE; 470857221772SChristopher Siden ret = upgrade_version(zhp, cbp->cb_version); 470957221772SChristopher Siden if (ret != 0) 471057221772SChristopher Siden return (ret); 471157221772SChristopher Siden printnl = B_TRUE; 471257221772SChristopher Siden 471357221772SChristopher Siden /* 471457221772SChristopher Siden * If they did "zpool upgrade -a", then we could 471557221772SChristopher Siden * be doing ioctls to different pools. We need 471657221772SChristopher Siden * to log this history once to each pool, and bypass 471757221772SChristopher Siden * the normal history logging that happens in main(). 471857221772SChristopher Siden */ 471957221772SChristopher Siden (void) zpool_log_history(g_zfs, history_str); 472057221772SChristopher Siden log_history = B_FALSE; 472157221772SChristopher Siden } 472257221772SChristopher Siden 472357221772SChristopher Siden if (cbp->cb_version >= SPA_VERSION_FEATURES) { 472457221772SChristopher Siden int count; 472557221772SChristopher Siden ret = upgrade_enable_all(zhp, &count); 472657221772SChristopher Siden if (ret != 0) 472757221772SChristopher Siden return (ret); 472857221772SChristopher Siden 472957221772SChristopher Siden if (count > 0) { 473099653d4eSeschrock cbp->cb_first = B_FALSE; 473157221772SChristopher Siden printnl = B_TRUE; 4732eaca9bbdSeschrock } 473357221772SChristopher Siden } 4734eaca9bbdSeschrock 473557221772SChristopher Siden if (printnl) { 473657221772SChristopher Siden (void) printf(gettext("\n")); 473757221772SChristopher Siden } 473857221772SChristopher Siden 473957221772SChristopher Siden return (0); 474057221772SChristopher Siden } 474157221772SChristopher Siden 474257221772SChristopher Siden static int 474357221772SChristopher Siden upgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 474457221772SChristopher Siden { 474557221772SChristopher Siden upgrade_cbdata_t *cbp = arg; 474657221772SChristopher Siden nvlist_t *config; 474757221772SChristopher Siden uint64_t version; 474857221772SChristopher Siden 474957221772SChristopher Siden config = zpool_get_config(zhp, NULL); 475057221772SChristopher Siden verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 475157221772SChristopher Siden &version) == 0); 475257221772SChristopher Siden 475357221772SChristopher Siden assert(SPA_VERSION_IS_SUPPORTED(version)); 475457221772SChristopher Siden 475557221772SChristopher Siden if (version < SPA_VERSION_FEATURES) { 4756eaca9bbdSeschrock if (cbp->cb_first) { 4757eaca9bbdSeschrock (void) printf(gettext("The following pools are " 475857221772SChristopher Siden "formatted with legacy version numbers and can\n" 475957221772SChristopher Siden "be upgraded to use feature flags. After " 476057221772SChristopher Siden "being upgraded, these pools\nwill no " 476157221772SChristopher Siden "longer be accessible by software that does not " 476257221772SChristopher Siden "support feature\nflags.\n\n")); 4763eaca9bbdSeschrock (void) printf(gettext("VER POOL\n")); 4764eaca9bbdSeschrock (void) printf(gettext("--- ------------\n")); 476599653d4eSeschrock cbp->cb_first = B_FALSE; 4766eaca9bbdSeschrock } 4767eaca9bbdSeschrock 47685ad82045Snd (void) printf("%2llu %s\n", (u_longlong_t)version, 4769eaca9bbdSeschrock zpool_get_name(zhp)); 4770eaca9bbdSeschrock } 4771eaca9bbdSeschrock 477257221772SChristopher Siden return (0); 477357221772SChristopher Siden } 477457221772SChristopher Siden 477557221772SChristopher Siden static int 477657221772SChristopher Siden upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 477757221772SChristopher Siden { 477857221772SChristopher Siden upgrade_cbdata_t *cbp = arg; 477957221772SChristopher Siden nvlist_t *config; 478057221772SChristopher Siden uint64_t version; 478157221772SChristopher Siden 478257221772SChristopher Siden config = zpool_get_config(zhp, NULL); 478357221772SChristopher Siden verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 478457221772SChristopher Siden &version) == 0); 478557221772SChristopher Siden 478657221772SChristopher Siden if (version >= SPA_VERSION_FEATURES) { 478757221772SChristopher Siden int i; 478857221772SChristopher Siden boolean_t poolfirst = B_TRUE; 478957221772SChristopher Siden nvlist_t *enabled = zpool_get_features(zhp); 479057221772SChristopher Siden 479157221772SChristopher Siden for (i = 0; i < SPA_FEATURES; i++) { 479257221772SChristopher Siden const char *fguid = spa_feature_table[i].fi_guid; 479357221772SChristopher Siden const char *fname = spa_feature_table[i].fi_uname; 479457221772SChristopher Siden if (!nvlist_exists(enabled, fguid)) { 479557221772SChristopher Siden if (cbp->cb_first) { 479657221772SChristopher Siden (void) printf(gettext("\nSome " 479757221772SChristopher Siden "supported features are not " 479857221772SChristopher Siden "enabled on the following pools. " 479957221772SChristopher Siden "Once a\nfeature is enabled the " 480057221772SChristopher Siden "pool may become incompatible with " 480157221772SChristopher Siden "software\nthat does not support " 480257221772SChristopher Siden "the feature. See " 480357221772SChristopher Siden "zpool-features(5) for " 480457221772SChristopher Siden "details.\n\n")); 480557221772SChristopher Siden (void) printf(gettext("POOL " 480657221772SChristopher Siden "FEATURE\n")); 480757221772SChristopher Siden (void) printf(gettext("------" 480857221772SChristopher Siden "---------\n")); 480957221772SChristopher Siden cbp->cb_first = B_FALSE; 481057221772SChristopher Siden } 481157221772SChristopher Siden 481257221772SChristopher Siden if (poolfirst) { 481357221772SChristopher Siden (void) printf(gettext("%s\n"), 481457221772SChristopher Siden zpool_get_name(zhp)); 481557221772SChristopher Siden poolfirst = B_FALSE; 481657221772SChristopher Siden } 481757221772SChristopher Siden 481857221772SChristopher Siden (void) printf(gettext(" %s\n"), fname); 481957221772SChristopher Siden } 482057221772SChristopher Siden } 482157221772SChristopher Siden } 482257221772SChristopher Siden 482357221772SChristopher Siden return (0); 4824eaca9bbdSeschrock } 4825eaca9bbdSeschrock 4826eaca9bbdSeschrock /* ARGSUSED */ 4827eaca9bbdSeschrock static int 482806eeb2adSek upgrade_one(zpool_handle_t *zhp, void *data) 4829eaca9bbdSeschrock { 483057221772SChristopher Siden boolean_t printnl = B_FALSE; 4831990b4856Slling upgrade_cbdata_t *cbp = data; 4832990b4856Slling uint64_t cur_version; 4833eaca9bbdSeschrock int ret; 4834eaca9bbdSeschrock 48358654d025Sperrin if (strcmp("log", zpool_get_name(zhp)) == 0) { 48368654d025Sperrin (void) printf(gettext("'log' is now a reserved word\n" 48378654d025Sperrin "Pool 'log' must be renamed using export and import" 48388654d025Sperrin " to upgrade.\n")); 48398654d025Sperrin return (1); 48408654d025Sperrin } 4841990b4856Slling 4842990b4856Slling cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4843e6c728e1Sbrendan if (cur_version > cbp->cb_version) { 4844eaca9bbdSeschrock (void) printf(gettext("Pool '%s' is already formatted " 484557221772SChristopher Siden "using more current version '%llu'.\n\n"), 4846e6c728e1Sbrendan zpool_get_name(zhp), cur_version); 4847e6c728e1Sbrendan return (0); 4848e6c728e1Sbrendan } 484957221772SChristopher Siden 485057221772SChristopher Siden if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 4851e6c728e1Sbrendan (void) printf(gettext("Pool '%s' is already formatted " 485257221772SChristopher Siden "using version %llu.\n\n"), zpool_get_name(zhp), 485357221772SChristopher Siden cbp->cb_version); 4854eaca9bbdSeschrock return (0); 4855eaca9bbdSeschrock } 4856eaca9bbdSeschrock 485757221772SChristopher Siden if (cur_version != cbp->cb_version) { 485857221772SChristopher Siden printnl = B_TRUE; 485957221772SChristopher Siden ret = upgrade_version(zhp, cbp->cb_version); 486057221772SChristopher Siden if (ret != 0) 486157221772SChristopher Siden return (ret); 486257221772SChristopher Siden } 486306eeb2adSek 486457221772SChristopher Siden if (cbp->cb_version >= SPA_VERSION_FEATURES) { 486557221772SChristopher Siden int count = 0; 486657221772SChristopher Siden ret = upgrade_enable_all(zhp, &count); 486757221772SChristopher Siden if (ret != 0) 486857221772SChristopher Siden return (ret); 486957221772SChristopher Siden 487057221772SChristopher Siden if (count != 0) { 487157221772SChristopher Siden printnl = B_TRUE; 487257221772SChristopher Siden } else if (cur_version == SPA_VERSION) { 487357221772SChristopher Siden (void) printf(gettext("Pool '%s' already has all " 487457221772SChristopher Siden "supported features enabled.\n"), 487557221772SChristopher Siden zpool_get_name(zhp)); 487657221772SChristopher Siden } 487757221772SChristopher Siden } 487857221772SChristopher Siden 487957221772SChristopher Siden if (printnl) { 488057221772SChristopher Siden (void) printf(gettext("\n")); 488106eeb2adSek } 4882eaca9bbdSeschrock 488357221772SChristopher Siden return (0); 4884eaca9bbdSeschrock } 4885eaca9bbdSeschrock 4886eaca9bbdSeschrock /* 4887eaca9bbdSeschrock * zpool upgrade 4888eaca9bbdSeschrock * zpool upgrade -v 4889990b4856Slling * zpool upgrade [-V version] <-a | pool ...> 4890eaca9bbdSeschrock * 4891eaca9bbdSeschrock * With no arguments, display downrev'd ZFS pool available for upgrade. 4892eaca9bbdSeschrock * Individual pools can be upgraded by specifying the pool, and '-a' will 4893eaca9bbdSeschrock * upgrade all pools. 4894eaca9bbdSeschrock */ 4895eaca9bbdSeschrock int 4896eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv) 4897eaca9bbdSeschrock { 4898eaca9bbdSeschrock int c; 4899eaca9bbdSeschrock upgrade_cbdata_t cb = { 0 }; 4900eaca9bbdSeschrock int ret = 0; 4901eaca9bbdSeschrock boolean_t showversions = B_FALSE; 490257221772SChristopher Siden boolean_t upgradeall = B_FALSE; 4903990b4856Slling char *end; 4904990b4856Slling 4905eaca9bbdSeschrock 4906eaca9bbdSeschrock /* check options */ 4907478ed9adSEric Taylor while ((c = getopt(argc, argv, ":avV:")) != -1) { 4908eaca9bbdSeschrock switch (c) { 4909eaca9bbdSeschrock case 'a': 491057221772SChristopher Siden upgradeall = B_TRUE; 4911eaca9bbdSeschrock break; 4912eaca9bbdSeschrock case 'v': 4913eaca9bbdSeschrock showversions = B_TRUE; 4914eaca9bbdSeschrock break; 4915990b4856Slling case 'V': 4916990b4856Slling cb.cb_version = strtoll(optarg, &end, 10); 4917ad135b5dSChristopher Siden if (*end != '\0' || 4918ad135b5dSChristopher Siden !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 4919990b4856Slling (void) fprintf(stderr, 4920990b4856Slling gettext("invalid version '%s'\n"), optarg); 4921990b4856Slling usage(B_FALSE); 4922990b4856Slling } 4923990b4856Slling break; 4924478ed9adSEric Taylor case ':': 4925478ed9adSEric Taylor (void) fprintf(stderr, gettext("missing argument for " 4926478ed9adSEric Taylor "'%c' option\n"), optopt); 4927478ed9adSEric Taylor usage(B_FALSE); 4928478ed9adSEric Taylor break; 4929eaca9bbdSeschrock case '?': 4930eaca9bbdSeschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4931eaca9bbdSeschrock optopt); 493299653d4eSeschrock usage(B_FALSE); 4933eaca9bbdSeschrock } 4934eaca9bbdSeschrock } 4935eaca9bbdSeschrock 493606eeb2adSek cb.cb_argc = argc; 493706eeb2adSek cb.cb_argv = argv; 4938eaca9bbdSeschrock argc -= optind; 4939eaca9bbdSeschrock argv += optind; 4940eaca9bbdSeschrock 4941351420b3Slling if (cb.cb_version == 0) { 4942351420b3Slling cb.cb_version = SPA_VERSION; 494357221772SChristopher Siden } else if (!upgradeall && argc == 0) { 4944351420b3Slling (void) fprintf(stderr, gettext("-V option is " 4945351420b3Slling "incompatible with other arguments\n")); 4946351420b3Slling usage(B_FALSE); 4947351420b3Slling } 4948351420b3Slling 4949eaca9bbdSeschrock if (showversions) { 495057221772SChristopher Siden if (upgradeall || argc != 0) { 4951eaca9bbdSeschrock (void) fprintf(stderr, gettext("-v option is " 4952eaca9bbdSeschrock "incompatible with other arguments\n")); 495399653d4eSeschrock usage(B_FALSE); 4954eaca9bbdSeschrock } 495557221772SChristopher Siden } else if (upgradeall) { 4956eaca9bbdSeschrock if (argc != 0) { 4957351420b3Slling (void) fprintf(stderr, gettext("-a option should not " 4958351420b3Slling "be used along with a pool name\n")); 495999653d4eSeschrock usage(B_FALSE); 4960eaca9bbdSeschrock } 4961eaca9bbdSeschrock } 4962eaca9bbdSeschrock 4963ad135b5dSChristopher Siden (void) printf(gettext("This system supports ZFS pool feature " 4964ad135b5dSChristopher Siden "flags.\n\n")); 4965eaca9bbdSeschrock if (showversions) { 496657221772SChristopher Siden int i; 496757221772SChristopher Siden 496857221772SChristopher Siden (void) printf(gettext("The following features are " 496957221772SChristopher Siden "supported:\n\n")); 497057221772SChristopher Siden (void) printf(gettext("FEAT DESCRIPTION\n")); 497157221772SChristopher Siden (void) printf("----------------------------------------------" 497257221772SChristopher Siden "---------------\n"); 497357221772SChristopher Siden for (i = 0; i < SPA_FEATURES; i++) { 497457221772SChristopher Siden zfeature_info_t *fi = &spa_feature_table[i]; 4975ca0cc391SMatthew Ahrens const char *ro = 4976ca0cc391SMatthew Ahrens (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ? 497757221772SChristopher Siden " (read-only compatible)" : ""; 497857221772SChristopher Siden 497957221772SChristopher Siden (void) printf("%-37s%s\n", fi->fi_uname, ro); 498057221772SChristopher Siden (void) printf(" %s\n", fi->fi_desc); 498157221772SChristopher Siden } 498257221772SChristopher Siden (void) printf("\n"); 498357221772SChristopher Siden 498457221772SChristopher Siden (void) printf(gettext("The following legacy versions are also " 4985d7d4af51Smmusante "supported:\n\n")); 4986eaca9bbdSeschrock (void) printf(gettext("VER DESCRIPTION\n")); 4987eaca9bbdSeschrock (void) printf("--- -----------------------------------------" 4988eaca9bbdSeschrock "---------------\n"); 498999653d4eSeschrock (void) printf(gettext(" 1 Initial ZFS version\n")); 499044cd46caSbillm (void) printf(gettext(" 2 Ditto blocks " 499144cd46caSbillm "(replicated metadata)\n")); 499299653d4eSeschrock (void) printf(gettext(" 3 Hot spares and double parity " 499399653d4eSeschrock "RAID-Z\n")); 4994d7306b64Sek (void) printf(gettext(" 4 zpool history\n")); 4995c9431fa1Sahl (void) printf(gettext(" 5 Compression using the gzip " 4996c9431fa1Sahl "algorithm\n")); 4997990b4856Slling (void) printf(gettext(" 6 bootfs pool property\n")); 49988654d025Sperrin (void) printf(gettext(" 7 Separate intent log devices\n")); 4999ecd6cf80Smarks (void) printf(gettext(" 8 Delegated administration\n")); 50008eed72d4Sck (void) printf(gettext(" 9 refquota and refreservation " 5001a9799022Sck "properties\n")); 5002fa94a07fSbrendan (void) printf(gettext(" 10 Cache devices\n")); 5003088f3894Sahrens (void) printf(gettext(" 11 Improved scrub performance\n")); 5004bb0ade09Sahrens (void) printf(gettext(" 12 Snapshot properties\n")); 500574e7dc98SMatthew Ahrens (void) printf(gettext(" 13 snapused property\n")); 500614843421SMatthew Ahrens (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 500714843421SMatthew Ahrens (void) printf(gettext(" 15 user/group space accounting\n")); 5008478ed9adSEric Taylor (void) printf(gettext(" 16 stmf property support\n")); 50097aeab329SAdam Leventhal (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 5010b24ab676SJeff Bonwick (void) printf(gettext(" 18 Snapshot user holds\n")); 501188ecc943SGeorge Wilson (void) printf(gettext(" 19 Log device removal\n")); 5012b24ab676SJeff Bonwick (void) printf(gettext(" 20 Compression using zle " 5013b24ab676SJeff Bonwick "(zero-length encoding)\n")); 5014b24ab676SJeff Bonwick (void) printf(gettext(" 21 Deduplication\n")); 501592241e0bSTom Erickson (void) printf(gettext(" 22 Received properties\n")); 50166e1f5caaSNeil Perrin (void) printf(gettext(" 23 Slim ZIL\n")); 50170a586ceaSMark Shellenbaum (void) printf(gettext(" 24 System attributes\n")); 50183f9d6ad7SLin Ling (void) printf(gettext(" 25 Improved scrub stats\n")); 5019cde58dbcSMatthew Ahrens (void) printf(gettext(" 26 Improved snapshot deletion " 5020cde58dbcSMatthew Ahrens "performance\n")); 50216e0cbcaaSMatthew Ahrens (void) printf(gettext(" 27 Improved snapshot creation " 50226e0cbcaaSMatthew Ahrens "performance\n")); 5023cb04b873SMark J Musante (void) printf(gettext(" 28 Multiple vdev replacements\n")); 5024b24ab676SJeff Bonwick (void) printf(gettext("\nFor more information on a particular " 50259a8685acSstephanie scheffler "version, including supported releases,\n")); 50269a8685acSstephanie scheffler (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 502757221772SChristopher Siden } else if (argc == 0 && upgradeall) { 502857221772SChristopher Siden cb.cb_first = B_TRUE; 502999653d4eSeschrock ret = zpool_iter(g_zfs, upgrade_cb, &cb); 503057221772SChristopher Siden if (ret == 0 && cb.cb_first) { 503157221772SChristopher Siden if (cb.cb_version == SPA_VERSION) { 503257221772SChristopher Siden (void) printf(gettext("All pools are already " 503357221772SChristopher Siden "formatted using feature flags.\n\n")); 503457221772SChristopher Siden (void) printf(gettext("Every feature flags " 503557221772SChristopher Siden "pool already has all supported features " 503657221772SChristopher Siden "enabled.\n")); 503757221772SChristopher Siden } else { 503857221772SChristopher Siden (void) printf(gettext("All pools are already " 503957221772SChristopher Siden "formatted with version %llu or higher.\n"), 504057221772SChristopher Siden cb.cb_version); 5041eaca9bbdSeschrock } 5042eaca9bbdSeschrock } 504357221772SChristopher Siden } else if (argc == 0) { 504457221772SChristopher Siden cb.cb_first = B_TRUE; 504557221772SChristopher Siden ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 504657221772SChristopher Siden assert(ret == 0); 5047eaca9bbdSeschrock 504857221772SChristopher Siden if (cb.cb_first) { 504957221772SChristopher Siden (void) printf(gettext("All pools are formatted " 505057221772SChristopher Siden "using feature flags.\n\n")); 505157221772SChristopher Siden } else { 505257221772SChristopher Siden (void) printf(gettext("\nUse 'zpool upgrade -v' " 505357221772SChristopher Siden "for a list of available legacy versions.\n")); 505457221772SChristopher Siden } 505557221772SChristopher Siden 505657221772SChristopher Siden cb.cb_first = B_TRUE; 505757221772SChristopher Siden ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 505857221772SChristopher Siden assert(ret == 0); 505957221772SChristopher Siden 506057221772SChristopher Siden if (cb.cb_first) { 506157221772SChristopher Siden (void) printf(gettext("Every feature flags pool has " 506257221772SChristopher Siden "all supported features enabled.\n")); 506357221772SChristopher Siden } else { 506457221772SChristopher Siden (void) printf(gettext("\n")); 5065eaca9bbdSeschrock } 5066eaca9bbdSeschrock } else { 5067b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, 5068b1b8ab34Slling upgrade_one, &cb); 506906eeb2adSek } 507006eeb2adSek 507106eeb2adSek return (ret); 507206eeb2adSek } 507306eeb2adSek 5074ecd6cf80Smarks typedef struct hist_cbdata { 5075ecd6cf80Smarks boolean_t first; 50764445fffbSMatthew Ahrens boolean_t longfmt; 50774445fffbSMatthew Ahrens boolean_t internal; 5078ecd6cf80Smarks } hist_cbdata_t; 5079ecd6cf80Smarks 508006eeb2adSek /* 508106eeb2adSek * Print out the command history for a specific pool. 508206eeb2adSek */ 508306eeb2adSek static int 508406eeb2adSek get_history_one(zpool_handle_t *zhp, void *data) 508506eeb2adSek { 508606eeb2adSek nvlist_t *nvhis; 508706eeb2adSek nvlist_t **records; 508806eeb2adSek uint_t numrecords; 508906eeb2adSek int ret, i; 5090ecd6cf80Smarks hist_cbdata_t *cb = (hist_cbdata_t *)data; 509106eeb2adSek 5092ecd6cf80Smarks cb->first = B_FALSE; 509306eeb2adSek 509406eeb2adSek (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 509506eeb2adSek 509606eeb2adSek if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 509706eeb2adSek return (ret); 509806eeb2adSek 509906eeb2adSek verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 510006eeb2adSek &records, &numrecords) == 0); 510106eeb2adSek for (i = 0; i < numrecords; i++) { 51024445fffbSMatthew Ahrens nvlist_t *rec = records[i]; 51034445fffbSMatthew Ahrens char tbuf[30] = ""; 5104ecd6cf80Smarks 51054445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_TIME)) { 51064445fffbSMatthew Ahrens time_t tsec; 51074445fffbSMatthew Ahrens struct tm t; 51084445fffbSMatthew Ahrens 51094445fffbSMatthew Ahrens tsec = fnvlist_lookup_uint64(records[i], 51104445fffbSMatthew Ahrens ZPOOL_HIST_TIME); 51114445fffbSMatthew Ahrens (void) localtime_r(&tsec, &t); 51124445fffbSMatthew Ahrens (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 51134445fffbSMatthew Ahrens } 5114ecd6cf80Smarks 51154445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_CMD)) { 51164445fffbSMatthew Ahrens (void) printf("%s %s", tbuf, 51174445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_CMD)); 51184445fffbSMatthew Ahrens } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) { 51194445fffbSMatthew Ahrens int ievent = 51204445fffbSMatthew Ahrens fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT); 51214445fffbSMatthew Ahrens if (!cb->internal) 51224445fffbSMatthew Ahrens continue; 51234445fffbSMatthew Ahrens if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) { 51244445fffbSMatthew Ahrens (void) printf("%s unrecognized record:\n", 51254445fffbSMatthew Ahrens tbuf); 51264445fffbSMatthew Ahrens dump_nvlist(rec, 4); 51274445fffbSMatthew Ahrens continue; 51284445fffbSMatthew Ahrens } 51294445fffbSMatthew Ahrens (void) printf("%s [internal %s txg:%lld] %s", tbuf, 51304445fffbSMatthew Ahrens zfs_history_event_names[ievent], 51314445fffbSMatthew Ahrens fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 51324445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR)); 51334445fffbSMatthew Ahrens } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) { 51344445fffbSMatthew Ahrens if (!cb->internal) 5135ecd6cf80Smarks continue; 51364445fffbSMatthew Ahrens (void) printf("%s [txg:%lld] %s", tbuf, 51374445fffbSMatthew Ahrens fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 51384445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME)); 51394445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) { 51404445fffbSMatthew Ahrens (void) printf(" %s (%llu)", 51414445fffbSMatthew Ahrens fnvlist_lookup_string(rec, 51424445fffbSMatthew Ahrens ZPOOL_HIST_DSNAME), 51434445fffbSMatthew Ahrens fnvlist_lookup_uint64(rec, 51444445fffbSMatthew Ahrens ZPOOL_HIST_DSID)); 51454445fffbSMatthew Ahrens } 51464445fffbSMatthew Ahrens (void) printf(" %s", fnvlist_lookup_string(rec, 51474445fffbSMatthew Ahrens ZPOOL_HIST_INT_STR)); 51484445fffbSMatthew Ahrens } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) { 51494445fffbSMatthew Ahrens if (!cb->internal) 51504445fffbSMatthew Ahrens continue; 51514445fffbSMatthew Ahrens (void) printf("%s ioctl %s\n", tbuf, 51524445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL)); 51534445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) { 51544445fffbSMatthew Ahrens (void) printf(" input:\n"); 51554445fffbSMatthew Ahrens dump_nvlist(fnvlist_lookup_nvlist(rec, 51564445fffbSMatthew Ahrens ZPOOL_HIST_INPUT_NVL), 8); 51574445fffbSMatthew Ahrens } 51584445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) { 51594445fffbSMatthew Ahrens (void) printf(" output:\n"); 51604445fffbSMatthew Ahrens dump_nvlist(fnvlist_lookup_nvlist(rec, 51614445fffbSMatthew Ahrens ZPOOL_HIST_OUTPUT_NVL), 8); 51624445fffbSMatthew Ahrens } 5163dfc11533SChris Williamson if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) { 5164dfc11533SChris Williamson (void) printf(" errno: %lld\n", 5165dfc11533SChris Williamson fnvlist_lookup_int64(rec, 5166dfc11533SChris Williamson ZPOOL_HIST_ERRNO)); 5167dfc11533SChris Williamson } 51684445fffbSMatthew Ahrens } else { 51694445fffbSMatthew Ahrens if (!cb->internal) 5170ecd6cf80Smarks continue; 51714445fffbSMatthew Ahrens (void) printf("%s unrecognized record:\n", tbuf); 51724445fffbSMatthew Ahrens dump_nvlist(rec, 4); 517306eeb2adSek } 5174ecd6cf80Smarks 5175ecd6cf80Smarks if (!cb->longfmt) { 5176ecd6cf80Smarks (void) printf("\n"); 5177ecd6cf80Smarks continue; 5178ecd6cf80Smarks } 5179ecd6cf80Smarks (void) printf(" ["); 51804445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_WHO)) { 51814445fffbSMatthew Ahrens uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO); 51824445fffbSMatthew Ahrens struct passwd *pwd = getpwuid(who); 51834445fffbSMatthew Ahrens (void) printf("user %d ", (int)who); 51844445fffbSMatthew Ahrens if (pwd != NULL) 51854445fffbSMatthew Ahrens (void) printf("(%s) ", pwd->pw_name); 5186ecd6cf80Smarks } 51874445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_HOST)) { 51884445fffbSMatthew Ahrens (void) printf("on %s", 51894445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_HOST)); 5190ecd6cf80Smarks } 51914445fffbSMatthew Ahrens if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) { 51924445fffbSMatthew Ahrens (void) printf(":%s", 51934445fffbSMatthew Ahrens fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE)); 5194ecd6cf80Smarks } 5195ecd6cf80Smarks (void) printf("]"); 5196ecd6cf80Smarks (void) printf("\n"); 519706eeb2adSek } 519806eeb2adSek (void) printf("\n"); 519906eeb2adSek nvlist_free(nvhis); 520006eeb2adSek 520106eeb2adSek return (ret); 520206eeb2adSek } 520306eeb2adSek 520406eeb2adSek /* 520506eeb2adSek * zpool history <pool> 520606eeb2adSek * 520706eeb2adSek * Displays the history of commands that modified pools. 520806eeb2adSek */ 520906eeb2adSek int 521006eeb2adSek zpool_do_history(int argc, char **argv) 521106eeb2adSek { 5212ecd6cf80Smarks hist_cbdata_t cbdata = { 0 }; 521306eeb2adSek int ret; 5214ecd6cf80Smarks int c; 521506eeb2adSek 5216ecd6cf80Smarks cbdata.first = B_TRUE; 5217ecd6cf80Smarks /* check options */ 5218ecd6cf80Smarks while ((c = getopt(argc, argv, "li")) != -1) { 5219ecd6cf80Smarks switch (c) { 5220ecd6cf80Smarks case 'l': 52214445fffbSMatthew Ahrens cbdata.longfmt = B_TRUE; 5222ecd6cf80Smarks break; 5223ecd6cf80Smarks case 'i': 52244445fffbSMatthew Ahrens cbdata.internal = B_TRUE; 5225ecd6cf80Smarks break; 5226ecd6cf80Smarks case '?': 5227ecd6cf80Smarks (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5228ecd6cf80Smarks optopt); 5229ecd6cf80Smarks usage(B_FALSE); 5230ecd6cf80Smarks } 5231ecd6cf80Smarks } 523206eeb2adSek argc -= optind; 523306eeb2adSek argv += optind; 523406eeb2adSek 5235b1b8ab34Slling ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 5236ecd6cf80Smarks &cbdata); 523706eeb2adSek 5238ecd6cf80Smarks if (argc == 0 && cbdata.first == B_TRUE) { 523906eeb2adSek (void) printf(gettext("no pools available\n")); 524006eeb2adSek return (0); 5241eaca9bbdSeschrock } 5242eaca9bbdSeschrock 5243eaca9bbdSeschrock return (ret); 5244eaca9bbdSeschrock } 5245eaca9bbdSeschrock 5246b1b8ab34Slling static int 5247b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data) 5248b1b8ab34Slling { 5249990b4856Slling zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 5250b1b8ab34Slling char value[MAXNAMELEN]; 5251990b4856Slling zprop_source_t srctype; 5252990b4856Slling zprop_list_t *pl; 5253b1b8ab34Slling 5254b1b8ab34Slling for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 5255b1b8ab34Slling 5256b1b8ab34Slling /* 5257990b4856Slling * Skip the special fake placeholder. This will also skip 5258990b4856Slling * over the name property when 'all' is specified. 5259b1b8ab34Slling */ 5260990b4856Slling if (pl->pl_prop == ZPOOL_PROP_NAME && 5261b1b8ab34Slling pl == cbp->cb_proplist) 5262b1b8ab34Slling continue; 5263b1b8ab34Slling 5264ad135b5dSChristopher Siden if (pl->pl_prop == ZPROP_INVAL && 5265ad135b5dSChristopher Siden (zpool_prop_feature(pl->pl_user_prop) || 5266ad135b5dSChristopher Siden zpool_prop_unsupported(pl->pl_user_prop))) { 5267ad135b5dSChristopher Siden srctype = ZPROP_SRC_LOCAL; 5268b1b8ab34Slling 5269ad135b5dSChristopher Siden if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 5270ad135b5dSChristopher Siden value, sizeof (value)) == 0) { 5271ad135b5dSChristopher Siden zprop_print_one_property(zpool_get_name(zhp), 5272ad135b5dSChristopher Siden cbp, pl->pl_user_prop, value, srctype, 5273ad135b5dSChristopher Siden NULL, NULL); 5274ad135b5dSChristopher Siden } 5275ad135b5dSChristopher Siden } else { 5276ad135b5dSChristopher Siden if (zpool_get_prop(zhp, pl->pl_prop, value, 5277c58b3526SAdam Stevko sizeof (value), &srctype, cbp->cb_literal) != 0) 5278ad135b5dSChristopher Siden continue; 5279ad135b5dSChristopher Siden 5280ad135b5dSChristopher Siden zprop_print_one_property(zpool_get_name(zhp), cbp, 5281ad135b5dSChristopher Siden zpool_prop_to_name(pl->pl_prop), value, srctype, 5282ad135b5dSChristopher Siden NULL, NULL); 5283ad135b5dSChristopher Siden } 5284b1b8ab34Slling } 5285b1b8ab34Slling return (0); 5286b1b8ab34Slling } 5287b1b8ab34Slling 5288c58b3526SAdam Stevko /* 5289c58b3526SAdam Stevko * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ... 5290c58b3526SAdam Stevko * 5291c58b3526SAdam Stevko * -H Scripted mode. Don't display headers, and separate properties 5292c58b3526SAdam Stevko * by a single tab. 5293c58b3526SAdam Stevko * -o List of columns to display. Defaults to 5294c58b3526SAdam Stevko * "name,property,value,source". 5295c58b3526SAdam Stevko * -p Diplay values in parsable (exact) format. 5296c58b3526SAdam Stevko * 5297c58b3526SAdam Stevko * Get properties of pools in the system. Output space statistics 5298c58b3526SAdam Stevko * for each one as well as other attributes. 5299c58b3526SAdam Stevko */ 5300b1b8ab34Slling int 5301b1b8ab34Slling zpool_do_get(int argc, char **argv) 5302b1b8ab34Slling { 5303990b4856Slling zprop_get_cbdata_t cb = { 0 }; 5304990b4856Slling zprop_list_t fake_name = { 0 }; 5305b1b8ab34Slling int ret; 5306c58b3526SAdam Stevko int c, i; 5307c58b3526SAdam Stevko char *value; 5308b1b8ab34Slling 5309b1b8ab34Slling cb.cb_first = B_TRUE; 5310c58b3526SAdam Stevko 5311c58b3526SAdam Stevko /* 5312c58b3526SAdam Stevko * Set up default columns and sources. 5313c58b3526SAdam Stevko */ 5314990b4856Slling cb.cb_sources = ZPROP_SRC_ALL; 5315b1b8ab34Slling cb.cb_columns[0] = GET_COL_NAME; 5316b1b8ab34Slling cb.cb_columns[1] = GET_COL_PROPERTY; 5317b1b8ab34Slling cb.cb_columns[2] = GET_COL_VALUE; 5318b1b8ab34Slling cb.cb_columns[3] = GET_COL_SOURCE; 5319990b4856Slling cb.cb_type = ZFS_TYPE_POOL; 5320b1b8ab34Slling 5321c58b3526SAdam Stevko /* check options */ 5322c58b3526SAdam Stevko while ((c = getopt(argc, argv, ":Hpo:")) != -1) { 5323c58b3526SAdam Stevko switch (c) { 5324c58b3526SAdam Stevko case 'p': 5325c58b3526SAdam Stevko cb.cb_literal = B_TRUE; 5326c58b3526SAdam Stevko break; 5327c58b3526SAdam Stevko case 'H': 5328c58b3526SAdam Stevko cb.cb_scripted = B_TRUE; 5329c58b3526SAdam Stevko break; 5330c58b3526SAdam Stevko case 'o': 5331c58b3526SAdam Stevko bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 5332c58b3526SAdam Stevko i = 0; 5333c58b3526SAdam Stevko while (*optarg != '\0') { 5334c58b3526SAdam Stevko static char *col_subopts[] = 5335c58b3526SAdam Stevko { "name", "property", "value", "source", 5336c58b3526SAdam Stevko "all", NULL }; 5337c58b3526SAdam Stevko 5338c58b3526SAdam Stevko if (i == ZFS_GET_NCOLS) { 5339c58b3526SAdam Stevko (void) fprintf(stderr, gettext("too " 5340c58b3526SAdam Stevko "many fields given to -o " 5341c58b3526SAdam Stevko "option\n")); 5342c58b3526SAdam Stevko usage(B_FALSE); 5343c58b3526SAdam Stevko } 5344c58b3526SAdam Stevko 5345c58b3526SAdam Stevko switch (getsubopt(&optarg, col_subopts, 5346c58b3526SAdam Stevko &value)) { 5347c58b3526SAdam Stevko case 0: 5348c58b3526SAdam Stevko cb.cb_columns[i++] = GET_COL_NAME; 5349c58b3526SAdam Stevko break; 5350c58b3526SAdam Stevko case 1: 5351c58b3526SAdam Stevko cb.cb_columns[i++] = GET_COL_PROPERTY; 5352c58b3526SAdam Stevko break; 5353c58b3526SAdam Stevko case 2: 5354c58b3526SAdam Stevko cb.cb_columns[i++] = GET_COL_VALUE; 5355c58b3526SAdam Stevko break; 5356c58b3526SAdam Stevko case 3: 5357c58b3526SAdam Stevko cb.cb_columns[i++] = GET_COL_SOURCE; 5358c58b3526SAdam Stevko break; 5359c58b3526SAdam Stevko case 4: 5360c58b3526SAdam Stevko if (i > 0) { 5361c58b3526SAdam Stevko (void) fprintf(stderr, 5362c58b3526SAdam Stevko gettext("\"all\" conflicts " 5363c58b3526SAdam Stevko "with specific fields " 5364c58b3526SAdam Stevko "given to -o option\n")); 5365c58b3526SAdam Stevko usage(B_FALSE); 5366c58b3526SAdam Stevko } 5367c58b3526SAdam Stevko cb.cb_columns[0] = GET_COL_NAME; 5368c58b3526SAdam Stevko cb.cb_columns[1] = GET_COL_PROPERTY; 5369c58b3526SAdam Stevko cb.cb_columns[2] = GET_COL_VALUE; 5370c58b3526SAdam Stevko cb.cb_columns[3] = GET_COL_SOURCE; 5371c58b3526SAdam Stevko i = ZFS_GET_NCOLS; 5372c58b3526SAdam Stevko break; 5373c58b3526SAdam Stevko default: 5374c58b3526SAdam Stevko (void) fprintf(stderr, 5375c58b3526SAdam Stevko gettext("invalid column name " 5376c58b3526SAdam Stevko "'%s'\n"), value); 5377c58b3526SAdam Stevko usage(B_FALSE); 5378c58b3526SAdam Stevko } 5379c58b3526SAdam Stevko } 5380c58b3526SAdam Stevko break; 5381c58b3526SAdam Stevko case '?': 5382c58b3526SAdam Stevko (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5383c58b3526SAdam Stevko optopt); 5384c58b3526SAdam Stevko usage(B_FALSE); 5385c58b3526SAdam Stevko } 5386c58b3526SAdam Stevko } 5387c58b3526SAdam Stevko 5388c58b3526SAdam Stevko argc -= optind; 5389c58b3526SAdam Stevko argv += optind; 5390c58b3526SAdam Stevko 5391c58b3526SAdam Stevko if (argc < 1) { 5392c58b3526SAdam Stevko (void) fprintf(stderr, gettext("missing property " 5393c58b3526SAdam Stevko "argument\n")); 5394c58b3526SAdam Stevko usage(B_FALSE); 5395c58b3526SAdam Stevko } 5396c58b3526SAdam Stevko 5397c58b3526SAdam Stevko if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, 5398990b4856Slling ZFS_TYPE_POOL) != 0) 5399b1b8ab34Slling usage(B_FALSE); 5400b1b8ab34Slling 5401c58b3526SAdam Stevko argc--; 5402c58b3526SAdam Stevko argv++; 5403c58b3526SAdam Stevko 5404b1b8ab34Slling if (cb.cb_proplist != NULL) { 5405990b4856Slling fake_name.pl_prop = ZPOOL_PROP_NAME; 5406b1b8ab34Slling fake_name.pl_width = strlen(gettext("NAME")); 5407b1b8ab34Slling fake_name.pl_next = cb.cb_proplist; 5408b1b8ab34Slling cb.cb_proplist = &fake_name; 5409b1b8ab34Slling } 5410b1b8ab34Slling 5411c58b3526SAdam Stevko ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 5412b1b8ab34Slling get_callback, &cb); 5413b1b8ab34Slling 5414b1b8ab34Slling if (cb.cb_proplist == &fake_name) 5415990b4856Slling zprop_free_list(fake_name.pl_next); 5416b1b8ab34Slling else 5417990b4856Slling zprop_free_list(cb.cb_proplist); 5418b1b8ab34Slling 5419b1b8ab34Slling return (ret); 5420b1b8ab34Slling } 5421b1b8ab34Slling 5422b1b8ab34Slling typedef struct set_cbdata { 5423b1b8ab34Slling char *cb_propname; 5424b1b8ab34Slling char *cb_value; 5425b1b8ab34Slling boolean_t cb_any_successful; 5426b1b8ab34Slling } set_cbdata_t; 5427b1b8ab34Slling 5428b1b8ab34Slling int 5429b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data) 5430b1b8ab34Slling { 5431b1b8ab34Slling int error; 5432b1b8ab34Slling set_cbdata_t *cb = (set_cbdata_t *)data; 5433b1b8ab34Slling 5434b1b8ab34Slling error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 5435b1b8ab34Slling 5436b1b8ab34Slling if (!error) 5437b1b8ab34Slling cb->cb_any_successful = B_TRUE; 5438b1b8ab34Slling 5439b1b8ab34Slling return (error); 5440b1b8ab34Slling } 5441b1b8ab34Slling 5442b1b8ab34Slling int 5443b1b8ab34Slling zpool_do_set(int argc, char **argv) 5444b1b8ab34Slling { 5445b1b8ab34Slling set_cbdata_t cb = { 0 }; 5446b1b8ab34Slling int error; 5447b1b8ab34Slling 5448b1b8ab34Slling if (argc > 1 && argv[1][0] == '-') { 5449b1b8ab34Slling (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5450b1b8ab34Slling argv[1][1]); 5451b1b8ab34Slling usage(B_FALSE); 5452b1b8ab34Slling } 5453b1b8ab34Slling 5454b1b8ab34Slling if (argc < 2) { 5455b1b8ab34Slling (void) fprintf(stderr, gettext("missing property=value " 5456b1b8ab34Slling "argument\n")); 5457b1b8ab34Slling usage(B_FALSE); 5458b1b8ab34Slling } 5459b1b8ab34Slling 5460b1b8ab34Slling if (argc < 3) { 5461b1b8ab34Slling (void) fprintf(stderr, gettext("missing pool name\n")); 5462b1b8ab34Slling usage(B_FALSE); 5463b1b8ab34Slling } 5464b1b8ab34Slling 5465b1b8ab34Slling if (argc > 3) { 5466b1b8ab34Slling (void) fprintf(stderr, gettext("too many pool names\n")); 5467b1b8ab34Slling usage(B_FALSE); 5468b1b8ab34Slling } 5469b1b8ab34Slling 5470b1b8ab34Slling cb.cb_propname = argv[1]; 5471b1b8ab34Slling cb.cb_value = strchr(cb.cb_propname, '='); 5472b1b8ab34Slling if (cb.cb_value == NULL) { 5473b1b8ab34Slling (void) fprintf(stderr, gettext("missing value in " 5474b1b8ab34Slling "property=value argument\n")); 5475b1b8ab34Slling usage(B_FALSE); 5476b1b8ab34Slling } 5477b1b8ab34Slling 5478b1b8ab34Slling *(cb.cb_value) = '\0'; 5479b1b8ab34Slling cb.cb_value++; 5480b1b8ab34Slling 5481b1b8ab34Slling error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 5482b1b8ab34Slling set_callback, &cb); 5483b1b8ab34Slling 5484b1b8ab34Slling return (error); 5485b1b8ab34Slling } 5486b1b8ab34Slling 5487b1b8ab34Slling static int 5488b1b8ab34Slling find_command_idx(char *command, int *idx) 5489b1b8ab34Slling { 5490b1b8ab34Slling int i; 5491b1b8ab34Slling 5492b1b8ab34Slling for (i = 0; i < NCOMMAND; i++) { 5493b1b8ab34Slling if (command_table[i].name == NULL) 5494b1b8ab34Slling continue; 5495b1b8ab34Slling 5496b1b8ab34Slling if (strcmp(command, command_table[i].name) == 0) { 5497b1b8ab34Slling *idx = i; 5498b1b8ab34Slling return (0); 5499b1b8ab34Slling } 5500b1b8ab34Slling } 5501b1b8ab34Slling return (1); 5502b1b8ab34Slling } 5503b1b8ab34Slling 5504fa9e4066Sahrens int 5505fa9e4066Sahrens main(int argc, char **argv) 5506fa9e4066Sahrens { 5507b327cd3fSIgor Kozhukhov int ret = 0; 5508fa9e4066Sahrens int i; 5509fa9e4066Sahrens char *cmdname; 5510fa9e4066Sahrens 5511fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 5512fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 5513fa9e4066Sahrens 551499653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) { 551599653d4eSeschrock (void) fprintf(stderr, gettext("internal error: failed to " 5516203a47d8Snd "initialize ZFS library\n")); 551799653d4eSeschrock return (1); 551899653d4eSeschrock } 551999653d4eSeschrock 552099653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE); 552199653d4eSeschrock 5522fa9e4066Sahrens opterr = 0; 5523fa9e4066Sahrens 5524fa9e4066Sahrens /* 5525fa9e4066Sahrens * Make sure the user has specified some command. 5526fa9e4066Sahrens */ 5527fa9e4066Sahrens if (argc < 2) { 5528fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 552999653d4eSeschrock usage(B_FALSE); 5530fa9e4066Sahrens } 5531fa9e4066Sahrens 5532fa9e4066Sahrens cmdname = argv[1]; 5533fa9e4066Sahrens 5534fa9e4066Sahrens /* 5535fa9e4066Sahrens * Special case '-?' 5536fa9e4066Sahrens */ 5537fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 553899653d4eSeschrock usage(B_TRUE); 5539fa9e4066Sahrens 55404445fffbSMatthew Ahrens zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); 55412a6b87f0Sek 5542fa9e4066Sahrens /* 5543fa9e4066Sahrens * Run the appropriate command. 5544fa9e4066Sahrens */ 5545b1b8ab34Slling if (find_command_idx(cmdname, &i) == 0) { 5546b1b8ab34Slling current_command = &command_table[i]; 5547b1b8ab34Slling ret = command_table[i].func(argc - 1, argv + 1); 554891ebeef5Sahrens } else if (strchr(cmdname, '=')) { 554991ebeef5Sahrens verify(find_command_idx("set", &i) == 0); 555091ebeef5Sahrens current_command = &command_table[i]; 555191ebeef5Sahrens ret = command_table[i].func(argc, argv); 555291ebeef5Sahrens } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 555391ebeef5Sahrens /* 555491ebeef5Sahrens * 'freeze' is a vile debugging abomination, so we treat 555591ebeef5Sahrens * it as such. 555691ebeef5Sahrens */ 5557ea8dc4b6Seschrock char buf[16384]; 5558ea8dc4b6Seschrock int fd = open(ZFS_DEV, O_RDWR); 5559fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 5560fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 556191ebeef5Sahrens } else { 5562fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 5563fa9e4066Sahrens "command '%s'\n"), cmdname); 556499653d4eSeschrock usage(B_FALSE); 5565fa9e4066Sahrens } 5566fa9e4066Sahrens 55674445fffbSMatthew Ahrens if (ret == 0 && log_history) 55684445fffbSMatthew Ahrens (void) zpool_log_history(g_zfs, history_str); 55694445fffbSMatthew Ahrens 557099653d4eSeschrock libzfs_fini(g_zfs); 557199653d4eSeschrock 5572fa9e4066Sahrens /* 5573fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 5574fa9e4066Sahrens * for the purposes of running ::findleaks. 5575fa9e4066Sahrens */ 5576fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 5577fa9e4066Sahrens (void) printf("dumping core by request\n"); 5578fa9e4066Sahrens abort(); 5579fa9e4066Sahrens } 5580fa9e4066Sahrens 5581fa9e4066Sahrens return (ret); 5582fa9e4066Sahrens } 5583