zpool_main.c revision 253441
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24227497Smm * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 25236155Smm * Copyright (c) 2012 by Delphix. All rights reserved. 26236145Smm * Copyright (c) 2012 by Frederik Wessels. All rights reserved. 27236155Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 28168404Spjd */ 29168404Spjd 30168404Spjd#include <solaris.h> 31168404Spjd#include <assert.h> 32168404Spjd#include <ctype.h> 33168404Spjd#include <dirent.h> 34168404Spjd#include <errno.h> 35168404Spjd#include <fcntl.h> 36168404Spjd#include <libgen.h> 37168404Spjd#include <libintl.h> 38168404Spjd#include <libuutil.h> 39168404Spjd#include <locale.h> 40168404Spjd#include <stdio.h> 41168404Spjd#include <stdlib.h> 42168404Spjd#include <string.h> 43168404Spjd#include <strings.h> 44168404Spjd#include <unistd.h> 45168404Spjd#include <priv.h> 46185029Spjd#include <pwd.h> 47185029Spjd#include <zone.h> 48168404Spjd#include <sys/time.h> 49236155Smm#include <zfs_prop.h> 50168404Spjd#include <sys/fs/zfs.h> 51168404Spjd#include <sys/stat.h> 52168404Spjd 53168404Spjd#include <libzfs.h> 54168404Spjd 55168404Spjd#include "zpool_util.h" 56185029Spjd#include "zfs_comutil.h" 57236884Smm#include "zfeature_common.h" 58168404Spjd 59219089Spjd#include "statcommon.h" 60219089Spjd 61168404Spjdstatic int zpool_do_create(int, char **); 62168404Spjdstatic int zpool_do_destroy(int, char **); 63168404Spjd 64168404Spjdstatic int zpool_do_add(int, char **); 65168404Spjdstatic int zpool_do_remove(int, char **); 66224171Sgibbsstatic int zpool_do_labelclear(int, char **); 67168404Spjd 68168404Spjdstatic int zpool_do_list(int, char **); 69168404Spjdstatic int zpool_do_iostat(int, char **); 70168404Spjdstatic int zpool_do_status(int, char **); 71168404Spjd 72168404Spjdstatic int zpool_do_online(int, char **); 73168404Spjdstatic int zpool_do_offline(int, char **); 74168404Spjdstatic int zpool_do_clear(int, char **); 75236155Smmstatic int zpool_do_reopen(int, char **); 76168404Spjd 77228103Smmstatic int zpool_do_reguid(int, char **); 78228103Smm 79168404Spjdstatic int zpool_do_attach(int, char **); 80168404Spjdstatic int zpool_do_detach(int, char **); 81168404Spjdstatic int zpool_do_replace(int, char **); 82219089Spjdstatic int zpool_do_split(int, char **); 83168404Spjd 84168404Spjdstatic int zpool_do_scrub(int, char **); 85168404Spjd 86168404Spjdstatic int zpool_do_import(int, char **); 87168404Spjdstatic int zpool_do_export(int, char **); 88168404Spjd 89168404Spjdstatic int zpool_do_upgrade(int, char **); 90168404Spjd 91168404Spjdstatic int zpool_do_history(int, char **); 92168404Spjd 93168404Spjdstatic int zpool_do_get(int, char **); 94168404Spjdstatic int zpool_do_set(int, char **); 95168404Spjd 96168404Spjd/* 97168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 98168404Spjd * debugging facilities. 99168404Spjd */ 100185029Spjd 101185029Spjd#ifdef DEBUG 102168404Spjdconst char * 103168404Spjd_umem_debug_init(void) 104168404Spjd{ 105168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 106168404Spjd} 107168404Spjd 108168404Spjdconst char * 109168404Spjd_umem_logging_init(void) 110168404Spjd{ 111168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 112168404Spjd} 113185029Spjd#endif 114168404Spjd 115168404Spjdtypedef enum { 116168404Spjd HELP_ADD, 117168404Spjd HELP_ATTACH, 118168404Spjd HELP_CLEAR, 119168404Spjd HELP_CREATE, 120168404Spjd HELP_DESTROY, 121168404Spjd HELP_DETACH, 122168404Spjd HELP_EXPORT, 123168404Spjd HELP_HISTORY, 124168404Spjd HELP_IMPORT, 125168404Spjd HELP_IOSTAT, 126224171Sgibbs HELP_LABELCLEAR, 127168404Spjd HELP_LIST, 128168404Spjd HELP_OFFLINE, 129168404Spjd HELP_ONLINE, 130168404Spjd HELP_REPLACE, 131168404Spjd HELP_REMOVE, 132168404Spjd HELP_SCRUB, 133168404Spjd HELP_STATUS, 134168404Spjd HELP_UPGRADE, 135168404Spjd HELP_GET, 136219089Spjd HELP_SET, 137228103Smm HELP_SPLIT, 138236155Smm HELP_REGUID, 139236155Smm HELP_REOPEN 140168404Spjd} zpool_help_t; 141168404Spjd 142168404Spjd 143168404Spjdtypedef struct zpool_command { 144168404Spjd const char *name; 145168404Spjd int (*func)(int, char **); 146168404Spjd zpool_help_t usage; 147168404Spjd} zpool_command_t; 148168404Spjd 149168404Spjd/* 150168404Spjd * Master command table. Each ZFS command has a name, associated function, and 151168404Spjd * usage message. The usage messages need to be internationalized, so we have 152168404Spjd * to have a function to return the usage message based on a command index. 153168404Spjd * 154168404Spjd * These commands are organized according to how they are displayed in the usage 155168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 156168404Spjd * the generic usage message. 157168404Spjd */ 158168404Spjdstatic zpool_command_t command_table[] = { 159168404Spjd { "create", zpool_do_create, HELP_CREATE }, 160168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 161168404Spjd { NULL }, 162168404Spjd { "add", zpool_do_add, HELP_ADD }, 163168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 164168404Spjd { NULL }, 165224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 166224171Sgibbs { NULL }, 167168404Spjd { "list", zpool_do_list, HELP_LIST }, 168168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 169168404Spjd { "status", zpool_do_status, HELP_STATUS }, 170168404Spjd { NULL }, 171168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 172168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 173168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 174236155Smm { "reopen", zpool_do_reopen, HELP_REOPEN }, 175168404Spjd { NULL }, 176168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 177168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 178168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 179219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 180168404Spjd { NULL }, 181168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 182168404Spjd { NULL }, 183168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 184168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 185168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 186228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 187168404Spjd { NULL }, 188168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 189168404Spjd { "get", zpool_do_get, HELP_GET }, 190168404Spjd { "set", zpool_do_set, HELP_SET }, 191168404Spjd}; 192168404Spjd 193168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 194168404Spjd 195248571Smmstatic zpool_command_t *current_command; 196185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 197248571Smmstatic boolean_t log_history = B_TRUE; 198219089Spjdstatic uint_t timestamp_fmt = NODATE; 199219089Spjd 200168404Spjdstatic const char * 201168404Spjdget_usage(zpool_help_t idx) { 202168404Spjd switch (idx) { 203168404Spjd case HELP_ADD: 204168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 205168404Spjd case HELP_ATTACH: 206168404Spjd return (gettext("\tattach [-f] <pool> <device> " 207185029Spjd "<new-device>\n")); 208168404Spjd case HELP_CLEAR: 209219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 210168404Spjd case HELP_CREATE: 211236884Smm return (gettext("\tcreate [-fnd] [-o property=value] ... \n" 212185029Spjd "\t [-O file-system-property=value] ... \n" 213185029Spjd "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 214168404Spjd case HELP_DESTROY: 215168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 216168404Spjd case HELP_DETACH: 217168404Spjd return (gettext("\tdetach <pool> <device>\n")); 218168404Spjd case HELP_EXPORT: 219168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 220168404Spjd case HELP_HISTORY: 221185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 222168404Spjd case HELP_IMPORT: 223168404Spjd return (gettext("\timport [-d dir] [-D]\n" 224219089Spjd "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 225185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 226219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 227219089Spjd "[-R root] [-F [-n]] -a\n" 228185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 229219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 230219089Spjd "[-R root] [-F [-n]]\n" 231219089Spjd "\t <pool | id> [newpool]\n")); 232168404Spjd case HELP_IOSTAT: 233219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 234168404Spjd "[count]]\n")); 235224171Sgibbs case HELP_LABELCLEAR: 236224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 237168404Spjd case HELP_LIST: 238236960Smm return (gettext("\tlist [-Hv] [-o property[,...]] " 239219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 240168404Spjd case HELP_OFFLINE: 241168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 242168404Spjd case HELP_ONLINE: 243228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 244168404Spjd case HELP_REPLACE: 245168404Spjd return (gettext("\treplace [-f] <pool> <device> " 246185029Spjd "[new-device]\n")); 247168404Spjd case HELP_REMOVE: 248185029Spjd return (gettext("\tremove <pool> <device> ...\n")); 249236155Smm case HELP_REOPEN: 250236155Smm return (""); /* Undocumented command */ 251168404Spjd case HELP_SCRUB: 252168404Spjd return (gettext("\tscrub [-s] <pool> ...\n")); 253168404Spjd case HELP_STATUS: 254219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 255219089Spjd "[count]]\n")); 256168404Spjd case HELP_UPGRADE: 257228020Smm return (gettext("\tupgrade [-v]\n" 258185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 259168404Spjd case HELP_GET: 260185029Spjd return (gettext("\tget <\"all\" | property[,...]> " 261168404Spjd "<pool> ...\n")); 262168404Spjd case HELP_SET: 263168404Spjd return (gettext("\tset <property=value> <pool> \n")); 264219089Spjd case HELP_SPLIT: 265219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 266219089Spjd "\t [-o property=value] <pool> <newpool> " 267219089Spjd "[<device> ...]\n")); 268228103Smm case HELP_REGUID: 269228103Smm return (gettext("\treguid <pool>\n")); 270168404Spjd } 271168404Spjd 272168404Spjd abort(); 273168404Spjd /* NOTREACHED */ 274168404Spjd} 275168404Spjd 276168404Spjd 277168404Spjd/* 278168404Spjd * Callback routine that will print out a pool property value. 279168404Spjd */ 280185029Spjdstatic int 281185029Spjdprint_prop_cb(int prop, void *cb) 282168404Spjd{ 283168404Spjd FILE *fp = cb; 284168404Spjd 285219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 286168404Spjd 287185029Spjd if (zpool_prop_readonly(prop)) 288185029Spjd (void) fprintf(fp, " NO "); 289185029Spjd else 290219089Spjd (void) fprintf(fp, " YES "); 291185029Spjd 292168404Spjd if (zpool_prop_values(prop) == NULL) 293168404Spjd (void) fprintf(fp, "-\n"); 294168404Spjd else 295168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 296168404Spjd 297185029Spjd return (ZPROP_CONT); 298168404Spjd} 299168404Spjd 300168404Spjd/* 301168404Spjd * Display usage message. If we're inside a command, display only the usage for 302168404Spjd * that command. Otherwise, iterate over the entire command table and display 303168404Spjd * a complete usage message. 304168404Spjd */ 305168404Spjdvoid 306168404Spjdusage(boolean_t requested) 307168404Spjd{ 308168404Spjd FILE *fp = requested ? stdout : stderr; 309168404Spjd 310168404Spjd if (current_command == NULL) { 311168404Spjd int i; 312168404Spjd 313168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 314168404Spjd (void) fprintf(fp, 315168404Spjd gettext("where 'command' is one of the following:\n\n")); 316168404Spjd 317168404Spjd for (i = 0; i < NCOMMAND; i++) { 318168404Spjd if (command_table[i].name == NULL) 319168404Spjd (void) fprintf(fp, "\n"); 320168404Spjd else 321168404Spjd (void) fprintf(fp, "%s", 322168404Spjd get_usage(command_table[i].usage)); 323168404Spjd } 324168404Spjd } else { 325168404Spjd (void) fprintf(fp, gettext("usage:\n")); 326168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 327168404Spjd } 328168404Spjd 329168404Spjd if (current_command != NULL && 330168404Spjd ((strcmp(current_command->name, "set") == 0) || 331185029Spjd (strcmp(current_command->name, "get") == 0) || 332185029Spjd (strcmp(current_command->name, "list") == 0))) { 333168404Spjd 334168404Spjd (void) fprintf(fp, 335168404Spjd gettext("\nthe following properties are supported:\n")); 336168404Spjd 337219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 338185029Spjd "PROPERTY", "EDIT", "VALUES"); 339168404Spjd 340168404Spjd /* Iterate over all properties */ 341185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 342185029Spjd ZFS_TYPE_POOL); 343236884Smm 344236884Smm (void) fprintf(fp, "\t%-15s ", "feature@..."); 345236884Smm (void) fprintf(fp, "YES disabled | enabled | active\n"); 346236884Smm 347236884Smm (void) fprintf(fp, gettext("\nThe feature@ properties must be " 348243014Smm "appended with a feature name.\nSee zpool-features(7).\n")); 349168404Spjd } 350168404Spjd 351168404Spjd /* 352168404Spjd * See comments at end of main(). 353168404Spjd */ 354168404Spjd if (getenv("ZFS_ABORT") != NULL) { 355168404Spjd (void) printf("dumping core by request\n"); 356168404Spjd abort(); 357168404Spjd } 358168404Spjd 359168404Spjd exit(requested ? 0 : 2); 360168404Spjd} 361168404Spjd 362168404Spjdvoid 363185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 364185029Spjd boolean_t print_logs) 365168404Spjd{ 366168404Spjd nvlist_t **child; 367168404Spjd uint_t c, children; 368168404Spjd char *vname; 369168404Spjd 370168404Spjd if (name != NULL) 371168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 372168404Spjd 373168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 374168404Spjd &child, &children) != 0) 375168404Spjd return; 376168404Spjd 377168404Spjd for (c = 0; c < children; c++) { 378185029Spjd uint64_t is_log = B_FALSE; 379185029Spjd 380185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 381185029Spjd &is_log); 382185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 383185029Spjd continue; 384185029Spjd 385219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 386185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 387185029Spjd B_FALSE); 388168404Spjd free(vname); 389168404Spjd } 390168404Spjd} 391168404Spjd 392238926Smmstatic boolean_t 393238926Smmprop_list_contains_feature(nvlist_t *proplist) 394238926Smm{ 395238926Smm nvpair_t *nvp; 396238926Smm for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; 397238926Smm nvp = nvlist_next_nvpair(proplist, nvp)) { 398238926Smm if (zpool_prop_feature(nvpair_name(nvp))) 399238926Smm return (B_TRUE); 400238926Smm } 401238926Smm return (B_FALSE); 402238926Smm} 403238926Smm 404168404Spjd/* 405185029Spjd * Add a property pair (name, string-value) into a property nvlist. 406185029Spjd */ 407185029Spjdstatic int 408185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 409185029Spjd boolean_t poolprop) 410185029Spjd{ 411185029Spjd zpool_prop_t prop = ZPROP_INVAL; 412185029Spjd zfs_prop_t fprop; 413185029Spjd nvlist_t *proplist; 414185029Spjd const char *normnm; 415185029Spjd char *strval; 416185029Spjd 417185029Spjd if (*props == NULL && 418185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 419185029Spjd (void) fprintf(stderr, 420185029Spjd gettext("internal error: out of memory\n")); 421185029Spjd return (1); 422185029Spjd } 423185029Spjd 424185029Spjd proplist = *props; 425185029Spjd 426185029Spjd if (poolprop) { 427238926Smm const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); 428238926Smm 429236884Smm if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 430236884Smm !zpool_prop_feature(propname)) { 431185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 432185029Spjd "not a valid pool property\n"), propname); 433185029Spjd return (2); 434185029Spjd } 435238926Smm 436238926Smm /* 437238926Smm * feature@ properties and version should not be specified 438238926Smm * at the same time. 439238926Smm */ 440238926Smm if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && 441238926Smm nvlist_exists(proplist, vname)) || 442238926Smm (prop == ZPOOL_PROP_VERSION && 443238926Smm prop_list_contains_feature(proplist))) { 444238926Smm (void) fprintf(stderr, gettext("'feature@' and " 445238926Smm "'version' properties cannot be specified " 446238926Smm "together\n")); 447238926Smm return (2); 448238926Smm } 449238926Smm 450238926Smm 451236884Smm if (zpool_prop_feature(propname)) 452236884Smm normnm = propname; 453236884Smm else 454236884Smm normnm = zpool_prop_to_name(prop); 455185029Spjd } else { 456209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 457209962Smm normnm = zfs_prop_to_name(fprop); 458209962Smm } else { 459209962Smm normnm = propname; 460185029Spjd } 461185029Spjd } 462185029Spjd 463185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 464185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 465185029Spjd (void) fprintf(stderr, gettext("property '%s' " 466185029Spjd "specified multiple times\n"), propname); 467185029Spjd return (2); 468185029Spjd } 469185029Spjd 470185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 471185029Spjd (void) fprintf(stderr, gettext("internal " 472185029Spjd "error: out of memory\n")); 473185029Spjd return (1); 474185029Spjd } 475185029Spjd 476185029Spjd return (0); 477185029Spjd} 478185029Spjd 479185029Spjd/* 480168404Spjd * zpool add [-fn] <pool> <vdev> ... 481168404Spjd * 482168404Spjd * -f Force addition of devices, even if they appear in use 483168404Spjd * -n Do not add the devices, but display the resulting layout if 484168404Spjd * they were to be added. 485168404Spjd * 486168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 487168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 488168404Spjd * libzfs. 489168404Spjd */ 490168404Spjdint 491168404Spjdzpool_do_add(int argc, char **argv) 492168404Spjd{ 493168404Spjd boolean_t force = B_FALSE; 494168404Spjd boolean_t dryrun = B_FALSE; 495168404Spjd int c; 496168404Spjd nvlist_t *nvroot; 497168404Spjd char *poolname; 498168404Spjd int ret; 499168404Spjd zpool_handle_t *zhp; 500168404Spjd nvlist_t *config; 501168404Spjd 502168404Spjd /* check options */ 503168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 504168404Spjd switch (c) { 505168404Spjd case 'f': 506168404Spjd force = B_TRUE; 507168404Spjd break; 508168404Spjd case 'n': 509168404Spjd dryrun = B_TRUE; 510168404Spjd break; 511168404Spjd case '?': 512168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 513168404Spjd optopt); 514168404Spjd usage(B_FALSE); 515168404Spjd } 516168404Spjd } 517168404Spjd 518168404Spjd argc -= optind; 519168404Spjd argv += optind; 520168404Spjd 521168404Spjd /* get pool name and check number of arguments */ 522168404Spjd if (argc < 1) { 523168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 524168404Spjd usage(B_FALSE); 525168404Spjd } 526168404Spjd if (argc < 2) { 527168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 528168404Spjd usage(B_FALSE); 529168404Spjd } 530168404Spjd 531168404Spjd poolname = argv[0]; 532168404Spjd 533168404Spjd argc--; 534168404Spjd argv++; 535168404Spjd 536168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 537168404Spjd return (1); 538168404Spjd 539168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 540168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 541168404Spjd poolname); 542168404Spjd zpool_close(zhp); 543168404Spjd return (1); 544168404Spjd } 545168404Spjd 546168404Spjd /* pass off to get_vdev_spec for processing */ 547185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 548185029Spjd argc, argv); 549168404Spjd if (nvroot == NULL) { 550168404Spjd zpool_close(zhp); 551168404Spjd return (1); 552168404Spjd } 553168404Spjd 554168404Spjd if (dryrun) { 555168404Spjd nvlist_t *poolnvroot; 556168404Spjd 557168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 558168404Spjd &poolnvroot) == 0); 559168404Spjd 560168404Spjd (void) printf(gettext("would update '%s' to the following " 561168404Spjd "configuration:\n"), zpool_get_name(zhp)); 562168404Spjd 563185029Spjd /* print original main pool and new tree */ 564185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 565185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 566168404Spjd 567185029Spjd /* Do the same for the logs */ 568185029Spjd if (num_logs(poolnvroot) > 0) { 569185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 570185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 571185029Spjd } else if (num_logs(nvroot) > 0) { 572185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 573185029Spjd } 574185029Spjd 575168404Spjd ret = 0; 576168404Spjd } else { 577168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 578168404Spjd } 579168404Spjd 580168404Spjd nvlist_free(nvroot); 581168404Spjd zpool_close(zhp); 582168404Spjd 583168404Spjd return (ret); 584168404Spjd} 585168404Spjd 586168404Spjd/* 587219089Spjd * zpool remove <pool> <vdev> ... 588168404Spjd * 589219089Spjd * Removes the given vdev from the pool. Currently, this supports removing 590219089Spjd * spares, cache, and log devices from the pool. 591168404Spjd */ 592168404Spjdint 593168404Spjdzpool_do_remove(int argc, char **argv) 594168404Spjd{ 595168404Spjd char *poolname; 596185029Spjd int i, ret = 0; 597168404Spjd zpool_handle_t *zhp; 598168404Spjd 599168404Spjd argc--; 600168404Spjd argv++; 601168404Spjd 602168404Spjd /* get pool name and check number of arguments */ 603168404Spjd if (argc < 1) { 604168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 605168404Spjd usage(B_FALSE); 606168404Spjd } 607168404Spjd if (argc < 2) { 608168404Spjd (void) fprintf(stderr, gettext("missing device\n")); 609168404Spjd usage(B_FALSE); 610168404Spjd } 611168404Spjd 612168404Spjd poolname = argv[0]; 613168404Spjd 614168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 615168404Spjd return (1); 616168404Spjd 617185029Spjd for (i = 1; i < argc; i++) { 618185029Spjd if (zpool_vdev_remove(zhp, argv[i]) != 0) 619185029Spjd ret = 1; 620168404Spjd } 621168404Spjd 622168404Spjd return (ret); 623168404Spjd} 624168404Spjd 625168404Spjd/* 626224171Sgibbs * zpool labelclear <vdev> 627224171Sgibbs * 628224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 629224171Sgibbs * on the device. 630224171Sgibbs */ 631224171Sgibbsint 632224171Sgibbszpool_do_labelclear(int argc, char **argv) 633224171Sgibbs{ 634224171Sgibbs char *vdev, *name; 635224171Sgibbs int c, fd = -1, ret = 0; 636224171Sgibbs pool_state_t state; 637224171Sgibbs boolean_t inuse = B_FALSE; 638224171Sgibbs boolean_t force = B_FALSE; 639224171Sgibbs 640224171Sgibbs /* check options */ 641224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 642224171Sgibbs switch (c) { 643224171Sgibbs case 'f': 644224171Sgibbs force = B_TRUE; 645224171Sgibbs break; 646224171Sgibbs default: 647224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 648224171Sgibbs optopt); 649224171Sgibbs usage(B_FALSE); 650224171Sgibbs } 651224171Sgibbs } 652224171Sgibbs 653224171Sgibbs argc -= optind; 654224171Sgibbs argv += optind; 655224171Sgibbs 656224171Sgibbs /* get vdev name */ 657224171Sgibbs if (argc < 1) { 658224171Sgibbs (void) fprintf(stderr, gettext("missing vdev device name\n")); 659224171Sgibbs usage(B_FALSE); 660224171Sgibbs } 661224171Sgibbs 662224171Sgibbs vdev = argv[0]; 663224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 664224171Sgibbs (void) fprintf(stderr, gettext("Unable to open %s\n"), vdev); 665224171Sgibbs return (B_FALSE); 666224171Sgibbs } 667224171Sgibbs 668224171Sgibbs name = NULL; 669224171Sgibbs if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) { 670224171Sgibbs if (force) 671224171Sgibbs goto wipe_label; 672224171Sgibbs 673224171Sgibbs (void) fprintf(stderr, 674224171Sgibbs gettext("Unable to determine pool state for %s\n" 675224171Sgibbs "Use -f to force the clearing any label data\n"), vdev); 676224171Sgibbs 677224171Sgibbs return (1); 678224171Sgibbs } 679224171Sgibbs 680224171Sgibbs if (inuse) { 681224171Sgibbs switch (state) { 682224171Sgibbs default: 683224171Sgibbs case POOL_STATE_ACTIVE: 684224171Sgibbs case POOL_STATE_SPARE: 685224171Sgibbs case POOL_STATE_L2CACHE: 686224171Sgibbs (void) fprintf(stderr, 687224171Sgibbsgettext("labelclear operation failed.\n" 688224171Sgibbs "\tVdev %s is a member (%s), of pool \"%s\".\n" 689224171Sgibbs "\tTo remove label information from this device, export or destroy\n" 690224171Sgibbs "\tthe pool, or remove %s from the configuration of this pool\n" 691224171Sgibbs "\tand retry the labelclear operation\n"), 692224171Sgibbs vdev, zpool_pool_state_to_name(state), name, vdev); 693224171Sgibbs ret = 1; 694224171Sgibbs goto errout; 695224171Sgibbs 696224171Sgibbs case POOL_STATE_EXPORTED: 697224171Sgibbs if (force) 698224171Sgibbs break; 699224171Sgibbs 700224171Sgibbs (void) fprintf(stderr, 701224171Sgibbsgettext("labelclear operation failed.\n" 702224171Sgibbs "\tVdev %s is a member of the exported pool \"%s\".\n" 703224171Sgibbs "\tUse \"zpool labelclear -f %s\" to force the removal of label\n" 704224171Sgibbs "\tinformation.\n"), 705224171Sgibbs vdev, name, vdev); 706224171Sgibbs ret = 1; 707224171Sgibbs goto errout; 708224171Sgibbs 709224171Sgibbs case POOL_STATE_POTENTIALLY_ACTIVE: 710224171Sgibbs if (force) 711224171Sgibbs break; 712224171Sgibbs 713224171Sgibbs (void) fprintf(stderr, 714224171Sgibbsgettext("labelclear operation failed.\n" 715224171Sgibbs "\tVdev %s is a member of the pool \"%s\".\n" 716224171Sgibbs "\tThis pool is unknown to this system, but may be active on\n" 717224171Sgibbs "\tanother system. Use \'zpool labelclear -f %s\' to force the\n" 718224171Sgibbs "\tremoval of label information.\n"), 719224171Sgibbs vdev, name, vdev); 720224171Sgibbs ret = 1; 721224171Sgibbs goto errout; 722224171Sgibbs 723224171Sgibbs case POOL_STATE_DESTROYED: 724224171Sgibbs /* inuse should never be set for a destoryed pool... */ 725224171Sgibbs break; 726224171Sgibbs } 727224171Sgibbs } 728224171Sgibbs 729224171Sgibbswipe_label: 730224171Sgibbs if (zpool_clear_label(fd) != 0) { 731224171Sgibbs (void) fprintf(stderr, 732224171Sgibbs gettext("Label clear failed on vdev %s\n"), vdev); 733224171Sgibbs ret = 1; 734224171Sgibbs } 735224171Sgibbs 736224171Sgibbserrout: 737224171Sgibbs close(fd); 738224171Sgibbs if (name != NULL) 739224171Sgibbs free(name); 740224171Sgibbs 741224171Sgibbs return (ret); 742224171Sgibbs} 743224171Sgibbs 744224171Sgibbs/* 745236884Smm * zpool create [-fnd] [-o property=value] ... 746185029Spjd * [-O file-system-property=value] ... 747185029Spjd * [-R root] [-m mountpoint] <pool> <dev> ... 748168404Spjd * 749168404Spjd * -f Force creation, even if devices appear in use 750168404Spjd * -n Do not create the pool, but display the resulting layout if it 751168404Spjd * were to be created. 752168404Spjd * -R Create a pool under an alternate root 753168404Spjd * -m Set default mountpoint for the root dataset. By default it's 754236884Smm * '/<pool>' 755185029Spjd * -o Set property=value. 756236884Smm * -d Don't automatically enable all supported pool features 757236884Smm * (individual features can be enabled with -o). 758185029Spjd * -O Set fsproperty=value in the pool's root file system 759168404Spjd * 760168404Spjd * Creates the named pool according to the given vdev specification. The 761168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 762168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 763168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 764168404Spjd */ 765168404Spjdint 766168404Spjdzpool_do_create(int argc, char **argv) 767168404Spjd{ 768168404Spjd boolean_t force = B_FALSE; 769168404Spjd boolean_t dryrun = B_FALSE; 770236884Smm boolean_t enable_all_pool_feat = B_TRUE; 771168404Spjd int c; 772185029Spjd nvlist_t *nvroot = NULL; 773168404Spjd char *poolname; 774185029Spjd int ret = 1; 775168404Spjd char *altroot = NULL; 776168404Spjd char *mountpoint = NULL; 777185029Spjd nvlist_t *fsprops = NULL; 778185029Spjd nvlist_t *props = NULL; 779185029Spjd char *propval; 780168404Spjd 781168404Spjd /* check options */ 782236884Smm while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) { 783168404Spjd switch (c) { 784168404Spjd case 'f': 785168404Spjd force = B_TRUE; 786168404Spjd break; 787168404Spjd case 'n': 788168404Spjd dryrun = B_TRUE; 789168404Spjd break; 790236884Smm case 'd': 791236884Smm enable_all_pool_feat = B_FALSE; 792236884Smm break; 793168404Spjd case 'R': 794168404Spjd altroot = optarg; 795185029Spjd if (add_prop_list(zpool_prop_to_name( 796185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 797185029Spjd goto errout; 798185029Spjd if (nvlist_lookup_string(props, 799185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 800185029Spjd &propval) == 0) 801185029Spjd break; 802185029Spjd if (add_prop_list(zpool_prop_to_name( 803185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 804185029Spjd goto errout; 805168404Spjd break; 806168404Spjd case 'm': 807251634Sdelphij /* Equivalent to -O mountpoint=optarg */ 808168404Spjd mountpoint = optarg; 809168404Spjd break; 810185029Spjd case 'o': 811185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 812185029Spjd (void) fprintf(stderr, gettext("missing " 813185029Spjd "'=' for -o option\n")); 814185029Spjd goto errout; 815185029Spjd } 816185029Spjd *propval = '\0'; 817185029Spjd propval++; 818185029Spjd 819185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 820185029Spjd goto errout; 821236884Smm 822236884Smm /* 823236884Smm * If the user is creating a pool that doesn't support 824236884Smm * feature flags, don't enable any features. 825236884Smm */ 826236884Smm if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 827236884Smm char *end; 828236884Smm u_longlong_t ver; 829236884Smm 830236884Smm ver = strtoull(propval, &end, 10); 831236884Smm if (*end == '\0' && 832236884Smm ver < SPA_VERSION_FEATURES) { 833236884Smm enable_all_pool_feat = B_FALSE; 834236884Smm } 835236884Smm } 836185029Spjd break; 837185029Spjd case 'O': 838185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 839185029Spjd (void) fprintf(stderr, gettext("missing " 840185029Spjd "'=' for -O option\n")); 841185029Spjd goto errout; 842185029Spjd } 843185029Spjd *propval = '\0'; 844185029Spjd propval++; 845185029Spjd 846251634Sdelphij /* 847251634Sdelphij * Mountpoints are checked and then added later. 848251634Sdelphij * Uniquely among properties, they can be specified 849251634Sdelphij * more than once, to avoid conflict with -m. 850251634Sdelphij */ 851251634Sdelphij if (0 == strcmp(optarg, 852251634Sdelphij zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) { 853251634Sdelphij mountpoint = propval; 854251634Sdelphij } else if (add_prop_list(optarg, propval, &fsprops, 855251634Sdelphij B_FALSE)) { 856185029Spjd goto errout; 857251634Sdelphij } 858185029Spjd break; 859168404Spjd case ':': 860168404Spjd (void) fprintf(stderr, gettext("missing argument for " 861168404Spjd "'%c' option\n"), optopt); 862185029Spjd goto badusage; 863168404Spjd case '?': 864168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 865168404Spjd optopt); 866185029Spjd goto badusage; 867168404Spjd } 868168404Spjd } 869168404Spjd 870168404Spjd argc -= optind; 871168404Spjd argv += optind; 872168404Spjd 873168404Spjd /* get pool name and check number of arguments */ 874168404Spjd if (argc < 1) { 875168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 876185029Spjd goto badusage; 877168404Spjd } 878168404Spjd if (argc < 2) { 879168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 880185029Spjd goto badusage; 881168404Spjd } 882168404Spjd 883168404Spjd poolname = argv[0]; 884168404Spjd 885168404Spjd /* 886168404Spjd * As a special case, check for use of '/' in the name, and direct the 887168404Spjd * user to use 'zfs create' instead. 888168404Spjd */ 889168404Spjd if (strchr(poolname, '/') != NULL) { 890168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 891168404Spjd "character '/' in pool name\n"), poolname); 892168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 893168404Spjd "create a dataset\n")); 894185029Spjd goto errout; 895168404Spjd } 896168404Spjd 897168404Spjd /* pass off to get_vdev_spec for bulk processing */ 898185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 899185029Spjd argc - 1, argv + 1); 900168404Spjd if (nvroot == NULL) 901185029Spjd goto errout; 902168404Spjd 903168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 904185029Spjd if (!zfs_allocatable_devs(nvroot)) { 905168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 906168404Spjd "specification: at least one toplevel vdev must be " 907168404Spjd "specified\n")); 908185029Spjd goto errout; 909168404Spjd } 910168404Spjd 911168404Spjd if (altroot != NULL && altroot[0] != '/') { 912168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 913168404Spjd "must be an absolute path\n"), altroot); 914185029Spjd goto errout; 915168404Spjd } 916168404Spjd 917168404Spjd /* 918168404Spjd * Check the validity of the mountpoint and direct the user to use the 919168404Spjd * '-m' mountpoint option if it looks like its in use. 920244857Spjd * Ignore the checks if the '-f' option is given. 921168404Spjd */ 922244857Spjd if (!force && (mountpoint == NULL || 923168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 924244857Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) { 925168404Spjd char buf[MAXPATHLEN]; 926185029Spjd DIR *dirp; 927168404Spjd 928168404Spjd if (mountpoint && mountpoint[0] != '/') { 929168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 930168404Spjd "'%s': must be an absolute path, 'legacy', or " 931168404Spjd "'none'\n"), mountpoint); 932185029Spjd goto errout; 933168404Spjd } 934168404Spjd 935168404Spjd if (mountpoint == NULL) { 936168404Spjd if (altroot != NULL) 937168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 938168404Spjd altroot, poolname); 939168404Spjd else 940168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 941168404Spjd poolname); 942168404Spjd } else { 943168404Spjd if (altroot != NULL) 944168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 945168404Spjd altroot, mountpoint); 946168404Spjd else 947168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 948168404Spjd mountpoint); 949168404Spjd } 950168404Spjd 951185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 952185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 953185029Spjd "%s\n"), buf, strerror(errno)); 954185029Spjd (void) fprintf(stderr, gettext("use '-m' " 955185029Spjd "option to provide a different default\n")); 956185029Spjd goto errout; 957185029Spjd } else if (dirp) { 958185029Spjd int count = 0; 959185029Spjd 960185029Spjd while (count < 3 && readdir(dirp) != NULL) 961185029Spjd count++; 962185029Spjd (void) closedir(dirp); 963185029Spjd 964185029Spjd if (count > 2) { 965168404Spjd (void) fprintf(stderr, gettext("mountpoint " 966168404Spjd "'%s' exists and is not empty\n"), buf); 967185029Spjd (void) fprintf(stderr, gettext("use '-m' " 968185029Spjd "option to provide a " 969185029Spjd "different default\n")); 970185029Spjd goto errout; 971185029Spjd } 972168404Spjd } 973168404Spjd } 974168404Spjd 975251634Sdelphij /* 976251634Sdelphij * Now that the mountpoint's validity has been checked, ensure that 977251634Sdelphij * the property is set appropriately prior to creating the pool. 978251634Sdelphij */ 979251634Sdelphij if (mountpoint != NULL) { 980251634Sdelphij ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 981251634Sdelphij mountpoint, &fsprops, B_FALSE); 982251634Sdelphij if (ret != 0) 983251634Sdelphij goto errout; 984251634Sdelphij } 985251634Sdelphij 986251634Sdelphij ret = 1; 987168404Spjd if (dryrun) { 988168404Spjd /* 989168404Spjd * For a dry run invocation, print out a basic message and run 990168404Spjd * through all the vdevs in the list and print out in an 991168404Spjd * appropriate hierarchy. 992168404Spjd */ 993168404Spjd (void) printf(gettext("would create '%s' with the " 994168404Spjd "following layout:\n\n"), poolname); 995168404Spjd 996185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 997185029Spjd if (num_logs(nvroot) > 0) 998185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 999168404Spjd 1000168404Spjd ret = 0; 1001168404Spjd } else { 1002168404Spjd /* 1003168404Spjd * Hand off to libzfs. 1004168404Spjd */ 1005236884Smm if (enable_all_pool_feat) { 1006236884Smm int i; 1007236884Smm for (i = 0; i < SPA_FEATURES; i++) { 1008236884Smm char propname[MAXPATHLEN]; 1009236884Smm zfeature_info_t *feat = &spa_feature_table[i]; 1010236884Smm 1011236884Smm (void) snprintf(propname, sizeof (propname), 1012236884Smm "feature@%s", feat->fi_uname); 1013236884Smm 1014236884Smm /* 1015236884Smm * Skip feature if user specified it manually 1016236884Smm * on the command line. 1017236884Smm */ 1018236884Smm if (nvlist_exists(props, propname)) 1019236884Smm continue; 1020236884Smm 1021251634Sdelphij ret = add_prop_list(propname, 1022251634Sdelphij ZFS_FEATURE_ENABLED, &props, B_TRUE); 1023251634Sdelphij if (ret != 0) 1024236884Smm goto errout; 1025236884Smm } 1026236884Smm } 1027251634Sdelphij 1028251634Sdelphij ret = 1; 1029185029Spjd if (zpool_create(g_zfs, poolname, 1030185029Spjd nvroot, props, fsprops) == 0) { 1031168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 1032168404Spjd ZFS_TYPE_FILESYSTEM); 1033168404Spjd if (pool != NULL) { 1034168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 1035185029Spjd ret = zfs_shareall(pool); 1036168404Spjd zfs_close(pool); 1037168404Spjd } 1038168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 1039168404Spjd (void) fprintf(stderr, gettext("pool name may have " 1040168404Spjd "been omitted\n")); 1041168404Spjd } 1042168404Spjd } 1043168404Spjd 1044185029Spjderrout: 1045168404Spjd nvlist_free(nvroot); 1046185029Spjd nvlist_free(fsprops); 1047185029Spjd nvlist_free(props); 1048168404Spjd return (ret); 1049185029Spjdbadusage: 1050185029Spjd nvlist_free(fsprops); 1051185029Spjd nvlist_free(props); 1052185029Spjd usage(B_FALSE); 1053185029Spjd return (2); 1054168404Spjd} 1055168404Spjd 1056168404Spjd/* 1057168404Spjd * zpool destroy <pool> 1058168404Spjd * 1059168404Spjd * -f Forcefully unmount any datasets 1060168404Spjd * 1061168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 1062168404Spjd */ 1063168404Spjdint 1064168404Spjdzpool_do_destroy(int argc, char **argv) 1065168404Spjd{ 1066168404Spjd boolean_t force = B_FALSE; 1067168404Spjd int c; 1068168404Spjd char *pool; 1069168404Spjd zpool_handle_t *zhp; 1070168404Spjd int ret; 1071168404Spjd 1072168404Spjd /* check options */ 1073168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 1074168404Spjd switch (c) { 1075168404Spjd case 'f': 1076168404Spjd force = B_TRUE; 1077168404Spjd break; 1078168404Spjd case '?': 1079168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1080168404Spjd optopt); 1081168404Spjd usage(B_FALSE); 1082168404Spjd } 1083168404Spjd } 1084168404Spjd 1085168404Spjd argc -= optind; 1086168404Spjd argv += optind; 1087168404Spjd 1088168404Spjd /* check arguments */ 1089168404Spjd if (argc < 1) { 1090168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1091168404Spjd usage(B_FALSE); 1092168404Spjd } 1093168404Spjd if (argc > 1) { 1094168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1095168404Spjd usage(B_FALSE); 1096168404Spjd } 1097168404Spjd 1098168404Spjd pool = argv[0]; 1099168404Spjd 1100168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1101168404Spjd /* 1102168404Spjd * As a special case, check for use of '/' in the name, and 1103168404Spjd * direct the user to use 'zfs destroy' instead. 1104168404Spjd */ 1105168404Spjd if (strchr(pool, '/') != NULL) 1106168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1107168404Spjd "destroy a dataset\n")); 1108168404Spjd return (1); 1109168404Spjd } 1110168404Spjd 1111168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1112168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1113168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1114168404Spjd return (1); 1115168404Spjd } 1116168404Spjd 1117248571Smm /* The history must be logged as part of the export */ 1118248571Smm log_history = B_FALSE; 1119168404Spjd 1120248571Smm ret = (zpool_destroy(zhp, history_str) != 0); 1121248571Smm 1122168404Spjd zpool_close(zhp); 1123168404Spjd 1124168404Spjd return (ret); 1125168404Spjd} 1126168404Spjd 1127168404Spjd/* 1128168404Spjd * zpool export [-f] <pool> ... 1129168404Spjd * 1130168404Spjd * -f Forcefully unmount datasets 1131168404Spjd * 1132168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1133168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1134168404Spjd * then the datasets will be forcefully unmounted. 1135168404Spjd */ 1136168404Spjdint 1137168404Spjdzpool_do_export(int argc, char **argv) 1138168404Spjd{ 1139168404Spjd boolean_t force = B_FALSE; 1140207670Smm boolean_t hardforce = B_FALSE; 1141168404Spjd int c; 1142168404Spjd zpool_handle_t *zhp; 1143168404Spjd int ret; 1144168404Spjd int i; 1145168404Spjd 1146168404Spjd /* check options */ 1147207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1148168404Spjd switch (c) { 1149168404Spjd case 'f': 1150168404Spjd force = B_TRUE; 1151168404Spjd break; 1152207670Smm case 'F': 1153207670Smm hardforce = B_TRUE; 1154207670Smm break; 1155168404Spjd case '?': 1156168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1157168404Spjd optopt); 1158168404Spjd usage(B_FALSE); 1159168404Spjd } 1160168404Spjd } 1161168404Spjd 1162168404Spjd argc -= optind; 1163168404Spjd argv += optind; 1164168404Spjd 1165168404Spjd /* check arguments */ 1166168404Spjd if (argc < 1) { 1167168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1168168404Spjd usage(B_FALSE); 1169168404Spjd } 1170168404Spjd 1171168404Spjd ret = 0; 1172168404Spjd for (i = 0; i < argc; i++) { 1173168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1174168404Spjd ret = 1; 1175168404Spjd continue; 1176168404Spjd } 1177168404Spjd 1178168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1179168404Spjd ret = 1; 1180168404Spjd zpool_close(zhp); 1181168404Spjd continue; 1182168404Spjd } 1183168404Spjd 1184248571Smm /* The history must be logged as part of the export */ 1185248571Smm log_history = B_FALSE; 1186248571Smm 1187207670Smm if (hardforce) { 1188248571Smm if (zpool_export_force(zhp, history_str) != 0) 1189207670Smm ret = 1; 1190248571Smm } else if (zpool_export(zhp, force, history_str) != 0) { 1191168404Spjd ret = 1; 1192207670Smm } 1193168404Spjd 1194168404Spjd zpool_close(zhp); 1195168404Spjd } 1196168404Spjd 1197168404Spjd return (ret); 1198168404Spjd} 1199168404Spjd 1200168404Spjd/* 1201168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1202168404Spjd * name column. 1203168404Spjd */ 1204168404Spjdstatic int 1205168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1206168404Spjd{ 1207219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1208168404Spjd nvlist_t **child; 1209168404Spjd uint_t c, children; 1210168404Spjd int ret; 1211168404Spjd 1212168404Spjd if (strlen(name) + depth > max) 1213168404Spjd max = strlen(name) + depth; 1214168404Spjd 1215168404Spjd free(name); 1216168404Spjd 1217168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1218168404Spjd &child, &children) == 0) { 1219168404Spjd for (c = 0; c < children; c++) 1220168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1221168404Spjd max)) > max) 1222168404Spjd max = ret; 1223168404Spjd } 1224168404Spjd 1225185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1226185029Spjd &child, &children) == 0) { 1227185029Spjd for (c = 0; c < children; c++) 1228185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1229185029Spjd max)) > max) 1230185029Spjd max = ret; 1231185029Spjd } 1232185029Spjd 1233168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1234168404Spjd &child, &children) == 0) { 1235168404Spjd for (c = 0; c < children; c++) 1236168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1237168404Spjd max)) > max) 1238168404Spjd max = ret; 1239168404Spjd } 1240168404Spjd 1241168404Spjd 1242168404Spjd return (max); 1243168404Spjd} 1244168404Spjd 1245213197Smmtypedef struct spare_cbdata { 1246213197Smm uint64_t cb_guid; 1247213197Smm zpool_handle_t *cb_zhp; 1248213197Smm} spare_cbdata_t; 1249168404Spjd 1250213197Smmstatic boolean_t 1251213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1252213197Smm{ 1253213197Smm uint64_t guid; 1254213197Smm nvlist_t **child; 1255213197Smm uint_t c, children; 1256213197Smm 1257213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1258213197Smm search == guid) 1259213197Smm return (B_TRUE); 1260213197Smm 1261213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1262213197Smm &child, &children) == 0) { 1263213197Smm for (c = 0; c < children; c++) 1264213197Smm if (find_vdev(child[c], search)) 1265213197Smm return (B_TRUE); 1266213197Smm } 1267213197Smm 1268213197Smm return (B_FALSE); 1269213197Smm} 1270213197Smm 1271213197Smmstatic int 1272213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1273213197Smm{ 1274213197Smm spare_cbdata_t *cbp = data; 1275213197Smm nvlist_t *config, *nvroot; 1276213197Smm 1277213197Smm config = zpool_get_config(zhp, NULL); 1278213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1279213197Smm &nvroot) == 0); 1280213197Smm 1281213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1282213197Smm cbp->cb_zhp = zhp; 1283213197Smm return (1); 1284213197Smm } 1285213197Smm 1286213197Smm zpool_close(zhp); 1287213197Smm return (0); 1288213197Smm} 1289213197Smm 1290168404Spjd/* 1291213197Smm * Print out configuration state as requested by status_callback. 1292213197Smm */ 1293213197Smmvoid 1294213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1295213197Smm int namewidth, int depth, boolean_t isspare) 1296213197Smm{ 1297213197Smm nvlist_t **child; 1298213197Smm uint_t c, children; 1299219089Spjd pool_scan_stat_t *ps = NULL; 1300213197Smm vdev_stat_t *vs; 1301219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1302213197Smm char *vname; 1303213197Smm uint64_t notpresent; 1304213197Smm spare_cbdata_t cb; 1305224169Sgibbs const char *state; 1306213197Smm 1307213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1308213197Smm &child, &children) != 0) 1309213197Smm children = 0; 1310213197Smm 1311219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1312219089Spjd (uint64_t **)&vs, &c) == 0); 1313219089Spjd 1314213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1315213197Smm if (isspare) { 1316213197Smm /* 1317213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1318213197Smm * online drives. 1319213197Smm */ 1320213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1321213197Smm state = "INUSE"; 1322213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1323213197Smm state = "AVAIL"; 1324213197Smm } 1325213197Smm 1326213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1327213197Smm name, state); 1328213197Smm 1329213197Smm if (!isspare) { 1330213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1331213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1332213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1333213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1334213197Smm } 1335213197Smm 1336213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1337224170Sgibbs ¬present) == 0 || 1338224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1339213197Smm char *path; 1340224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1341224170Sgibbs (void) printf(" was %s", path); 1342213197Smm } else if (vs->vs_aux != 0) { 1343213197Smm (void) printf(" "); 1344213197Smm 1345213197Smm switch (vs->vs_aux) { 1346213197Smm case VDEV_AUX_OPEN_FAILED: 1347213197Smm (void) printf(gettext("cannot open")); 1348213197Smm break; 1349213197Smm 1350213197Smm case VDEV_AUX_BAD_GUID_SUM: 1351213197Smm (void) printf(gettext("missing device")); 1352213197Smm break; 1353213197Smm 1354213197Smm case VDEV_AUX_NO_REPLICAS: 1355213197Smm (void) printf(gettext("insufficient replicas")); 1356213197Smm break; 1357213197Smm 1358213197Smm case VDEV_AUX_VERSION_NEWER: 1359213197Smm (void) printf(gettext("newer version")); 1360213197Smm break; 1361213197Smm 1362236884Smm case VDEV_AUX_UNSUP_FEAT: 1363236884Smm (void) printf(gettext("unsupported feature(s)")); 1364236884Smm break; 1365236884Smm 1366213197Smm case VDEV_AUX_SPARED: 1367213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1368213197Smm &cb.cb_guid) == 0); 1369213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1370213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1371213197Smm zpool_get_name(zhp)) == 0) 1372213197Smm (void) printf(gettext("currently in " 1373213197Smm "use")); 1374213197Smm else 1375213197Smm (void) printf(gettext("in use by " 1376213197Smm "pool '%s'"), 1377213197Smm zpool_get_name(cb.cb_zhp)); 1378213197Smm zpool_close(cb.cb_zhp); 1379213197Smm } else { 1380213197Smm (void) printf(gettext("currently in use")); 1381213197Smm } 1382213197Smm break; 1383213197Smm 1384213197Smm case VDEV_AUX_ERR_EXCEEDED: 1385213197Smm (void) printf(gettext("too many errors")); 1386213197Smm break; 1387213197Smm 1388213197Smm case VDEV_AUX_IO_FAILURE: 1389213197Smm (void) printf(gettext("experienced I/O failures")); 1390213197Smm break; 1391213197Smm 1392213197Smm case VDEV_AUX_BAD_LOG: 1393213197Smm (void) printf(gettext("bad intent log")); 1394213197Smm break; 1395213197Smm 1396219089Spjd case VDEV_AUX_EXTERNAL: 1397219089Spjd (void) printf(gettext("external device fault")); 1398219089Spjd break; 1399219089Spjd 1400219089Spjd case VDEV_AUX_SPLIT_POOL: 1401219089Spjd (void) printf(gettext("split into new pool")); 1402219089Spjd break; 1403219089Spjd 1404213197Smm default: 1405213197Smm (void) printf(gettext("corrupted data")); 1406213197Smm break; 1407213197Smm } 1408213197Smm } 1409213197Smm 1410219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1411219089Spjd (uint64_t **)&ps, &c); 1412219089Spjd 1413219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1414219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1415219089Spjd (void) printf(gettext(" (%s)"), 1416219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1417219089Spjd "resilvering" : "repairing"); 1418219089Spjd } 1419219089Spjd 1420213197Smm (void) printf("\n"); 1421213197Smm 1422213197Smm for (c = 0; c < children; c++) { 1423219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1424213197Smm 1425219089Spjd /* Don't print logs or holes here */ 1426213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1427219089Spjd &islog); 1428219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1429219089Spjd &ishole); 1430219089Spjd if (islog || ishole) 1431213197Smm continue; 1432219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1433213197Smm print_status_config(zhp, vname, child[c], 1434213197Smm namewidth, depth + 2, isspare); 1435213197Smm free(vname); 1436213197Smm } 1437213197Smm} 1438213197Smm 1439213197Smm 1440213197Smm/* 1441168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1442168404Spjd * pool, printing out the name and status for each one. 1443168404Spjd */ 1444168404Spjdvoid 1445213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1446168404Spjd{ 1447168404Spjd nvlist_t **child; 1448168404Spjd uint_t c, children; 1449168404Spjd vdev_stat_t *vs; 1450168404Spjd char *type, *vname; 1451168404Spjd 1452168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1453219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1454219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1455168404Spjd return; 1456168404Spjd 1457219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1458168404Spjd (uint64_t **)&vs, &c) == 0); 1459168404Spjd 1460168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1461185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1462168404Spjd 1463168404Spjd if (vs->vs_aux != 0) { 1464185029Spjd (void) printf(" "); 1465168404Spjd 1466168404Spjd switch (vs->vs_aux) { 1467168404Spjd case VDEV_AUX_OPEN_FAILED: 1468168404Spjd (void) printf(gettext("cannot open")); 1469168404Spjd break; 1470168404Spjd 1471168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1472168404Spjd (void) printf(gettext("missing device")); 1473168404Spjd break; 1474168404Spjd 1475168404Spjd case VDEV_AUX_NO_REPLICAS: 1476168404Spjd (void) printf(gettext("insufficient replicas")); 1477168404Spjd break; 1478168404Spjd 1479168404Spjd case VDEV_AUX_VERSION_NEWER: 1480168404Spjd (void) printf(gettext("newer version")); 1481168404Spjd break; 1482168404Spjd 1483236884Smm case VDEV_AUX_UNSUP_FEAT: 1484236884Smm (void) printf(gettext("unsupported feature(s)")); 1485236884Smm break; 1486236884Smm 1487185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1488185029Spjd (void) printf(gettext("too many errors")); 1489185029Spjd break; 1490185029Spjd 1491168404Spjd default: 1492168404Spjd (void) printf(gettext("corrupted data")); 1493168404Spjd break; 1494168404Spjd } 1495168404Spjd } 1496168404Spjd (void) printf("\n"); 1497168404Spjd 1498168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1499168404Spjd &child, &children) != 0) 1500168404Spjd return; 1501168404Spjd 1502168404Spjd for (c = 0; c < children; c++) { 1503185029Spjd uint64_t is_log = B_FALSE; 1504185029Spjd 1505185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1506185029Spjd &is_log); 1507213197Smm if (is_log) 1508185029Spjd continue; 1509185029Spjd 1510219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1511213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1512168404Spjd free(vname); 1513168404Spjd } 1514168404Spjd 1515185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1516185029Spjd &child, &children) == 0) { 1517185029Spjd (void) printf(gettext("\tcache\n")); 1518185029Spjd for (c = 0; c < children; c++) { 1519219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1520185029Spjd (void) printf("\t %s\n", vname); 1521185029Spjd free(vname); 1522185029Spjd } 1523185029Spjd } 1524185029Spjd 1525168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1526185029Spjd &child, &children) == 0) { 1527185029Spjd (void) printf(gettext("\tspares\n")); 1528185029Spjd for (c = 0; c < children; c++) { 1529219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1530185029Spjd (void) printf("\t %s\n", vname); 1531185029Spjd free(vname); 1532185029Spjd } 1533168404Spjd } 1534168404Spjd} 1535168404Spjd 1536168404Spjd/* 1537213197Smm * Print log vdevs. 1538213197Smm * Logs are recorded as top level vdevs in the main pool child array 1539213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1540213197Smm * print_import_config() to print the top level logs then any log 1541213197Smm * children (eg mirrored slogs) are printed recursively - which 1542213197Smm * works because only the top level vdev is marked "is_log" 1543213197Smm */ 1544213197Smmstatic void 1545213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1546213197Smm{ 1547213197Smm uint_t c, children; 1548213197Smm nvlist_t **child; 1549213197Smm 1550213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1551213197Smm &children) != 0) 1552213197Smm return; 1553213197Smm 1554213197Smm (void) printf(gettext("\tlogs\n")); 1555213197Smm 1556213197Smm for (c = 0; c < children; c++) { 1557213197Smm uint64_t is_log = B_FALSE; 1558213197Smm char *name; 1559213197Smm 1560213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1561213197Smm &is_log); 1562213197Smm if (!is_log) 1563213197Smm continue; 1564219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1565213197Smm if (verbose) 1566213197Smm print_status_config(zhp, name, child[c], namewidth, 1567213197Smm 2, B_FALSE); 1568213197Smm else 1569213197Smm print_import_config(name, child[c], namewidth, 2); 1570213197Smm free(name); 1571213197Smm } 1572213197Smm} 1573219089Spjd 1574213197Smm/* 1575168404Spjd * Display the status for the given pool. 1576168404Spjd */ 1577168404Spjdstatic void 1578168404Spjdshow_import(nvlist_t *config) 1579168404Spjd{ 1580168404Spjd uint64_t pool_state; 1581168404Spjd vdev_stat_t *vs; 1582168404Spjd char *name; 1583168404Spjd uint64_t guid; 1584168404Spjd char *msgid; 1585168404Spjd nvlist_t *nvroot; 1586168404Spjd int reason; 1587168404Spjd const char *health; 1588168404Spjd uint_t vsc; 1589168404Spjd int namewidth; 1590228103Smm char *comment; 1591168404Spjd 1592168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1593168404Spjd &name) == 0); 1594168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1595168404Spjd &guid) == 0); 1596168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1597168404Spjd &pool_state) == 0); 1598168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1599168404Spjd &nvroot) == 0); 1600168404Spjd 1601219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1602168404Spjd (uint64_t **)&vs, &vsc) == 0); 1603185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1604168404Spjd 1605168404Spjd reason = zpool_import_status(config, &msgid); 1606168404Spjd 1607228103Smm (void) printf(gettext(" pool: %s\n"), name); 1608228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1609228103Smm (void) printf(gettext(" state: %s"), health); 1610168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1611168404Spjd (void) printf(gettext(" (DESTROYED)")); 1612168404Spjd (void) printf("\n"); 1613168404Spjd 1614168404Spjd switch (reason) { 1615168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1616168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1617168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1618228103Smm (void) printf(gettext(" status: One or more devices are " 1619228103Smm "missing from the system.\n")); 1620168404Spjd break; 1621168404Spjd 1622168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1623168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1624228103Smm (void) printf(gettext(" status: One or more devices contains " 1625168404Spjd "corrupted data.\n")); 1626168404Spjd break; 1627168404Spjd 1628168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1629228103Smm (void) printf( 1630228103Smm gettext(" status: The pool data is corrupted.\n")); 1631168404Spjd break; 1632168404Spjd 1633168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1634228103Smm (void) printf(gettext(" status: One or more devices " 1635168404Spjd "are offlined.\n")); 1636168404Spjd break; 1637168404Spjd 1638168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1639228103Smm (void) printf(gettext(" status: The pool metadata is " 1640168404Spjd "corrupted.\n")); 1641168404Spjd break; 1642168404Spjd 1643168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1644238926Smm (void) printf(gettext(" status: The pool is formatted using a " 1645238926Smm "legacy on-disk version.\n")); 1646168404Spjd break; 1647168404Spjd 1648168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1649228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1650168404Spjd "incompatible version.\n")); 1651168404Spjd break; 1652168404Spjd 1653238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 1654238926Smm (void) printf(gettext(" status: Some supported features are " 1655238926Smm "not enabled on the pool.\n")); 1656238926Smm break; 1657238926Smm 1658236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1659236884Smm (void) printf(gettext("status: The pool uses the following " 1660236884Smm "feature(s) not supported on this sytem:\n")); 1661236884Smm zpool_print_unsup_feat(config); 1662236884Smm break; 1663236884Smm 1664236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1665236884Smm (void) printf(gettext("status: The pool can only be accessed " 1666236884Smm "in read-only mode on this system. It\n\tcannot be " 1667236884Smm "accessed in read-write mode because it uses the " 1668236884Smm "following\n\tfeature(s) not supported on this system:\n")); 1669236884Smm zpool_print_unsup_feat(config); 1670236884Smm break; 1671236884Smm 1672168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1673228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1674168498Spjd "another system.\n")); 1675168498Spjd break; 1676185029Spjd 1677185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1678185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1679228103Smm (void) printf(gettext(" status: One or more devices are " 1680185029Spjd "faulted.\n")); 1681185029Spjd break; 1682185029Spjd 1683185029Spjd case ZPOOL_STATUS_BAD_LOG: 1684228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1685185029Spjd "read.\n")); 1686185029Spjd break; 1687185029Spjd 1688219089Spjd case ZPOOL_STATUS_RESILVERING: 1689228103Smm (void) printf(gettext(" status: One or more devices were being " 1690219089Spjd "resilvered.\n")); 1691219089Spjd break; 1692219089Spjd 1693168404Spjd default: 1694168404Spjd /* 1695168404Spjd * No other status can be seen when importing pools. 1696168404Spjd */ 1697168404Spjd assert(reason == ZPOOL_STATUS_OK); 1698168404Spjd } 1699168404Spjd 1700168404Spjd /* 1701168404Spjd * Print out an action according to the overall state of the pool. 1702168404Spjd */ 1703168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1704238926Smm if (reason == ZPOOL_STATUS_VERSION_OLDER || 1705238926Smm reason == ZPOOL_STATUS_FEAT_DISABLED) { 1706228103Smm (void) printf(gettext(" action: The pool can be " 1707168404Spjd "imported using its name or numeric identifier, " 1708168404Spjd "though\n\tsome features will not be available " 1709168404Spjd "without an explicit 'zpool upgrade'.\n")); 1710238926Smm } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 1711228103Smm (void) printf(gettext(" action: The pool can be " 1712168498Spjd "imported using its name or numeric " 1713168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1714238926Smm } else { 1715228103Smm (void) printf(gettext(" action: The pool can be " 1716168404Spjd "imported using its name or numeric " 1717168404Spjd "identifier.\n")); 1718238926Smm } 1719168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1720228103Smm (void) printf(gettext(" action: The pool can be imported " 1721168404Spjd "despite missing or damaged devices. The\n\tfault " 1722168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1723168404Spjd } else { 1724168404Spjd switch (reason) { 1725168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1726228103Smm (void) printf(gettext(" action: The pool cannot be " 1727168404Spjd "imported. Access the pool on a system running " 1728168404Spjd "newer\n\tsoftware, or recreate the pool from " 1729168404Spjd "backup.\n")); 1730168404Spjd break; 1731236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1732236884Smm (void) printf(gettext("action: The pool cannot be " 1733236884Smm "imported. Access the pool on a system that " 1734236884Smm "supports\n\tthe required feature(s), or recreate " 1735236884Smm "the pool from backup.\n")); 1736236884Smm break; 1737236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1738236884Smm (void) printf(gettext("action: The pool cannot be " 1739236884Smm "imported in read-write mode. Import the pool " 1740236884Smm "with\n" 1741236884Smm "\t\"-o readonly=on\", access the pool on a system " 1742236884Smm "that supports the\n\trequired feature(s), or " 1743236884Smm "recreate the pool from backup.\n")); 1744236884Smm break; 1745168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1746168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1747168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1748228103Smm (void) printf(gettext(" action: The pool cannot be " 1749168404Spjd "imported. Attach the missing\n\tdevices and try " 1750168404Spjd "again.\n")); 1751168404Spjd break; 1752168404Spjd default: 1753228103Smm (void) printf(gettext(" action: The pool cannot be " 1754168404Spjd "imported due to damaged devices or data.\n")); 1755168404Spjd } 1756168404Spjd } 1757168404Spjd 1758228103Smm /* Print the comment attached to the pool. */ 1759228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 1760228103Smm (void) printf(gettext("comment: %s\n"), comment); 1761228103Smm 1762168404Spjd /* 1763168404Spjd * If the state is "closed" or "can't open", and the aux state 1764168404Spjd * is "corrupt data": 1765168404Spjd */ 1766168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1767168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1768168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1769168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1770168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1771168404Spjd "but can be imported using the '-Df' flags.\n")); 1772168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1773168404Spjd (void) printf(gettext("\tThe pool may be active on " 1774185029Spjd "another system, but can be imported using\n\t" 1775168404Spjd "the '-f' flag.\n")); 1776168404Spjd } 1777168404Spjd 1778168404Spjd if (msgid != NULL) 1779236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1780168404Spjd msgid); 1781168404Spjd 1782228103Smm (void) printf(gettext(" config:\n\n")); 1783168404Spjd 1784168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1785168404Spjd if (namewidth < 10) 1786168404Spjd namewidth = 10; 1787168404Spjd 1788213197Smm print_import_config(name, nvroot, namewidth, 0); 1789213197Smm if (num_logs(nvroot) > 0) 1790213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1791185029Spjd 1792168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1793168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1794168404Spjd "be part of this pool, though their\n\texact " 1795168404Spjd "configuration cannot be determined.\n")); 1796168404Spjd } 1797168404Spjd} 1798168404Spjd 1799168404Spjd/* 1800168404Spjd * Perform the import for the given configuration. This passes the heavy 1801185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1802185029Spjd * within the pool. 1803168404Spjd */ 1804168404Spjdstatic int 1805168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1806219089Spjd nvlist_t *props, int flags) 1807168404Spjd{ 1808168404Spjd zpool_handle_t *zhp; 1809168404Spjd char *name; 1810168404Spjd uint64_t state; 1811168404Spjd uint64_t version; 1812168404Spjd 1813168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1814168404Spjd &name) == 0); 1815168404Spjd 1816168404Spjd verify(nvlist_lookup_uint64(config, 1817168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1818168404Spjd verify(nvlist_lookup_uint64(config, 1819168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1820236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 1821168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1822236884Smm "is formatted using an unsupported ZFS version\n"), name); 1823168404Spjd return (1); 1824219089Spjd } else if (state != POOL_STATE_EXPORTED && 1825219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 1826168498Spjd uint64_t hostid; 1827168498Spjd 1828168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1829168498Spjd &hostid) == 0) { 1830168498Spjd if ((unsigned long)hostid != gethostid()) { 1831168498Spjd char *hostname; 1832168498Spjd uint64_t timestamp; 1833168498Spjd time_t t; 1834168498Spjd 1835168498Spjd verify(nvlist_lookup_string(config, 1836168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1837168498Spjd verify(nvlist_lookup_uint64(config, 1838168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1839168498Spjd t = timestamp; 1840168498Spjd (void) fprintf(stderr, gettext("cannot import " 1841168498Spjd "'%s': pool may be in use from other " 1842168498Spjd "system, it was last accessed by %s " 1843168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1844168498Spjd (unsigned long)hostid, 1845168498Spjd asctime(localtime(&t))); 1846168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1847168498Spjd "import anyway\n")); 1848168498Spjd return (1); 1849168498Spjd } 1850168498Spjd } else { 1851168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1852168498Spjd "pool may be in use from other system\n"), name); 1853168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1854168498Spjd "anyway\n")); 1855168498Spjd return (1); 1856168498Spjd } 1857168404Spjd } 1858168404Spjd 1859219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1860168404Spjd return (1); 1861168404Spjd 1862168404Spjd if (newname != NULL) 1863168404Spjd name = (char *)newname; 1864168404Spjd 1865209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 1866209962Smm return (1); 1867168404Spjd 1868209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1869219089Spjd !(flags & ZFS_IMPORT_ONLY) && 1870209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1871168404Spjd zpool_close(zhp); 1872168404Spjd return (1); 1873168404Spjd } 1874168404Spjd 1875168404Spjd zpool_close(zhp); 1876219089Spjd return (0); 1877168404Spjd} 1878168404Spjd 1879168404Spjd/* 1880168404Spjd * zpool import [-d dir] [-D] 1881185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1882185029Spjd * [-d dir | -c cachefile] [-f] -a 1883185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1884219089Spjd * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 1885168404Spjd * 1886185029Spjd * -c Read pool information from a cachefile instead of searching 1887185029Spjd * devices. 1888185029Spjd * 1889168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1890168404Spjd * one directory can be specified using multiple '-d' options. 1891168404Spjd * 1892168404Spjd * -D Scan for previously destroyed pools or import all or only 1893168404Spjd * specified destroyed pools. 1894168404Spjd * 1895168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1896168404Spjd * the given root. The pool will remain exported when the machine 1897168404Spjd * is rebooted. 1898168404Spjd * 1899219089Spjd * -V Import even in the presence of faulted vdevs. This is an 1900185029Spjd * intentionally undocumented option for testing purposes, and 1901185029Spjd * treats the pool configuration as complete, leaving any bad 1902209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 1903209962Smm * import. 1904185029Spjd * 1905219089Spjd * -f Force import, even if it appears that the pool is active. 1906219089Spjd * 1907219089Spjd * -F Attempt rewind if necessary. 1908219089Spjd * 1909219089Spjd * -n See if rewind would work, but don't actually rewind. 1910219089Spjd * 1911219089Spjd * -N Import the pool but don't mount datasets. 1912219089Spjd * 1913219089Spjd * -T Specify a starting txg to use for import. This option is 1914219089Spjd * intentionally undocumented option for testing purposes. 1915219089Spjd * 1916168404Spjd * -a Import all pools found. 1917168404Spjd * 1918185029Spjd * -o Set property=value and/or temporary mount options (without '='). 1919185029Spjd * 1920168404Spjd * The import command scans for pools to import, and import pools based on pool 1921168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 1922168404Spjd */ 1923168404Spjdint 1924168404Spjdzpool_do_import(int argc, char **argv) 1925168404Spjd{ 1926168404Spjd char **searchdirs = NULL; 1927168404Spjd int nsearch = 0; 1928168404Spjd int c; 1929219089Spjd int err = 0; 1930185029Spjd nvlist_t *pools = NULL; 1931168404Spjd boolean_t do_all = B_FALSE; 1932168404Spjd boolean_t do_destroyed = B_FALSE; 1933168404Spjd char *mntopts = NULL; 1934168404Spjd nvpair_t *elem; 1935168404Spjd nvlist_t *config; 1936185029Spjd uint64_t searchguid = 0; 1937185029Spjd char *searchname = NULL; 1938185029Spjd char *propval; 1939168404Spjd nvlist_t *found_config; 1940219089Spjd nvlist_t *policy = NULL; 1941185029Spjd nvlist_t *props = NULL; 1942168404Spjd boolean_t first; 1943219089Spjd int flags = ZFS_IMPORT_NORMAL; 1944219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 1945219089Spjd boolean_t dryrun = B_FALSE; 1946219089Spjd boolean_t do_rewind = B_FALSE; 1947219089Spjd boolean_t xtreme_rewind = B_FALSE; 1948219089Spjd uint64_t pool_state, txg = -1ULL; 1949185029Spjd char *cachefile = NULL; 1950219089Spjd importargs_t idata = { 0 }; 1951219089Spjd char *endptr; 1952168404Spjd 1953168404Spjd /* check options */ 1954219089Spjd while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) { 1955168404Spjd switch (c) { 1956168404Spjd case 'a': 1957168404Spjd do_all = B_TRUE; 1958168404Spjd break; 1959185029Spjd case 'c': 1960185029Spjd cachefile = optarg; 1961185029Spjd break; 1962168404Spjd case 'd': 1963168404Spjd if (searchdirs == NULL) { 1964168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1965168404Spjd } else { 1966168404Spjd char **tmp = safe_malloc((nsearch + 1) * 1967168404Spjd sizeof (char *)); 1968168404Spjd bcopy(searchdirs, tmp, nsearch * 1969168404Spjd sizeof (char *)); 1970168404Spjd free(searchdirs); 1971168404Spjd searchdirs = tmp; 1972168404Spjd } 1973168404Spjd searchdirs[nsearch++] = optarg; 1974168404Spjd break; 1975168404Spjd case 'D': 1976168404Spjd do_destroyed = B_TRUE; 1977168404Spjd break; 1978168404Spjd case 'f': 1979219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 1980168404Spjd break; 1981185029Spjd case 'F': 1982219089Spjd do_rewind = B_TRUE; 1983185029Spjd break; 1984219089Spjd case 'm': 1985219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 1986219089Spjd break; 1987219089Spjd case 'n': 1988219089Spjd dryrun = B_TRUE; 1989219089Spjd break; 1990219089Spjd case 'N': 1991219089Spjd flags |= ZFS_IMPORT_ONLY; 1992219089Spjd break; 1993168404Spjd case 'o': 1994185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 1995185029Spjd *propval = '\0'; 1996185029Spjd propval++; 1997185029Spjd if (add_prop_list(optarg, propval, 1998185029Spjd &props, B_TRUE)) 1999185029Spjd goto error; 2000185029Spjd } else { 2001185029Spjd mntopts = optarg; 2002185029Spjd } 2003168404Spjd break; 2004168404Spjd case 'R': 2005185029Spjd if (add_prop_list(zpool_prop_to_name( 2006185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 2007185029Spjd goto error; 2008185029Spjd if (nvlist_lookup_string(props, 2009185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 2010185029Spjd &propval) == 0) 2011185029Spjd break; 2012185029Spjd if (add_prop_list(zpool_prop_to_name( 2013185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2014185029Spjd goto error; 2015168404Spjd break; 2016219089Spjd case 'T': 2017219089Spjd errno = 0; 2018219089Spjd txg = strtoull(optarg, &endptr, 10); 2019219089Spjd if (errno != 0 || *endptr != '\0') { 2020219089Spjd (void) fprintf(stderr, 2021219089Spjd gettext("invalid txg value\n")); 2022219089Spjd usage(B_FALSE); 2023219089Spjd } 2024219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 2025219089Spjd break; 2026219089Spjd case 'V': 2027219089Spjd flags |= ZFS_IMPORT_VERBATIM; 2028219089Spjd break; 2029219089Spjd case 'X': 2030219089Spjd xtreme_rewind = B_TRUE; 2031219089Spjd break; 2032168404Spjd case ':': 2033168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2034168404Spjd "'%c' option\n"), optopt); 2035168404Spjd usage(B_FALSE); 2036168404Spjd break; 2037168404Spjd case '?': 2038168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2039168404Spjd optopt); 2040168404Spjd usage(B_FALSE); 2041168404Spjd } 2042168404Spjd } 2043168404Spjd 2044168404Spjd argc -= optind; 2045168404Spjd argv += optind; 2046168404Spjd 2047185029Spjd if (cachefile && nsearch != 0) { 2048185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 2049185029Spjd usage(B_FALSE); 2050185029Spjd } 2051185029Spjd 2052219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 2053219089Spjd (void) fprintf(stderr, 2054219089Spjd gettext("-n or -X only meaningful with -F\n")); 2055219089Spjd usage(B_FALSE); 2056219089Spjd } 2057219089Spjd if (dryrun) 2058219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 2059219089Spjd else if (do_rewind) 2060219089Spjd rewind_policy = ZPOOL_DO_REWIND; 2061219089Spjd if (xtreme_rewind) 2062219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 2063219089Spjd 2064219089Spjd /* In the future, we can capture further policy and include it here */ 2065219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2066219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 2067219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 2068219089Spjd goto error; 2069219089Spjd 2070168404Spjd if (searchdirs == NULL) { 2071168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2072235478Savg searchdirs[0] = "/dev"; 2073168404Spjd nsearch = 1; 2074168404Spjd } 2075168404Spjd 2076168404Spjd /* check argument count */ 2077168404Spjd if (do_all) { 2078168404Spjd if (argc != 0) { 2079168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2080168404Spjd usage(B_FALSE); 2081168404Spjd } 2082168404Spjd } else { 2083168404Spjd if (argc > 2) { 2084168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2085168404Spjd usage(B_FALSE); 2086168404Spjd } 2087168404Spjd 2088168404Spjd /* 2089168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 2090168404Spjd * here because otherwise any attempt to discover pools will 2091168404Spjd * silently fail. 2092168404Spjd */ 2093168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2094168404Spjd (void) fprintf(stderr, gettext("cannot " 2095168404Spjd "discover pools: permission denied\n")); 2096168404Spjd free(searchdirs); 2097219089Spjd nvlist_free(policy); 2098168404Spjd return (1); 2099168404Spjd } 2100168404Spjd } 2101168404Spjd 2102168404Spjd /* 2103168404Spjd * Depending on the arguments given, we do one of the following: 2104168404Spjd * 2105168404Spjd * <none> Iterate through all pools and display information about 2106168404Spjd * each one. 2107168404Spjd * 2108168404Spjd * -a Iterate through all pools and try to import each one. 2109168404Spjd * 2110168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 2111168404Spjd * name and import that one. 2112168404Spjd * 2113168404Spjd * -D Above options applies only to destroyed pools. 2114168404Spjd */ 2115168404Spjd if (argc != 0) { 2116168404Spjd char *endptr; 2117168404Spjd 2118168404Spjd errno = 0; 2119168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 2120168404Spjd if (errno != 0 || *endptr != '\0') 2121168404Spjd searchname = argv[0]; 2122168404Spjd found_config = NULL; 2123168404Spjd 2124185029Spjd /* 2125219089Spjd * User specified a name or guid. Ensure it's unique. 2126185029Spjd */ 2127219089Spjd idata.unique = B_TRUE; 2128185029Spjd } 2129185029Spjd 2130219089Spjd 2131219089Spjd idata.path = searchdirs; 2132219089Spjd idata.paths = nsearch; 2133219089Spjd idata.poolname = searchname; 2134219089Spjd idata.guid = searchguid; 2135219089Spjd idata.cachefile = cachefile; 2136219089Spjd 2137219089Spjd pools = zpool_search_import(g_zfs, &idata); 2138219089Spjd 2139219089Spjd if (pools != NULL && idata.exists && 2140219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2141219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2142219089Spjd "a pool with that name already exists\n"), 2143219089Spjd argv[0]); 2144219089Spjd (void) fprintf(stderr, gettext("use the form '%s " 2145219089Spjd "<pool | id> <newpool>' to give it a new name\n"), 2146219089Spjd "zpool import"); 2147219089Spjd err = 1; 2148219089Spjd } else if (pools == NULL && idata.exists) { 2149219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2150219089Spjd "a pool with that name is already created/imported,\n"), 2151219089Spjd argv[0]); 2152219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2153219089Spjd "with that name were found\n")); 2154219089Spjd err = 1; 2155219089Spjd } else if (pools == NULL) { 2156185029Spjd if (argc != 0) { 2157185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2158185029Spjd "no such pool available\n"), argv[0]); 2159185029Spjd } 2160219089Spjd err = 1; 2161219089Spjd } 2162219089Spjd 2163219089Spjd if (err == 1) { 2164185029Spjd free(searchdirs); 2165219089Spjd nvlist_free(policy); 2166185029Spjd return (1); 2167185029Spjd } 2168185029Spjd 2169185029Spjd /* 2170185029Spjd * At this point we have a list of import candidate configs. Even if 2171185029Spjd * we were searching by pool name or guid, we still need to 2172185029Spjd * post-process the list to deal with pool state and possible 2173185029Spjd * duplicate names. 2174185029Spjd */ 2175168404Spjd err = 0; 2176168404Spjd elem = NULL; 2177168404Spjd first = B_TRUE; 2178168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2179168404Spjd 2180168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2181168404Spjd 2182168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2183168404Spjd &pool_state) == 0); 2184168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2185168404Spjd continue; 2186168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2187168404Spjd continue; 2188168404Spjd 2189219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2190219089Spjd policy) == 0); 2191219089Spjd 2192168404Spjd if (argc == 0) { 2193168404Spjd if (first) 2194168404Spjd first = B_FALSE; 2195168404Spjd else if (!do_all) 2196168404Spjd (void) printf("\n"); 2197168404Spjd 2198219089Spjd if (do_all) { 2199168404Spjd err |= do_import(config, NULL, mntopts, 2200219089Spjd props, flags); 2201219089Spjd } else { 2202168404Spjd show_import(config); 2203219089Spjd } 2204168404Spjd } else if (searchname != NULL) { 2205168404Spjd char *name; 2206168404Spjd 2207168404Spjd /* 2208168404Spjd * We are searching for a pool based on name. 2209168404Spjd */ 2210168404Spjd verify(nvlist_lookup_string(config, 2211168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2212168404Spjd 2213168404Spjd if (strcmp(name, searchname) == 0) { 2214168404Spjd if (found_config != NULL) { 2215168404Spjd (void) fprintf(stderr, gettext( 2216168404Spjd "cannot import '%s': more than " 2217168404Spjd "one matching pool\n"), searchname); 2218168404Spjd (void) fprintf(stderr, gettext( 2219168404Spjd "import by numeric ID instead\n")); 2220168404Spjd err = B_TRUE; 2221168404Spjd } 2222168404Spjd found_config = config; 2223168404Spjd } 2224168404Spjd } else { 2225168404Spjd uint64_t guid; 2226168404Spjd 2227168404Spjd /* 2228168404Spjd * Search for a pool by guid. 2229168404Spjd */ 2230168404Spjd verify(nvlist_lookup_uint64(config, 2231168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2232168404Spjd 2233168404Spjd if (guid == searchguid) 2234168404Spjd found_config = config; 2235168404Spjd } 2236168404Spjd } 2237168404Spjd 2238168404Spjd /* 2239168404Spjd * If we were searching for a specific pool, verify that we found a 2240168404Spjd * pool, and then do the import. 2241168404Spjd */ 2242168404Spjd if (argc != 0 && err == 0) { 2243168404Spjd if (found_config == NULL) { 2244168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2245168404Spjd "no such pool available\n"), argv[0]); 2246168404Spjd err = B_TRUE; 2247168404Spjd } else { 2248168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2249219089Spjd argv[1], mntopts, props, flags); 2250168404Spjd } 2251168404Spjd } 2252168404Spjd 2253168404Spjd /* 2254168404Spjd * If we were just looking for pools, report an error if none were 2255168404Spjd * found. 2256168404Spjd */ 2257168404Spjd if (argc == 0 && first) 2258168404Spjd (void) fprintf(stderr, 2259168404Spjd gettext("no pools available to import\n")); 2260168404Spjd 2261185029Spjderror: 2262185029Spjd nvlist_free(props); 2263168404Spjd nvlist_free(pools); 2264219089Spjd nvlist_free(policy); 2265168404Spjd free(searchdirs); 2266168404Spjd 2267168404Spjd return (err ? 1 : 0); 2268168404Spjd} 2269168404Spjd 2270168404Spjdtypedef struct iostat_cbdata { 2271236155Smm boolean_t cb_verbose; 2272236155Smm int cb_namewidth; 2273236155Smm int cb_iteration; 2274168404Spjd zpool_list_t *cb_list; 2275168404Spjd} iostat_cbdata_t; 2276168404Spjd 2277168404Spjdstatic void 2278168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2279168404Spjd{ 2280168404Spjd int i = 0; 2281168404Spjd 2282168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2283168404Spjd (void) printf("-"); 2284168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2285168404Spjd} 2286168404Spjd 2287168404Spjdstatic void 2288168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2289168404Spjd{ 2290168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2291168404Spjd cb->cb_namewidth, ""); 2292219089Spjd (void) printf("%-*s alloc free read write read write\n", 2293168404Spjd cb->cb_namewidth, "pool"); 2294168404Spjd print_iostat_separator(cb); 2295168404Spjd} 2296168404Spjd 2297168404Spjd/* 2298168404Spjd * Display a single statistic. 2299168404Spjd */ 2300185029Spjdstatic void 2301168404Spjdprint_one_stat(uint64_t value) 2302168404Spjd{ 2303168404Spjd char buf[64]; 2304168404Spjd 2305168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2306168404Spjd (void) printf(" %5s", buf); 2307168404Spjd} 2308168404Spjd 2309168404Spjd/* 2310168404Spjd * Print out all the statistics for the given vdev. This can either be the 2311168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2312168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2313168404Spjd */ 2314168404Spjdvoid 2315168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2316168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2317168404Spjd{ 2318168404Spjd nvlist_t **oldchild, **newchild; 2319168404Spjd uint_t c, children; 2320168404Spjd vdev_stat_t *oldvs, *newvs; 2321168404Spjd vdev_stat_t zerovs = { 0 }; 2322168404Spjd uint64_t tdelta; 2323168404Spjd double scale; 2324168404Spjd char *vname; 2325168404Spjd 2326168404Spjd if (oldnv != NULL) { 2327219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2328219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2329168404Spjd } else { 2330168404Spjd oldvs = &zerovs; 2331168404Spjd } 2332168404Spjd 2333219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2334168404Spjd (uint64_t **)&newvs, &c) == 0); 2335168404Spjd 2336168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2337168404Spjd (void) printf("%*s%s", depth, "", name); 2338168404Spjd else 2339168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2340168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2341168404Spjd 2342168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2343168404Spjd 2344168404Spjd if (tdelta == 0) 2345168404Spjd scale = 1.0; 2346168404Spjd else 2347168404Spjd scale = (double)NANOSEC / tdelta; 2348168404Spjd 2349168404Spjd /* only toplevel vdevs have capacity stats */ 2350168404Spjd if (newvs->vs_space == 0) { 2351168404Spjd (void) printf(" - -"); 2352168404Spjd } else { 2353168404Spjd print_one_stat(newvs->vs_alloc); 2354168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2355168404Spjd } 2356168404Spjd 2357168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2358168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2359168404Spjd 2360168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2361168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2362168404Spjd 2363168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2364168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2365168404Spjd 2366168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2367168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2368168404Spjd 2369168404Spjd (void) printf("\n"); 2370168404Spjd 2371168404Spjd if (!cb->cb_verbose) 2372168404Spjd return; 2373168404Spjd 2374168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2375168404Spjd &newchild, &children) != 0) 2376168404Spjd return; 2377168404Spjd 2378168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2379168404Spjd &oldchild, &c) != 0) 2380168404Spjd return; 2381168404Spjd 2382168404Spjd for (c = 0; c < children; c++) { 2383227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2384219089Spjd 2385227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2386227497Smm &ishole); 2387227497Smm 2388227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2389227497Smm &islog); 2390227497Smm 2391227497Smm if (ishole || islog) 2392219089Spjd continue; 2393219089Spjd 2394219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2395168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2396168404Spjd newchild[c], cb, depth + 2); 2397168404Spjd free(vname); 2398168404Spjd } 2399185029Spjd 2400185029Spjd /* 2401227497Smm * Log device section 2402227497Smm */ 2403227497Smm 2404227497Smm if (num_logs(newnv) > 0) { 2405227497Smm (void) printf("%-*s - - - - - " 2406227497Smm "-\n", cb->cb_namewidth, "logs"); 2407227497Smm 2408227497Smm for (c = 0; c < children; c++) { 2409227497Smm uint64_t islog = B_FALSE; 2410227497Smm (void) nvlist_lookup_uint64(newchild[c], 2411227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2412227497Smm 2413227497Smm if (islog) { 2414227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2415227497Smm B_FALSE); 2416227497Smm print_vdev_stats(zhp, vname, oldnv ? 2417227497Smm oldchild[c] : NULL, newchild[c], 2418227497Smm cb, depth + 2); 2419227497Smm free(vname); 2420227497Smm } 2421227497Smm } 2422227497Smm 2423227497Smm } 2424227497Smm 2425227497Smm /* 2426185029Spjd * Include level 2 ARC devices in iostat output 2427185029Spjd */ 2428185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2429185029Spjd &newchild, &children) != 0) 2430185029Spjd return; 2431185029Spjd 2432185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2433185029Spjd &oldchild, &c) != 0) 2434185029Spjd return; 2435185029Spjd 2436185029Spjd if (children > 0) { 2437185029Spjd (void) printf("%-*s - - - - - " 2438185029Spjd "-\n", cb->cb_namewidth, "cache"); 2439185029Spjd for (c = 0; c < children; c++) { 2440219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2441219089Spjd B_FALSE); 2442185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2443185029Spjd newchild[c], cb, depth + 2); 2444185029Spjd free(vname); 2445185029Spjd } 2446185029Spjd } 2447168404Spjd} 2448168404Spjd 2449168404Spjdstatic int 2450168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2451168404Spjd{ 2452168404Spjd iostat_cbdata_t *cb = data; 2453168404Spjd boolean_t missing; 2454168404Spjd 2455168404Spjd /* 2456168404Spjd * If the pool has disappeared, remove it from the list and continue. 2457168404Spjd */ 2458168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2459168404Spjd return (-1); 2460168404Spjd 2461168404Spjd if (missing) 2462168404Spjd pool_list_remove(cb->cb_list, zhp); 2463168404Spjd 2464168404Spjd return (0); 2465168404Spjd} 2466168404Spjd 2467168404Spjd/* 2468168404Spjd * Callback to print out the iostats for the given pool. 2469168404Spjd */ 2470168404Spjdint 2471168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2472168404Spjd{ 2473168404Spjd iostat_cbdata_t *cb = data; 2474168404Spjd nvlist_t *oldconfig, *newconfig; 2475168404Spjd nvlist_t *oldnvroot, *newnvroot; 2476168404Spjd 2477168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2478168404Spjd 2479168404Spjd if (cb->cb_iteration == 1) 2480168404Spjd oldconfig = NULL; 2481168404Spjd 2482168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2483168404Spjd &newnvroot) == 0); 2484168404Spjd 2485168404Spjd if (oldconfig == NULL) 2486168404Spjd oldnvroot = NULL; 2487168404Spjd else 2488168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2489168404Spjd &oldnvroot) == 0); 2490168404Spjd 2491168404Spjd /* 2492168404Spjd * Print out the statistics for the pool. 2493168404Spjd */ 2494168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2495168404Spjd 2496168404Spjd if (cb->cb_verbose) 2497168404Spjd print_iostat_separator(cb); 2498168404Spjd 2499168404Spjd return (0); 2500168404Spjd} 2501168404Spjd 2502168404Spjdint 2503168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2504168404Spjd{ 2505168404Spjd iostat_cbdata_t *cb = data; 2506168404Spjd nvlist_t *config, *nvroot; 2507168404Spjd 2508168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2509168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2510168404Spjd &nvroot) == 0); 2511168404Spjd if (!cb->cb_verbose) 2512168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2513168404Spjd else 2514236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2515236145Smm cb->cb_namewidth); 2516168404Spjd } 2517168404Spjd 2518168404Spjd /* 2519168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2520168404Spjd * maximum we can have and still fit in 80 columns. 2521168404Spjd */ 2522168404Spjd if (cb->cb_namewidth < 10) 2523168404Spjd cb->cb_namewidth = 10; 2524168404Spjd if (cb->cb_namewidth > 38) 2525168404Spjd cb->cb_namewidth = 38; 2526168404Spjd 2527168404Spjd return (0); 2528168404Spjd} 2529168404Spjd 2530168404Spjd/* 2531219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2532168404Spjd */ 2533219089Spjdstatic void 2534219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2535219089Spjd unsigned long *cnt) 2536168404Spjd{ 2537168404Spjd unsigned long interval = 0, count = 0; 2538219089Spjd int argc = *argcp, errno; 2539168404Spjd 2540168404Spjd /* 2541168404Spjd * Determine if the last argument is an integer or a pool name 2542168404Spjd */ 2543168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2544168404Spjd char *end; 2545168404Spjd 2546168404Spjd errno = 0; 2547168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2548168404Spjd 2549168404Spjd if (*end == '\0' && errno == 0) { 2550168404Spjd if (interval == 0) { 2551168404Spjd (void) fprintf(stderr, gettext("interval " 2552168404Spjd "cannot be zero\n")); 2553168404Spjd usage(B_FALSE); 2554168404Spjd } 2555168404Spjd /* 2556168404Spjd * Ignore the last parameter 2557168404Spjd */ 2558168404Spjd argc--; 2559168404Spjd } else { 2560168404Spjd /* 2561168404Spjd * If this is not a valid number, just plow on. The 2562168404Spjd * user will get a more informative error message later 2563168404Spjd * on. 2564168404Spjd */ 2565168404Spjd interval = 0; 2566168404Spjd } 2567168404Spjd } 2568168404Spjd 2569168404Spjd /* 2570168404Spjd * If the last argument is also an integer, then we have both a count 2571219089Spjd * and an interval. 2572168404Spjd */ 2573168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2574168404Spjd char *end; 2575168404Spjd 2576168404Spjd errno = 0; 2577168404Spjd count = interval; 2578168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2579168404Spjd 2580168404Spjd if (*end == '\0' && errno == 0) { 2581168404Spjd if (interval == 0) { 2582168404Spjd (void) fprintf(stderr, gettext("interval " 2583168404Spjd "cannot be zero\n")); 2584168404Spjd usage(B_FALSE); 2585168404Spjd } 2586168404Spjd 2587168404Spjd /* 2588168404Spjd * Ignore the last parameter 2589168404Spjd */ 2590168404Spjd argc--; 2591168404Spjd } else { 2592168404Spjd interval = 0; 2593168404Spjd } 2594168404Spjd } 2595168404Spjd 2596219089Spjd *iv = interval; 2597219089Spjd *cnt = count; 2598219089Spjd *argcp = argc; 2599219089Spjd} 2600219089Spjd 2601219089Spjdstatic void 2602219089Spjdget_timestamp_arg(char c) 2603219089Spjd{ 2604219089Spjd if (c == 'u') 2605219089Spjd timestamp_fmt = UDATE; 2606219089Spjd else if (c == 'd') 2607219089Spjd timestamp_fmt = DDATE; 2608219089Spjd else 2609219089Spjd usage(B_FALSE); 2610219089Spjd} 2611219089Spjd 2612219089Spjd/* 2613219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2614219089Spjd * 2615219089Spjd * -v Display statistics for individual vdevs 2616219089Spjd * -T Display a timestamp in date(1) or Unix format 2617219089Spjd * 2618219089Spjd * This command can be tricky because we want to be able to deal with pool 2619219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2620219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2621219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2622219089Spjd * changes are all handled within libzfs. 2623219089Spjd */ 2624219089Spjdint 2625219089Spjdzpool_do_iostat(int argc, char **argv) 2626219089Spjd{ 2627219089Spjd int c; 2628219089Spjd int ret; 2629219089Spjd int npools; 2630219089Spjd unsigned long interval = 0, count = 0; 2631219089Spjd zpool_list_t *list; 2632219089Spjd boolean_t verbose = B_FALSE; 2633219089Spjd iostat_cbdata_t cb; 2634219089Spjd 2635219089Spjd /* check options */ 2636219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2637219089Spjd switch (c) { 2638219089Spjd case 'T': 2639219089Spjd get_timestamp_arg(*optarg); 2640219089Spjd break; 2641219089Spjd case 'v': 2642219089Spjd verbose = B_TRUE; 2643219089Spjd break; 2644219089Spjd case '?': 2645219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2646219089Spjd optopt); 2647219089Spjd usage(B_FALSE); 2648219089Spjd } 2649219089Spjd } 2650219089Spjd 2651219089Spjd argc -= optind; 2652219089Spjd argv += optind; 2653219089Spjd 2654219089Spjd get_interval_count(&argc, argv, &interval, &count); 2655219089Spjd 2656168404Spjd /* 2657168404Spjd * Construct the list of all interesting pools. 2658168404Spjd */ 2659168404Spjd ret = 0; 2660168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2661168404Spjd return (1); 2662168404Spjd 2663168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2664168404Spjd pool_list_free(list); 2665168404Spjd return (1); 2666168404Spjd } 2667168404Spjd 2668168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2669168404Spjd pool_list_free(list); 2670168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2671168404Spjd return (1); 2672168404Spjd } 2673168404Spjd 2674168404Spjd /* 2675168404Spjd * Enter the main iostat loop. 2676168404Spjd */ 2677168404Spjd cb.cb_list = list; 2678168404Spjd cb.cb_verbose = verbose; 2679168404Spjd cb.cb_iteration = 0; 2680168404Spjd cb.cb_namewidth = 0; 2681168404Spjd 2682168404Spjd for (;;) { 2683168404Spjd pool_list_update(list); 2684168404Spjd 2685168404Spjd if ((npools = pool_list_count(list)) == 0) 2686168404Spjd break; 2687168404Spjd 2688168404Spjd /* 2689168404Spjd * Refresh all statistics. This is done as an explicit step 2690168404Spjd * before calculating the maximum name width, so that any 2691168404Spjd * configuration changes are properly accounted for. 2692168404Spjd */ 2693168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2694168404Spjd 2695168404Spjd /* 2696168404Spjd * Iterate over all pools to determine the maximum width 2697168404Spjd * for the pool / device name column across all pools. 2698168404Spjd */ 2699168404Spjd cb.cb_namewidth = 0; 2700168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2701168404Spjd 2702219089Spjd if (timestamp_fmt != NODATE) 2703219089Spjd print_timestamp(timestamp_fmt); 2704219089Spjd 2705168404Spjd /* 2706168404Spjd * If it's the first time, or verbose mode, print the header. 2707168404Spjd */ 2708168404Spjd if (++cb.cb_iteration == 1 || verbose) 2709168404Spjd print_iostat_header(&cb); 2710168404Spjd 2711168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2712168404Spjd 2713168404Spjd /* 2714168404Spjd * If there's more than one pool, and we're not in verbose mode 2715168404Spjd * (which prints a separator for us), then print a separator. 2716168404Spjd */ 2717168404Spjd if (npools > 1 && !verbose) 2718168404Spjd print_iostat_separator(&cb); 2719168404Spjd 2720168404Spjd if (verbose) 2721168404Spjd (void) printf("\n"); 2722168404Spjd 2723168404Spjd /* 2724168404Spjd * Flush the output so that redirection to a file isn't buffered 2725168404Spjd * indefinitely. 2726168404Spjd */ 2727168404Spjd (void) fflush(stdout); 2728168404Spjd 2729168404Spjd if (interval == 0) 2730168404Spjd break; 2731168404Spjd 2732168404Spjd if (count != 0 && --count == 0) 2733168404Spjd break; 2734168404Spjd 2735168404Spjd (void) sleep(interval); 2736168404Spjd } 2737168404Spjd 2738168404Spjd pool_list_free(list); 2739168404Spjd 2740168404Spjd return (ret); 2741168404Spjd} 2742168404Spjd 2743168404Spjdtypedef struct list_cbdata { 2744236155Smm boolean_t cb_verbose; 2745236155Smm int cb_namewidth; 2746168404Spjd boolean_t cb_scripted; 2747185029Spjd zprop_list_t *cb_proplist; 2748168404Spjd} list_cbdata_t; 2749168404Spjd 2750168404Spjd/* 2751168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2752168404Spjd */ 2753185029Spjdstatic void 2754236155Smmprint_header(list_cbdata_t *cb) 2755168404Spjd{ 2756236155Smm zprop_list_t *pl = cb->cb_proplist; 2757236884Smm char headerbuf[ZPOOL_MAXPROPLEN]; 2758185029Spjd const char *header; 2759185029Spjd boolean_t first = B_TRUE; 2760185029Spjd boolean_t right_justify; 2761236155Smm size_t width = 0; 2762168404Spjd 2763185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2764236155Smm width = pl->pl_width; 2765236155Smm if (first && cb->cb_verbose) { 2766236155Smm /* 2767236155Smm * Reset the width to accommodate the verbose listing 2768236155Smm * of devices. 2769236155Smm */ 2770236155Smm width = cb->cb_namewidth; 2771236155Smm } 2772236155Smm 2773185029Spjd if (!first) 2774168404Spjd (void) printf(" "); 2775168404Spjd else 2776185029Spjd first = B_FALSE; 2777168404Spjd 2778236884Smm right_justify = B_FALSE; 2779236884Smm if (pl->pl_prop != ZPROP_INVAL) { 2780236884Smm header = zpool_prop_column_name(pl->pl_prop); 2781236884Smm right_justify = zpool_prop_align_right(pl->pl_prop); 2782236884Smm } else { 2783236884Smm int i; 2784185029Spjd 2785236884Smm for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2786236884Smm headerbuf[i] = toupper(pl->pl_user_prop[i]); 2787236884Smm headerbuf[i] = '\0'; 2788236884Smm header = headerbuf; 2789236884Smm } 2790236884Smm 2791185029Spjd if (pl->pl_next == NULL && !right_justify) 2792185029Spjd (void) printf("%s", header); 2793185029Spjd else if (right_justify) 2794236155Smm (void) printf("%*s", width, header); 2795185029Spjd else 2796236155Smm (void) printf("%-*s", width, header); 2797236155Smm 2798168404Spjd } 2799168404Spjd 2800168404Spjd (void) printf("\n"); 2801168404Spjd} 2802168404Spjd 2803185029Spjd/* 2804185029Spjd * Given a pool and a list of properties, print out all the properties according 2805185029Spjd * to the described layout. 2806185029Spjd */ 2807185029Spjdstatic void 2808236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 2809168404Spjd{ 2810236155Smm zprop_list_t *pl = cb->cb_proplist; 2811185029Spjd boolean_t first = B_TRUE; 2812185029Spjd char property[ZPOOL_MAXPROPLEN]; 2813185029Spjd char *propstr; 2814185029Spjd boolean_t right_justify; 2815236155Smm size_t width; 2816168404Spjd 2817185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2818236155Smm 2819236155Smm width = pl->pl_width; 2820236155Smm if (first && cb->cb_verbose) { 2821236155Smm /* 2822236155Smm * Reset the width to accommodate the verbose listing 2823236155Smm * of devices. 2824236155Smm */ 2825236155Smm width = cb->cb_namewidth; 2826236155Smm } 2827236155Smm 2828185029Spjd if (!first) { 2829236155Smm if (cb->cb_scripted) 2830168404Spjd (void) printf("\t"); 2831168404Spjd else 2832168404Spjd (void) printf(" "); 2833185029Spjd } else { 2834185029Spjd first = B_FALSE; 2835168404Spjd } 2836168404Spjd 2837185029Spjd right_justify = B_FALSE; 2838185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2839236155Smm if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ && 2840236155Smm zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0) 2841236155Smm propstr = "-"; 2842236155Smm else if (zpool_get_prop(zhp, pl->pl_prop, property, 2843185029Spjd sizeof (property), NULL) != 0) 2844185029Spjd propstr = "-"; 2845168404Spjd else 2846185029Spjd propstr = property; 2847168404Spjd 2848185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2849236884Smm } else if ((zpool_prop_feature(pl->pl_user_prop) || 2850236884Smm zpool_prop_unsupported(pl->pl_user_prop)) && 2851236884Smm zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 2852236884Smm sizeof (property)) == 0) { 2853236884Smm propstr = property; 2854185029Spjd } else { 2855185029Spjd propstr = "-"; 2856185029Spjd } 2857168404Spjd 2858168404Spjd 2859185029Spjd /* 2860185029Spjd * If this is being called in scripted mode, or if this is the 2861185029Spjd * last column and it is left-justified, don't include a width 2862185029Spjd * format specifier. 2863185029Spjd */ 2864236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 2865185029Spjd (void) printf("%s", propstr); 2866185029Spjd else if (right_justify) 2867185029Spjd (void) printf("%*s", width, propstr); 2868185029Spjd else 2869185029Spjd (void) printf("%-*s", width, propstr); 2870185029Spjd } 2871168404Spjd 2872185029Spjd (void) printf("\n"); 2873185029Spjd} 2874168404Spjd 2875236155Smmstatic void 2876236155Smmprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted) 2877236155Smm{ 2878236155Smm char propval[64]; 2879236155Smm boolean_t fixed; 2880236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 2881236155Smm 2882236155Smm zfs_nicenum(value, propval, sizeof (propval)); 2883236155Smm 2884236155Smm if (prop == ZPOOL_PROP_EXPANDSZ && value == 0) 2885236155Smm (void) strlcpy(propval, "-", sizeof (propval)); 2886236155Smm 2887236155Smm if (scripted) 2888236155Smm (void) printf("\t%s", propval); 2889236155Smm else 2890236155Smm (void) printf(" %*s", width, propval); 2891236155Smm} 2892236155Smm 2893236155Smmvoid 2894236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 2895236155Smm list_cbdata_t *cb, int depth) 2896236155Smm{ 2897236155Smm nvlist_t **child; 2898236155Smm vdev_stat_t *vs; 2899236155Smm uint_t c, children; 2900236155Smm char *vname; 2901236155Smm boolean_t scripted = cb->cb_scripted; 2902236155Smm 2903236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 2904236155Smm (uint64_t **)&vs, &c) == 0); 2905236155Smm 2906236155Smm if (name != NULL) { 2907236155Smm if (scripted) 2908236155Smm (void) printf("\t%s", name); 2909236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 2910236155Smm (void) printf("%*s%s", depth, "", name); 2911236155Smm else 2912236155Smm (void) printf("%*s%s%*s", depth, "", name, 2913236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2914236155Smm 2915236155Smm /* only toplevel vdevs have capacity stats */ 2916236155Smm if (vs->vs_space == 0) { 2917236155Smm if (scripted) 2918236155Smm (void) printf("\t-\t-\t-"); 2919236155Smm else 2920236155Smm (void) printf(" - - -"); 2921236155Smm } else { 2922236155Smm print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, 2923236155Smm scripted); 2924236155Smm print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc, 2925236155Smm scripted); 2926236155Smm print_one_column(ZPOOL_PROP_FREE, 2927236155Smm vs->vs_space - vs->vs_alloc, scripted); 2928236155Smm } 2929236155Smm print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, 2930236155Smm scripted); 2931236155Smm (void) printf("\n"); 2932236155Smm } 2933236155Smm 2934236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2935236155Smm &child, &children) != 0) 2936236155Smm return; 2937236155Smm 2938236155Smm for (c = 0; c < children; c++) { 2939236155Smm uint64_t ishole = B_FALSE; 2940236155Smm 2941236155Smm if (nvlist_lookup_uint64(child[c], 2942236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 2943236155Smm continue; 2944236155Smm 2945236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 2946236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 2947236155Smm free(vname); 2948236155Smm } 2949236155Smm 2950236155Smm /* 2951236155Smm * Include level 2 ARC devices in iostat output 2952236155Smm */ 2953236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 2954236155Smm &child, &children) != 0) 2955236155Smm return; 2956236155Smm 2957236155Smm if (children > 0) { 2958236155Smm (void) printf("%-*s - - - - - " 2959236155Smm "-\n", cb->cb_namewidth, "cache"); 2960236155Smm for (c = 0; c < children; c++) { 2961236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], 2962236155Smm B_FALSE); 2963236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 2964236155Smm free(vname); 2965236155Smm } 2966236155Smm } 2967236155Smm} 2968236155Smm 2969236155Smm 2970185029Spjd/* 2971185029Spjd * Generic callback function to list a pool. 2972185029Spjd */ 2973185029Spjdint 2974185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 2975185029Spjd{ 2976185029Spjd list_cbdata_t *cbp = data; 2977236155Smm nvlist_t *config; 2978236155Smm nvlist_t *nvroot; 2979168404Spjd 2980236155Smm config = zpool_get_config(zhp, NULL); 2981168404Spjd 2982236155Smm print_pool(zhp, cbp); 2983236155Smm if (!cbp->cb_verbose) 2984236155Smm return (0); 2985168404Spjd 2986236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2987236155Smm &nvroot) == 0); 2988236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 2989236155Smm 2990168404Spjd return (0); 2991168404Spjd} 2992168404Spjd 2993168404Spjd/* 2994219089Spjd * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 2995168404Spjd * 2996185029Spjd * -H Scripted mode. Don't display headers, and separate properties 2997185029Spjd * by a single tab. 2998185029Spjd * -o List of properties to display. Defaults to 2999219089Spjd * "name,size,allocated,free,capacity,health,altroot" 3000219089Spjd * -T Display a timestamp in date(1) or Unix format 3001168404Spjd * 3002168404Spjd * List all pools in the system, whether or not they're healthy. Output space 3003168404Spjd * statistics for each one, as well as health status summary. 3004168404Spjd */ 3005168404Spjdint 3006168404Spjdzpool_do_list(int argc, char **argv) 3007168404Spjd{ 3008168404Spjd int c; 3009168404Spjd int ret; 3010168404Spjd list_cbdata_t cb = { 0 }; 3011185029Spjd static char default_props[] = 3012236155Smm "name,size,allocated,free,capacity,dedupratio," 3013236155Smm "health,altroot"; 3014185029Spjd char *props = default_props; 3015219089Spjd unsigned long interval = 0, count = 0; 3016236155Smm zpool_list_t *list; 3017236155Smm boolean_t first = B_TRUE; 3018168404Spjd 3019168404Spjd /* check options */ 3020236155Smm while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) { 3021168404Spjd switch (c) { 3022168404Spjd case 'H': 3023168404Spjd cb.cb_scripted = B_TRUE; 3024168404Spjd break; 3025168404Spjd case 'o': 3026185029Spjd props = optarg; 3027168404Spjd break; 3028219089Spjd case 'T': 3029219089Spjd get_timestamp_arg(*optarg); 3030219089Spjd break; 3031236155Smm case 'v': 3032236155Smm cb.cb_verbose = B_TRUE; 3033236155Smm break; 3034168404Spjd case ':': 3035168404Spjd (void) fprintf(stderr, gettext("missing argument for " 3036168404Spjd "'%c' option\n"), optopt); 3037168404Spjd usage(B_FALSE); 3038168404Spjd break; 3039168404Spjd case '?': 3040168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3041168404Spjd optopt); 3042168404Spjd usage(B_FALSE); 3043168404Spjd } 3044168404Spjd } 3045168404Spjd 3046168404Spjd argc -= optind; 3047168404Spjd argv += optind; 3048168404Spjd 3049219089Spjd get_interval_count(&argc, argv, &interval, &count); 3050219089Spjd 3051185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3052185029Spjd usage(B_FALSE); 3053168404Spjd 3054236155Smm if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL) 3055236155Smm return (1); 3056168404Spjd 3057236155Smm if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3058236155Smm (void) printf(gettext("no pools available\n")); 3059236155Smm zprop_free_list(cb.cb_proplist); 3060236155Smm return (0); 3061236155Smm } 3062236155Smm 3063219089Spjd for (;;) { 3064236155Smm pool_list_update(list); 3065168404Spjd 3066236155Smm if (pool_list_count(list) == 0) 3067236155Smm break; 3068236155Smm 3069236155Smm cb.cb_namewidth = 0; 3070236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3071236155Smm 3072219089Spjd if (timestamp_fmt != NODATE) 3073219089Spjd print_timestamp(timestamp_fmt); 3074168404Spjd 3075236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 3076236155Smm print_header(&cb); 3077236155Smm first = B_FALSE; 3078219089Spjd } 3079236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 3080219089Spjd 3081219089Spjd if (interval == 0) 3082219089Spjd break; 3083219089Spjd 3084219089Spjd if (count != 0 && --count == 0) 3085219089Spjd break; 3086219089Spjd 3087219089Spjd (void) sleep(interval); 3088168404Spjd } 3089168404Spjd 3090219089Spjd zprop_free_list(cb.cb_proplist); 3091168404Spjd return (ret); 3092168404Spjd} 3093168404Spjd 3094168404Spjdstatic nvlist_t * 3095168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name) 3096168404Spjd{ 3097168404Spjd nvlist_t **child; 3098168404Spjd uint_t c, children; 3099168404Spjd nvlist_t *match; 3100168404Spjd char *path; 3101168404Spjd 3102168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 3103168404Spjd &child, &children) != 0) { 3104168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 3105219089Spjd if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 3106219089Spjd name += sizeof(_PATH_DEV) - 1; 3107219089Spjd if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 3108219089Spjd path += sizeof(_PATH_DEV) - 1; 3109168404Spjd if (strcmp(name, path) == 0) 3110168404Spjd return (nv); 3111168404Spjd return (NULL); 3112168404Spjd } 3113168404Spjd 3114168404Spjd for (c = 0; c < children; c++) 3115168404Spjd if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 3116168404Spjd return (match); 3117168404Spjd 3118168404Spjd return (NULL); 3119168404Spjd} 3120168404Spjd 3121168404Spjdstatic int 3122168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 3123168404Spjd{ 3124168404Spjd boolean_t force = B_FALSE; 3125168404Spjd int c; 3126168404Spjd nvlist_t *nvroot; 3127168404Spjd char *poolname, *old_disk, *new_disk; 3128168404Spjd zpool_handle_t *zhp; 3129168404Spjd int ret; 3130168404Spjd 3131168404Spjd /* check options */ 3132168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3133168404Spjd switch (c) { 3134168404Spjd case 'f': 3135168404Spjd force = B_TRUE; 3136168404Spjd break; 3137168404Spjd case '?': 3138168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3139168404Spjd optopt); 3140168404Spjd usage(B_FALSE); 3141168404Spjd } 3142168404Spjd } 3143168404Spjd 3144168404Spjd argc -= optind; 3145168404Spjd argv += optind; 3146168404Spjd 3147168404Spjd /* get pool name and check number of arguments */ 3148168404Spjd if (argc < 1) { 3149168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3150168404Spjd usage(B_FALSE); 3151168404Spjd } 3152168404Spjd 3153168404Spjd poolname = argv[0]; 3154168404Spjd 3155168404Spjd if (argc < 2) { 3156168404Spjd (void) fprintf(stderr, 3157168404Spjd gettext("missing <device> specification\n")); 3158168404Spjd usage(B_FALSE); 3159168404Spjd } 3160168404Spjd 3161168404Spjd old_disk = argv[1]; 3162168404Spjd 3163168404Spjd if (argc < 3) { 3164168404Spjd if (!replacing) { 3165168404Spjd (void) fprintf(stderr, 3166168404Spjd gettext("missing <new_device> specification\n")); 3167168404Spjd usage(B_FALSE); 3168168404Spjd } 3169168404Spjd new_disk = old_disk; 3170168404Spjd argc -= 1; 3171168404Spjd argv += 1; 3172168404Spjd } else { 3173168404Spjd new_disk = argv[2]; 3174168404Spjd argc -= 2; 3175168404Spjd argv += 2; 3176168404Spjd } 3177168404Spjd 3178168404Spjd if (argc > 1) { 3179168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3180168404Spjd usage(B_FALSE); 3181168404Spjd } 3182168404Spjd 3183168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3184168404Spjd return (1); 3185168404Spjd 3186185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3187168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3188168404Spjd poolname); 3189168404Spjd zpool_close(zhp); 3190168404Spjd return (1); 3191168404Spjd } 3192168404Spjd 3193185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3194185029Spjd argc, argv); 3195168404Spjd if (nvroot == NULL) { 3196168404Spjd zpool_close(zhp); 3197168404Spjd return (1); 3198168404Spjd } 3199168404Spjd 3200168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3201168404Spjd 3202168404Spjd nvlist_free(nvroot); 3203168404Spjd zpool_close(zhp); 3204168404Spjd 3205168404Spjd return (ret); 3206168404Spjd} 3207168404Spjd 3208168404Spjd/* 3209168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3210168404Spjd * 3211168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3212168404Spjd * 3213168404Spjd * Replace <device> with <new_device>. 3214168404Spjd */ 3215168404Spjd/* ARGSUSED */ 3216168404Spjdint 3217168404Spjdzpool_do_replace(int argc, char **argv) 3218168404Spjd{ 3219168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3220168404Spjd} 3221168404Spjd 3222168404Spjd/* 3223168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3224168404Spjd * 3225168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3226168404Spjd * 3227168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3228168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3229168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3230168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3231168404Spjd */ 3232168404Spjdint 3233168404Spjdzpool_do_attach(int argc, char **argv) 3234168404Spjd{ 3235168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3236168404Spjd} 3237168404Spjd 3238168404Spjd/* 3239168404Spjd * zpool detach [-f] <pool> <device> 3240168404Spjd * 3241168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3242168404Spjd * (not supported yet) 3243168404Spjd * 3244168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3245168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3246168404Spjd * has the only valid copy of some data. 3247168404Spjd */ 3248168404Spjd/* ARGSUSED */ 3249168404Spjdint 3250168404Spjdzpool_do_detach(int argc, char **argv) 3251168404Spjd{ 3252168404Spjd int c; 3253168404Spjd char *poolname, *path; 3254168404Spjd zpool_handle_t *zhp; 3255168404Spjd int ret; 3256168404Spjd 3257168404Spjd /* check options */ 3258168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3259168404Spjd switch (c) { 3260168404Spjd case 'f': 3261168404Spjd case '?': 3262168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3263168404Spjd optopt); 3264168404Spjd usage(B_FALSE); 3265168404Spjd } 3266168404Spjd } 3267168404Spjd 3268168404Spjd argc -= optind; 3269168404Spjd argv += optind; 3270168404Spjd 3271168404Spjd /* get pool name and check number of arguments */ 3272168404Spjd if (argc < 1) { 3273168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3274168404Spjd usage(B_FALSE); 3275168404Spjd } 3276168404Spjd 3277168404Spjd if (argc < 2) { 3278168404Spjd (void) fprintf(stderr, 3279168404Spjd gettext("missing <device> specification\n")); 3280168404Spjd usage(B_FALSE); 3281168404Spjd } 3282168404Spjd 3283168404Spjd poolname = argv[0]; 3284168404Spjd path = argv[1]; 3285168404Spjd 3286168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3287168404Spjd return (1); 3288168404Spjd 3289168404Spjd ret = zpool_vdev_detach(zhp, path); 3290168404Spjd 3291168404Spjd zpool_close(zhp); 3292168404Spjd 3293168404Spjd return (ret); 3294168404Spjd} 3295168404Spjd 3296168404Spjd/* 3297219089Spjd * zpool split [-n] [-o prop=val] ... 3298219089Spjd * [-o mntopt] ... 3299219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3300219089Spjd * 3301219089Spjd * -n Do not split the pool, but display the resulting layout if 3302219089Spjd * it were to be split. 3303219089Spjd * -o Set property=value, or set mount options. 3304219089Spjd * -R Mount the split-off pool under an alternate root. 3305219089Spjd * 3306219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3307219089Spjd * off may be listed, provided that no more than one device is specified 3308219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3309219089Spjd * state unless -R is specified. 3310219089Spjd * 3311219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3312219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3313219089Spjd * undergoing a resilvering operation. 3314219089Spjd */ 3315219089Spjdint 3316219089Spjdzpool_do_split(int argc, char **argv) 3317219089Spjd{ 3318219089Spjd char *srcpool, *newpool, *propval; 3319219089Spjd char *mntopts = NULL; 3320219089Spjd splitflags_t flags; 3321219089Spjd int c, ret = 0; 3322219089Spjd zpool_handle_t *zhp; 3323219089Spjd nvlist_t *config, *props = NULL; 3324219089Spjd 3325219089Spjd flags.dryrun = B_FALSE; 3326219089Spjd flags.import = B_FALSE; 3327219089Spjd 3328219089Spjd /* check options */ 3329219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3330219089Spjd switch (c) { 3331219089Spjd case 'R': 3332219089Spjd flags.import = B_TRUE; 3333219089Spjd if (add_prop_list( 3334219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3335219089Spjd &props, B_TRUE) != 0) { 3336219089Spjd if (props) 3337219089Spjd nvlist_free(props); 3338219089Spjd usage(B_FALSE); 3339219089Spjd } 3340219089Spjd break; 3341219089Spjd case 'n': 3342219089Spjd flags.dryrun = B_TRUE; 3343219089Spjd break; 3344219089Spjd case 'o': 3345219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3346219089Spjd *propval = '\0'; 3347219089Spjd propval++; 3348219089Spjd if (add_prop_list(optarg, propval, 3349219089Spjd &props, B_TRUE) != 0) { 3350219089Spjd if (props) 3351219089Spjd nvlist_free(props); 3352219089Spjd usage(B_FALSE); 3353219089Spjd } 3354219089Spjd } else { 3355219089Spjd mntopts = optarg; 3356219089Spjd } 3357219089Spjd break; 3358219089Spjd case ':': 3359219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3360219089Spjd "'%c' option\n"), optopt); 3361219089Spjd usage(B_FALSE); 3362219089Spjd break; 3363219089Spjd case '?': 3364219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3365219089Spjd optopt); 3366219089Spjd usage(B_FALSE); 3367219089Spjd break; 3368219089Spjd } 3369219089Spjd } 3370219089Spjd 3371219089Spjd if (!flags.import && mntopts != NULL) { 3372219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3373219089Spjd "valid when importing the pool\n")); 3374219089Spjd usage(B_FALSE); 3375219089Spjd } 3376219089Spjd 3377219089Spjd argc -= optind; 3378219089Spjd argv += optind; 3379219089Spjd 3380219089Spjd if (argc < 1) { 3381219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3382219089Spjd usage(B_FALSE); 3383219089Spjd } 3384219089Spjd if (argc < 2) { 3385219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3386219089Spjd usage(B_FALSE); 3387219089Spjd } 3388219089Spjd 3389219089Spjd srcpool = argv[0]; 3390219089Spjd newpool = argv[1]; 3391219089Spjd 3392219089Spjd argc -= 2; 3393219089Spjd argv += 2; 3394219089Spjd 3395219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3396219089Spjd return (1); 3397219089Spjd 3398219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3399219089Spjd if (config == NULL) { 3400219089Spjd ret = 1; 3401219089Spjd } else { 3402219089Spjd if (flags.dryrun) { 3403219089Spjd (void) printf(gettext("would create '%s' with the " 3404219089Spjd "following layout:\n\n"), newpool); 3405219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3406219089Spjd } 3407219089Spjd nvlist_free(config); 3408219089Spjd } 3409219089Spjd 3410219089Spjd zpool_close(zhp); 3411219089Spjd 3412219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3413219089Spjd return (ret); 3414219089Spjd 3415219089Spjd /* 3416219089Spjd * The split was successful. Now we need to open the new 3417219089Spjd * pool and import it. 3418219089Spjd */ 3419219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3420219089Spjd return (1); 3421219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3422219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3423219089Spjd ret = 1; 3424240415Smm (void) fprintf(stderr, gettext("Split was successful, but " 3425219089Spjd "the datasets could not all be mounted\n")); 3426219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3427219089Spjd "different altroot\n"), "zpool import"); 3428219089Spjd } 3429219089Spjd zpool_close(zhp); 3430219089Spjd 3431219089Spjd return (ret); 3432219089Spjd} 3433219089Spjd 3434219089Spjd 3435219089Spjd 3436219089Spjd/* 3437168404Spjd * zpool online <pool> <device> ... 3438168404Spjd */ 3439168404Spjdint 3440168404Spjdzpool_do_online(int argc, char **argv) 3441168404Spjd{ 3442168404Spjd int c, i; 3443168404Spjd char *poolname; 3444168404Spjd zpool_handle_t *zhp; 3445168404Spjd int ret = 0; 3446185029Spjd vdev_state_t newstate; 3447219089Spjd int flags = 0; 3448168404Spjd 3449168404Spjd /* check options */ 3450219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3451168404Spjd switch (c) { 3452219089Spjd case 'e': 3453219089Spjd flags |= ZFS_ONLINE_EXPAND; 3454219089Spjd break; 3455168404Spjd case 't': 3456168404Spjd case '?': 3457168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3458168404Spjd optopt); 3459168404Spjd usage(B_FALSE); 3460168404Spjd } 3461168404Spjd } 3462168404Spjd 3463168404Spjd argc -= optind; 3464168404Spjd argv += optind; 3465168404Spjd 3466168404Spjd /* get pool name and check number of arguments */ 3467168404Spjd if (argc < 1) { 3468168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3469168404Spjd usage(B_FALSE); 3470168404Spjd } 3471168404Spjd if (argc < 2) { 3472168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3473168404Spjd usage(B_FALSE); 3474168404Spjd } 3475168404Spjd 3476168404Spjd poolname = argv[0]; 3477168404Spjd 3478168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3479168404Spjd return (1); 3480168404Spjd 3481185029Spjd for (i = 1; i < argc; i++) { 3482219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3483185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3484185029Spjd (void) printf(gettext("warning: device '%s' " 3485185029Spjd "onlined, but remains in faulted state\n"), 3486185029Spjd argv[i]); 3487185029Spjd if (newstate == VDEV_STATE_FAULTED) 3488185029Spjd (void) printf(gettext("use 'zpool " 3489185029Spjd "clear' to restore a faulted " 3490185029Spjd "device\n")); 3491185029Spjd else 3492185029Spjd (void) printf(gettext("use 'zpool " 3493185029Spjd "replace' to replace devices " 3494185029Spjd "that are no longer present\n")); 3495185029Spjd } 3496185029Spjd } else { 3497168404Spjd ret = 1; 3498185029Spjd } 3499185029Spjd } 3500168404Spjd 3501168404Spjd zpool_close(zhp); 3502168404Spjd 3503168404Spjd return (ret); 3504168404Spjd} 3505168404Spjd 3506168404Spjd/* 3507168404Spjd * zpool offline [-ft] <pool> <device> ... 3508168404Spjd * 3509168404Spjd * -f Force the device into the offline state, even if doing 3510168404Spjd * so would appear to compromise pool availability. 3511168404Spjd * (not supported yet) 3512168404Spjd * 3513168404Spjd * -t Only take the device off-line temporarily. The offline 3514168404Spjd * state will not be persistent across reboots. 3515168404Spjd */ 3516168404Spjd/* ARGSUSED */ 3517168404Spjdint 3518168404Spjdzpool_do_offline(int argc, char **argv) 3519168404Spjd{ 3520168404Spjd int c, i; 3521168404Spjd char *poolname; 3522168404Spjd zpool_handle_t *zhp; 3523168404Spjd int ret = 0; 3524168404Spjd boolean_t istmp = B_FALSE; 3525168404Spjd 3526168404Spjd /* check options */ 3527168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3528168404Spjd switch (c) { 3529168404Spjd case 't': 3530168404Spjd istmp = B_TRUE; 3531168404Spjd break; 3532168404Spjd case 'f': 3533168404Spjd case '?': 3534168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3535168404Spjd optopt); 3536168404Spjd usage(B_FALSE); 3537168404Spjd } 3538168404Spjd } 3539168404Spjd 3540168404Spjd argc -= optind; 3541168404Spjd argv += optind; 3542168404Spjd 3543168404Spjd /* get pool name and check number of arguments */ 3544168404Spjd if (argc < 1) { 3545168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3546168404Spjd usage(B_FALSE); 3547168404Spjd } 3548168404Spjd if (argc < 2) { 3549168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3550168404Spjd usage(B_FALSE); 3551168404Spjd } 3552168404Spjd 3553168404Spjd poolname = argv[0]; 3554168404Spjd 3555168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3556168404Spjd return (1); 3557168404Spjd 3558185029Spjd for (i = 1; i < argc; i++) { 3559185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3560168404Spjd ret = 1; 3561185029Spjd } 3562168404Spjd 3563168404Spjd zpool_close(zhp); 3564168404Spjd 3565168404Spjd return (ret); 3566168404Spjd} 3567168404Spjd 3568168404Spjd/* 3569168404Spjd * zpool clear <pool> [device] 3570168404Spjd * 3571168404Spjd * Clear all errors associated with a pool or a particular device. 3572168404Spjd */ 3573168404Spjdint 3574168404Spjdzpool_do_clear(int argc, char **argv) 3575168404Spjd{ 3576219089Spjd int c; 3577168404Spjd int ret = 0; 3578219089Spjd boolean_t dryrun = B_FALSE; 3579219089Spjd boolean_t do_rewind = B_FALSE; 3580219089Spjd boolean_t xtreme_rewind = B_FALSE; 3581219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3582219089Spjd nvlist_t *policy = NULL; 3583168404Spjd zpool_handle_t *zhp; 3584168404Spjd char *pool, *device; 3585168404Spjd 3586219089Spjd /* check options */ 3587219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3588219089Spjd switch (c) { 3589219089Spjd case 'F': 3590219089Spjd do_rewind = B_TRUE; 3591219089Spjd break; 3592219089Spjd case 'n': 3593219089Spjd dryrun = B_TRUE; 3594219089Spjd break; 3595219089Spjd case 'X': 3596219089Spjd xtreme_rewind = B_TRUE; 3597219089Spjd break; 3598219089Spjd case '?': 3599219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3600219089Spjd optopt); 3601219089Spjd usage(B_FALSE); 3602219089Spjd } 3603219089Spjd } 3604219089Spjd 3605219089Spjd argc -= optind; 3606219089Spjd argv += optind; 3607219089Spjd 3608219089Spjd if (argc < 1) { 3609168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3610168404Spjd usage(B_FALSE); 3611168404Spjd } 3612168404Spjd 3613219089Spjd if (argc > 2) { 3614168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3615168404Spjd usage(B_FALSE); 3616168404Spjd } 3617168404Spjd 3618219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3619219089Spjd (void) fprintf(stderr, 3620219089Spjd gettext("-n or -X only meaningful with -F\n")); 3621219089Spjd usage(B_FALSE); 3622219089Spjd } 3623219089Spjd if (dryrun) 3624219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3625219089Spjd else if (do_rewind) 3626219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3627219089Spjd if (xtreme_rewind) 3628219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3629168404Spjd 3630219089Spjd /* In future, further rewind policy choices can be passed along here */ 3631219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3632219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3633168404Spjd return (1); 3634168404Spjd 3635219089Spjd pool = argv[0]; 3636219089Spjd device = argc == 2 ? argv[1] : NULL; 3637219089Spjd 3638219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3639219089Spjd nvlist_free(policy); 3640219089Spjd return (1); 3641219089Spjd } 3642219089Spjd 3643219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3644168404Spjd ret = 1; 3645168404Spjd 3646168404Spjd zpool_close(zhp); 3647168404Spjd 3648219089Spjd nvlist_free(policy); 3649219089Spjd 3650168404Spjd return (ret); 3651168404Spjd} 3652168404Spjd 3653228103Smm/* 3654228103Smm * zpool reguid <pool> 3655228103Smm */ 3656228103Smmint 3657228103Smmzpool_do_reguid(int argc, char **argv) 3658228103Smm{ 3659228103Smm int c; 3660228103Smm char *poolname; 3661228103Smm zpool_handle_t *zhp; 3662228103Smm int ret = 0; 3663228103Smm 3664228103Smm /* check options */ 3665228103Smm while ((c = getopt(argc, argv, "")) != -1) { 3666228103Smm switch (c) { 3667228103Smm case '?': 3668228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3669228103Smm optopt); 3670228103Smm usage(B_FALSE); 3671228103Smm } 3672228103Smm } 3673228103Smm 3674228103Smm argc -= optind; 3675228103Smm argv += optind; 3676228103Smm 3677228103Smm /* get pool name and check number of arguments */ 3678228103Smm if (argc < 1) { 3679228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 3680228103Smm usage(B_FALSE); 3681228103Smm } 3682228103Smm 3683228103Smm if (argc > 1) { 3684228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 3685228103Smm usage(B_FALSE); 3686228103Smm } 3687228103Smm 3688228103Smm poolname = argv[0]; 3689228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3690228103Smm return (1); 3691228103Smm 3692228103Smm ret = zpool_reguid(zhp); 3693228103Smm 3694228103Smm zpool_close(zhp); 3695228103Smm return (ret); 3696228103Smm} 3697228103Smm 3698228103Smm 3699236155Smm/* 3700236155Smm * zpool reopen <pool> 3701236155Smm * 3702236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 3703236155Smm * 3704236155Smm * NOTE: This command is currently undocumented. If the command is ever 3705236155Smm * exposed then the appropriate usage() messages will need to be made. 3706236155Smm */ 3707236155Smmint 3708236155Smmzpool_do_reopen(int argc, char **argv) 3709236155Smm{ 3710236155Smm int ret = 0; 3711236155Smm zpool_handle_t *zhp; 3712236155Smm char *pool; 3713236155Smm 3714236155Smm argc--; 3715236155Smm argv++; 3716236155Smm 3717236155Smm if (argc != 1) 3718236155Smm return (2); 3719236155Smm 3720236155Smm pool = argv[0]; 3721236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 3722236155Smm return (1); 3723236155Smm 3724236155Smm ret = zpool_reopen(zhp); 3725236155Smm zpool_close(zhp); 3726236155Smm return (ret); 3727236155Smm} 3728236155Smm 3729168404Spjdtypedef struct scrub_cbdata { 3730168404Spjd int cb_type; 3731168404Spjd int cb_argc; 3732168404Spjd char **cb_argv; 3733168404Spjd} scrub_cbdata_t; 3734168404Spjd 3735168404Spjdint 3736168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3737168404Spjd{ 3738168404Spjd scrub_cbdata_t *cb = data; 3739168404Spjd int err; 3740168404Spjd 3741168404Spjd /* 3742168404Spjd * Ignore faulted pools. 3743168404Spjd */ 3744168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3745168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3746168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 3747168404Spjd return (1); 3748168404Spjd } 3749168404Spjd 3750219089Spjd err = zpool_scan(zhp, cb->cb_type); 3751168404Spjd 3752168404Spjd return (err != 0); 3753168404Spjd} 3754168404Spjd 3755168404Spjd/* 3756168404Spjd * zpool scrub [-s] <pool> ... 3757168404Spjd * 3758168404Spjd * -s Stop. Stops any in-progress scrub. 3759168404Spjd */ 3760168404Spjdint 3761168404Spjdzpool_do_scrub(int argc, char **argv) 3762168404Spjd{ 3763168404Spjd int c; 3764168404Spjd scrub_cbdata_t cb; 3765168404Spjd 3766219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 3767168404Spjd 3768168404Spjd /* check options */ 3769168404Spjd while ((c = getopt(argc, argv, "s")) != -1) { 3770168404Spjd switch (c) { 3771168404Spjd case 's': 3772219089Spjd cb.cb_type = POOL_SCAN_NONE; 3773168404Spjd break; 3774168404Spjd case '?': 3775168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3776168404Spjd optopt); 3777168404Spjd usage(B_FALSE); 3778168404Spjd } 3779168404Spjd } 3780168404Spjd 3781168404Spjd cb.cb_argc = argc; 3782168404Spjd cb.cb_argv = argv; 3783168404Spjd argc -= optind; 3784168404Spjd argv += optind; 3785168404Spjd 3786168404Spjd if (argc < 1) { 3787168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3788168404Spjd usage(B_FALSE); 3789168404Spjd } 3790168404Spjd 3791168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3792168404Spjd} 3793168404Spjd 3794168404Spjdtypedef struct status_cbdata { 3795168404Spjd int cb_count; 3796168404Spjd boolean_t cb_allpools; 3797168404Spjd boolean_t cb_verbose; 3798168404Spjd boolean_t cb_explain; 3799168404Spjd boolean_t cb_first; 3800219089Spjd boolean_t cb_dedup_stats; 3801168404Spjd} status_cbdata_t; 3802168404Spjd 3803168404Spjd/* 3804168404Spjd * Print out detailed scrub status. 3805168404Spjd */ 3806168404Spjdvoid 3807219089Spjdprint_scan_status(pool_scan_stat_t *ps) 3808168404Spjd{ 3809219089Spjd time_t start, end; 3810219089Spjd uint64_t elapsed, mins_left, hours_left; 3811219089Spjd uint64_t pass_exam, examined, total; 3812219089Spjd uint_t rate; 3813168404Spjd double fraction_done; 3814219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3815168404Spjd 3816226583Spjd (void) printf(gettext(" scan: ")); 3817168404Spjd 3818219089Spjd /* If there's never been a scan, there's not much to say. */ 3819219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 3820219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 3821168404Spjd (void) printf(gettext("none requested\n")); 3822168404Spjd return; 3823168404Spjd } 3824168404Spjd 3825219089Spjd start = ps->pss_start_time; 3826219089Spjd end = ps->pss_end_time; 3827219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3828168404Spjd 3829219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 3830219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 3831219089Spjd /* 3832219089Spjd * Scan is finished or canceled. 3833219089Spjd */ 3834219089Spjd if (ps->pss_state == DSS_FINISHED) { 3835219089Spjd uint64_t minutes_taken = (end - start) / 60; 3836219089Spjd char *fmt; 3837168404Spjd 3838219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3839219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 3840219089Spjd "%llu errors on %s"); 3841219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3842219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 3843219089Spjd "%llu errors on %s"); 3844219089Spjd } 3845219089Spjd /* LINTED */ 3846219089Spjd (void) printf(fmt, processed_buf, 3847185029Spjd (u_longlong_t)(minutes_taken / 60), 3848185029Spjd (uint_t)(minutes_taken % 60), 3849219089Spjd (u_longlong_t)ps->pss_errors, 3850219089Spjd ctime((time_t *)&end)); 3851168404Spjd return; 3852219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 3853219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3854219089Spjd (void) printf(gettext("scrub canceled on %s"), 3855219089Spjd ctime(&end)); 3856219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3857219089Spjd (void) printf(gettext("resilver canceled on %s"), 3858219089Spjd ctime(&end)); 3859219089Spjd } 3860219089Spjd return; 3861168404Spjd } 3862168404Spjd 3863219089Spjd assert(ps->pss_state == DSS_SCANNING); 3864168404Spjd 3865219089Spjd /* 3866219089Spjd * Scan is in progress. 3867219089Spjd */ 3868219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3869219089Spjd (void) printf(gettext("scrub in progress since %s"), 3870219089Spjd ctime(&start)); 3871219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3872219089Spjd (void) printf(gettext("resilver in progress since %s"), 3873219089Spjd ctime(&start)); 3874219089Spjd } 3875219089Spjd 3876219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 3877219089Spjd total = ps->pss_to_examine; 3878168404Spjd fraction_done = (double)examined / total; 3879168404Spjd 3880219089Spjd /* elapsed time for this pass */ 3881219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 3882219089Spjd elapsed = elapsed ? elapsed : 1; 3883219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 3884219089Spjd rate = pass_exam / elapsed; 3885219089Spjd rate = rate ? rate : 1; 3886219089Spjd mins_left = ((total - examined) / rate) / 60; 3887219089Spjd hours_left = mins_left / 60; 3888219089Spjd 3889219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 3890219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 3891219089Spjd zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 3892219089Spjd 3893219089Spjd /* 3894219089Spjd * do not print estimated time if hours_left is more than 30 days 3895219089Spjd */ 3896226583Spjd (void) printf(gettext(" %s scanned out of %s at %s/s"), 3897219089Spjd examined_buf, total_buf, rate_buf); 3898219089Spjd if (hours_left < (30 * 24)) { 3899219089Spjd (void) printf(gettext(", %lluh%um to go\n"), 3900219089Spjd (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 3901219089Spjd } else { 3902219089Spjd (void) printf(gettext( 3903219089Spjd ", (scan is slow, no estimated time)\n")); 3904219089Spjd } 3905219089Spjd 3906219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 3907226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 3908219089Spjd processed_buf, 100 * fraction_done); 3909219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 3910226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 3911219089Spjd processed_buf, 100 * fraction_done); 3912219089Spjd } 3913168404Spjd} 3914168404Spjd 3915168404Spjdstatic void 3916168404Spjdprint_error_log(zpool_handle_t *zhp) 3917168404Spjd{ 3918185029Spjd nvlist_t *nverrlist = NULL; 3919168404Spjd nvpair_t *elem; 3920168404Spjd char *pathname; 3921168404Spjd size_t len = MAXPATHLEN * 2; 3922168404Spjd 3923168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 3924168404Spjd (void) printf("errors: List of errors unavailable " 3925168404Spjd "(insufficient privileges)\n"); 3926168404Spjd return; 3927168404Spjd } 3928168404Spjd 3929168404Spjd (void) printf("errors: Permanent errors have been " 3930168404Spjd "detected in the following files:\n\n"); 3931168404Spjd 3932168404Spjd pathname = safe_malloc(len); 3933168404Spjd elem = NULL; 3934168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 3935168404Spjd nvlist_t *nv; 3936168404Spjd uint64_t dsobj, obj; 3937168404Spjd 3938168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 3939168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 3940168404Spjd &dsobj) == 0); 3941168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 3942168404Spjd &obj) == 0); 3943168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 3944168404Spjd (void) printf("%7s %s\n", "", pathname); 3945168404Spjd } 3946168404Spjd free(pathname); 3947168404Spjd nvlist_free(nverrlist); 3948168404Spjd} 3949168404Spjd 3950168404Spjdstatic void 3951168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 3952168404Spjd int namewidth) 3953168404Spjd{ 3954168404Spjd uint_t i; 3955168404Spjd char *name; 3956168404Spjd 3957168404Spjd if (nspares == 0) 3958168404Spjd return; 3959168404Spjd 3960168404Spjd (void) printf(gettext("\tspares\n")); 3961168404Spjd 3962168404Spjd for (i = 0; i < nspares; i++) { 3963219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 3964168404Spjd print_status_config(zhp, name, spares[i], 3965209962Smm namewidth, 2, B_TRUE); 3966168404Spjd free(name); 3967168404Spjd } 3968168404Spjd} 3969168404Spjd 3970185029Spjdstatic void 3971185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 3972185029Spjd int namewidth) 3973185029Spjd{ 3974185029Spjd uint_t i; 3975185029Spjd char *name; 3976185029Spjd 3977185029Spjd if (nl2cache == 0) 3978185029Spjd return; 3979185029Spjd 3980185029Spjd (void) printf(gettext("\tcache\n")); 3981185029Spjd 3982185029Spjd for (i = 0; i < nl2cache; i++) { 3983219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 3984185029Spjd print_status_config(zhp, name, l2cache[i], 3985209962Smm namewidth, 2, B_FALSE); 3986185029Spjd free(name); 3987185029Spjd } 3988185029Spjd} 3989185029Spjd 3990219089Spjdstatic void 3991219089Spjdprint_dedup_stats(nvlist_t *config) 3992219089Spjd{ 3993219089Spjd ddt_histogram_t *ddh; 3994219089Spjd ddt_stat_t *dds; 3995219089Spjd ddt_object_t *ddo; 3996219089Spjd uint_t c; 3997219089Spjd 3998219089Spjd /* 3999219089Spjd * If the pool was faulted then we may not have been able to 4000253441Sdelphij * obtain the config. Otherwise, if we have anything in the dedup 4001219089Spjd * table continue processing the stats. 4002219089Spjd */ 4003219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 4004227497Smm (uint64_t **)&ddo, &c) != 0) 4005219089Spjd return; 4006219089Spjd 4007219089Spjd (void) printf("\n"); 4008227497Smm (void) printf(gettext(" dedup: ")); 4009227497Smm if (ddo->ddo_count == 0) { 4010227497Smm (void) printf(gettext("no DDT entries\n")); 4011227497Smm return; 4012227497Smm } 4013227497Smm 4014219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 4015219089Spjd (u_longlong_t)ddo->ddo_count, 4016219089Spjd (u_longlong_t)ddo->ddo_dspace, 4017219089Spjd (u_longlong_t)ddo->ddo_mspace); 4018219089Spjd 4019219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 4020219089Spjd (uint64_t **)&dds, &c) == 0); 4021219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 4022219089Spjd (uint64_t **)&ddh, &c) == 0); 4023219089Spjd zpool_dump_ddt(dds, ddh); 4024219089Spjd} 4025219089Spjd 4026168404Spjd/* 4027168404Spjd * Display a summary of pool status. Displays a summary such as: 4028168404Spjd * 4029168404Spjd * pool: tank 4030168404Spjd * status: DEGRADED 4031168404Spjd * reason: One or more devices ... 4032236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 4033168404Spjd * config: 4034168404Spjd * mirror DEGRADED 4035168404Spjd * c1t0d0 OK 4036168404Spjd * c2t0d0 UNAVAIL 4037168404Spjd * 4038168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 4039168404Spjd * option is specified, then we print out error rate information as well. 4040168404Spjd */ 4041168404Spjdint 4042168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 4043168404Spjd{ 4044168404Spjd status_cbdata_t *cbp = data; 4045168404Spjd nvlist_t *config, *nvroot; 4046168404Spjd char *msgid; 4047168404Spjd int reason; 4048168404Spjd const char *health; 4049168404Spjd uint_t c; 4050168404Spjd vdev_stat_t *vs; 4051168404Spjd 4052168404Spjd config = zpool_get_config(zhp, NULL); 4053168404Spjd reason = zpool_get_status(zhp, &msgid); 4054168404Spjd 4055168404Spjd cbp->cb_count++; 4056168404Spjd 4057168404Spjd /* 4058168404Spjd * If we were given 'zpool status -x', only report those pools with 4059168404Spjd * problems. 4060168404Spjd */ 4061248267Smm if (cbp->cb_explain && 4062248267Smm (reason == ZPOOL_STATUS_OK || 4063248267Smm reason == ZPOOL_STATUS_VERSION_OLDER || 4064248267Smm reason == ZPOOL_STATUS_FEAT_DISABLED)) { 4065168404Spjd if (!cbp->cb_allpools) { 4066168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 4067168404Spjd zpool_get_name(zhp)); 4068168404Spjd if (cbp->cb_first) 4069168404Spjd cbp->cb_first = B_FALSE; 4070168404Spjd } 4071168404Spjd return (0); 4072168404Spjd } 4073168404Spjd 4074168404Spjd if (cbp->cb_first) 4075168404Spjd cbp->cb_first = B_FALSE; 4076168404Spjd else 4077168404Spjd (void) printf("\n"); 4078168404Spjd 4079168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 4080168404Spjd &nvroot) == 0); 4081219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 4082168404Spjd (uint64_t **)&vs, &c) == 0); 4083185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4084168404Spjd 4085168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4086168404Spjd (void) printf(gettext(" state: %s\n"), health); 4087168404Spjd 4088168404Spjd switch (reason) { 4089168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 4090168404Spjd (void) printf(gettext("status: One or more devices could not " 4091168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 4092168404Spjd "continue functioning in a degraded state.\n")); 4093168404Spjd (void) printf(gettext("action: Attach the missing device and " 4094168404Spjd "online it using 'zpool online'.\n")); 4095168404Spjd break; 4096168404Spjd 4097168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 4098168404Spjd (void) printf(gettext("status: One or more devices could not " 4099168404Spjd "be opened. There are insufficient\n\treplicas for the " 4100168404Spjd "pool to continue functioning.\n")); 4101168404Spjd (void) printf(gettext("action: Attach the missing device and " 4102168404Spjd "online it using 'zpool online'.\n")); 4103168404Spjd break; 4104168404Spjd 4105168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 4106168404Spjd (void) printf(gettext("status: One or more devices could not " 4107168404Spjd "be used because the label is missing or\n\tinvalid. " 4108168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 4109168404Spjd "functioning in a degraded state.\n")); 4110168404Spjd (void) printf(gettext("action: Replace the device using " 4111168404Spjd "'zpool replace'.\n")); 4112168404Spjd break; 4113168404Spjd 4114168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4115168404Spjd (void) printf(gettext("status: One or more devices could not " 4116168404Spjd "be used because the label is missing \n\tor invalid. " 4117168404Spjd "There are insufficient replicas for the pool to " 4118168404Spjd "continue\n\tfunctioning.\n")); 4119219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4120219089Spjd zpool_get_name(zhp), reason, config); 4121168404Spjd break; 4122168404Spjd 4123168404Spjd case ZPOOL_STATUS_FAILING_DEV: 4124168404Spjd (void) printf(gettext("status: One or more devices has " 4125168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 4126168404Spjd "made to correct the error. Applications are " 4127168404Spjd "unaffected.\n")); 4128168404Spjd (void) printf(gettext("action: Determine if the device needs " 4129168404Spjd "to be replaced, and clear the errors\n\tusing " 4130168404Spjd "'zpool clear' or replace the device with 'zpool " 4131168404Spjd "replace'.\n")); 4132168404Spjd break; 4133168404Spjd 4134168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 4135168404Spjd (void) printf(gettext("status: One or more devices has " 4136168404Spjd "been taken offline by the administrator.\n\tSufficient " 4137168404Spjd "replicas exist for the pool to continue functioning in " 4138168404Spjd "a\n\tdegraded state.\n")); 4139168404Spjd (void) printf(gettext("action: Online the device using " 4140168404Spjd "'zpool online' or replace the device with\n\t'zpool " 4141168404Spjd "replace'.\n")); 4142168404Spjd break; 4143168404Spjd 4144219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 4145219089Spjd (void) printf(gettext("status: One or more devices has " 4146219089Spjd "been removed by the administrator.\n\tSufficient " 4147219089Spjd "replicas exist for the pool to continue functioning in " 4148219089Spjd "a\n\tdegraded state.\n")); 4149219089Spjd (void) printf(gettext("action: Online the device using " 4150219089Spjd "'zpool online' or replace the device with\n\t'zpool " 4151219089Spjd "replace'.\n")); 4152219089Spjd break; 4153219089Spjd 4154168404Spjd case ZPOOL_STATUS_RESILVERING: 4155168404Spjd (void) printf(gettext("status: One or more devices is " 4156168404Spjd "currently being resilvered. The pool will\n\tcontinue " 4157168404Spjd "to function, possibly in a degraded state.\n")); 4158168404Spjd (void) printf(gettext("action: Wait for the resilver to " 4159168404Spjd "complete.\n")); 4160168404Spjd break; 4161168404Spjd 4162168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 4163168404Spjd (void) printf(gettext("status: One or more devices has " 4164168404Spjd "experienced an error resulting in data\n\tcorruption. " 4165168404Spjd "Applications may be affected.\n")); 4166168404Spjd (void) printf(gettext("action: Restore the file in question " 4167168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 4168168404Spjd "backup.\n")); 4169168404Spjd break; 4170168404Spjd 4171168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4172168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4173168404Spjd "and the pool cannot be opened.\n")); 4174219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4175219089Spjd zpool_get_name(zhp), reason, config); 4176168404Spjd break; 4177168404Spjd 4178168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4179238926Smm (void) printf(gettext("status: The pool is formatted using a " 4180238926Smm "legacy on-disk format. The pool can\n\tstill be used, " 4181238926Smm "but some features are unavailable.\n")); 4182168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4183168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 4184238926Smm "be accessible on software that does not support feature\n" 4185238926Smm "\tflags.\n")); 4186168404Spjd break; 4187168404Spjd 4188168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 4189168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 4190168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 4191168404Spjd "be accessed on this system.\n")); 4192168404Spjd (void) printf(gettext("action: Access the pool from a system " 4193168404Spjd "running more recent software, or\n\trestore the pool from " 4194168404Spjd "backup.\n")); 4195168404Spjd break; 4196168404Spjd 4197238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 4198238926Smm (void) printf(gettext("status: Some supported features are not " 4199238926Smm "enabled on the pool. The pool can\n\tstill be used, but " 4200238926Smm "some features are unavailable.\n")); 4201238926Smm (void) printf(gettext("action: Enable all features using " 4202238926Smm "'zpool upgrade'. Once this is done,\n\tthe pool may no " 4203238926Smm "longer be accessible by software that does not support\n\t" 4204243014Smm "the features. See zpool-features(7) for details.\n")); 4205238926Smm break; 4206238926Smm 4207236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 4208236884Smm (void) printf(gettext("status: The pool cannot be accessed on " 4209236884Smm "this system because it uses the\n\tfollowing feature(s) " 4210236884Smm "not supported on this system:\n")); 4211236884Smm zpool_print_unsup_feat(config); 4212236884Smm (void) printf("\n"); 4213236884Smm (void) printf(gettext("action: Access the pool from a system " 4214236884Smm "that supports the required feature(s),\n\tor restore the " 4215236884Smm "pool from backup.\n")); 4216236884Smm break; 4217236884Smm 4218236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4219236884Smm (void) printf(gettext("status: The pool can only be accessed " 4220236884Smm "in read-only mode on this system. It\n\tcannot be " 4221236884Smm "accessed in read-write mode because it uses the " 4222236884Smm "following\n\tfeature(s) not supported on this system:\n")); 4223236884Smm zpool_print_unsup_feat(config); 4224236884Smm (void) printf("\n"); 4225236884Smm (void) printf(gettext("action: The pool cannot be accessed in " 4226236884Smm "read-write mode. Import the pool with\n" 4227236884Smm "\t\"-o readonly=on\", access the pool from a system that " 4228236884Smm "supports the\n\trequired feature(s), or restore the " 4229236884Smm "pool from backup.\n")); 4230236884Smm break; 4231236884Smm 4232185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 4233185029Spjd (void) printf(gettext("status: One or more devices are " 4234185029Spjd "faulted in response to persistent errors.\n\tSufficient " 4235185029Spjd "replicas exist for the pool to continue functioning " 4236185029Spjd "in a\n\tdegraded state.\n")); 4237185029Spjd (void) printf(gettext("action: Replace the faulted device, " 4238185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 4239185029Spjd break; 4240185029Spjd 4241185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 4242185029Spjd (void) printf(gettext("status: One or more devices are " 4243185029Spjd "faulted in response to persistent errors. There are " 4244185029Spjd "insufficient replicas for the pool to\n\tcontinue " 4245185029Spjd "functioning.\n")); 4246185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 4247185029Spjd "from a backup source. Manually marking the device\n" 4248185029Spjd "\trepaired using 'zpool clear' may allow some data " 4249185029Spjd "to be recovered.\n")); 4250185029Spjd break; 4251185029Spjd 4252185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 4253185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 4254185029Spjd (void) printf(gettext("status: One or more devices are " 4255185029Spjd "faulted in response to IO failures.\n")); 4256185029Spjd (void) printf(gettext("action: Make sure the affected devices " 4257185029Spjd "are connected, then run 'zpool clear'.\n")); 4258185029Spjd break; 4259185029Spjd 4260185029Spjd case ZPOOL_STATUS_BAD_LOG: 4261185029Spjd (void) printf(gettext("status: An intent log record " 4262185029Spjd "could not be read.\n" 4263185029Spjd "\tWaiting for adminstrator intervention to fix the " 4264185029Spjd "faulted pool.\n")); 4265185029Spjd (void) printf(gettext("action: Either restore the affected " 4266185029Spjd "device(s) and run 'zpool online',\n" 4267185029Spjd "\tor ignore the intent log records by running " 4268185029Spjd "'zpool clear'.\n")); 4269185029Spjd break; 4270185029Spjd 4271168404Spjd default: 4272168404Spjd /* 4273168404Spjd * The remaining errors can't actually be generated, yet. 4274168404Spjd */ 4275168404Spjd assert(reason == ZPOOL_STATUS_OK); 4276168404Spjd } 4277168404Spjd 4278168404Spjd if (msgid != NULL) 4279236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4280168404Spjd msgid); 4281168404Spjd 4282168404Spjd if (config != NULL) { 4283168404Spjd int namewidth; 4284168404Spjd uint64_t nerr; 4285185029Spjd nvlist_t **spares, **l2cache; 4286185029Spjd uint_t nspares, nl2cache; 4287219089Spjd pool_scan_stat_t *ps = NULL; 4288168404Spjd 4289219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 4290219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 4291219089Spjd print_scan_status(ps); 4292168404Spjd 4293168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 4294168404Spjd if (namewidth < 10) 4295168404Spjd namewidth = 10; 4296168404Spjd 4297168404Spjd (void) printf(gettext("config:\n\n")); 4298168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4299168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4300168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 4301209962Smm namewidth, 0, B_FALSE); 4302209962Smm 4303185029Spjd if (num_logs(nvroot) > 0) 4304213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 4305185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4306185029Spjd &l2cache, &nl2cache) == 0) 4307185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 4308185029Spjd 4309168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 4310168404Spjd &spares, &nspares) == 0) 4311168404Spjd print_spares(zhp, spares, nspares, namewidth); 4312168404Spjd 4313168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4314168404Spjd &nerr) == 0) { 4315168404Spjd nvlist_t *nverrlist = NULL; 4316168404Spjd 4317168404Spjd /* 4318168404Spjd * If the approximate error count is small, get a 4319168404Spjd * precise count by fetching the entire log and 4320168404Spjd * uniquifying the results. 4321168404Spjd */ 4322185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 4323168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 4324168404Spjd nvpair_t *elem; 4325168404Spjd 4326168404Spjd elem = NULL; 4327168404Spjd nerr = 0; 4328168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 4329168404Spjd elem)) != NULL) { 4330168404Spjd nerr++; 4331168404Spjd } 4332168404Spjd } 4333168404Spjd nvlist_free(nverrlist); 4334168404Spjd 4335168404Spjd (void) printf("\n"); 4336168404Spjd 4337168404Spjd if (nerr == 0) 4338168404Spjd (void) printf(gettext("errors: No known data " 4339168404Spjd "errors\n")); 4340168404Spjd else if (!cbp->cb_verbose) 4341168404Spjd (void) printf(gettext("errors: %llu data " 4342168404Spjd "errors, use '-v' for a list\n"), 4343168404Spjd (u_longlong_t)nerr); 4344168404Spjd else 4345168404Spjd print_error_log(zhp); 4346168404Spjd } 4347219089Spjd 4348219089Spjd if (cbp->cb_dedup_stats) 4349219089Spjd print_dedup_stats(config); 4350168404Spjd } else { 4351168404Spjd (void) printf(gettext("config: The configuration cannot be " 4352168404Spjd "determined.\n")); 4353168404Spjd } 4354168404Spjd 4355168404Spjd return (0); 4356168404Spjd} 4357168404Spjd 4358168404Spjd/* 4359219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4360168404Spjd * 4361168404Spjd * -v Display complete error logs 4362168404Spjd * -x Display only pools with potential problems 4363219089Spjd * -D Display dedup status (undocumented) 4364219089Spjd * -T Display a timestamp in date(1) or Unix format 4365168404Spjd * 4366168404Spjd * Describes the health status of all pools or some subset. 4367168404Spjd */ 4368168404Spjdint 4369168404Spjdzpool_do_status(int argc, char **argv) 4370168404Spjd{ 4371168404Spjd int c; 4372168404Spjd int ret; 4373219089Spjd unsigned long interval = 0, count = 0; 4374168404Spjd status_cbdata_t cb = { 0 }; 4375168404Spjd 4376168404Spjd /* check options */ 4377219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4378168404Spjd switch (c) { 4379168404Spjd case 'v': 4380168404Spjd cb.cb_verbose = B_TRUE; 4381168404Spjd break; 4382168404Spjd case 'x': 4383168404Spjd cb.cb_explain = B_TRUE; 4384168404Spjd break; 4385219089Spjd case 'D': 4386219089Spjd cb.cb_dedup_stats = B_TRUE; 4387219089Spjd break; 4388219089Spjd case 'T': 4389219089Spjd get_timestamp_arg(*optarg); 4390219089Spjd break; 4391168404Spjd case '?': 4392168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4393168404Spjd optopt); 4394168404Spjd usage(B_FALSE); 4395168404Spjd } 4396168404Spjd } 4397168404Spjd 4398168404Spjd argc -= optind; 4399168404Spjd argv += optind; 4400168404Spjd 4401219089Spjd get_interval_count(&argc, argv, &interval, &count); 4402168404Spjd 4403168404Spjd if (argc == 0) 4404168404Spjd cb.cb_allpools = B_TRUE; 4405168404Spjd 4406219089Spjd cb.cb_first = B_TRUE; 4407168404Spjd 4408219089Spjd for (;;) { 4409219089Spjd if (timestamp_fmt != NODATE) 4410219089Spjd print_timestamp(timestamp_fmt); 4411168404Spjd 4412219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 4413219089Spjd status_callback, &cb); 4414219089Spjd 4415219089Spjd if (argc == 0 && cb.cb_count == 0) 4416219089Spjd (void) printf(gettext("no pools available\n")); 4417219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 4418219089Spjd (void) printf(gettext("all pools are healthy\n")); 4419219089Spjd 4420219089Spjd if (ret != 0) 4421219089Spjd return (ret); 4422219089Spjd 4423219089Spjd if (interval == 0) 4424219089Spjd break; 4425219089Spjd 4426219089Spjd if (count != 0 && --count == 0) 4427219089Spjd break; 4428219089Spjd 4429219089Spjd (void) sleep(interval); 4430219089Spjd } 4431219089Spjd 4432219089Spjd return (0); 4433168404Spjd} 4434168404Spjd 4435168404Spjdtypedef struct upgrade_cbdata { 4436168404Spjd int cb_first; 4437212050Spjd char cb_poolname[ZPOOL_MAXNAMELEN]; 4438168404Spjd int cb_argc; 4439185029Spjd uint64_t cb_version; 4440168404Spjd char **cb_argv; 4441168404Spjd} upgrade_cbdata_t; 4442168404Spjd 4443238950Smm#ifdef __FreeBSD__ 4444168404Spjdstatic int 4445212050Spjdis_root_pool(zpool_handle_t *zhp) 4446212050Spjd{ 4447212050Spjd static struct statfs sfs; 4448212050Spjd static char *poolname = NULL; 4449212050Spjd static boolean_t stated = B_FALSE; 4450212050Spjd char *slash; 4451212050Spjd 4452212067Spjd if (!stated) { 4453212050Spjd stated = B_TRUE; 4454212050Spjd if (statfs("/", &sfs) == -1) { 4455212050Spjd (void) fprintf(stderr, 4456212050Spjd "Unable to stat root file system: %s.\n", 4457212050Spjd strerror(errno)); 4458212067Spjd return (0); 4459212050Spjd } 4460212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4461212067Spjd return (0); 4462212050Spjd poolname = sfs.f_mntfromname; 4463212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4464212050Spjd *slash = '\0'; 4465212050Spjd } 4466212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4467212050Spjd} 4468212050Spjd 4469238950Smmstatic void 4470238950Smmroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size) { 4471238950Smm 4472238950Smm if (poolname[0] == '\0' && is_root_pool(zhp)) 4473238950Smm (void) strlcpy(poolname, zpool_get_name(zhp), size); 4474238950Smm} 4475238950Smm#endif /* FreeBSD */ 4476238950Smm 4477212050Spjdstatic int 4478238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version) 4479238926Smm{ 4480238926Smm int ret; 4481238926Smm nvlist_t *config; 4482238926Smm uint64_t oldversion; 4483238926Smm 4484238926Smm config = zpool_get_config(zhp, NULL); 4485238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4486238926Smm &oldversion) == 0); 4487238926Smm 4488238926Smm assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 4489238926Smm assert(oldversion < version); 4490238926Smm 4491238926Smm ret = zpool_upgrade(zhp, version); 4492238926Smm if (ret != 0) 4493238926Smm return (ret); 4494238926Smm 4495238926Smm if (version >= SPA_VERSION_FEATURES) { 4496238926Smm (void) printf(gettext("Successfully upgraded " 4497238926Smm "'%s' from version %llu to feature flags.\n"), 4498238926Smm zpool_get_name(zhp), oldversion); 4499238926Smm } else { 4500238926Smm (void) printf(gettext("Successfully upgraded " 4501238926Smm "'%s' from version %llu to version %llu.\n"), 4502238926Smm zpool_get_name(zhp), oldversion, version); 4503238926Smm } 4504238926Smm 4505238926Smm return (0); 4506238926Smm} 4507238926Smm 4508238926Smmstatic int 4509238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp) 4510238926Smm{ 4511238926Smm int i, ret, count; 4512238926Smm boolean_t firstff = B_TRUE; 4513238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4514238926Smm 4515238926Smm count = 0; 4516238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4517238926Smm const char *fname = spa_feature_table[i].fi_uname; 4518238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4519238926Smm if (!nvlist_exists(enabled, fguid)) { 4520238926Smm char *propname; 4521238926Smm verify(-1 != asprintf(&propname, "feature@%s", fname)); 4522238926Smm ret = zpool_set_prop(zhp, propname, 4523238926Smm ZFS_FEATURE_ENABLED); 4524238926Smm if (ret != 0) { 4525238926Smm free(propname); 4526238926Smm return (ret); 4527238926Smm } 4528238926Smm count++; 4529238926Smm 4530238926Smm if (firstff) { 4531238926Smm (void) printf(gettext("Enabled the " 4532238926Smm "following features on '%s':\n"), 4533238926Smm zpool_get_name(zhp)); 4534238926Smm firstff = B_FALSE; 4535238926Smm } 4536238926Smm (void) printf(gettext(" %s\n"), fname); 4537238926Smm free(propname); 4538238926Smm } 4539238926Smm } 4540238926Smm 4541238926Smm if (countp != NULL) 4542238926Smm *countp = count; 4543238926Smm return (0); 4544238926Smm} 4545238926Smm 4546238926Smmstatic int 4547168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4548168404Spjd{ 4549168404Spjd upgrade_cbdata_t *cbp = arg; 4550168404Spjd nvlist_t *config; 4551168404Spjd uint64_t version; 4552238926Smm boolean_t printnl = B_FALSE; 4553238926Smm int ret; 4554168404Spjd 4555168404Spjd config = zpool_get_config(zhp, NULL); 4556168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4557168404Spjd &version) == 0); 4558168404Spjd 4559238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4560168404Spjd 4561238926Smm if (version < cbp->cb_version) { 4562238926Smm cbp->cb_first = B_FALSE; 4563238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4564238926Smm if (ret != 0) 4565238926Smm return (ret); 4566238926Smm#ifdef __FreeBSD__ 4567238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4568238950Smm sizeof(cbp->cb_poolname)); 4569238926Smm#endif /* ___FreeBSD__ */ 4570238926Smm printnl = B_TRUE; 4571238926Smm 4572238926Smm#ifdef illumos 4573238926Smm /* 4574238926Smm * If they did "zpool upgrade -a", then we could 4575238926Smm * be doing ioctls to different pools. We need 4576238926Smm * to log this history once to each pool, and bypass 4577238926Smm * the normal history logging that happens in main(). 4578238926Smm */ 4579238926Smm (void) zpool_log_history(g_zfs, history_str); 4580238926Smm log_history = B_FALSE; 4581238926Smm#endif 4582238926Smm } 4583238926Smm 4584238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4585238926Smm int count; 4586238926Smm ret = upgrade_enable_all(zhp, &count); 4587238926Smm if (ret != 0) 4588238926Smm return (ret); 4589238926Smm 4590238926Smm if (count > 0) { 4591168404Spjd cbp->cb_first = B_FALSE; 4592238926Smm printnl = B_TRUE; 4593248571Smm /* 4594248571Smm * If they did "zpool upgrade -a", then we could 4595248571Smm * be doing ioctls to different pools. We need 4596248571Smm * to log this history once to each pool, and bypass 4597248571Smm * the normal history logging that happens in main(). 4598248571Smm */ 4599248571Smm (void) zpool_log_history(g_zfs, history_str); 4600248571Smm log_history = B_FALSE; 4601168404Spjd } 4602238926Smm } 4603168404Spjd 4604238926Smm if (printnl) { 4605238926Smm (void) printf(gettext("\n")); 4606238926Smm } 4607238926Smm 4608238926Smm return (0); 4609238926Smm} 4610238926Smm 4611238926Smmstatic int 4612238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 4613238926Smm{ 4614238926Smm upgrade_cbdata_t *cbp = arg; 4615238926Smm nvlist_t *config; 4616238926Smm uint64_t version; 4617238926Smm 4618238926Smm config = zpool_get_config(zhp, NULL); 4619238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4620238926Smm &version) == 0); 4621238926Smm 4622238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4623238926Smm 4624238926Smm if (version < SPA_VERSION_FEATURES) { 4625168404Spjd if (cbp->cb_first) { 4626168404Spjd (void) printf(gettext("The following pools are " 4627238926Smm "formatted with legacy version numbers and can\n" 4628238926Smm "be upgraded to use feature flags. After " 4629238926Smm "being upgraded, these pools\nwill no " 4630238926Smm "longer be accessible by software that does not " 4631238926Smm "support feature\nflags.\n\n")); 4632168404Spjd (void) printf(gettext("VER POOL\n")); 4633168404Spjd (void) printf(gettext("--- ------------\n")); 4634168404Spjd cbp->cb_first = B_FALSE; 4635168404Spjd } 4636168404Spjd 4637168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4638168404Spjd zpool_get_name(zhp)); 4639168404Spjd } 4640168404Spjd 4641238926Smm return (0); 4642168404Spjd} 4643168404Spjd 4644238926Smmstatic int 4645238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 4646238926Smm{ 4647238926Smm upgrade_cbdata_t *cbp = arg; 4648238926Smm nvlist_t *config; 4649238926Smm uint64_t version; 4650238926Smm 4651238926Smm config = zpool_get_config(zhp, NULL); 4652238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4653238926Smm &version) == 0); 4654238926Smm 4655238926Smm if (version >= SPA_VERSION_FEATURES) { 4656238926Smm int i; 4657238926Smm boolean_t poolfirst = B_TRUE; 4658238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4659238926Smm 4660238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4661238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4662238926Smm const char *fname = spa_feature_table[i].fi_uname; 4663238926Smm if (!nvlist_exists(enabled, fguid)) { 4664238926Smm if (cbp->cb_first) { 4665238926Smm (void) printf(gettext("\nSome " 4666238926Smm "supported features are not " 4667238926Smm "enabled on the following pools. " 4668238926Smm "Once a\nfeature is enabled the " 4669238926Smm "pool may become incompatible with " 4670238926Smm "software\nthat does not support " 4671238926Smm "the feature. See " 4672243014Smm "zpool-features(7) for " 4673238926Smm "details.\n\n")); 4674238926Smm (void) printf(gettext("POOL " 4675238926Smm "FEATURE\n")); 4676238926Smm (void) printf(gettext("------" 4677238926Smm "---------\n")); 4678238926Smm cbp->cb_first = B_FALSE; 4679238926Smm } 4680238926Smm 4681238926Smm if (poolfirst) { 4682238926Smm (void) printf(gettext("%s\n"), 4683238926Smm zpool_get_name(zhp)); 4684238926Smm poolfirst = B_FALSE; 4685238926Smm } 4686238926Smm 4687238926Smm (void) printf(gettext(" %s\n"), fname); 4688238926Smm } 4689238926Smm } 4690238926Smm } 4691238926Smm 4692238926Smm return (0); 4693238926Smm} 4694238926Smm 4695168404Spjd/* ARGSUSED */ 4696168404Spjdstatic int 4697168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 4698168404Spjd{ 4699238926Smm boolean_t printnl = B_FALSE; 4700185029Spjd upgrade_cbdata_t *cbp = data; 4701185029Spjd uint64_t cur_version; 4702168404Spjd int ret; 4703168404Spjd 4704185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 4705185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 4706185029Spjd "Pool 'log' must be renamed using export and import" 4707185029Spjd " to upgrade.\n")); 4708185029Spjd return (1); 4709185029Spjd } 4710168404Spjd 4711185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4712185029Spjd if (cur_version > cbp->cb_version) { 4713168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 4714238926Smm "using more current version '%llu'.\n\n"), 4715185029Spjd zpool_get_name(zhp), cur_version); 4716185029Spjd return (0); 4717185029Spjd } 4718238926Smm 4719238926Smm if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 4720185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 4721238926Smm "using version %llu.\n\n"), zpool_get_name(zhp), 4722238926Smm cbp->cb_version); 4723168404Spjd return (0); 4724168404Spjd } 4725168404Spjd 4726238926Smm if (cur_version != cbp->cb_version) { 4727238926Smm printnl = B_TRUE; 4728238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4729238950Smm if (ret != 0) 4730238950Smm return (ret); 4731238926Smm#ifdef __FreeBSD__ 4732238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4733238950Smm sizeof(cbp->cb_poolname)); 4734238926Smm#endif /* ___FreeBSD__ */ 4735238926Smm } 4736168404Spjd 4737238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4738238926Smm int count = 0; 4739238926Smm ret = upgrade_enable_all(zhp, &count); 4740238926Smm if (ret != 0) 4741238926Smm return (ret); 4742238926Smm 4743238926Smm if (count != 0) { 4744238926Smm printnl = B_TRUE; 4745238950Smm#ifdef __FreeBSD__ 4746238951Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4747238951Smm sizeof(cbp->cb_poolname)); 4748238950Smm#endif /* __FreeBSD __*/ 4749238926Smm } else if (cur_version == SPA_VERSION) { 4750238926Smm (void) printf(gettext("Pool '%s' already has all " 4751238926Smm "supported features enabled.\n"), 4752238926Smm zpool_get_name(zhp)); 4753238926Smm } 4754168404Spjd } 4755168404Spjd 4756238926Smm if (printnl) { 4757238926Smm (void) printf(gettext("\n")); 4758238926Smm } 4759238926Smm 4760238926Smm return (0); 4761168404Spjd} 4762168404Spjd 4763168404Spjd/* 4764168404Spjd * zpool upgrade 4765168404Spjd * zpool upgrade -v 4766185029Spjd * zpool upgrade [-V version] <-a | pool ...> 4767168404Spjd * 4768168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 4769168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 4770168404Spjd * upgrade all pools. 4771168404Spjd */ 4772168404Spjdint 4773168404Spjdzpool_do_upgrade(int argc, char **argv) 4774168404Spjd{ 4775168404Spjd int c; 4776168404Spjd upgrade_cbdata_t cb = { 0 }; 4777168404Spjd int ret = 0; 4778168404Spjd boolean_t showversions = B_FALSE; 4779238926Smm boolean_t upgradeall = B_FALSE; 4780185029Spjd char *end; 4781168404Spjd 4782185029Spjd 4783168404Spjd /* check options */ 4784219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 4785168404Spjd switch (c) { 4786168404Spjd case 'a': 4787238926Smm upgradeall = B_TRUE; 4788168404Spjd break; 4789168404Spjd case 'v': 4790168404Spjd showversions = B_TRUE; 4791168404Spjd break; 4792185029Spjd case 'V': 4793185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 4794236884Smm if (*end != '\0' || 4795236884Smm !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 4796185029Spjd (void) fprintf(stderr, 4797185029Spjd gettext("invalid version '%s'\n"), optarg); 4798185029Spjd usage(B_FALSE); 4799185029Spjd } 4800185029Spjd break; 4801219089Spjd case ':': 4802219089Spjd (void) fprintf(stderr, gettext("missing argument for " 4803219089Spjd "'%c' option\n"), optopt); 4804219089Spjd usage(B_FALSE); 4805219089Spjd break; 4806168404Spjd case '?': 4807168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4808168404Spjd optopt); 4809168404Spjd usage(B_FALSE); 4810168404Spjd } 4811168404Spjd } 4812168404Spjd 4813168404Spjd cb.cb_argc = argc; 4814168404Spjd cb.cb_argv = argv; 4815168404Spjd argc -= optind; 4816168404Spjd argv += optind; 4817168404Spjd 4818185029Spjd if (cb.cb_version == 0) { 4819185029Spjd cb.cb_version = SPA_VERSION; 4820238926Smm } else if (!upgradeall && argc == 0) { 4821185029Spjd (void) fprintf(stderr, gettext("-V option is " 4822185029Spjd "incompatible with other arguments\n")); 4823185029Spjd usage(B_FALSE); 4824185029Spjd } 4825185029Spjd 4826168404Spjd if (showversions) { 4827238926Smm if (upgradeall || argc != 0) { 4828168404Spjd (void) fprintf(stderr, gettext("-v option is " 4829168404Spjd "incompatible with other arguments\n")); 4830168404Spjd usage(B_FALSE); 4831168404Spjd } 4832238926Smm } else if (upgradeall) { 4833168404Spjd if (argc != 0) { 4834185029Spjd (void) fprintf(stderr, gettext("-a option should not " 4835185029Spjd "be used along with a pool name\n")); 4836168404Spjd usage(B_FALSE); 4837168404Spjd } 4838168404Spjd } 4839168404Spjd 4840236884Smm (void) printf(gettext("This system supports ZFS pool feature " 4841236884Smm "flags.\n\n")); 4842168404Spjd if (showversions) { 4843238926Smm int i; 4844238926Smm 4845238926Smm (void) printf(gettext("The following features are " 4846168404Spjd "supported:\n\n")); 4847238926Smm (void) printf(gettext("FEAT DESCRIPTION\n")); 4848238926Smm (void) printf("----------------------------------------------" 4849238926Smm "---------------\n"); 4850238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4851238926Smm zfeature_info_t *fi = &spa_feature_table[i]; 4852238926Smm const char *ro = fi->fi_can_readonly ? 4853238926Smm " (read-only compatible)" : ""; 4854238926Smm 4855238926Smm (void) printf("%-37s%s\n", fi->fi_uname, ro); 4856238926Smm (void) printf(" %s\n", fi->fi_desc); 4857238926Smm } 4858238926Smm (void) printf("\n"); 4859238926Smm 4860238926Smm (void) printf(gettext("The following legacy versions are also " 4861238926Smm "supported:\n\n")); 4862168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 4863168404Spjd (void) printf("--- -----------------------------------------" 4864168404Spjd "---------------\n"); 4865168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 4866168404Spjd (void) printf(gettext(" 2 Ditto blocks " 4867168404Spjd "(replicated metadata)\n")); 4868168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 4869168404Spjd "RAID-Z\n")); 4870168404Spjd (void) printf(gettext(" 4 zpool history\n")); 4871168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 4872168404Spjd "algorithm\n")); 4873185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 4874185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 4875185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 4876185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 4877185029Spjd "properties\n")); 4878185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 4879185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 4880185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 4881185029Spjd (void) printf(gettext(" 13 snapused property\n")); 4882209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 4883209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 4884219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 4885219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 4886219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 4887219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 4888219089Spjd (void) printf(gettext(" 20 Compression using zle " 4889219089Spjd "(zero-length encoding)\n")); 4890219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 4891219089Spjd (void) printf(gettext(" 22 Received properties\n")); 4892219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 4893219089Spjd (void) printf(gettext(" 24 System attributes\n")); 4894219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 4895219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 4896219089Spjd "performance\n")); 4897219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 4898219089Spjd "performance\n")); 4899219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 4900219089Spjd (void) printf(gettext("\nFor more information on a particular " 4901219089Spjd "version, including supported releases,\n")); 4902219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 4903238926Smm } else if (argc == 0 && upgradeall) { 4904238926Smm cb.cb_first = B_TRUE; 4905168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4906238926Smm if (ret == 0 && cb.cb_first) { 4907238926Smm if (cb.cb_version == SPA_VERSION) { 4908238926Smm (void) printf(gettext("All pools are already " 4909238926Smm "formatted using feature flags.\n\n")); 4910238926Smm (void) printf(gettext("Every feature flags " 4911238926Smm "pool already has all supported features " 4912238926Smm "enabled.\n")); 4913238926Smm } else { 4914238926Smm (void) printf(gettext("All pools are already " 4915238926Smm "formatted with version %llu or higher.\n"), 4916238926Smm cb.cb_version); 4917168404Spjd } 4918168404Spjd } 4919238926Smm } else if (argc == 0) { 4920238926Smm cb.cb_first = B_TRUE; 4921238926Smm ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 4922238926Smm assert(ret == 0); 4923168404Spjd 4924238926Smm if (cb.cb_first) { 4925238926Smm (void) printf(gettext("All pools are formatted " 4926238926Smm "using feature flags.\n\n")); 4927238926Smm } else { 4928238926Smm (void) printf(gettext("\nUse 'zpool upgrade -v' " 4929238926Smm "for a list of available legacy versions.\n")); 4930168404Spjd } 4931238926Smm 4932238926Smm cb.cb_first = B_TRUE; 4933238926Smm ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 4934238926Smm assert(ret == 0); 4935238926Smm 4936238926Smm if (cb.cb_first) { 4937238926Smm (void) printf(gettext("Every feature flags pool has " 4938238926Smm "all supported features enabled.\n")); 4939238926Smm } else { 4940238926Smm (void) printf(gettext("\n")); 4941238926Smm } 4942168404Spjd } else { 4943168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, 4944168404Spjd upgrade_one, &cb); 4945168404Spjd } 4946168404Spjd 4947212050Spjd if (cb.cb_poolname[0] != '\0') { 4948212050Spjd (void) printf( 4949212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 4950212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 4951212050Spjd "the following command will do it:\n" 4952212050Spjd "\n" 4953212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 4954212050Spjd cb.cb_poolname); 4955212050Spjd } 4956212050Spjd 4957168404Spjd return (ret); 4958168404Spjd} 4959168404Spjd 4960185029Spjdtypedef struct hist_cbdata { 4961185029Spjd boolean_t first; 4962248571Smm boolean_t longfmt; 4963248571Smm boolean_t internal; 4964185029Spjd} hist_cbdata_t; 4965185029Spjd 4966168404Spjd/* 4967168404Spjd * Print out the command history for a specific pool. 4968168404Spjd */ 4969168404Spjdstatic int 4970168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 4971168404Spjd{ 4972168404Spjd nvlist_t *nvhis; 4973168404Spjd nvlist_t **records; 4974168404Spjd uint_t numrecords; 4975168404Spjd int ret, i; 4976185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 4977168404Spjd 4978185029Spjd cb->first = B_FALSE; 4979168404Spjd 4980168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 4981168404Spjd 4982168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 4983168404Spjd return (ret); 4984168404Spjd 4985168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 4986168404Spjd &records, &numrecords) == 0); 4987168404Spjd for (i = 0; i < numrecords; i++) { 4988248571Smm nvlist_t *rec = records[i]; 4989248571Smm char tbuf[30] = ""; 4990185029Spjd 4991248571Smm if (nvlist_exists(rec, ZPOOL_HIST_TIME)) { 4992248571Smm time_t tsec; 4993248571Smm struct tm t; 4994185029Spjd 4995248571Smm tsec = fnvlist_lookup_uint64(records[i], 4996248571Smm ZPOOL_HIST_TIME); 4997248571Smm (void) localtime_r(&tsec, &t); 4998248571Smm (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 4999248571Smm } 5000248571Smm 5001248571Smm if (nvlist_exists(rec, ZPOOL_HIST_CMD)) { 5002248571Smm (void) printf("%s %s", tbuf, 5003248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_CMD)); 5004248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) { 5005248571Smm int ievent = 5006248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT); 5007248571Smm if (!cb->internal) 5008185029Spjd continue; 5009248571Smm if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) { 5010248571Smm (void) printf("%s unrecognized record:\n", 5011248571Smm tbuf); 5012248571Smm dump_nvlist(rec, 4); 5013185029Spjd continue; 5014248571Smm } 5015248571Smm (void) printf("%s [internal %s txg:%lld] %s", tbuf, 5016248571Smm zfs_history_event_names[ievent], 5017248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5018248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR)); 5019248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) { 5020248571Smm if (!cb->internal) 5021248571Smm continue; 5022248571Smm (void) printf("%s [txg:%lld] %s", tbuf, 5023248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5024248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME)); 5025248571Smm if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) { 5026248571Smm (void) printf(" %s (%llu)", 5027248571Smm fnvlist_lookup_string(rec, 5028248571Smm ZPOOL_HIST_DSNAME), 5029248571Smm fnvlist_lookup_uint64(rec, 5030248571Smm ZPOOL_HIST_DSID)); 5031248571Smm } 5032248571Smm (void) printf(" %s", fnvlist_lookup_string(rec, 5033248571Smm ZPOOL_HIST_INT_STR)); 5034248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) { 5035248571Smm if (!cb->internal) 5036248571Smm continue; 5037248571Smm (void) printf("%s ioctl %s\n", tbuf, 5038248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL)); 5039248571Smm if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) { 5040248571Smm (void) printf(" input:\n"); 5041248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5042248571Smm ZPOOL_HIST_INPUT_NVL), 8); 5043248571Smm } 5044248571Smm if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) { 5045248571Smm (void) printf(" output:\n"); 5046248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5047248571Smm ZPOOL_HIST_OUTPUT_NVL), 8); 5048248571Smm } 5049248571Smm } else { 5050248571Smm if (!cb->internal) 5051248571Smm continue; 5052248571Smm (void) printf("%s unrecognized record:\n", tbuf); 5053248571Smm dump_nvlist(rec, 4); 5054168404Spjd } 5055185029Spjd 5056185029Spjd if (!cb->longfmt) { 5057185029Spjd (void) printf("\n"); 5058185029Spjd continue; 5059185029Spjd } 5060185029Spjd (void) printf(" ["); 5061248571Smm if (nvlist_exists(rec, ZPOOL_HIST_WHO)) { 5062248571Smm uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO); 5063248571Smm struct passwd *pwd = getpwuid(who); 5064248571Smm (void) printf("user %d ", (int)who); 5065248571Smm if (pwd != NULL) 5066248571Smm (void) printf("(%s) ", pwd->pw_name); 5067185029Spjd } 5068248571Smm if (nvlist_exists(rec, ZPOOL_HIST_HOST)) { 5069248571Smm (void) printf("on %s", 5070248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_HOST)); 5071185029Spjd } 5072248571Smm if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) { 5073248571Smm (void) printf(":%s", 5074248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE)); 5075185029Spjd } 5076185029Spjd (void) printf("]"); 5077185029Spjd (void) printf("\n"); 5078168404Spjd } 5079168404Spjd (void) printf("\n"); 5080168404Spjd nvlist_free(nvhis); 5081168404Spjd 5082168404Spjd return (ret); 5083168404Spjd} 5084168404Spjd 5085168404Spjd/* 5086168404Spjd * zpool history <pool> 5087168404Spjd * 5088168404Spjd * Displays the history of commands that modified pools. 5089168404Spjd */ 5090168404Spjdint 5091168404Spjdzpool_do_history(int argc, char **argv) 5092168404Spjd{ 5093185029Spjd hist_cbdata_t cbdata = { 0 }; 5094168404Spjd int ret; 5095185029Spjd int c; 5096168404Spjd 5097185029Spjd cbdata.first = B_TRUE; 5098185029Spjd /* check options */ 5099185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 5100185029Spjd switch (c) { 5101185029Spjd case 'l': 5102248571Smm cbdata.longfmt = B_TRUE; 5103185029Spjd break; 5104185029Spjd case 'i': 5105248571Smm cbdata.internal = B_TRUE; 5106185029Spjd break; 5107185029Spjd case '?': 5108185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5109185029Spjd optopt); 5110185029Spjd usage(B_FALSE); 5111185029Spjd } 5112185029Spjd } 5113168404Spjd argc -= optind; 5114168404Spjd argv += optind; 5115168404Spjd 5116168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 5117185029Spjd &cbdata); 5118168404Spjd 5119185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 5120168404Spjd (void) printf(gettext("no pools available\n")); 5121168404Spjd return (0); 5122168404Spjd } 5123168404Spjd 5124168404Spjd return (ret); 5125168404Spjd} 5126168404Spjd 5127168404Spjdstatic int 5128168404Spjdget_callback(zpool_handle_t *zhp, void *data) 5129168404Spjd{ 5130185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 5131168404Spjd char value[MAXNAMELEN]; 5132185029Spjd zprop_source_t srctype; 5133185029Spjd zprop_list_t *pl; 5134168404Spjd 5135168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 5136168404Spjd 5137168404Spjd /* 5138185029Spjd * Skip the special fake placeholder. This will also skip 5139185029Spjd * over the name property when 'all' is specified. 5140168404Spjd */ 5141185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 5142168404Spjd pl == cbp->cb_proplist) 5143168404Spjd continue; 5144168404Spjd 5145236884Smm if (pl->pl_prop == ZPROP_INVAL && 5146236884Smm (zpool_prop_feature(pl->pl_user_prop) || 5147236884Smm zpool_prop_unsupported(pl->pl_user_prop))) { 5148236884Smm srctype = ZPROP_SRC_LOCAL; 5149168404Spjd 5150236884Smm if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 5151236884Smm value, sizeof (value)) == 0) { 5152236884Smm zprop_print_one_property(zpool_get_name(zhp), 5153236884Smm cbp, pl->pl_user_prop, value, srctype, 5154236884Smm NULL, NULL); 5155236884Smm } 5156236884Smm } else { 5157236884Smm if (zpool_get_prop(zhp, pl->pl_prop, value, 5158236884Smm sizeof (value), &srctype) != 0) 5159236884Smm continue; 5160236884Smm 5161236884Smm zprop_print_one_property(zpool_get_name(zhp), cbp, 5162236884Smm zpool_prop_to_name(pl->pl_prop), value, srctype, 5163236884Smm NULL, NULL); 5164236884Smm } 5165168404Spjd } 5166168404Spjd return (0); 5167168404Spjd} 5168168404Spjd 5169168404Spjdint 5170168404Spjdzpool_do_get(int argc, char **argv) 5171168404Spjd{ 5172185029Spjd zprop_get_cbdata_t cb = { 0 }; 5173185029Spjd zprop_list_t fake_name = { 0 }; 5174168404Spjd int ret; 5175168404Spjd 5176236884Smm if (argc < 2) { 5177236884Smm (void) fprintf(stderr, gettext("missing property " 5178236884Smm "argument\n")); 5179168404Spjd usage(B_FALSE); 5180236884Smm } 5181168404Spjd 5182168404Spjd cb.cb_first = B_TRUE; 5183185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 5184168404Spjd cb.cb_columns[0] = GET_COL_NAME; 5185168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 5186168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 5187168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 5188185029Spjd cb.cb_type = ZFS_TYPE_POOL; 5189168404Spjd 5190236884Smm if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 5191185029Spjd ZFS_TYPE_POOL) != 0) 5192168404Spjd usage(B_FALSE); 5193168404Spjd 5194168404Spjd if (cb.cb_proplist != NULL) { 5195185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 5196168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 5197168404Spjd fake_name.pl_next = cb.cb_proplist; 5198168404Spjd cb.cb_proplist = &fake_name; 5199168404Spjd } 5200168404Spjd 5201168404Spjd ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 5202168404Spjd get_callback, &cb); 5203168404Spjd 5204168404Spjd if (cb.cb_proplist == &fake_name) 5205185029Spjd zprop_free_list(fake_name.pl_next); 5206168404Spjd else 5207185029Spjd zprop_free_list(cb.cb_proplist); 5208168404Spjd 5209168404Spjd return (ret); 5210168404Spjd} 5211168404Spjd 5212168404Spjdtypedef struct set_cbdata { 5213168404Spjd char *cb_propname; 5214168404Spjd char *cb_value; 5215168404Spjd boolean_t cb_any_successful; 5216168404Spjd} set_cbdata_t; 5217168404Spjd 5218168404Spjdint 5219168404Spjdset_callback(zpool_handle_t *zhp, void *data) 5220168404Spjd{ 5221168404Spjd int error; 5222168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 5223168404Spjd 5224168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 5225168404Spjd 5226168404Spjd if (!error) 5227168404Spjd cb->cb_any_successful = B_TRUE; 5228168404Spjd 5229168404Spjd return (error); 5230168404Spjd} 5231168404Spjd 5232168404Spjdint 5233168404Spjdzpool_do_set(int argc, char **argv) 5234168404Spjd{ 5235168404Spjd set_cbdata_t cb = { 0 }; 5236168404Spjd int error; 5237168404Spjd 5238168404Spjd if (argc > 1 && argv[1][0] == '-') { 5239168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5240168404Spjd argv[1][1]); 5241168404Spjd usage(B_FALSE); 5242168404Spjd } 5243168404Spjd 5244168404Spjd if (argc < 2) { 5245168404Spjd (void) fprintf(stderr, gettext("missing property=value " 5246168404Spjd "argument\n")); 5247168404Spjd usage(B_FALSE); 5248168404Spjd } 5249168404Spjd 5250168404Spjd if (argc < 3) { 5251168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 5252168404Spjd usage(B_FALSE); 5253168404Spjd } 5254168404Spjd 5255168404Spjd if (argc > 3) { 5256168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 5257168404Spjd usage(B_FALSE); 5258168404Spjd } 5259168404Spjd 5260168404Spjd cb.cb_propname = argv[1]; 5261168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 5262168404Spjd if (cb.cb_value == NULL) { 5263168404Spjd (void) fprintf(stderr, gettext("missing value in " 5264168404Spjd "property=value argument\n")); 5265168404Spjd usage(B_FALSE); 5266168404Spjd } 5267168404Spjd 5268168404Spjd *(cb.cb_value) = '\0'; 5269168404Spjd cb.cb_value++; 5270168404Spjd 5271168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 5272168404Spjd set_callback, &cb); 5273168404Spjd 5274168404Spjd return (error); 5275168404Spjd} 5276168404Spjd 5277168404Spjdstatic int 5278168404Spjdfind_command_idx(char *command, int *idx) 5279168404Spjd{ 5280168404Spjd int i; 5281168404Spjd 5282168404Spjd for (i = 0; i < NCOMMAND; i++) { 5283168404Spjd if (command_table[i].name == NULL) 5284168404Spjd continue; 5285168404Spjd 5286168404Spjd if (strcmp(command, command_table[i].name) == 0) { 5287168404Spjd *idx = i; 5288168404Spjd return (0); 5289168404Spjd } 5290168404Spjd } 5291168404Spjd return (1); 5292168404Spjd} 5293168404Spjd 5294168404Spjdint 5295168404Spjdmain(int argc, char **argv) 5296168404Spjd{ 5297168404Spjd int ret; 5298168404Spjd int i; 5299168404Spjd char *cmdname; 5300168404Spjd 5301168404Spjd (void) setlocale(LC_ALL, ""); 5302168404Spjd (void) textdomain(TEXT_DOMAIN); 5303168404Spjd 5304168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 5305168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 5306168404Spjd "initialize ZFS library\n")); 5307168404Spjd return (1); 5308168404Spjd } 5309168404Spjd 5310168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 5311168404Spjd 5312168404Spjd opterr = 0; 5313168404Spjd 5314168404Spjd /* 5315168404Spjd * Make sure the user has specified some command. 5316168404Spjd */ 5317168404Spjd if (argc < 2) { 5318168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 5319168404Spjd usage(B_FALSE); 5320168404Spjd } 5321168404Spjd 5322168404Spjd cmdname = argv[1]; 5323168404Spjd 5324168404Spjd /* 5325168404Spjd * Special case '-?' 5326168404Spjd */ 5327168404Spjd if (strcmp(cmdname, "-?") == 0) 5328168404Spjd usage(B_TRUE); 5329168404Spjd 5330248571Smm zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); 5331185029Spjd 5332168404Spjd /* 5333168404Spjd * Run the appropriate command. 5334168404Spjd */ 5335168404Spjd if (find_command_idx(cmdname, &i) == 0) { 5336168404Spjd current_command = &command_table[i]; 5337168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 5338185029Spjd } else if (strchr(cmdname, '=')) { 5339185029Spjd verify(find_command_idx("set", &i) == 0); 5340185029Spjd current_command = &command_table[i]; 5341185029Spjd ret = command_table[i].func(argc, argv); 5342185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 5343185029Spjd /* 5344185029Spjd * 'freeze' is a vile debugging abomination, so we treat 5345185029Spjd * it as such. 5346185029Spjd */ 5347252059Ssmh zfs_cmd_t zc = { 0 }; 5348252059Ssmh (void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name)); 5349252059Ssmh return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc)); 5350185029Spjd } else { 5351168404Spjd (void) fprintf(stderr, gettext("unrecognized " 5352168404Spjd "command '%s'\n"), cmdname); 5353168404Spjd usage(B_FALSE); 5354168404Spjd } 5355168404Spjd 5356248571Smm if (ret == 0 && log_history) 5357248571Smm (void) zpool_log_history(g_zfs, history_str); 5358248571Smm 5359168404Spjd libzfs_fini(g_zfs); 5360168404Spjd 5361168404Spjd /* 5362168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 5363168404Spjd * for the purposes of running ::findleaks. 5364168404Spjd */ 5365168404Spjd if (getenv("ZFS_ABORT") != NULL) { 5366168404Spjd (void) printf("dumping core by request\n"); 5367168404Spjd abort(); 5368168404Spjd } 5369168404Spjd 5370168404Spjd return (ret); 5371168404Spjd} 5372