zpool_main.c revision 243014
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 195168404Spjdzpool_command_t *current_command; 196185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 197168404Spjd 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': 807168404Spjd mountpoint = optarg; 808168404Spjd break; 809185029Spjd case 'o': 810185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 811185029Spjd (void) fprintf(stderr, gettext("missing " 812185029Spjd "'=' for -o option\n")); 813185029Spjd goto errout; 814185029Spjd } 815185029Spjd *propval = '\0'; 816185029Spjd propval++; 817185029Spjd 818185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 819185029Spjd goto errout; 820236884Smm 821236884Smm /* 822236884Smm * If the user is creating a pool that doesn't support 823236884Smm * feature flags, don't enable any features. 824236884Smm */ 825236884Smm if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 826236884Smm char *end; 827236884Smm u_longlong_t ver; 828236884Smm 829236884Smm ver = strtoull(propval, &end, 10); 830236884Smm if (*end == '\0' && 831236884Smm ver < SPA_VERSION_FEATURES) { 832236884Smm enable_all_pool_feat = B_FALSE; 833236884Smm } 834236884Smm } 835185029Spjd break; 836185029Spjd case 'O': 837185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 838185029Spjd (void) fprintf(stderr, gettext("missing " 839185029Spjd "'=' for -O option\n")); 840185029Spjd goto errout; 841185029Spjd } 842185029Spjd *propval = '\0'; 843185029Spjd propval++; 844185029Spjd 845185029Spjd if (add_prop_list(optarg, propval, &fsprops, B_FALSE)) 846185029Spjd goto errout; 847185029Spjd break; 848168404Spjd case ':': 849168404Spjd (void) fprintf(stderr, gettext("missing argument for " 850168404Spjd "'%c' option\n"), optopt); 851185029Spjd goto badusage; 852168404Spjd case '?': 853168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 854168404Spjd optopt); 855185029Spjd goto badusage; 856168404Spjd } 857168404Spjd } 858168404Spjd 859168404Spjd argc -= optind; 860168404Spjd argv += optind; 861168404Spjd 862168404Spjd /* get pool name and check number of arguments */ 863168404Spjd if (argc < 1) { 864168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 865185029Spjd goto badusage; 866168404Spjd } 867168404Spjd if (argc < 2) { 868168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 869185029Spjd goto badusage; 870168404Spjd } 871168404Spjd 872168404Spjd poolname = argv[0]; 873168404Spjd 874168404Spjd /* 875168404Spjd * As a special case, check for use of '/' in the name, and direct the 876168404Spjd * user to use 'zfs create' instead. 877168404Spjd */ 878168404Spjd if (strchr(poolname, '/') != NULL) { 879168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 880168404Spjd "character '/' in pool name\n"), poolname); 881168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 882168404Spjd "create a dataset\n")); 883185029Spjd goto errout; 884168404Spjd } 885168404Spjd 886168404Spjd /* pass off to get_vdev_spec for bulk processing */ 887185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 888185029Spjd argc - 1, argv + 1); 889168404Spjd if (nvroot == NULL) 890185029Spjd goto errout; 891168404Spjd 892168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 893185029Spjd if (!zfs_allocatable_devs(nvroot)) { 894168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 895168404Spjd "specification: at least one toplevel vdev must be " 896168404Spjd "specified\n")); 897185029Spjd goto errout; 898168404Spjd } 899168404Spjd 900168404Spjd if (altroot != NULL && altroot[0] != '/') { 901168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 902168404Spjd "must be an absolute path\n"), altroot); 903185029Spjd goto errout; 904168404Spjd } 905168404Spjd 906168404Spjd /* 907168404Spjd * Check the validity of the mountpoint and direct the user to use the 908168404Spjd * '-m' mountpoint option if it looks like its in use. 909168404Spjd */ 910168404Spjd if (mountpoint == NULL || 911168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 912168404Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 913168404Spjd char buf[MAXPATHLEN]; 914185029Spjd DIR *dirp; 915168404Spjd 916168404Spjd if (mountpoint && mountpoint[0] != '/') { 917168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 918168404Spjd "'%s': must be an absolute path, 'legacy', or " 919168404Spjd "'none'\n"), mountpoint); 920185029Spjd goto errout; 921168404Spjd } 922168404Spjd 923168404Spjd if (mountpoint == NULL) { 924168404Spjd if (altroot != NULL) 925168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 926168404Spjd altroot, poolname); 927168404Spjd else 928168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 929168404Spjd poolname); 930168404Spjd } else { 931168404Spjd if (altroot != NULL) 932168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 933168404Spjd altroot, mountpoint); 934168404Spjd else 935168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 936168404Spjd mountpoint); 937168404Spjd } 938168404Spjd 939185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 940185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 941185029Spjd "%s\n"), buf, strerror(errno)); 942185029Spjd (void) fprintf(stderr, gettext("use '-m' " 943185029Spjd "option to provide a different default\n")); 944185029Spjd goto errout; 945185029Spjd } else if (dirp) { 946185029Spjd int count = 0; 947185029Spjd 948185029Spjd while (count < 3 && readdir(dirp) != NULL) 949185029Spjd count++; 950185029Spjd (void) closedir(dirp); 951185029Spjd 952185029Spjd if (count > 2) { 953168404Spjd (void) fprintf(stderr, gettext("mountpoint " 954168404Spjd "'%s' exists and is not empty\n"), buf); 955185029Spjd (void) fprintf(stderr, gettext("use '-m' " 956185029Spjd "option to provide a " 957185029Spjd "different default\n")); 958185029Spjd goto errout; 959185029Spjd } 960168404Spjd } 961168404Spjd } 962168404Spjd 963168404Spjd if (dryrun) { 964168404Spjd /* 965168404Spjd * For a dry run invocation, print out a basic message and run 966168404Spjd * through all the vdevs in the list and print out in an 967168404Spjd * appropriate hierarchy. 968168404Spjd */ 969168404Spjd (void) printf(gettext("would create '%s' with the " 970168404Spjd "following layout:\n\n"), poolname); 971168404Spjd 972185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 973185029Spjd if (num_logs(nvroot) > 0) 974185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 975168404Spjd 976168404Spjd ret = 0; 977168404Spjd } else { 978168404Spjd /* 979168404Spjd * Hand off to libzfs. 980168404Spjd */ 981236884Smm if (enable_all_pool_feat) { 982236884Smm int i; 983236884Smm for (i = 0; i < SPA_FEATURES; i++) { 984236884Smm char propname[MAXPATHLEN]; 985236884Smm zfeature_info_t *feat = &spa_feature_table[i]; 986236884Smm 987236884Smm (void) snprintf(propname, sizeof (propname), 988236884Smm "feature@%s", feat->fi_uname); 989236884Smm 990236884Smm /* 991236884Smm * Skip feature if user specified it manually 992236884Smm * on the command line. 993236884Smm */ 994236884Smm if (nvlist_exists(props, propname)) 995236884Smm continue; 996236884Smm 997236884Smm if (add_prop_list(propname, ZFS_FEATURE_ENABLED, 998236884Smm &props, B_TRUE) != 0) 999236884Smm goto errout; 1000236884Smm } 1001236884Smm } 1002185029Spjd if (zpool_create(g_zfs, poolname, 1003185029Spjd nvroot, props, fsprops) == 0) { 1004168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 1005168404Spjd ZFS_TYPE_FILESYSTEM); 1006168404Spjd if (pool != NULL) { 1007168404Spjd if (mountpoint != NULL) 1008168404Spjd verify(zfs_prop_set(pool, 1009168404Spjd zfs_prop_to_name( 1010168404Spjd ZFS_PROP_MOUNTPOINT), 1011168404Spjd mountpoint) == 0); 1012168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 1013185029Spjd ret = zfs_shareall(pool); 1014168404Spjd zfs_close(pool); 1015168404Spjd } 1016168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 1017168404Spjd (void) fprintf(stderr, gettext("pool name may have " 1018168404Spjd "been omitted\n")); 1019168404Spjd } 1020168404Spjd } 1021168404Spjd 1022185029Spjderrout: 1023168404Spjd nvlist_free(nvroot); 1024185029Spjd nvlist_free(fsprops); 1025185029Spjd nvlist_free(props); 1026168404Spjd return (ret); 1027185029Spjdbadusage: 1028185029Spjd nvlist_free(fsprops); 1029185029Spjd nvlist_free(props); 1030185029Spjd usage(B_FALSE); 1031185029Spjd return (2); 1032168404Spjd} 1033168404Spjd 1034168404Spjd/* 1035168404Spjd * zpool destroy <pool> 1036168404Spjd * 1037168404Spjd * -f Forcefully unmount any datasets 1038168404Spjd * 1039168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 1040168404Spjd */ 1041168404Spjdint 1042168404Spjdzpool_do_destroy(int argc, char **argv) 1043168404Spjd{ 1044168404Spjd boolean_t force = B_FALSE; 1045168404Spjd int c; 1046168404Spjd char *pool; 1047168404Spjd zpool_handle_t *zhp; 1048168404Spjd int ret; 1049168404Spjd 1050168404Spjd /* check options */ 1051168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 1052168404Spjd switch (c) { 1053168404Spjd case 'f': 1054168404Spjd force = B_TRUE; 1055168404Spjd break; 1056168404Spjd case '?': 1057168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1058168404Spjd optopt); 1059168404Spjd usage(B_FALSE); 1060168404Spjd } 1061168404Spjd } 1062168404Spjd 1063168404Spjd argc -= optind; 1064168404Spjd argv += optind; 1065168404Spjd 1066168404Spjd /* check arguments */ 1067168404Spjd if (argc < 1) { 1068168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1069168404Spjd usage(B_FALSE); 1070168404Spjd } 1071168404Spjd if (argc > 1) { 1072168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1073168404Spjd usage(B_FALSE); 1074168404Spjd } 1075168404Spjd 1076168404Spjd pool = argv[0]; 1077168404Spjd 1078168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1079168404Spjd /* 1080168404Spjd * As a special case, check for use of '/' in the name, and 1081168404Spjd * direct the user to use 'zfs destroy' instead. 1082168404Spjd */ 1083168404Spjd if (strchr(pool, '/') != NULL) 1084168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1085168404Spjd "destroy a dataset\n")); 1086168404Spjd return (1); 1087168404Spjd } 1088168404Spjd 1089168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1090168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1091168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1092168404Spjd return (1); 1093168404Spjd } 1094168404Spjd 1095168404Spjd ret = (zpool_destroy(zhp) != 0); 1096168404Spjd 1097168404Spjd zpool_close(zhp); 1098168404Spjd 1099168404Spjd return (ret); 1100168404Spjd} 1101168404Spjd 1102168404Spjd/* 1103168404Spjd * zpool export [-f] <pool> ... 1104168404Spjd * 1105168404Spjd * -f Forcefully unmount datasets 1106168404Spjd * 1107168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1108168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1109168404Spjd * then the datasets will be forcefully unmounted. 1110168404Spjd */ 1111168404Spjdint 1112168404Spjdzpool_do_export(int argc, char **argv) 1113168404Spjd{ 1114168404Spjd boolean_t force = B_FALSE; 1115207670Smm boolean_t hardforce = B_FALSE; 1116168404Spjd int c; 1117168404Spjd zpool_handle_t *zhp; 1118168404Spjd int ret; 1119168404Spjd int i; 1120168404Spjd 1121168404Spjd /* check options */ 1122207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1123168404Spjd switch (c) { 1124168404Spjd case 'f': 1125168404Spjd force = B_TRUE; 1126168404Spjd break; 1127207670Smm case 'F': 1128207670Smm hardforce = B_TRUE; 1129207670Smm break; 1130168404Spjd case '?': 1131168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1132168404Spjd optopt); 1133168404Spjd usage(B_FALSE); 1134168404Spjd } 1135168404Spjd } 1136168404Spjd 1137168404Spjd argc -= optind; 1138168404Spjd argv += optind; 1139168404Spjd 1140168404Spjd /* check arguments */ 1141168404Spjd if (argc < 1) { 1142168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1143168404Spjd usage(B_FALSE); 1144168404Spjd } 1145168404Spjd 1146168404Spjd ret = 0; 1147168404Spjd for (i = 0; i < argc; i++) { 1148168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1149168404Spjd ret = 1; 1150168404Spjd continue; 1151168404Spjd } 1152168404Spjd 1153168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1154168404Spjd ret = 1; 1155168404Spjd zpool_close(zhp); 1156168404Spjd continue; 1157168404Spjd } 1158168404Spjd 1159207670Smm if (hardforce) { 1160207670Smm if (zpool_export_force(zhp) != 0) 1161207670Smm ret = 1; 1162207670Smm } else if (zpool_export(zhp, force) != 0) { 1163168404Spjd ret = 1; 1164207670Smm } 1165168404Spjd 1166168404Spjd zpool_close(zhp); 1167168404Spjd } 1168168404Spjd 1169168404Spjd return (ret); 1170168404Spjd} 1171168404Spjd 1172168404Spjd/* 1173168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1174168404Spjd * name column. 1175168404Spjd */ 1176168404Spjdstatic int 1177168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1178168404Spjd{ 1179219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1180168404Spjd nvlist_t **child; 1181168404Spjd uint_t c, children; 1182168404Spjd int ret; 1183168404Spjd 1184168404Spjd if (strlen(name) + depth > max) 1185168404Spjd max = strlen(name) + depth; 1186168404Spjd 1187168404Spjd free(name); 1188168404Spjd 1189168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1190168404Spjd &child, &children) == 0) { 1191168404Spjd for (c = 0; c < children; c++) 1192168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1193168404Spjd max)) > max) 1194168404Spjd max = ret; 1195168404Spjd } 1196168404Spjd 1197185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1198185029Spjd &child, &children) == 0) { 1199185029Spjd for (c = 0; c < children; c++) 1200185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1201185029Spjd max)) > max) 1202185029Spjd max = ret; 1203185029Spjd } 1204185029Spjd 1205168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1206168404Spjd &child, &children) == 0) { 1207168404Spjd for (c = 0; c < children; c++) 1208168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1209168404Spjd max)) > max) 1210168404Spjd max = ret; 1211168404Spjd } 1212168404Spjd 1213168404Spjd 1214168404Spjd return (max); 1215168404Spjd} 1216168404Spjd 1217213197Smmtypedef struct spare_cbdata { 1218213197Smm uint64_t cb_guid; 1219213197Smm zpool_handle_t *cb_zhp; 1220213197Smm} spare_cbdata_t; 1221168404Spjd 1222213197Smmstatic boolean_t 1223213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1224213197Smm{ 1225213197Smm uint64_t guid; 1226213197Smm nvlist_t **child; 1227213197Smm uint_t c, children; 1228213197Smm 1229213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1230213197Smm search == guid) 1231213197Smm return (B_TRUE); 1232213197Smm 1233213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1234213197Smm &child, &children) == 0) { 1235213197Smm for (c = 0; c < children; c++) 1236213197Smm if (find_vdev(child[c], search)) 1237213197Smm return (B_TRUE); 1238213197Smm } 1239213197Smm 1240213197Smm return (B_FALSE); 1241213197Smm} 1242213197Smm 1243213197Smmstatic int 1244213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1245213197Smm{ 1246213197Smm spare_cbdata_t *cbp = data; 1247213197Smm nvlist_t *config, *nvroot; 1248213197Smm 1249213197Smm config = zpool_get_config(zhp, NULL); 1250213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1251213197Smm &nvroot) == 0); 1252213197Smm 1253213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1254213197Smm cbp->cb_zhp = zhp; 1255213197Smm return (1); 1256213197Smm } 1257213197Smm 1258213197Smm zpool_close(zhp); 1259213197Smm return (0); 1260213197Smm} 1261213197Smm 1262168404Spjd/* 1263213197Smm * Print out configuration state as requested by status_callback. 1264213197Smm */ 1265213197Smmvoid 1266213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1267213197Smm int namewidth, int depth, boolean_t isspare) 1268213197Smm{ 1269213197Smm nvlist_t **child; 1270213197Smm uint_t c, children; 1271219089Spjd pool_scan_stat_t *ps = NULL; 1272213197Smm vdev_stat_t *vs; 1273219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1274213197Smm char *vname; 1275213197Smm uint64_t notpresent; 1276213197Smm spare_cbdata_t cb; 1277224169Sgibbs const char *state; 1278213197Smm 1279213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1280213197Smm &child, &children) != 0) 1281213197Smm children = 0; 1282213197Smm 1283219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1284219089Spjd (uint64_t **)&vs, &c) == 0); 1285219089Spjd 1286213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1287213197Smm if (isspare) { 1288213197Smm /* 1289213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1290213197Smm * online drives. 1291213197Smm */ 1292213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1293213197Smm state = "INUSE"; 1294213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1295213197Smm state = "AVAIL"; 1296213197Smm } 1297213197Smm 1298213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1299213197Smm name, state); 1300213197Smm 1301213197Smm if (!isspare) { 1302213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1303213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1304213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1305213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1306213197Smm } 1307213197Smm 1308213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1309224170Sgibbs ¬present) == 0 || 1310224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1311213197Smm char *path; 1312224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1313224170Sgibbs (void) printf(" was %s", path); 1314213197Smm } else if (vs->vs_aux != 0) { 1315213197Smm (void) printf(" "); 1316213197Smm 1317213197Smm switch (vs->vs_aux) { 1318213197Smm case VDEV_AUX_OPEN_FAILED: 1319213197Smm (void) printf(gettext("cannot open")); 1320213197Smm break; 1321213197Smm 1322213197Smm case VDEV_AUX_BAD_GUID_SUM: 1323213197Smm (void) printf(gettext("missing device")); 1324213197Smm break; 1325213197Smm 1326213197Smm case VDEV_AUX_NO_REPLICAS: 1327213197Smm (void) printf(gettext("insufficient replicas")); 1328213197Smm break; 1329213197Smm 1330213197Smm case VDEV_AUX_VERSION_NEWER: 1331213197Smm (void) printf(gettext("newer version")); 1332213197Smm break; 1333213197Smm 1334236884Smm case VDEV_AUX_UNSUP_FEAT: 1335236884Smm (void) printf(gettext("unsupported feature(s)")); 1336236884Smm break; 1337236884Smm 1338213197Smm case VDEV_AUX_SPARED: 1339213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1340213197Smm &cb.cb_guid) == 0); 1341213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1342213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1343213197Smm zpool_get_name(zhp)) == 0) 1344213197Smm (void) printf(gettext("currently in " 1345213197Smm "use")); 1346213197Smm else 1347213197Smm (void) printf(gettext("in use by " 1348213197Smm "pool '%s'"), 1349213197Smm zpool_get_name(cb.cb_zhp)); 1350213197Smm zpool_close(cb.cb_zhp); 1351213197Smm } else { 1352213197Smm (void) printf(gettext("currently in use")); 1353213197Smm } 1354213197Smm break; 1355213197Smm 1356213197Smm case VDEV_AUX_ERR_EXCEEDED: 1357213197Smm (void) printf(gettext("too many errors")); 1358213197Smm break; 1359213197Smm 1360213197Smm case VDEV_AUX_IO_FAILURE: 1361213197Smm (void) printf(gettext("experienced I/O failures")); 1362213197Smm break; 1363213197Smm 1364213197Smm case VDEV_AUX_BAD_LOG: 1365213197Smm (void) printf(gettext("bad intent log")); 1366213197Smm break; 1367213197Smm 1368219089Spjd case VDEV_AUX_EXTERNAL: 1369219089Spjd (void) printf(gettext("external device fault")); 1370219089Spjd break; 1371219089Spjd 1372219089Spjd case VDEV_AUX_SPLIT_POOL: 1373219089Spjd (void) printf(gettext("split into new pool")); 1374219089Spjd break; 1375219089Spjd 1376213197Smm default: 1377213197Smm (void) printf(gettext("corrupted data")); 1378213197Smm break; 1379213197Smm } 1380213197Smm } 1381213197Smm 1382219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1383219089Spjd (uint64_t **)&ps, &c); 1384219089Spjd 1385219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1386219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1387219089Spjd (void) printf(gettext(" (%s)"), 1388219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1389219089Spjd "resilvering" : "repairing"); 1390219089Spjd } 1391219089Spjd 1392213197Smm (void) printf("\n"); 1393213197Smm 1394213197Smm for (c = 0; c < children; c++) { 1395219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1396213197Smm 1397219089Spjd /* Don't print logs or holes here */ 1398213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1399219089Spjd &islog); 1400219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1401219089Spjd &ishole); 1402219089Spjd if (islog || ishole) 1403213197Smm continue; 1404219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1405213197Smm print_status_config(zhp, vname, child[c], 1406213197Smm namewidth, depth + 2, isspare); 1407213197Smm free(vname); 1408213197Smm } 1409213197Smm} 1410213197Smm 1411213197Smm 1412213197Smm/* 1413168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1414168404Spjd * pool, printing out the name and status for each one. 1415168404Spjd */ 1416168404Spjdvoid 1417213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1418168404Spjd{ 1419168404Spjd nvlist_t **child; 1420168404Spjd uint_t c, children; 1421168404Spjd vdev_stat_t *vs; 1422168404Spjd char *type, *vname; 1423168404Spjd 1424168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1425219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1426219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1427168404Spjd return; 1428168404Spjd 1429219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1430168404Spjd (uint64_t **)&vs, &c) == 0); 1431168404Spjd 1432168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1433185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1434168404Spjd 1435168404Spjd if (vs->vs_aux != 0) { 1436185029Spjd (void) printf(" "); 1437168404Spjd 1438168404Spjd switch (vs->vs_aux) { 1439168404Spjd case VDEV_AUX_OPEN_FAILED: 1440168404Spjd (void) printf(gettext("cannot open")); 1441168404Spjd break; 1442168404Spjd 1443168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1444168404Spjd (void) printf(gettext("missing device")); 1445168404Spjd break; 1446168404Spjd 1447168404Spjd case VDEV_AUX_NO_REPLICAS: 1448168404Spjd (void) printf(gettext("insufficient replicas")); 1449168404Spjd break; 1450168404Spjd 1451168404Spjd case VDEV_AUX_VERSION_NEWER: 1452168404Spjd (void) printf(gettext("newer version")); 1453168404Spjd break; 1454168404Spjd 1455236884Smm case VDEV_AUX_UNSUP_FEAT: 1456236884Smm (void) printf(gettext("unsupported feature(s)")); 1457236884Smm break; 1458236884Smm 1459185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1460185029Spjd (void) printf(gettext("too many errors")); 1461185029Spjd break; 1462185029Spjd 1463168404Spjd default: 1464168404Spjd (void) printf(gettext("corrupted data")); 1465168404Spjd break; 1466168404Spjd } 1467168404Spjd } 1468168404Spjd (void) printf("\n"); 1469168404Spjd 1470168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1471168404Spjd &child, &children) != 0) 1472168404Spjd return; 1473168404Spjd 1474168404Spjd for (c = 0; c < children; c++) { 1475185029Spjd uint64_t is_log = B_FALSE; 1476185029Spjd 1477185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1478185029Spjd &is_log); 1479213197Smm if (is_log) 1480185029Spjd continue; 1481185029Spjd 1482219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1483213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1484168404Spjd free(vname); 1485168404Spjd } 1486168404Spjd 1487185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1488185029Spjd &child, &children) == 0) { 1489185029Spjd (void) printf(gettext("\tcache\n")); 1490185029Spjd for (c = 0; c < children; c++) { 1491219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1492185029Spjd (void) printf("\t %s\n", vname); 1493185029Spjd free(vname); 1494185029Spjd } 1495185029Spjd } 1496185029Spjd 1497168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1498185029Spjd &child, &children) == 0) { 1499185029Spjd (void) printf(gettext("\tspares\n")); 1500185029Spjd for (c = 0; c < children; c++) { 1501219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1502185029Spjd (void) printf("\t %s\n", vname); 1503185029Spjd free(vname); 1504185029Spjd } 1505168404Spjd } 1506168404Spjd} 1507168404Spjd 1508168404Spjd/* 1509213197Smm * Print log vdevs. 1510213197Smm * Logs are recorded as top level vdevs in the main pool child array 1511213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1512213197Smm * print_import_config() to print the top level logs then any log 1513213197Smm * children (eg mirrored slogs) are printed recursively - which 1514213197Smm * works because only the top level vdev is marked "is_log" 1515213197Smm */ 1516213197Smmstatic void 1517213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1518213197Smm{ 1519213197Smm uint_t c, children; 1520213197Smm nvlist_t **child; 1521213197Smm 1522213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1523213197Smm &children) != 0) 1524213197Smm return; 1525213197Smm 1526213197Smm (void) printf(gettext("\tlogs\n")); 1527213197Smm 1528213197Smm for (c = 0; c < children; c++) { 1529213197Smm uint64_t is_log = B_FALSE; 1530213197Smm char *name; 1531213197Smm 1532213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1533213197Smm &is_log); 1534213197Smm if (!is_log) 1535213197Smm continue; 1536219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1537213197Smm if (verbose) 1538213197Smm print_status_config(zhp, name, child[c], namewidth, 1539213197Smm 2, B_FALSE); 1540213197Smm else 1541213197Smm print_import_config(name, child[c], namewidth, 2); 1542213197Smm free(name); 1543213197Smm } 1544213197Smm} 1545219089Spjd 1546213197Smm/* 1547168404Spjd * Display the status for the given pool. 1548168404Spjd */ 1549168404Spjdstatic void 1550168404Spjdshow_import(nvlist_t *config) 1551168404Spjd{ 1552168404Spjd uint64_t pool_state; 1553168404Spjd vdev_stat_t *vs; 1554168404Spjd char *name; 1555168404Spjd uint64_t guid; 1556168404Spjd char *msgid; 1557168404Spjd nvlist_t *nvroot; 1558168404Spjd int reason; 1559168404Spjd const char *health; 1560168404Spjd uint_t vsc; 1561168404Spjd int namewidth; 1562228103Smm char *comment; 1563168404Spjd 1564168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1565168404Spjd &name) == 0); 1566168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1567168404Spjd &guid) == 0); 1568168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1569168404Spjd &pool_state) == 0); 1570168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1571168404Spjd &nvroot) == 0); 1572168404Spjd 1573219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1574168404Spjd (uint64_t **)&vs, &vsc) == 0); 1575185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1576168404Spjd 1577168404Spjd reason = zpool_import_status(config, &msgid); 1578168404Spjd 1579228103Smm (void) printf(gettext(" pool: %s\n"), name); 1580228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1581228103Smm (void) printf(gettext(" state: %s"), health); 1582168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1583168404Spjd (void) printf(gettext(" (DESTROYED)")); 1584168404Spjd (void) printf("\n"); 1585168404Spjd 1586168404Spjd switch (reason) { 1587168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1588168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1589168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1590228103Smm (void) printf(gettext(" status: One or more devices are " 1591228103Smm "missing from the system.\n")); 1592168404Spjd break; 1593168404Spjd 1594168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1595168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1596228103Smm (void) printf(gettext(" status: One or more devices contains " 1597168404Spjd "corrupted data.\n")); 1598168404Spjd break; 1599168404Spjd 1600168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1601228103Smm (void) printf( 1602228103Smm gettext(" status: The pool data is corrupted.\n")); 1603168404Spjd break; 1604168404Spjd 1605168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1606228103Smm (void) printf(gettext(" status: One or more devices " 1607168404Spjd "are offlined.\n")); 1608168404Spjd break; 1609168404Spjd 1610168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1611228103Smm (void) printf(gettext(" status: The pool metadata is " 1612168404Spjd "corrupted.\n")); 1613168404Spjd break; 1614168404Spjd 1615168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1616238926Smm (void) printf(gettext(" status: The pool is formatted using a " 1617238926Smm "legacy on-disk version.\n")); 1618168404Spjd break; 1619168404Spjd 1620168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1621228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1622168404Spjd "incompatible version.\n")); 1623168404Spjd break; 1624168404Spjd 1625238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 1626238926Smm (void) printf(gettext(" status: Some supported features are " 1627238926Smm "not enabled on the pool.\n")); 1628238926Smm break; 1629238926Smm 1630236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1631236884Smm (void) printf(gettext("status: The pool uses the following " 1632236884Smm "feature(s) not supported on this sytem:\n")); 1633236884Smm zpool_print_unsup_feat(config); 1634236884Smm break; 1635236884Smm 1636236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1637236884Smm (void) printf(gettext("status: The pool can only be accessed " 1638236884Smm "in read-only mode on this system. It\n\tcannot be " 1639236884Smm "accessed in read-write mode because it uses the " 1640236884Smm "following\n\tfeature(s) not supported on this system:\n")); 1641236884Smm zpool_print_unsup_feat(config); 1642236884Smm break; 1643236884Smm 1644168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1645228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1646168498Spjd "another system.\n")); 1647168498Spjd break; 1648185029Spjd 1649185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1650185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1651228103Smm (void) printf(gettext(" status: One or more devices are " 1652185029Spjd "faulted.\n")); 1653185029Spjd break; 1654185029Spjd 1655185029Spjd case ZPOOL_STATUS_BAD_LOG: 1656228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1657185029Spjd "read.\n")); 1658185029Spjd break; 1659185029Spjd 1660219089Spjd case ZPOOL_STATUS_RESILVERING: 1661228103Smm (void) printf(gettext(" status: One or more devices were being " 1662219089Spjd "resilvered.\n")); 1663219089Spjd break; 1664219089Spjd 1665168404Spjd default: 1666168404Spjd /* 1667168404Spjd * No other status can be seen when importing pools. 1668168404Spjd */ 1669168404Spjd assert(reason == ZPOOL_STATUS_OK); 1670168404Spjd } 1671168404Spjd 1672168404Spjd /* 1673168404Spjd * Print out an action according to the overall state of the pool. 1674168404Spjd */ 1675168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1676238926Smm if (reason == ZPOOL_STATUS_VERSION_OLDER || 1677238926Smm reason == ZPOOL_STATUS_FEAT_DISABLED) { 1678228103Smm (void) printf(gettext(" action: The pool can be " 1679168404Spjd "imported using its name or numeric identifier, " 1680168404Spjd "though\n\tsome features will not be available " 1681168404Spjd "without an explicit 'zpool upgrade'.\n")); 1682238926Smm } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 1683228103Smm (void) printf(gettext(" action: The pool can be " 1684168498Spjd "imported using its name or numeric " 1685168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1686238926Smm } else { 1687228103Smm (void) printf(gettext(" action: The pool can be " 1688168404Spjd "imported using its name or numeric " 1689168404Spjd "identifier.\n")); 1690238926Smm } 1691168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1692228103Smm (void) printf(gettext(" action: The pool can be imported " 1693168404Spjd "despite missing or damaged devices. The\n\tfault " 1694168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1695168404Spjd } else { 1696168404Spjd switch (reason) { 1697168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1698228103Smm (void) printf(gettext(" action: The pool cannot be " 1699168404Spjd "imported. Access the pool on a system running " 1700168404Spjd "newer\n\tsoftware, or recreate the pool from " 1701168404Spjd "backup.\n")); 1702168404Spjd break; 1703236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1704236884Smm (void) printf(gettext("action: The pool cannot be " 1705236884Smm "imported. Access the pool on a system that " 1706236884Smm "supports\n\tthe required feature(s), or recreate " 1707236884Smm "the pool from backup.\n")); 1708236884Smm break; 1709236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1710236884Smm (void) printf(gettext("action: The pool cannot be " 1711236884Smm "imported in read-write mode. Import the pool " 1712236884Smm "with\n" 1713236884Smm "\t\"-o readonly=on\", access the pool on a system " 1714236884Smm "that supports the\n\trequired feature(s), or " 1715236884Smm "recreate the pool from backup.\n")); 1716236884Smm break; 1717168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1718168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1719168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1720228103Smm (void) printf(gettext(" action: The pool cannot be " 1721168404Spjd "imported. Attach the missing\n\tdevices and try " 1722168404Spjd "again.\n")); 1723168404Spjd break; 1724168404Spjd default: 1725228103Smm (void) printf(gettext(" action: The pool cannot be " 1726168404Spjd "imported due to damaged devices or data.\n")); 1727168404Spjd } 1728168404Spjd } 1729168404Spjd 1730228103Smm /* Print the comment attached to the pool. */ 1731228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 1732228103Smm (void) printf(gettext("comment: %s\n"), comment); 1733228103Smm 1734168404Spjd /* 1735168404Spjd * If the state is "closed" or "can't open", and the aux state 1736168404Spjd * is "corrupt data": 1737168404Spjd */ 1738168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1739168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1740168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1741168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1742168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1743168404Spjd "but can be imported using the '-Df' flags.\n")); 1744168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1745168404Spjd (void) printf(gettext("\tThe pool may be active on " 1746185029Spjd "another system, but can be imported using\n\t" 1747168404Spjd "the '-f' flag.\n")); 1748168404Spjd } 1749168404Spjd 1750168404Spjd if (msgid != NULL) 1751236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1752168404Spjd msgid); 1753168404Spjd 1754228103Smm (void) printf(gettext(" config:\n\n")); 1755168404Spjd 1756168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1757168404Spjd if (namewidth < 10) 1758168404Spjd namewidth = 10; 1759168404Spjd 1760213197Smm print_import_config(name, nvroot, namewidth, 0); 1761213197Smm if (num_logs(nvroot) > 0) 1762213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1763185029Spjd 1764168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1765168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1766168404Spjd "be part of this pool, though their\n\texact " 1767168404Spjd "configuration cannot be determined.\n")); 1768168404Spjd } 1769168404Spjd} 1770168404Spjd 1771168404Spjd/* 1772168404Spjd * Perform the import for the given configuration. This passes the heavy 1773185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1774185029Spjd * within the pool. 1775168404Spjd */ 1776168404Spjdstatic int 1777168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1778219089Spjd nvlist_t *props, int flags) 1779168404Spjd{ 1780168404Spjd zpool_handle_t *zhp; 1781168404Spjd char *name; 1782168404Spjd uint64_t state; 1783168404Spjd uint64_t version; 1784168404Spjd 1785168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1786168404Spjd &name) == 0); 1787168404Spjd 1788168404Spjd verify(nvlist_lookup_uint64(config, 1789168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1790168404Spjd verify(nvlist_lookup_uint64(config, 1791168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1792236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 1793168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1794236884Smm "is formatted using an unsupported ZFS version\n"), name); 1795168404Spjd return (1); 1796219089Spjd } else if (state != POOL_STATE_EXPORTED && 1797219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 1798168498Spjd uint64_t hostid; 1799168498Spjd 1800168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1801168498Spjd &hostid) == 0) { 1802168498Spjd if ((unsigned long)hostid != gethostid()) { 1803168498Spjd char *hostname; 1804168498Spjd uint64_t timestamp; 1805168498Spjd time_t t; 1806168498Spjd 1807168498Spjd verify(nvlist_lookup_string(config, 1808168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1809168498Spjd verify(nvlist_lookup_uint64(config, 1810168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1811168498Spjd t = timestamp; 1812168498Spjd (void) fprintf(stderr, gettext("cannot import " 1813168498Spjd "'%s': pool may be in use from other " 1814168498Spjd "system, it was last accessed by %s " 1815168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1816168498Spjd (unsigned long)hostid, 1817168498Spjd asctime(localtime(&t))); 1818168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1819168498Spjd "import anyway\n")); 1820168498Spjd return (1); 1821168498Spjd } 1822168498Spjd } else { 1823168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1824168498Spjd "pool may be in use from other system\n"), name); 1825168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1826168498Spjd "anyway\n")); 1827168498Spjd return (1); 1828168498Spjd } 1829168404Spjd } 1830168404Spjd 1831219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1832168404Spjd return (1); 1833168404Spjd 1834168404Spjd if (newname != NULL) 1835168404Spjd name = (char *)newname; 1836168404Spjd 1837209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 1838209962Smm return (1); 1839168404Spjd 1840209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1841219089Spjd !(flags & ZFS_IMPORT_ONLY) && 1842209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1843168404Spjd zpool_close(zhp); 1844168404Spjd return (1); 1845168404Spjd } 1846168404Spjd 1847168404Spjd zpool_close(zhp); 1848219089Spjd return (0); 1849168404Spjd} 1850168404Spjd 1851168404Spjd/* 1852168404Spjd * zpool import [-d dir] [-D] 1853185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1854185029Spjd * [-d dir | -c cachefile] [-f] -a 1855185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1856219089Spjd * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 1857168404Spjd * 1858185029Spjd * -c Read pool information from a cachefile instead of searching 1859185029Spjd * devices. 1860185029Spjd * 1861168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1862168404Spjd * one directory can be specified using multiple '-d' options. 1863168404Spjd * 1864168404Spjd * -D Scan for previously destroyed pools or import all or only 1865168404Spjd * specified destroyed pools. 1866168404Spjd * 1867168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1868168404Spjd * the given root. The pool will remain exported when the machine 1869168404Spjd * is rebooted. 1870168404Spjd * 1871219089Spjd * -V Import even in the presence of faulted vdevs. This is an 1872185029Spjd * intentionally undocumented option for testing purposes, and 1873185029Spjd * treats the pool configuration as complete, leaving any bad 1874209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 1875209962Smm * import. 1876185029Spjd * 1877219089Spjd * -f Force import, even if it appears that the pool is active. 1878219089Spjd * 1879219089Spjd * -F Attempt rewind if necessary. 1880219089Spjd * 1881219089Spjd * -n See if rewind would work, but don't actually rewind. 1882219089Spjd * 1883219089Spjd * -N Import the pool but don't mount datasets. 1884219089Spjd * 1885219089Spjd * -T Specify a starting txg to use for import. This option is 1886219089Spjd * intentionally undocumented option for testing purposes. 1887219089Spjd * 1888168404Spjd * -a Import all pools found. 1889168404Spjd * 1890185029Spjd * -o Set property=value and/or temporary mount options (without '='). 1891185029Spjd * 1892168404Spjd * The import command scans for pools to import, and import pools based on pool 1893168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 1894168404Spjd */ 1895168404Spjdint 1896168404Spjdzpool_do_import(int argc, char **argv) 1897168404Spjd{ 1898168404Spjd char **searchdirs = NULL; 1899168404Spjd int nsearch = 0; 1900168404Spjd int c; 1901219089Spjd int err = 0; 1902185029Spjd nvlist_t *pools = NULL; 1903168404Spjd boolean_t do_all = B_FALSE; 1904168404Spjd boolean_t do_destroyed = B_FALSE; 1905168404Spjd char *mntopts = NULL; 1906168404Spjd nvpair_t *elem; 1907168404Spjd nvlist_t *config; 1908185029Spjd uint64_t searchguid = 0; 1909185029Spjd char *searchname = NULL; 1910185029Spjd char *propval; 1911168404Spjd nvlist_t *found_config; 1912219089Spjd nvlist_t *policy = NULL; 1913185029Spjd nvlist_t *props = NULL; 1914168404Spjd boolean_t first; 1915219089Spjd int flags = ZFS_IMPORT_NORMAL; 1916219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 1917219089Spjd boolean_t dryrun = B_FALSE; 1918219089Spjd boolean_t do_rewind = B_FALSE; 1919219089Spjd boolean_t xtreme_rewind = B_FALSE; 1920219089Spjd uint64_t pool_state, txg = -1ULL; 1921185029Spjd char *cachefile = NULL; 1922219089Spjd importargs_t idata = { 0 }; 1923219089Spjd char *endptr; 1924168404Spjd 1925168404Spjd /* check options */ 1926219089Spjd while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) { 1927168404Spjd switch (c) { 1928168404Spjd case 'a': 1929168404Spjd do_all = B_TRUE; 1930168404Spjd break; 1931185029Spjd case 'c': 1932185029Spjd cachefile = optarg; 1933185029Spjd break; 1934168404Spjd case 'd': 1935168404Spjd if (searchdirs == NULL) { 1936168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1937168404Spjd } else { 1938168404Spjd char **tmp = safe_malloc((nsearch + 1) * 1939168404Spjd sizeof (char *)); 1940168404Spjd bcopy(searchdirs, tmp, nsearch * 1941168404Spjd sizeof (char *)); 1942168404Spjd free(searchdirs); 1943168404Spjd searchdirs = tmp; 1944168404Spjd } 1945168404Spjd searchdirs[nsearch++] = optarg; 1946168404Spjd break; 1947168404Spjd case 'D': 1948168404Spjd do_destroyed = B_TRUE; 1949168404Spjd break; 1950168404Spjd case 'f': 1951219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 1952168404Spjd break; 1953185029Spjd case 'F': 1954219089Spjd do_rewind = B_TRUE; 1955185029Spjd break; 1956219089Spjd case 'm': 1957219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 1958219089Spjd break; 1959219089Spjd case 'n': 1960219089Spjd dryrun = B_TRUE; 1961219089Spjd break; 1962219089Spjd case 'N': 1963219089Spjd flags |= ZFS_IMPORT_ONLY; 1964219089Spjd break; 1965168404Spjd case 'o': 1966185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 1967185029Spjd *propval = '\0'; 1968185029Spjd propval++; 1969185029Spjd if (add_prop_list(optarg, propval, 1970185029Spjd &props, B_TRUE)) 1971185029Spjd goto error; 1972185029Spjd } else { 1973185029Spjd mntopts = optarg; 1974185029Spjd } 1975168404Spjd break; 1976168404Spjd case 'R': 1977185029Spjd if (add_prop_list(zpool_prop_to_name( 1978185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 1979185029Spjd goto error; 1980185029Spjd if (nvlist_lookup_string(props, 1981185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 1982185029Spjd &propval) == 0) 1983185029Spjd break; 1984185029Spjd if (add_prop_list(zpool_prop_to_name( 1985185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1986185029Spjd goto error; 1987168404Spjd break; 1988219089Spjd case 'T': 1989219089Spjd errno = 0; 1990219089Spjd txg = strtoull(optarg, &endptr, 10); 1991219089Spjd if (errno != 0 || *endptr != '\0') { 1992219089Spjd (void) fprintf(stderr, 1993219089Spjd gettext("invalid txg value\n")); 1994219089Spjd usage(B_FALSE); 1995219089Spjd } 1996219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 1997219089Spjd break; 1998219089Spjd case 'V': 1999219089Spjd flags |= ZFS_IMPORT_VERBATIM; 2000219089Spjd break; 2001219089Spjd case 'X': 2002219089Spjd xtreme_rewind = B_TRUE; 2003219089Spjd break; 2004168404Spjd case ':': 2005168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2006168404Spjd "'%c' option\n"), optopt); 2007168404Spjd usage(B_FALSE); 2008168404Spjd break; 2009168404Spjd case '?': 2010168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2011168404Spjd optopt); 2012168404Spjd usage(B_FALSE); 2013168404Spjd } 2014168404Spjd } 2015168404Spjd 2016168404Spjd argc -= optind; 2017168404Spjd argv += optind; 2018168404Spjd 2019185029Spjd if (cachefile && nsearch != 0) { 2020185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 2021185029Spjd usage(B_FALSE); 2022185029Spjd } 2023185029Spjd 2024219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 2025219089Spjd (void) fprintf(stderr, 2026219089Spjd gettext("-n or -X only meaningful with -F\n")); 2027219089Spjd usage(B_FALSE); 2028219089Spjd } 2029219089Spjd if (dryrun) 2030219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 2031219089Spjd else if (do_rewind) 2032219089Spjd rewind_policy = ZPOOL_DO_REWIND; 2033219089Spjd if (xtreme_rewind) 2034219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 2035219089Spjd 2036219089Spjd /* In the future, we can capture further policy and include it here */ 2037219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2038219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 2039219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 2040219089Spjd goto error; 2041219089Spjd 2042168404Spjd if (searchdirs == NULL) { 2043168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2044235478Savg searchdirs[0] = "/dev"; 2045168404Spjd nsearch = 1; 2046168404Spjd } 2047168404Spjd 2048168404Spjd /* check argument count */ 2049168404Spjd if (do_all) { 2050168404Spjd if (argc != 0) { 2051168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2052168404Spjd usage(B_FALSE); 2053168404Spjd } 2054168404Spjd } else { 2055168404Spjd if (argc > 2) { 2056168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2057168404Spjd usage(B_FALSE); 2058168404Spjd } 2059168404Spjd 2060168404Spjd /* 2061168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 2062168404Spjd * here because otherwise any attempt to discover pools will 2063168404Spjd * silently fail. 2064168404Spjd */ 2065168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2066168404Spjd (void) fprintf(stderr, gettext("cannot " 2067168404Spjd "discover pools: permission denied\n")); 2068168404Spjd free(searchdirs); 2069219089Spjd nvlist_free(policy); 2070168404Spjd return (1); 2071168404Spjd } 2072168404Spjd } 2073168404Spjd 2074168404Spjd /* 2075168404Spjd * Depending on the arguments given, we do one of the following: 2076168404Spjd * 2077168404Spjd * <none> Iterate through all pools and display information about 2078168404Spjd * each one. 2079168404Spjd * 2080168404Spjd * -a Iterate through all pools and try to import each one. 2081168404Spjd * 2082168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 2083168404Spjd * name and import that one. 2084168404Spjd * 2085168404Spjd * -D Above options applies only to destroyed pools. 2086168404Spjd */ 2087168404Spjd if (argc != 0) { 2088168404Spjd char *endptr; 2089168404Spjd 2090168404Spjd errno = 0; 2091168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 2092168404Spjd if (errno != 0 || *endptr != '\0') 2093168404Spjd searchname = argv[0]; 2094168404Spjd found_config = NULL; 2095168404Spjd 2096185029Spjd /* 2097219089Spjd * User specified a name or guid. Ensure it's unique. 2098185029Spjd */ 2099219089Spjd idata.unique = B_TRUE; 2100185029Spjd } 2101185029Spjd 2102219089Spjd 2103219089Spjd idata.path = searchdirs; 2104219089Spjd idata.paths = nsearch; 2105219089Spjd idata.poolname = searchname; 2106219089Spjd idata.guid = searchguid; 2107219089Spjd idata.cachefile = cachefile; 2108219089Spjd 2109219089Spjd pools = zpool_search_import(g_zfs, &idata); 2110219089Spjd 2111219089Spjd if (pools != NULL && idata.exists && 2112219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2113219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2114219089Spjd "a pool with that name already exists\n"), 2115219089Spjd argv[0]); 2116219089Spjd (void) fprintf(stderr, gettext("use the form '%s " 2117219089Spjd "<pool | id> <newpool>' to give it a new name\n"), 2118219089Spjd "zpool import"); 2119219089Spjd err = 1; 2120219089Spjd } else if (pools == NULL && idata.exists) { 2121219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2122219089Spjd "a pool with that name is already created/imported,\n"), 2123219089Spjd argv[0]); 2124219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2125219089Spjd "with that name were found\n")); 2126219089Spjd err = 1; 2127219089Spjd } else if (pools == NULL) { 2128185029Spjd if (argc != 0) { 2129185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2130185029Spjd "no such pool available\n"), argv[0]); 2131185029Spjd } 2132219089Spjd err = 1; 2133219089Spjd } 2134219089Spjd 2135219089Spjd if (err == 1) { 2136185029Spjd free(searchdirs); 2137219089Spjd nvlist_free(policy); 2138185029Spjd return (1); 2139185029Spjd } 2140185029Spjd 2141185029Spjd /* 2142185029Spjd * At this point we have a list of import candidate configs. Even if 2143185029Spjd * we were searching by pool name or guid, we still need to 2144185029Spjd * post-process the list to deal with pool state and possible 2145185029Spjd * duplicate names. 2146185029Spjd */ 2147168404Spjd err = 0; 2148168404Spjd elem = NULL; 2149168404Spjd first = B_TRUE; 2150168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2151168404Spjd 2152168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2153168404Spjd 2154168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2155168404Spjd &pool_state) == 0); 2156168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2157168404Spjd continue; 2158168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2159168404Spjd continue; 2160168404Spjd 2161219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2162219089Spjd policy) == 0); 2163219089Spjd 2164168404Spjd if (argc == 0) { 2165168404Spjd if (first) 2166168404Spjd first = B_FALSE; 2167168404Spjd else if (!do_all) 2168168404Spjd (void) printf("\n"); 2169168404Spjd 2170219089Spjd if (do_all) { 2171168404Spjd err |= do_import(config, NULL, mntopts, 2172219089Spjd props, flags); 2173219089Spjd } else { 2174168404Spjd show_import(config); 2175219089Spjd } 2176168404Spjd } else if (searchname != NULL) { 2177168404Spjd char *name; 2178168404Spjd 2179168404Spjd /* 2180168404Spjd * We are searching for a pool based on name. 2181168404Spjd */ 2182168404Spjd verify(nvlist_lookup_string(config, 2183168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2184168404Spjd 2185168404Spjd if (strcmp(name, searchname) == 0) { 2186168404Spjd if (found_config != NULL) { 2187168404Spjd (void) fprintf(stderr, gettext( 2188168404Spjd "cannot import '%s': more than " 2189168404Spjd "one matching pool\n"), searchname); 2190168404Spjd (void) fprintf(stderr, gettext( 2191168404Spjd "import by numeric ID instead\n")); 2192168404Spjd err = B_TRUE; 2193168404Spjd } 2194168404Spjd found_config = config; 2195168404Spjd } 2196168404Spjd } else { 2197168404Spjd uint64_t guid; 2198168404Spjd 2199168404Spjd /* 2200168404Spjd * Search for a pool by guid. 2201168404Spjd */ 2202168404Spjd verify(nvlist_lookup_uint64(config, 2203168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2204168404Spjd 2205168404Spjd if (guid == searchguid) 2206168404Spjd found_config = config; 2207168404Spjd } 2208168404Spjd } 2209168404Spjd 2210168404Spjd /* 2211168404Spjd * If we were searching for a specific pool, verify that we found a 2212168404Spjd * pool, and then do the import. 2213168404Spjd */ 2214168404Spjd if (argc != 0 && err == 0) { 2215168404Spjd if (found_config == NULL) { 2216168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2217168404Spjd "no such pool available\n"), argv[0]); 2218168404Spjd err = B_TRUE; 2219168404Spjd } else { 2220168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2221219089Spjd argv[1], mntopts, props, flags); 2222168404Spjd } 2223168404Spjd } 2224168404Spjd 2225168404Spjd /* 2226168404Spjd * If we were just looking for pools, report an error if none were 2227168404Spjd * found. 2228168404Spjd */ 2229168404Spjd if (argc == 0 && first) 2230168404Spjd (void) fprintf(stderr, 2231168404Spjd gettext("no pools available to import\n")); 2232168404Spjd 2233185029Spjderror: 2234185029Spjd nvlist_free(props); 2235168404Spjd nvlist_free(pools); 2236219089Spjd nvlist_free(policy); 2237168404Spjd free(searchdirs); 2238168404Spjd 2239168404Spjd return (err ? 1 : 0); 2240168404Spjd} 2241168404Spjd 2242168404Spjdtypedef struct iostat_cbdata { 2243236155Smm boolean_t cb_verbose; 2244236155Smm int cb_namewidth; 2245236155Smm int cb_iteration; 2246168404Spjd zpool_list_t *cb_list; 2247168404Spjd} iostat_cbdata_t; 2248168404Spjd 2249168404Spjdstatic void 2250168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2251168404Spjd{ 2252168404Spjd int i = 0; 2253168404Spjd 2254168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2255168404Spjd (void) printf("-"); 2256168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2257168404Spjd} 2258168404Spjd 2259168404Spjdstatic void 2260168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2261168404Spjd{ 2262168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2263168404Spjd cb->cb_namewidth, ""); 2264219089Spjd (void) printf("%-*s alloc free read write read write\n", 2265168404Spjd cb->cb_namewidth, "pool"); 2266168404Spjd print_iostat_separator(cb); 2267168404Spjd} 2268168404Spjd 2269168404Spjd/* 2270168404Spjd * Display a single statistic. 2271168404Spjd */ 2272185029Spjdstatic void 2273168404Spjdprint_one_stat(uint64_t value) 2274168404Spjd{ 2275168404Spjd char buf[64]; 2276168404Spjd 2277168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2278168404Spjd (void) printf(" %5s", buf); 2279168404Spjd} 2280168404Spjd 2281168404Spjd/* 2282168404Spjd * Print out all the statistics for the given vdev. This can either be the 2283168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2284168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2285168404Spjd */ 2286168404Spjdvoid 2287168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2288168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2289168404Spjd{ 2290168404Spjd nvlist_t **oldchild, **newchild; 2291168404Spjd uint_t c, children; 2292168404Spjd vdev_stat_t *oldvs, *newvs; 2293168404Spjd vdev_stat_t zerovs = { 0 }; 2294168404Spjd uint64_t tdelta; 2295168404Spjd double scale; 2296168404Spjd char *vname; 2297168404Spjd 2298168404Spjd if (oldnv != NULL) { 2299219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2300219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2301168404Spjd } else { 2302168404Spjd oldvs = &zerovs; 2303168404Spjd } 2304168404Spjd 2305219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2306168404Spjd (uint64_t **)&newvs, &c) == 0); 2307168404Spjd 2308168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2309168404Spjd (void) printf("%*s%s", depth, "", name); 2310168404Spjd else 2311168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2312168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2313168404Spjd 2314168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2315168404Spjd 2316168404Spjd if (tdelta == 0) 2317168404Spjd scale = 1.0; 2318168404Spjd else 2319168404Spjd scale = (double)NANOSEC / tdelta; 2320168404Spjd 2321168404Spjd /* only toplevel vdevs have capacity stats */ 2322168404Spjd if (newvs->vs_space == 0) { 2323168404Spjd (void) printf(" - -"); 2324168404Spjd } else { 2325168404Spjd print_one_stat(newvs->vs_alloc); 2326168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2327168404Spjd } 2328168404Spjd 2329168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2330168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2331168404Spjd 2332168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2333168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2334168404Spjd 2335168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2336168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2337168404Spjd 2338168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2339168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2340168404Spjd 2341168404Spjd (void) printf("\n"); 2342168404Spjd 2343168404Spjd if (!cb->cb_verbose) 2344168404Spjd return; 2345168404Spjd 2346168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2347168404Spjd &newchild, &children) != 0) 2348168404Spjd return; 2349168404Spjd 2350168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2351168404Spjd &oldchild, &c) != 0) 2352168404Spjd return; 2353168404Spjd 2354168404Spjd for (c = 0; c < children; c++) { 2355227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2356219089Spjd 2357227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2358227497Smm &ishole); 2359227497Smm 2360227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2361227497Smm &islog); 2362227497Smm 2363227497Smm if (ishole || islog) 2364219089Spjd continue; 2365219089Spjd 2366219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2367168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2368168404Spjd newchild[c], cb, depth + 2); 2369168404Spjd free(vname); 2370168404Spjd } 2371185029Spjd 2372185029Spjd /* 2373227497Smm * Log device section 2374227497Smm */ 2375227497Smm 2376227497Smm if (num_logs(newnv) > 0) { 2377227497Smm (void) printf("%-*s - - - - - " 2378227497Smm "-\n", cb->cb_namewidth, "logs"); 2379227497Smm 2380227497Smm for (c = 0; c < children; c++) { 2381227497Smm uint64_t islog = B_FALSE; 2382227497Smm (void) nvlist_lookup_uint64(newchild[c], 2383227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2384227497Smm 2385227497Smm if (islog) { 2386227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2387227497Smm B_FALSE); 2388227497Smm print_vdev_stats(zhp, vname, oldnv ? 2389227497Smm oldchild[c] : NULL, newchild[c], 2390227497Smm cb, depth + 2); 2391227497Smm free(vname); 2392227497Smm } 2393227497Smm } 2394227497Smm 2395227497Smm } 2396227497Smm 2397227497Smm /* 2398185029Spjd * Include level 2 ARC devices in iostat output 2399185029Spjd */ 2400185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2401185029Spjd &newchild, &children) != 0) 2402185029Spjd return; 2403185029Spjd 2404185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2405185029Spjd &oldchild, &c) != 0) 2406185029Spjd return; 2407185029Spjd 2408185029Spjd if (children > 0) { 2409185029Spjd (void) printf("%-*s - - - - - " 2410185029Spjd "-\n", cb->cb_namewidth, "cache"); 2411185029Spjd for (c = 0; c < children; c++) { 2412219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2413219089Spjd B_FALSE); 2414185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2415185029Spjd newchild[c], cb, depth + 2); 2416185029Spjd free(vname); 2417185029Spjd } 2418185029Spjd } 2419168404Spjd} 2420168404Spjd 2421168404Spjdstatic int 2422168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2423168404Spjd{ 2424168404Spjd iostat_cbdata_t *cb = data; 2425168404Spjd boolean_t missing; 2426168404Spjd 2427168404Spjd /* 2428168404Spjd * If the pool has disappeared, remove it from the list and continue. 2429168404Spjd */ 2430168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2431168404Spjd return (-1); 2432168404Spjd 2433168404Spjd if (missing) 2434168404Spjd pool_list_remove(cb->cb_list, zhp); 2435168404Spjd 2436168404Spjd return (0); 2437168404Spjd} 2438168404Spjd 2439168404Spjd/* 2440168404Spjd * Callback to print out the iostats for the given pool. 2441168404Spjd */ 2442168404Spjdint 2443168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2444168404Spjd{ 2445168404Spjd iostat_cbdata_t *cb = data; 2446168404Spjd nvlist_t *oldconfig, *newconfig; 2447168404Spjd nvlist_t *oldnvroot, *newnvroot; 2448168404Spjd 2449168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2450168404Spjd 2451168404Spjd if (cb->cb_iteration == 1) 2452168404Spjd oldconfig = NULL; 2453168404Spjd 2454168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2455168404Spjd &newnvroot) == 0); 2456168404Spjd 2457168404Spjd if (oldconfig == NULL) 2458168404Spjd oldnvroot = NULL; 2459168404Spjd else 2460168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2461168404Spjd &oldnvroot) == 0); 2462168404Spjd 2463168404Spjd /* 2464168404Spjd * Print out the statistics for the pool. 2465168404Spjd */ 2466168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2467168404Spjd 2468168404Spjd if (cb->cb_verbose) 2469168404Spjd print_iostat_separator(cb); 2470168404Spjd 2471168404Spjd return (0); 2472168404Spjd} 2473168404Spjd 2474168404Spjdint 2475168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2476168404Spjd{ 2477168404Spjd iostat_cbdata_t *cb = data; 2478168404Spjd nvlist_t *config, *nvroot; 2479168404Spjd 2480168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2481168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2482168404Spjd &nvroot) == 0); 2483168404Spjd if (!cb->cb_verbose) 2484168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2485168404Spjd else 2486236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2487236145Smm cb->cb_namewidth); 2488168404Spjd } 2489168404Spjd 2490168404Spjd /* 2491168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2492168404Spjd * maximum we can have and still fit in 80 columns. 2493168404Spjd */ 2494168404Spjd if (cb->cb_namewidth < 10) 2495168404Spjd cb->cb_namewidth = 10; 2496168404Spjd if (cb->cb_namewidth > 38) 2497168404Spjd cb->cb_namewidth = 38; 2498168404Spjd 2499168404Spjd return (0); 2500168404Spjd} 2501168404Spjd 2502168404Spjd/* 2503219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2504168404Spjd */ 2505219089Spjdstatic void 2506219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2507219089Spjd unsigned long *cnt) 2508168404Spjd{ 2509168404Spjd unsigned long interval = 0, count = 0; 2510219089Spjd int argc = *argcp, errno; 2511168404Spjd 2512168404Spjd /* 2513168404Spjd * Determine if the last argument is an integer or a pool name 2514168404Spjd */ 2515168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2516168404Spjd char *end; 2517168404Spjd 2518168404Spjd errno = 0; 2519168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2520168404Spjd 2521168404Spjd if (*end == '\0' && errno == 0) { 2522168404Spjd if (interval == 0) { 2523168404Spjd (void) fprintf(stderr, gettext("interval " 2524168404Spjd "cannot be zero\n")); 2525168404Spjd usage(B_FALSE); 2526168404Spjd } 2527168404Spjd /* 2528168404Spjd * Ignore the last parameter 2529168404Spjd */ 2530168404Spjd argc--; 2531168404Spjd } else { 2532168404Spjd /* 2533168404Spjd * If this is not a valid number, just plow on. The 2534168404Spjd * user will get a more informative error message later 2535168404Spjd * on. 2536168404Spjd */ 2537168404Spjd interval = 0; 2538168404Spjd } 2539168404Spjd } 2540168404Spjd 2541168404Spjd /* 2542168404Spjd * If the last argument is also an integer, then we have both a count 2543219089Spjd * and an interval. 2544168404Spjd */ 2545168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2546168404Spjd char *end; 2547168404Spjd 2548168404Spjd errno = 0; 2549168404Spjd count = interval; 2550168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2551168404Spjd 2552168404Spjd if (*end == '\0' && errno == 0) { 2553168404Spjd if (interval == 0) { 2554168404Spjd (void) fprintf(stderr, gettext("interval " 2555168404Spjd "cannot be zero\n")); 2556168404Spjd usage(B_FALSE); 2557168404Spjd } 2558168404Spjd 2559168404Spjd /* 2560168404Spjd * Ignore the last parameter 2561168404Spjd */ 2562168404Spjd argc--; 2563168404Spjd } else { 2564168404Spjd interval = 0; 2565168404Spjd } 2566168404Spjd } 2567168404Spjd 2568219089Spjd *iv = interval; 2569219089Spjd *cnt = count; 2570219089Spjd *argcp = argc; 2571219089Spjd} 2572219089Spjd 2573219089Spjdstatic void 2574219089Spjdget_timestamp_arg(char c) 2575219089Spjd{ 2576219089Spjd if (c == 'u') 2577219089Spjd timestamp_fmt = UDATE; 2578219089Spjd else if (c == 'd') 2579219089Spjd timestamp_fmt = DDATE; 2580219089Spjd else 2581219089Spjd usage(B_FALSE); 2582219089Spjd} 2583219089Spjd 2584219089Spjd/* 2585219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2586219089Spjd * 2587219089Spjd * -v Display statistics for individual vdevs 2588219089Spjd * -T Display a timestamp in date(1) or Unix format 2589219089Spjd * 2590219089Spjd * This command can be tricky because we want to be able to deal with pool 2591219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2592219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2593219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2594219089Spjd * changes are all handled within libzfs. 2595219089Spjd */ 2596219089Spjdint 2597219089Spjdzpool_do_iostat(int argc, char **argv) 2598219089Spjd{ 2599219089Spjd int c; 2600219089Spjd int ret; 2601219089Spjd int npools; 2602219089Spjd unsigned long interval = 0, count = 0; 2603219089Spjd zpool_list_t *list; 2604219089Spjd boolean_t verbose = B_FALSE; 2605219089Spjd iostat_cbdata_t cb; 2606219089Spjd 2607219089Spjd /* check options */ 2608219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2609219089Spjd switch (c) { 2610219089Spjd case 'T': 2611219089Spjd get_timestamp_arg(*optarg); 2612219089Spjd break; 2613219089Spjd case 'v': 2614219089Spjd verbose = B_TRUE; 2615219089Spjd break; 2616219089Spjd case '?': 2617219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2618219089Spjd optopt); 2619219089Spjd usage(B_FALSE); 2620219089Spjd } 2621219089Spjd } 2622219089Spjd 2623219089Spjd argc -= optind; 2624219089Spjd argv += optind; 2625219089Spjd 2626219089Spjd get_interval_count(&argc, argv, &interval, &count); 2627219089Spjd 2628168404Spjd /* 2629168404Spjd * Construct the list of all interesting pools. 2630168404Spjd */ 2631168404Spjd ret = 0; 2632168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2633168404Spjd return (1); 2634168404Spjd 2635168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2636168404Spjd pool_list_free(list); 2637168404Spjd return (1); 2638168404Spjd } 2639168404Spjd 2640168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2641168404Spjd pool_list_free(list); 2642168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2643168404Spjd return (1); 2644168404Spjd } 2645168404Spjd 2646168404Spjd /* 2647168404Spjd * Enter the main iostat loop. 2648168404Spjd */ 2649168404Spjd cb.cb_list = list; 2650168404Spjd cb.cb_verbose = verbose; 2651168404Spjd cb.cb_iteration = 0; 2652168404Spjd cb.cb_namewidth = 0; 2653168404Spjd 2654168404Spjd for (;;) { 2655168404Spjd pool_list_update(list); 2656168404Spjd 2657168404Spjd if ((npools = pool_list_count(list)) == 0) 2658168404Spjd break; 2659168404Spjd 2660168404Spjd /* 2661168404Spjd * Refresh all statistics. This is done as an explicit step 2662168404Spjd * before calculating the maximum name width, so that any 2663168404Spjd * configuration changes are properly accounted for. 2664168404Spjd */ 2665168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2666168404Spjd 2667168404Spjd /* 2668168404Spjd * Iterate over all pools to determine the maximum width 2669168404Spjd * for the pool / device name column across all pools. 2670168404Spjd */ 2671168404Spjd cb.cb_namewidth = 0; 2672168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2673168404Spjd 2674219089Spjd if (timestamp_fmt != NODATE) 2675219089Spjd print_timestamp(timestamp_fmt); 2676219089Spjd 2677168404Spjd /* 2678168404Spjd * If it's the first time, or verbose mode, print the header. 2679168404Spjd */ 2680168404Spjd if (++cb.cb_iteration == 1 || verbose) 2681168404Spjd print_iostat_header(&cb); 2682168404Spjd 2683168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2684168404Spjd 2685168404Spjd /* 2686168404Spjd * If there's more than one pool, and we're not in verbose mode 2687168404Spjd * (which prints a separator for us), then print a separator. 2688168404Spjd */ 2689168404Spjd if (npools > 1 && !verbose) 2690168404Spjd print_iostat_separator(&cb); 2691168404Spjd 2692168404Spjd if (verbose) 2693168404Spjd (void) printf("\n"); 2694168404Spjd 2695168404Spjd /* 2696168404Spjd * Flush the output so that redirection to a file isn't buffered 2697168404Spjd * indefinitely. 2698168404Spjd */ 2699168404Spjd (void) fflush(stdout); 2700168404Spjd 2701168404Spjd if (interval == 0) 2702168404Spjd break; 2703168404Spjd 2704168404Spjd if (count != 0 && --count == 0) 2705168404Spjd break; 2706168404Spjd 2707168404Spjd (void) sleep(interval); 2708168404Spjd } 2709168404Spjd 2710168404Spjd pool_list_free(list); 2711168404Spjd 2712168404Spjd return (ret); 2713168404Spjd} 2714168404Spjd 2715168404Spjdtypedef struct list_cbdata { 2716236155Smm boolean_t cb_verbose; 2717236155Smm int cb_namewidth; 2718168404Spjd boolean_t cb_scripted; 2719185029Spjd zprop_list_t *cb_proplist; 2720168404Spjd} list_cbdata_t; 2721168404Spjd 2722168404Spjd/* 2723168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2724168404Spjd */ 2725185029Spjdstatic void 2726236155Smmprint_header(list_cbdata_t *cb) 2727168404Spjd{ 2728236155Smm zprop_list_t *pl = cb->cb_proplist; 2729236884Smm char headerbuf[ZPOOL_MAXPROPLEN]; 2730185029Spjd const char *header; 2731185029Spjd boolean_t first = B_TRUE; 2732185029Spjd boolean_t right_justify; 2733236155Smm size_t width = 0; 2734168404Spjd 2735185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2736236155Smm width = pl->pl_width; 2737236155Smm if (first && cb->cb_verbose) { 2738236155Smm /* 2739236155Smm * Reset the width to accommodate the verbose listing 2740236155Smm * of devices. 2741236155Smm */ 2742236155Smm width = cb->cb_namewidth; 2743236155Smm } 2744236155Smm 2745185029Spjd if (!first) 2746168404Spjd (void) printf(" "); 2747168404Spjd else 2748185029Spjd first = B_FALSE; 2749168404Spjd 2750236884Smm right_justify = B_FALSE; 2751236884Smm if (pl->pl_prop != ZPROP_INVAL) { 2752236884Smm header = zpool_prop_column_name(pl->pl_prop); 2753236884Smm right_justify = zpool_prop_align_right(pl->pl_prop); 2754236884Smm } else { 2755236884Smm int i; 2756185029Spjd 2757236884Smm for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2758236884Smm headerbuf[i] = toupper(pl->pl_user_prop[i]); 2759236884Smm headerbuf[i] = '\0'; 2760236884Smm header = headerbuf; 2761236884Smm } 2762236884Smm 2763185029Spjd if (pl->pl_next == NULL && !right_justify) 2764185029Spjd (void) printf("%s", header); 2765185029Spjd else if (right_justify) 2766236155Smm (void) printf("%*s", width, header); 2767185029Spjd else 2768236155Smm (void) printf("%-*s", width, header); 2769236155Smm 2770168404Spjd } 2771168404Spjd 2772168404Spjd (void) printf("\n"); 2773168404Spjd} 2774168404Spjd 2775185029Spjd/* 2776185029Spjd * Given a pool and a list of properties, print out all the properties according 2777185029Spjd * to the described layout. 2778185029Spjd */ 2779185029Spjdstatic void 2780236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 2781168404Spjd{ 2782236155Smm zprop_list_t *pl = cb->cb_proplist; 2783185029Spjd boolean_t first = B_TRUE; 2784185029Spjd char property[ZPOOL_MAXPROPLEN]; 2785185029Spjd char *propstr; 2786185029Spjd boolean_t right_justify; 2787236155Smm size_t width; 2788168404Spjd 2789185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2790236155Smm 2791236155Smm width = pl->pl_width; 2792236155Smm if (first && cb->cb_verbose) { 2793236155Smm /* 2794236155Smm * Reset the width to accommodate the verbose listing 2795236155Smm * of devices. 2796236155Smm */ 2797236155Smm width = cb->cb_namewidth; 2798236155Smm } 2799236155Smm 2800185029Spjd if (!first) { 2801236155Smm if (cb->cb_scripted) 2802168404Spjd (void) printf("\t"); 2803168404Spjd else 2804168404Spjd (void) printf(" "); 2805185029Spjd } else { 2806185029Spjd first = B_FALSE; 2807168404Spjd } 2808168404Spjd 2809185029Spjd right_justify = B_FALSE; 2810185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2811236155Smm if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ && 2812236155Smm zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0) 2813236155Smm propstr = "-"; 2814236155Smm else if (zpool_get_prop(zhp, pl->pl_prop, property, 2815185029Spjd sizeof (property), NULL) != 0) 2816185029Spjd propstr = "-"; 2817168404Spjd else 2818185029Spjd propstr = property; 2819168404Spjd 2820185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2821236884Smm } else if ((zpool_prop_feature(pl->pl_user_prop) || 2822236884Smm zpool_prop_unsupported(pl->pl_user_prop)) && 2823236884Smm zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 2824236884Smm sizeof (property)) == 0) { 2825236884Smm propstr = property; 2826185029Spjd } else { 2827185029Spjd propstr = "-"; 2828185029Spjd } 2829168404Spjd 2830168404Spjd 2831185029Spjd /* 2832185029Spjd * If this is being called in scripted mode, or if this is the 2833185029Spjd * last column and it is left-justified, don't include a width 2834185029Spjd * format specifier. 2835185029Spjd */ 2836236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 2837185029Spjd (void) printf("%s", propstr); 2838185029Spjd else if (right_justify) 2839185029Spjd (void) printf("%*s", width, propstr); 2840185029Spjd else 2841185029Spjd (void) printf("%-*s", width, propstr); 2842185029Spjd } 2843168404Spjd 2844185029Spjd (void) printf("\n"); 2845185029Spjd} 2846168404Spjd 2847236155Smmstatic void 2848236155Smmprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted) 2849236155Smm{ 2850236155Smm char propval[64]; 2851236155Smm boolean_t fixed; 2852236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 2853236155Smm 2854236155Smm zfs_nicenum(value, propval, sizeof (propval)); 2855236155Smm 2856236155Smm if (prop == ZPOOL_PROP_EXPANDSZ && value == 0) 2857236155Smm (void) strlcpy(propval, "-", sizeof (propval)); 2858236155Smm 2859236155Smm if (scripted) 2860236155Smm (void) printf("\t%s", propval); 2861236155Smm else 2862236155Smm (void) printf(" %*s", width, propval); 2863236155Smm} 2864236155Smm 2865236155Smmvoid 2866236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 2867236155Smm list_cbdata_t *cb, int depth) 2868236155Smm{ 2869236155Smm nvlist_t **child; 2870236155Smm vdev_stat_t *vs; 2871236155Smm uint_t c, children; 2872236155Smm char *vname; 2873236155Smm boolean_t scripted = cb->cb_scripted; 2874236155Smm 2875236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 2876236155Smm (uint64_t **)&vs, &c) == 0); 2877236155Smm 2878236155Smm if (name != NULL) { 2879236155Smm if (scripted) 2880236155Smm (void) printf("\t%s", name); 2881236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 2882236155Smm (void) printf("%*s%s", depth, "", name); 2883236155Smm else 2884236155Smm (void) printf("%*s%s%*s", depth, "", name, 2885236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2886236155Smm 2887236155Smm /* only toplevel vdevs have capacity stats */ 2888236155Smm if (vs->vs_space == 0) { 2889236155Smm if (scripted) 2890236155Smm (void) printf("\t-\t-\t-"); 2891236155Smm else 2892236155Smm (void) printf(" - - -"); 2893236155Smm } else { 2894236155Smm print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, 2895236155Smm scripted); 2896236155Smm print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc, 2897236155Smm scripted); 2898236155Smm print_one_column(ZPOOL_PROP_FREE, 2899236155Smm vs->vs_space - vs->vs_alloc, scripted); 2900236155Smm } 2901236155Smm print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, 2902236155Smm scripted); 2903236155Smm (void) printf("\n"); 2904236155Smm } 2905236155Smm 2906236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2907236155Smm &child, &children) != 0) 2908236155Smm return; 2909236155Smm 2910236155Smm for (c = 0; c < children; c++) { 2911236155Smm uint64_t ishole = B_FALSE; 2912236155Smm 2913236155Smm if (nvlist_lookup_uint64(child[c], 2914236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 2915236155Smm continue; 2916236155Smm 2917236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 2918236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 2919236155Smm free(vname); 2920236155Smm } 2921236155Smm 2922236155Smm /* 2923236155Smm * Include level 2 ARC devices in iostat output 2924236155Smm */ 2925236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 2926236155Smm &child, &children) != 0) 2927236155Smm return; 2928236155Smm 2929236155Smm if (children > 0) { 2930236155Smm (void) printf("%-*s - - - - - " 2931236155Smm "-\n", cb->cb_namewidth, "cache"); 2932236155Smm for (c = 0; c < children; c++) { 2933236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], 2934236155Smm B_FALSE); 2935236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 2936236155Smm free(vname); 2937236155Smm } 2938236155Smm } 2939236155Smm} 2940236155Smm 2941236155Smm 2942185029Spjd/* 2943185029Spjd * Generic callback function to list a pool. 2944185029Spjd */ 2945185029Spjdint 2946185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 2947185029Spjd{ 2948185029Spjd list_cbdata_t *cbp = data; 2949236155Smm nvlist_t *config; 2950236155Smm nvlist_t *nvroot; 2951168404Spjd 2952236155Smm config = zpool_get_config(zhp, NULL); 2953168404Spjd 2954236155Smm print_pool(zhp, cbp); 2955236155Smm if (!cbp->cb_verbose) 2956236155Smm return (0); 2957168404Spjd 2958236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2959236155Smm &nvroot) == 0); 2960236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 2961236155Smm 2962168404Spjd return (0); 2963168404Spjd} 2964168404Spjd 2965168404Spjd/* 2966219089Spjd * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 2967168404Spjd * 2968185029Spjd * -H Scripted mode. Don't display headers, and separate properties 2969185029Spjd * by a single tab. 2970185029Spjd * -o List of properties to display. Defaults to 2971219089Spjd * "name,size,allocated,free,capacity,health,altroot" 2972219089Spjd * -T Display a timestamp in date(1) or Unix format 2973168404Spjd * 2974168404Spjd * List all pools in the system, whether or not they're healthy. Output space 2975168404Spjd * statistics for each one, as well as health status summary. 2976168404Spjd */ 2977168404Spjdint 2978168404Spjdzpool_do_list(int argc, char **argv) 2979168404Spjd{ 2980168404Spjd int c; 2981168404Spjd int ret; 2982168404Spjd list_cbdata_t cb = { 0 }; 2983185029Spjd static char default_props[] = 2984236155Smm "name,size,allocated,free,capacity,dedupratio," 2985236155Smm "health,altroot"; 2986185029Spjd char *props = default_props; 2987219089Spjd unsigned long interval = 0, count = 0; 2988236155Smm zpool_list_t *list; 2989236155Smm boolean_t first = B_TRUE; 2990168404Spjd 2991168404Spjd /* check options */ 2992236155Smm while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) { 2993168404Spjd switch (c) { 2994168404Spjd case 'H': 2995168404Spjd cb.cb_scripted = B_TRUE; 2996168404Spjd break; 2997168404Spjd case 'o': 2998185029Spjd props = optarg; 2999168404Spjd break; 3000219089Spjd case 'T': 3001219089Spjd get_timestamp_arg(*optarg); 3002219089Spjd break; 3003236155Smm case 'v': 3004236155Smm cb.cb_verbose = B_TRUE; 3005236155Smm break; 3006168404Spjd case ':': 3007168404Spjd (void) fprintf(stderr, gettext("missing argument for " 3008168404Spjd "'%c' option\n"), optopt); 3009168404Spjd usage(B_FALSE); 3010168404Spjd break; 3011168404Spjd case '?': 3012168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3013168404Spjd optopt); 3014168404Spjd usage(B_FALSE); 3015168404Spjd } 3016168404Spjd } 3017168404Spjd 3018168404Spjd argc -= optind; 3019168404Spjd argv += optind; 3020168404Spjd 3021219089Spjd get_interval_count(&argc, argv, &interval, &count); 3022219089Spjd 3023185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3024185029Spjd usage(B_FALSE); 3025168404Spjd 3026236155Smm if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL) 3027236155Smm return (1); 3028168404Spjd 3029236155Smm if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3030236155Smm (void) printf(gettext("no pools available\n")); 3031236155Smm zprop_free_list(cb.cb_proplist); 3032236155Smm return (0); 3033236155Smm } 3034236155Smm 3035219089Spjd for (;;) { 3036236155Smm pool_list_update(list); 3037168404Spjd 3038236155Smm if (pool_list_count(list) == 0) 3039236155Smm break; 3040236155Smm 3041236155Smm cb.cb_namewidth = 0; 3042236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3043236155Smm 3044219089Spjd if (timestamp_fmt != NODATE) 3045219089Spjd print_timestamp(timestamp_fmt); 3046168404Spjd 3047236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 3048236155Smm print_header(&cb); 3049236155Smm first = B_FALSE; 3050219089Spjd } 3051236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 3052219089Spjd 3053219089Spjd if (interval == 0) 3054219089Spjd break; 3055219089Spjd 3056219089Spjd if (count != 0 && --count == 0) 3057219089Spjd break; 3058219089Spjd 3059219089Spjd (void) sleep(interval); 3060168404Spjd } 3061168404Spjd 3062219089Spjd zprop_free_list(cb.cb_proplist); 3063168404Spjd return (ret); 3064168404Spjd} 3065168404Spjd 3066168404Spjdstatic nvlist_t * 3067168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name) 3068168404Spjd{ 3069168404Spjd nvlist_t **child; 3070168404Spjd uint_t c, children; 3071168404Spjd nvlist_t *match; 3072168404Spjd char *path; 3073168404Spjd 3074168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 3075168404Spjd &child, &children) != 0) { 3076168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 3077219089Spjd if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 3078219089Spjd name += sizeof(_PATH_DEV) - 1; 3079219089Spjd if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 3080219089Spjd path += sizeof(_PATH_DEV) - 1; 3081168404Spjd if (strcmp(name, path) == 0) 3082168404Spjd return (nv); 3083168404Spjd return (NULL); 3084168404Spjd } 3085168404Spjd 3086168404Spjd for (c = 0; c < children; c++) 3087168404Spjd if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 3088168404Spjd return (match); 3089168404Spjd 3090168404Spjd return (NULL); 3091168404Spjd} 3092168404Spjd 3093168404Spjdstatic int 3094168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 3095168404Spjd{ 3096168404Spjd boolean_t force = B_FALSE; 3097168404Spjd int c; 3098168404Spjd nvlist_t *nvroot; 3099168404Spjd char *poolname, *old_disk, *new_disk; 3100168404Spjd zpool_handle_t *zhp; 3101168404Spjd int ret; 3102168404Spjd 3103168404Spjd /* check options */ 3104168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3105168404Spjd switch (c) { 3106168404Spjd case 'f': 3107168404Spjd force = B_TRUE; 3108168404Spjd break; 3109168404Spjd case '?': 3110168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3111168404Spjd optopt); 3112168404Spjd usage(B_FALSE); 3113168404Spjd } 3114168404Spjd } 3115168404Spjd 3116168404Spjd argc -= optind; 3117168404Spjd argv += optind; 3118168404Spjd 3119168404Spjd /* get pool name and check number of arguments */ 3120168404Spjd if (argc < 1) { 3121168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3122168404Spjd usage(B_FALSE); 3123168404Spjd } 3124168404Spjd 3125168404Spjd poolname = argv[0]; 3126168404Spjd 3127168404Spjd if (argc < 2) { 3128168404Spjd (void) fprintf(stderr, 3129168404Spjd gettext("missing <device> specification\n")); 3130168404Spjd usage(B_FALSE); 3131168404Spjd } 3132168404Spjd 3133168404Spjd old_disk = argv[1]; 3134168404Spjd 3135168404Spjd if (argc < 3) { 3136168404Spjd if (!replacing) { 3137168404Spjd (void) fprintf(stderr, 3138168404Spjd gettext("missing <new_device> specification\n")); 3139168404Spjd usage(B_FALSE); 3140168404Spjd } 3141168404Spjd new_disk = old_disk; 3142168404Spjd argc -= 1; 3143168404Spjd argv += 1; 3144168404Spjd } else { 3145168404Spjd new_disk = argv[2]; 3146168404Spjd argc -= 2; 3147168404Spjd argv += 2; 3148168404Spjd } 3149168404Spjd 3150168404Spjd if (argc > 1) { 3151168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3152168404Spjd usage(B_FALSE); 3153168404Spjd } 3154168404Spjd 3155168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3156168404Spjd return (1); 3157168404Spjd 3158185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3159168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3160168404Spjd poolname); 3161168404Spjd zpool_close(zhp); 3162168404Spjd return (1); 3163168404Spjd } 3164168404Spjd 3165185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3166185029Spjd argc, argv); 3167168404Spjd if (nvroot == NULL) { 3168168404Spjd zpool_close(zhp); 3169168404Spjd return (1); 3170168404Spjd } 3171168404Spjd 3172168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3173168404Spjd 3174168404Spjd nvlist_free(nvroot); 3175168404Spjd zpool_close(zhp); 3176168404Spjd 3177168404Spjd return (ret); 3178168404Spjd} 3179168404Spjd 3180168404Spjd/* 3181168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3182168404Spjd * 3183168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3184168404Spjd * 3185168404Spjd * Replace <device> with <new_device>. 3186168404Spjd */ 3187168404Spjd/* ARGSUSED */ 3188168404Spjdint 3189168404Spjdzpool_do_replace(int argc, char **argv) 3190168404Spjd{ 3191168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3192168404Spjd} 3193168404Spjd 3194168404Spjd/* 3195168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3196168404Spjd * 3197168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3198168404Spjd * 3199168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3200168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3201168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3202168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3203168404Spjd */ 3204168404Spjdint 3205168404Spjdzpool_do_attach(int argc, char **argv) 3206168404Spjd{ 3207168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3208168404Spjd} 3209168404Spjd 3210168404Spjd/* 3211168404Spjd * zpool detach [-f] <pool> <device> 3212168404Spjd * 3213168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3214168404Spjd * (not supported yet) 3215168404Spjd * 3216168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3217168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3218168404Spjd * has the only valid copy of some data. 3219168404Spjd */ 3220168404Spjd/* ARGSUSED */ 3221168404Spjdint 3222168404Spjdzpool_do_detach(int argc, char **argv) 3223168404Spjd{ 3224168404Spjd int c; 3225168404Spjd char *poolname, *path; 3226168404Spjd zpool_handle_t *zhp; 3227168404Spjd int ret; 3228168404Spjd 3229168404Spjd /* check options */ 3230168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3231168404Spjd switch (c) { 3232168404Spjd case 'f': 3233168404Spjd case '?': 3234168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3235168404Spjd optopt); 3236168404Spjd usage(B_FALSE); 3237168404Spjd } 3238168404Spjd } 3239168404Spjd 3240168404Spjd argc -= optind; 3241168404Spjd argv += optind; 3242168404Spjd 3243168404Spjd /* get pool name and check number of arguments */ 3244168404Spjd if (argc < 1) { 3245168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3246168404Spjd usage(B_FALSE); 3247168404Spjd } 3248168404Spjd 3249168404Spjd if (argc < 2) { 3250168404Spjd (void) fprintf(stderr, 3251168404Spjd gettext("missing <device> specification\n")); 3252168404Spjd usage(B_FALSE); 3253168404Spjd } 3254168404Spjd 3255168404Spjd poolname = argv[0]; 3256168404Spjd path = argv[1]; 3257168404Spjd 3258168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3259168404Spjd return (1); 3260168404Spjd 3261168404Spjd ret = zpool_vdev_detach(zhp, path); 3262168404Spjd 3263168404Spjd zpool_close(zhp); 3264168404Spjd 3265168404Spjd return (ret); 3266168404Spjd} 3267168404Spjd 3268168404Spjd/* 3269219089Spjd * zpool split [-n] [-o prop=val] ... 3270219089Spjd * [-o mntopt] ... 3271219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3272219089Spjd * 3273219089Spjd * -n Do not split the pool, but display the resulting layout if 3274219089Spjd * it were to be split. 3275219089Spjd * -o Set property=value, or set mount options. 3276219089Spjd * -R Mount the split-off pool under an alternate root. 3277219089Spjd * 3278219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3279219089Spjd * off may be listed, provided that no more than one device is specified 3280219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3281219089Spjd * state unless -R is specified. 3282219089Spjd * 3283219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3284219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3285219089Spjd * undergoing a resilvering operation. 3286219089Spjd */ 3287219089Spjdint 3288219089Spjdzpool_do_split(int argc, char **argv) 3289219089Spjd{ 3290219089Spjd char *srcpool, *newpool, *propval; 3291219089Spjd char *mntopts = NULL; 3292219089Spjd splitflags_t flags; 3293219089Spjd int c, ret = 0; 3294219089Spjd zpool_handle_t *zhp; 3295219089Spjd nvlist_t *config, *props = NULL; 3296219089Spjd 3297219089Spjd flags.dryrun = B_FALSE; 3298219089Spjd flags.import = B_FALSE; 3299219089Spjd 3300219089Spjd /* check options */ 3301219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3302219089Spjd switch (c) { 3303219089Spjd case 'R': 3304219089Spjd flags.import = B_TRUE; 3305219089Spjd if (add_prop_list( 3306219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3307219089Spjd &props, B_TRUE) != 0) { 3308219089Spjd if (props) 3309219089Spjd nvlist_free(props); 3310219089Spjd usage(B_FALSE); 3311219089Spjd } 3312219089Spjd break; 3313219089Spjd case 'n': 3314219089Spjd flags.dryrun = B_TRUE; 3315219089Spjd break; 3316219089Spjd case 'o': 3317219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3318219089Spjd *propval = '\0'; 3319219089Spjd propval++; 3320219089Spjd if (add_prop_list(optarg, propval, 3321219089Spjd &props, B_TRUE) != 0) { 3322219089Spjd if (props) 3323219089Spjd nvlist_free(props); 3324219089Spjd usage(B_FALSE); 3325219089Spjd } 3326219089Spjd } else { 3327219089Spjd mntopts = optarg; 3328219089Spjd } 3329219089Spjd break; 3330219089Spjd case ':': 3331219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3332219089Spjd "'%c' option\n"), optopt); 3333219089Spjd usage(B_FALSE); 3334219089Spjd break; 3335219089Spjd case '?': 3336219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3337219089Spjd optopt); 3338219089Spjd usage(B_FALSE); 3339219089Spjd break; 3340219089Spjd } 3341219089Spjd } 3342219089Spjd 3343219089Spjd if (!flags.import && mntopts != NULL) { 3344219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3345219089Spjd "valid when importing the pool\n")); 3346219089Spjd usage(B_FALSE); 3347219089Spjd } 3348219089Spjd 3349219089Spjd argc -= optind; 3350219089Spjd argv += optind; 3351219089Spjd 3352219089Spjd if (argc < 1) { 3353219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3354219089Spjd usage(B_FALSE); 3355219089Spjd } 3356219089Spjd if (argc < 2) { 3357219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3358219089Spjd usage(B_FALSE); 3359219089Spjd } 3360219089Spjd 3361219089Spjd srcpool = argv[0]; 3362219089Spjd newpool = argv[1]; 3363219089Spjd 3364219089Spjd argc -= 2; 3365219089Spjd argv += 2; 3366219089Spjd 3367219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3368219089Spjd return (1); 3369219089Spjd 3370219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3371219089Spjd if (config == NULL) { 3372219089Spjd ret = 1; 3373219089Spjd } else { 3374219089Spjd if (flags.dryrun) { 3375219089Spjd (void) printf(gettext("would create '%s' with the " 3376219089Spjd "following layout:\n\n"), newpool); 3377219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3378219089Spjd } 3379219089Spjd nvlist_free(config); 3380219089Spjd } 3381219089Spjd 3382219089Spjd zpool_close(zhp); 3383219089Spjd 3384219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3385219089Spjd return (ret); 3386219089Spjd 3387219089Spjd /* 3388219089Spjd * The split was successful. Now we need to open the new 3389219089Spjd * pool and import it. 3390219089Spjd */ 3391219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3392219089Spjd return (1); 3393219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3394219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3395219089Spjd ret = 1; 3396240415Smm (void) fprintf(stderr, gettext("Split was successful, but " 3397219089Spjd "the datasets could not all be mounted\n")); 3398219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3399219089Spjd "different altroot\n"), "zpool import"); 3400219089Spjd } 3401219089Spjd zpool_close(zhp); 3402219089Spjd 3403219089Spjd return (ret); 3404219089Spjd} 3405219089Spjd 3406219089Spjd 3407219089Spjd 3408219089Spjd/* 3409168404Spjd * zpool online <pool> <device> ... 3410168404Spjd */ 3411168404Spjdint 3412168404Spjdzpool_do_online(int argc, char **argv) 3413168404Spjd{ 3414168404Spjd int c, i; 3415168404Spjd char *poolname; 3416168404Spjd zpool_handle_t *zhp; 3417168404Spjd int ret = 0; 3418185029Spjd vdev_state_t newstate; 3419219089Spjd int flags = 0; 3420168404Spjd 3421168404Spjd /* check options */ 3422219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3423168404Spjd switch (c) { 3424219089Spjd case 'e': 3425219089Spjd flags |= ZFS_ONLINE_EXPAND; 3426219089Spjd break; 3427168404Spjd case 't': 3428168404Spjd case '?': 3429168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3430168404Spjd optopt); 3431168404Spjd usage(B_FALSE); 3432168404Spjd } 3433168404Spjd } 3434168404Spjd 3435168404Spjd argc -= optind; 3436168404Spjd argv += optind; 3437168404Spjd 3438168404Spjd /* get pool name and check number of arguments */ 3439168404Spjd if (argc < 1) { 3440168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3441168404Spjd usage(B_FALSE); 3442168404Spjd } 3443168404Spjd if (argc < 2) { 3444168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3445168404Spjd usage(B_FALSE); 3446168404Spjd } 3447168404Spjd 3448168404Spjd poolname = argv[0]; 3449168404Spjd 3450168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3451168404Spjd return (1); 3452168404Spjd 3453185029Spjd for (i = 1; i < argc; i++) { 3454219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3455185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3456185029Spjd (void) printf(gettext("warning: device '%s' " 3457185029Spjd "onlined, but remains in faulted state\n"), 3458185029Spjd argv[i]); 3459185029Spjd if (newstate == VDEV_STATE_FAULTED) 3460185029Spjd (void) printf(gettext("use 'zpool " 3461185029Spjd "clear' to restore a faulted " 3462185029Spjd "device\n")); 3463185029Spjd else 3464185029Spjd (void) printf(gettext("use 'zpool " 3465185029Spjd "replace' to replace devices " 3466185029Spjd "that are no longer present\n")); 3467185029Spjd } 3468185029Spjd } else { 3469168404Spjd ret = 1; 3470185029Spjd } 3471185029Spjd } 3472168404Spjd 3473168404Spjd zpool_close(zhp); 3474168404Spjd 3475168404Spjd return (ret); 3476168404Spjd} 3477168404Spjd 3478168404Spjd/* 3479168404Spjd * zpool offline [-ft] <pool> <device> ... 3480168404Spjd * 3481168404Spjd * -f Force the device into the offline state, even if doing 3482168404Spjd * so would appear to compromise pool availability. 3483168404Spjd * (not supported yet) 3484168404Spjd * 3485168404Spjd * -t Only take the device off-line temporarily. The offline 3486168404Spjd * state will not be persistent across reboots. 3487168404Spjd */ 3488168404Spjd/* ARGSUSED */ 3489168404Spjdint 3490168404Spjdzpool_do_offline(int argc, char **argv) 3491168404Spjd{ 3492168404Spjd int c, i; 3493168404Spjd char *poolname; 3494168404Spjd zpool_handle_t *zhp; 3495168404Spjd int ret = 0; 3496168404Spjd boolean_t istmp = B_FALSE; 3497168404Spjd 3498168404Spjd /* check options */ 3499168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3500168404Spjd switch (c) { 3501168404Spjd case 't': 3502168404Spjd istmp = B_TRUE; 3503168404Spjd break; 3504168404Spjd case 'f': 3505168404Spjd case '?': 3506168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3507168404Spjd optopt); 3508168404Spjd usage(B_FALSE); 3509168404Spjd } 3510168404Spjd } 3511168404Spjd 3512168404Spjd argc -= optind; 3513168404Spjd argv += optind; 3514168404Spjd 3515168404Spjd /* get pool name and check number of arguments */ 3516168404Spjd if (argc < 1) { 3517168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3518168404Spjd usage(B_FALSE); 3519168404Spjd } 3520168404Spjd if (argc < 2) { 3521168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3522168404Spjd usage(B_FALSE); 3523168404Spjd } 3524168404Spjd 3525168404Spjd poolname = argv[0]; 3526168404Spjd 3527168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3528168404Spjd return (1); 3529168404Spjd 3530185029Spjd for (i = 1; i < argc; i++) { 3531185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3532168404Spjd ret = 1; 3533185029Spjd } 3534168404Spjd 3535168404Spjd zpool_close(zhp); 3536168404Spjd 3537168404Spjd return (ret); 3538168404Spjd} 3539168404Spjd 3540168404Spjd/* 3541168404Spjd * zpool clear <pool> [device] 3542168404Spjd * 3543168404Spjd * Clear all errors associated with a pool or a particular device. 3544168404Spjd */ 3545168404Spjdint 3546168404Spjdzpool_do_clear(int argc, char **argv) 3547168404Spjd{ 3548219089Spjd int c; 3549168404Spjd int ret = 0; 3550219089Spjd boolean_t dryrun = B_FALSE; 3551219089Spjd boolean_t do_rewind = B_FALSE; 3552219089Spjd boolean_t xtreme_rewind = B_FALSE; 3553219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3554219089Spjd nvlist_t *policy = NULL; 3555168404Spjd zpool_handle_t *zhp; 3556168404Spjd char *pool, *device; 3557168404Spjd 3558219089Spjd /* check options */ 3559219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3560219089Spjd switch (c) { 3561219089Spjd case 'F': 3562219089Spjd do_rewind = B_TRUE; 3563219089Spjd break; 3564219089Spjd case 'n': 3565219089Spjd dryrun = B_TRUE; 3566219089Spjd break; 3567219089Spjd case 'X': 3568219089Spjd xtreme_rewind = B_TRUE; 3569219089Spjd break; 3570219089Spjd case '?': 3571219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3572219089Spjd optopt); 3573219089Spjd usage(B_FALSE); 3574219089Spjd } 3575219089Spjd } 3576219089Spjd 3577219089Spjd argc -= optind; 3578219089Spjd argv += optind; 3579219089Spjd 3580219089Spjd if (argc < 1) { 3581168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3582168404Spjd usage(B_FALSE); 3583168404Spjd } 3584168404Spjd 3585219089Spjd if (argc > 2) { 3586168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3587168404Spjd usage(B_FALSE); 3588168404Spjd } 3589168404Spjd 3590219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3591219089Spjd (void) fprintf(stderr, 3592219089Spjd gettext("-n or -X only meaningful with -F\n")); 3593219089Spjd usage(B_FALSE); 3594219089Spjd } 3595219089Spjd if (dryrun) 3596219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3597219089Spjd else if (do_rewind) 3598219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3599219089Spjd if (xtreme_rewind) 3600219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3601168404Spjd 3602219089Spjd /* In future, further rewind policy choices can be passed along here */ 3603219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3604219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3605168404Spjd return (1); 3606168404Spjd 3607219089Spjd pool = argv[0]; 3608219089Spjd device = argc == 2 ? argv[1] : NULL; 3609219089Spjd 3610219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3611219089Spjd nvlist_free(policy); 3612219089Spjd return (1); 3613219089Spjd } 3614219089Spjd 3615219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3616168404Spjd ret = 1; 3617168404Spjd 3618168404Spjd zpool_close(zhp); 3619168404Spjd 3620219089Spjd nvlist_free(policy); 3621219089Spjd 3622168404Spjd return (ret); 3623168404Spjd} 3624168404Spjd 3625228103Smm/* 3626228103Smm * zpool reguid <pool> 3627228103Smm */ 3628228103Smmint 3629228103Smmzpool_do_reguid(int argc, char **argv) 3630228103Smm{ 3631228103Smm int c; 3632228103Smm char *poolname; 3633228103Smm zpool_handle_t *zhp; 3634228103Smm int ret = 0; 3635228103Smm 3636228103Smm /* check options */ 3637228103Smm while ((c = getopt(argc, argv, "")) != -1) { 3638228103Smm switch (c) { 3639228103Smm case '?': 3640228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3641228103Smm optopt); 3642228103Smm usage(B_FALSE); 3643228103Smm } 3644228103Smm } 3645228103Smm 3646228103Smm argc -= optind; 3647228103Smm argv += optind; 3648228103Smm 3649228103Smm /* get pool name and check number of arguments */ 3650228103Smm if (argc < 1) { 3651228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 3652228103Smm usage(B_FALSE); 3653228103Smm } 3654228103Smm 3655228103Smm if (argc > 1) { 3656228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 3657228103Smm usage(B_FALSE); 3658228103Smm } 3659228103Smm 3660228103Smm poolname = argv[0]; 3661228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3662228103Smm return (1); 3663228103Smm 3664228103Smm ret = zpool_reguid(zhp); 3665228103Smm 3666228103Smm zpool_close(zhp); 3667228103Smm return (ret); 3668228103Smm} 3669228103Smm 3670228103Smm 3671236155Smm/* 3672236155Smm * zpool reopen <pool> 3673236155Smm * 3674236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 3675236155Smm * 3676236155Smm * NOTE: This command is currently undocumented. If the command is ever 3677236155Smm * exposed then the appropriate usage() messages will need to be made. 3678236155Smm */ 3679236155Smmint 3680236155Smmzpool_do_reopen(int argc, char **argv) 3681236155Smm{ 3682236155Smm int ret = 0; 3683236155Smm zpool_handle_t *zhp; 3684236155Smm char *pool; 3685236155Smm 3686236155Smm argc--; 3687236155Smm argv++; 3688236155Smm 3689236155Smm if (argc != 1) 3690236155Smm return (2); 3691236155Smm 3692236155Smm pool = argv[0]; 3693236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 3694236155Smm return (1); 3695236155Smm 3696236155Smm ret = zpool_reopen(zhp); 3697236155Smm zpool_close(zhp); 3698236155Smm return (ret); 3699236155Smm} 3700236155Smm 3701168404Spjdtypedef struct scrub_cbdata { 3702168404Spjd int cb_type; 3703168404Spjd int cb_argc; 3704168404Spjd char **cb_argv; 3705168404Spjd} scrub_cbdata_t; 3706168404Spjd 3707168404Spjdint 3708168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3709168404Spjd{ 3710168404Spjd scrub_cbdata_t *cb = data; 3711168404Spjd int err; 3712168404Spjd 3713168404Spjd /* 3714168404Spjd * Ignore faulted pools. 3715168404Spjd */ 3716168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3717168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3718168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 3719168404Spjd return (1); 3720168404Spjd } 3721168404Spjd 3722219089Spjd err = zpool_scan(zhp, cb->cb_type); 3723168404Spjd 3724168404Spjd return (err != 0); 3725168404Spjd} 3726168404Spjd 3727168404Spjd/* 3728168404Spjd * zpool scrub [-s] <pool> ... 3729168404Spjd * 3730168404Spjd * -s Stop. Stops any in-progress scrub. 3731168404Spjd */ 3732168404Spjdint 3733168404Spjdzpool_do_scrub(int argc, char **argv) 3734168404Spjd{ 3735168404Spjd int c; 3736168404Spjd scrub_cbdata_t cb; 3737168404Spjd 3738219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 3739168404Spjd 3740168404Spjd /* check options */ 3741168404Spjd while ((c = getopt(argc, argv, "s")) != -1) { 3742168404Spjd switch (c) { 3743168404Spjd case 's': 3744219089Spjd cb.cb_type = POOL_SCAN_NONE; 3745168404Spjd break; 3746168404Spjd case '?': 3747168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3748168404Spjd optopt); 3749168404Spjd usage(B_FALSE); 3750168404Spjd } 3751168404Spjd } 3752168404Spjd 3753168404Spjd cb.cb_argc = argc; 3754168404Spjd cb.cb_argv = argv; 3755168404Spjd argc -= optind; 3756168404Spjd argv += optind; 3757168404Spjd 3758168404Spjd if (argc < 1) { 3759168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3760168404Spjd usage(B_FALSE); 3761168404Spjd } 3762168404Spjd 3763168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3764168404Spjd} 3765168404Spjd 3766168404Spjdtypedef struct status_cbdata { 3767168404Spjd int cb_count; 3768168404Spjd boolean_t cb_allpools; 3769168404Spjd boolean_t cb_verbose; 3770168404Spjd boolean_t cb_explain; 3771168404Spjd boolean_t cb_first; 3772219089Spjd boolean_t cb_dedup_stats; 3773168404Spjd} status_cbdata_t; 3774168404Spjd 3775168404Spjd/* 3776168404Spjd * Print out detailed scrub status. 3777168404Spjd */ 3778168404Spjdvoid 3779219089Spjdprint_scan_status(pool_scan_stat_t *ps) 3780168404Spjd{ 3781219089Spjd time_t start, end; 3782219089Spjd uint64_t elapsed, mins_left, hours_left; 3783219089Spjd uint64_t pass_exam, examined, total; 3784219089Spjd uint_t rate; 3785168404Spjd double fraction_done; 3786219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3787168404Spjd 3788226583Spjd (void) printf(gettext(" scan: ")); 3789168404Spjd 3790219089Spjd /* If there's never been a scan, there's not much to say. */ 3791219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 3792219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 3793168404Spjd (void) printf(gettext("none requested\n")); 3794168404Spjd return; 3795168404Spjd } 3796168404Spjd 3797219089Spjd start = ps->pss_start_time; 3798219089Spjd end = ps->pss_end_time; 3799219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3800168404Spjd 3801219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 3802219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 3803219089Spjd /* 3804219089Spjd * Scan is finished or canceled. 3805219089Spjd */ 3806219089Spjd if (ps->pss_state == DSS_FINISHED) { 3807219089Spjd uint64_t minutes_taken = (end - start) / 60; 3808219089Spjd char *fmt; 3809168404Spjd 3810219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3811219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 3812219089Spjd "%llu errors on %s"); 3813219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3814219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 3815219089Spjd "%llu errors on %s"); 3816219089Spjd } 3817219089Spjd /* LINTED */ 3818219089Spjd (void) printf(fmt, processed_buf, 3819185029Spjd (u_longlong_t)(minutes_taken / 60), 3820185029Spjd (uint_t)(minutes_taken % 60), 3821219089Spjd (u_longlong_t)ps->pss_errors, 3822219089Spjd ctime((time_t *)&end)); 3823168404Spjd return; 3824219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 3825219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3826219089Spjd (void) printf(gettext("scrub canceled on %s"), 3827219089Spjd ctime(&end)); 3828219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3829219089Spjd (void) printf(gettext("resilver canceled on %s"), 3830219089Spjd ctime(&end)); 3831219089Spjd } 3832219089Spjd return; 3833168404Spjd } 3834168404Spjd 3835219089Spjd assert(ps->pss_state == DSS_SCANNING); 3836168404Spjd 3837219089Spjd /* 3838219089Spjd * Scan is in progress. 3839219089Spjd */ 3840219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3841219089Spjd (void) printf(gettext("scrub in progress since %s"), 3842219089Spjd ctime(&start)); 3843219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3844219089Spjd (void) printf(gettext("resilver in progress since %s"), 3845219089Spjd ctime(&start)); 3846219089Spjd } 3847219089Spjd 3848219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 3849219089Spjd total = ps->pss_to_examine; 3850168404Spjd fraction_done = (double)examined / total; 3851168404Spjd 3852219089Spjd /* elapsed time for this pass */ 3853219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 3854219089Spjd elapsed = elapsed ? elapsed : 1; 3855219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 3856219089Spjd rate = pass_exam / elapsed; 3857219089Spjd rate = rate ? rate : 1; 3858219089Spjd mins_left = ((total - examined) / rate) / 60; 3859219089Spjd hours_left = mins_left / 60; 3860219089Spjd 3861219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 3862219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 3863219089Spjd zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 3864219089Spjd 3865219089Spjd /* 3866219089Spjd * do not print estimated time if hours_left is more than 30 days 3867219089Spjd */ 3868226583Spjd (void) printf(gettext(" %s scanned out of %s at %s/s"), 3869219089Spjd examined_buf, total_buf, rate_buf); 3870219089Spjd if (hours_left < (30 * 24)) { 3871219089Spjd (void) printf(gettext(", %lluh%um to go\n"), 3872219089Spjd (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 3873219089Spjd } else { 3874219089Spjd (void) printf(gettext( 3875219089Spjd ", (scan is slow, no estimated time)\n")); 3876219089Spjd } 3877219089Spjd 3878219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 3879226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 3880219089Spjd processed_buf, 100 * fraction_done); 3881219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 3882226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 3883219089Spjd processed_buf, 100 * fraction_done); 3884219089Spjd } 3885168404Spjd} 3886168404Spjd 3887168404Spjdstatic void 3888168404Spjdprint_error_log(zpool_handle_t *zhp) 3889168404Spjd{ 3890185029Spjd nvlist_t *nverrlist = NULL; 3891168404Spjd nvpair_t *elem; 3892168404Spjd char *pathname; 3893168404Spjd size_t len = MAXPATHLEN * 2; 3894168404Spjd 3895168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 3896168404Spjd (void) printf("errors: List of errors unavailable " 3897168404Spjd "(insufficient privileges)\n"); 3898168404Spjd return; 3899168404Spjd } 3900168404Spjd 3901168404Spjd (void) printf("errors: Permanent errors have been " 3902168404Spjd "detected in the following files:\n\n"); 3903168404Spjd 3904168404Spjd pathname = safe_malloc(len); 3905168404Spjd elem = NULL; 3906168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 3907168404Spjd nvlist_t *nv; 3908168404Spjd uint64_t dsobj, obj; 3909168404Spjd 3910168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 3911168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 3912168404Spjd &dsobj) == 0); 3913168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 3914168404Spjd &obj) == 0); 3915168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 3916168404Spjd (void) printf("%7s %s\n", "", pathname); 3917168404Spjd } 3918168404Spjd free(pathname); 3919168404Spjd nvlist_free(nverrlist); 3920168404Spjd} 3921168404Spjd 3922168404Spjdstatic void 3923168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 3924168404Spjd int namewidth) 3925168404Spjd{ 3926168404Spjd uint_t i; 3927168404Spjd char *name; 3928168404Spjd 3929168404Spjd if (nspares == 0) 3930168404Spjd return; 3931168404Spjd 3932168404Spjd (void) printf(gettext("\tspares\n")); 3933168404Spjd 3934168404Spjd for (i = 0; i < nspares; i++) { 3935219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 3936168404Spjd print_status_config(zhp, name, spares[i], 3937209962Smm namewidth, 2, B_TRUE); 3938168404Spjd free(name); 3939168404Spjd } 3940168404Spjd} 3941168404Spjd 3942185029Spjdstatic void 3943185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 3944185029Spjd int namewidth) 3945185029Spjd{ 3946185029Spjd uint_t i; 3947185029Spjd char *name; 3948185029Spjd 3949185029Spjd if (nl2cache == 0) 3950185029Spjd return; 3951185029Spjd 3952185029Spjd (void) printf(gettext("\tcache\n")); 3953185029Spjd 3954185029Spjd for (i = 0; i < nl2cache; i++) { 3955219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 3956185029Spjd print_status_config(zhp, name, l2cache[i], 3957209962Smm namewidth, 2, B_FALSE); 3958185029Spjd free(name); 3959185029Spjd } 3960185029Spjd} 3961185029Spjd 3962219089Spjdstatic void 3963219089Spjdprint_dedup_stats(nvlist_t *config) 3964219089Spjd{ 3965219089Spjd ddt_histogram_t *ddh; 3966219089Spjd ddt_stat_t *dds; 3967219089Spjd ddt_object_t *ddo; 3968219089Spjd uint_t c; 3969219089Spjd 3970219089Spjd /* 3971219089Spjd * If the pool was faulted then we may not have been able to 3972219089Spjd * obtain the config. Otherwise, if have anything in the dedup 3973219089Spjd * table continue processing the stats. 3974219089Spjd */ 3975219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 3976227497Smm (uint64_t **)&ddo, &c) != 0) 3977219089Spjd return; 3978219089Spjd 3979219089Spjd (void) printf("\n"); 3980227497Smm (void) printf(gettext(" dedup: ")); 3981227497Smm if (ddo->ddo_count == 0) { 3982227497Smm (void) printf(gettext("no DDT entries\n")); 3983227497Smm return; 3984227497Smm } 3985227497Smm 3986219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 3987219089Spjd (u_longlong_t)ddo->ddo_count, 3988219089Spjd (u_longlong_t)ddo->ddo_dspace, 3989219089Spjd (u_longlong_t)ddo->ddo_mspace); 3990219089Spjd 3991219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 3992219089Spjd (uint64_t **)&dds, &c) == 0); 3993219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 3994219089Spjd (uint64_t **)&ddh, &c) == 0); 3995219089Spjd zpool_dump_ddt(dds, ddh); 3996219089Spjd} 3997219089Spjd 3998168404Spjd/* 3999168404Spjd * Display a summary of pool status. Displays a summary such as: 4000168404Spjd * 4001168404Spjd * pool: tank 4002168404Spjd * status: DEGRADED 4003168404Spjd * reason: One or more devices ... 4004236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 4005168404Spjd * config: 4006168404Spjd * mirror DEGRADED 4007168404Spjd * c1t0d0 OK 4008168404Spjd * c2t0d0 UNAVAIL 4009168404Spjd * 4010168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 4011168404Spjd * option is specified, then we print out error rate information as well. 4012168404Spjd */ 4013168404Spjdint 4014168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 4015168404Spjd{ 4016168404Spjd status_cbdata_t *cbp = data; 4017168404Spjd nvlist_t *config, *nvroot; 4018168404Spjd char *msgid; 4019168404Spjd int reason; 4020168404Spjd const char *health; 4021168404Spjd uint_t c; 4022168404Spjd vdev_stat_t *vs; 4023168404Spjd 4024168404Spjd config = zpool_get_config(zhp, NULL); 4025168404Spjd reason = zpool_get_status(zhp, &msgid); 4026168404Spjd 4027168404Spjd cbp->cb_count++; 4028168404Spjd 4029168404Spjd /* 4030168404Spjd * If we were given 'zpool status -x', only report those pools with 4031168404Spjd * problems. 4032168404Spjd */ 4033168404Spjd if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 4034168404Spjd if (!cbp->cb_allpools) { 4035168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 4036168404Spjd zpool_get_name(zhp)); 4037168404Spjd if (cbp->cb_first) 4038168404Spjd cbp->cb_first = B_FALSE; 4039168404Spjd } 4040168404Spjd return (0); 4041168404Spjd } 4042168404Spjd 4043168404Spjd if (cbp->cb_first) 4044168404Spjd cbp->cb_first = B_FALSE; 4045168404Spjd else 4046168404Spjd (void) printf("\n"); 4047168404Spjd 4048168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 4049168404Spjd &nvroot) == 0); 4050219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 4051168404Spjd (uint64_t **)&vs, &c) == 0); 4052185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4053168404Spjd 4054168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4055168404Spjd (void) printf(gettext(" state: %s\n"), health); 4056168404Spjd 4057168404Spjd switch (reason) { 4058168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 4059168404Spjd (void) printf(gettext("status: One or more devices could not " 4060168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 4061168404Spjd "continue functioning in a degraded state.\n")); 4062168404Spjd (void) printf(gettext("action: Attach the missing device and " 4063168404Spjd "online it using 'zpool online'.\n")); 4064168404Spjd break; 4065168404Spjd 4066168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 4067168404Spjd (void) printf(gettext("status: One or more devices could not " 4068168404Spjd "be opened. There are insufficient\n\treplicas for the " 4069168404Spjd "pool to continue functioning.\n")); 4070168404Spjd (void) printf(gettext("action: Attach the missing device and " 4071168404Spjd "online it using 'zpool online'.\n")); 4072168404Spjd break; 4073168404Spjd 4074168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 4075168404Spjd (void) printf(gettext("status: One or more devices could not " 4076168404Spjd "be used because the label is missing or\n\tinvalid. " 4077168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 4078168404Spjd "functioning in a degraded state.\n")); 4079168404Spjd (void) printf(gettext("action: Replace the device using " 4080168404Spjd "'zpool replace'.\n")); 4081168404Spjd break; 4082168404Spjd 4083168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4084168404Spjd (void) printf(gettext("status: One or more devices could not " 4085168404Spjd "be used because the label is missing \n\tor invalid. " 4086168404Spjd "There are insufficient replicas for the pool to " 4087168404Spjd "continue\n\tfunctioning.\n")); 4088219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4089219089Spjd zpool_get_name(zhp), reason, config); 4090168404Spjd break; 4091168404Spjd 4092168404Spjd case ZPOOL_STATUS_FAILING_DEV: 4093168404Spjd (void) printf(gettext("status: One or more devices has " 4094168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 4095168404Spjd "made to correct the error. Applications are " 4096168404Spjd "unaffected.\n")); 4097168404Spjd (void) printf(gettext("action: Determine if the device needs " 4098168404Spjd "to be replaced, and clear the errors\n\tusing " 4099168404Spjd "'zpool clear' or replace the device with 'zpool " 4100168404Spjd "replace'.\n")); 4101168404Spjd break; 4102168404Spjd 4103168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 4104168404Spjd (void) printf(gettext("status: One or more devices has " 4105168404Spjd "been taken offline by the administrator.\n\tSufficient " 4106168404Spjd "replicas exist for the pool to continue functioning in " 4107168404Spjd "a\n\tdegraded state.\n")); 4108168404Spjd (void) printf(gettext("action: Online the device using " 4109168404Spjd "'zpool online' or replace the device with\n\t'zpool " 4110168404Spjd "replace'.\n")); 4111168404Spjd break; 4112168404Spjd 4113219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 4114219089Spjd (void) printf(gettext("status: One or more devices has " 4115219089Spjd "been removed by the administrator.\n\tSufficient " 4116219089Spjd "replicas exist for the pool to continue functioning in " 4117219089Spjd "a\n\tdegraded state.\n")); 4118219089Spjd (void) printf(gettext("action: Online the device using " 4119219089Spjd "'zpool online' or replace the device with\n\t'zpool " 4120219089Spjd "replace'.\n")); 4121219089Spjd break; 4122219089Spjd 4123168404Spjd case ZPOOL_STATUS_RESILVERING: 4124168404Spjd (void) printf(gettext("status: One or more devices is " 4125168404Spjd "currently being resilvered. The pool will\n\tcontinue " 4126168404Spjd "to function, possibly in a degraded state.\n")); 4127168404Spjd (void) printf(gettext("action: Wait for the resilver to " 4128168404Spjd "complete.\n")); 4129168404Spjd break; 4130168404Spjd 4131168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 4132168404Spjd (void) printf(gettext("status: One or more devices has " 4133168404Spjd "experienced an error resulting in data\n\tcorruption. " 4134168404Spjd "Applications may be affected.\n")); 4135168404Spjd (void) printf(gettext("action: Restore the file in question " 4136168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 4137168404Spjd "backup.\n")); 4138168404Spjd break; 4139168404Spjd 4140168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4141168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4142168404Spjd "and the pool cannot be opened.\n")); 4143219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4144219089Spjd zpool_get_name(zhp), reason, config); 4145168404Spjd break; 4146168404Spjd 4147168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4148238926Smm (void) printf(gettext("status: The pool is formatted using a " 4149238926Smm "legacy on-disk format. The pool can\n\tstill be used, " 4150238926Smm "but some features are unavailable.\n")); 4151168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4152168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 4153238926Smm "be accessible on software that does not support feature\n" 4154238926Smm "\tflags.\n")); 4155168404Spjd break; 4156168404Spjd 4157168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 4158168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 4159168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 4160168404Spjd "be accessed on this system.\n")); 4161168404Spjd (void) printf(gettext("action: Access the pool from a system " 4162168404Spjd "running more recent software, or\n\trestore the pool from " 4163168404Spjd "backup.\n")); 4164168404Spjd break; 4165168404Spjd 4166238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 4167238926Smm (void) printf(gettext("status: Some supported features are not " 4168238926Smm "enabled on the pool. The pool can\n\tstill be used, but " 4169238926Smm "some features are unavailable.\n")); 4170238926Smm (void) printf(gettext("action: Enable all features using " 4171238926Smm "'zpool upgrade'. Once this is done,\n\tthe pool may no " 4172238926Smm "longer be accessible by software that does not support\n\t" 4173243014Smm "the features. See zpool-features(7) for details.\n")); 4174238926Smm break; 4175238926Smm 4176236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 4177236884Smm (void) printf(gettext("status: The pool cannot be accessed on " 4178236884Smm "this system because it uses the\n\tfollowing feature(s) " 4179236884Smm "not supported on this system:\n")); 4180236884Smm zpool_print_unsup_feat(config); 4181236884Smm (void) printf("\n"); 4182236884Smm (void) printf(gettext("action: Access the pool from a system " 4183236884Smm "that supports the required feature(s),\n\tor restore the " 4184236884Smm "pool from backup.\n")); 4185236884Smm break; 4186236884Smm 4187236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4188236884Smm (void) printf(gettext("status: The pool can only be accessed " 4189236884Smm "in read-only mode on this system. It\n\tcannot be " 4190236884Smm "accessed in read-write mode because it uses the " 4191236884Smm "following\n\tfeature(s) not supported on this system:\n")); 4192236884Smm zpool_print_unsup_feat(config); 4193236884Smm (void) printf("\n"); 4194236884Smm (void) printf(gettext("action: The pool cannot be accessed in " 4195236884Smm "read-write mode. Import the pool with\n" 4196236884Smm "\t\"-o readonly=on\", access the pool from a system that " 4197236884Smm "supports the\n\trequired feature(s), or restore the " 4198236884Smm "pool from backup.\n")); 4199236884Smm break; 4200236884Smm 4201185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 4202185029Spjd (void) printf(gettext("status: One or more devices are " 4203185029Spjd "faulted in response to persistent errors.\n\tSufficient " 4204185029Spjd "replicas exist for the pool to continue functioning " 4205185029Spjd "in a\n\tdegraded state.\n")); 4206185029Spjd (void) printf(gettext("action: Replace the faulted device, " 4207185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 4208185029Spjd break; 4209185029Spjd 4210185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 4211185029Spjd (void) printf(gettext("status: One or more devices are " 4212185029Spjd "faulted in response to persistent errors. There are " 4213185029Spjd "insufficient replicas for the pool to\n\tcontinue " 4214185029Spjd "functioning.\n")); 4215185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 4216185029Spjd "from a backup source. Manually marking the device\n" 4217185029Spjd "\trepaired using 'zpool clear' may allow some data " 4218185029Spjd "to be recovered.\n")); 4219185029Spjd break; 4220185029Spjd 4221185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 4222185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 4223185029Spjd (void) printf(gettext("status: One or more devices are " 4224185029Spjd "faulted in response to IO failures.\n")); 4225185029Spjd (void) printf(gettext("action: Make sure the affected devices " 4226185029Spjd "are connected, then run 'zpool clear'.\n")); 4227185029Spjd break; 4228185029Spjd 4229185029Spjd case ZPOOL_STATUS_BAD_LOG: 4230185029Spjd (void) printf(gettext("status: An intent log record " 4231185029Spjd "could not be read.\n" 4232185029Spjd "\tWaiting for adminstrator intervention to fix the " 4233185029Spjd "faulted pool.\n")); 4234185029Spjd (void) printf(gettext("action: Either restore the affected " 4235185029Spjd "device(s) and run 'zpool online',\n" 4236185029Spjd "\tor ignore the intent log records by running " 4237185029Spjd "'zpool clear'.\n")); 4238185029Spjd break; 4239185029Spjd 4240168404Spjd default: 4241168404Spjd /* 4242168404Spjd * The remaining errors can't actually be generated, yet. 4243168404Spjd */ 4244168404Spjd assert(reason == ZPOOL_STATUS_OK); 4245168404Spjd } 4246168404Spjd 4247168404Spjd if (msgid != NULL) 4248236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4249168404Spjd msgid); 4250168404Spjd 4251168404Spjd if (config != NULL) { 4252168404Spjd int namewidth; 4253168404Spjd uint64_t nerr; 4254185029Spjd nvlist_t **spares, **l2cache; 4255185029Spjd uint_t nspares, nl2cache; 4256219089Spjd pool_scan_stat_t *ps = NULL; 4257168404Spjd 4258219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 4259219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 4260219089Spjd print_scan_status(ps); 4261168404Spjd 4262168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 4263168404Spjd if (namewidth < 10) 4264168404Spjd namewidth = 10; 4265168404Spjd 4266168404Spjd (void) printf(gettext("config:\n\n")); 4267168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4268168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4269168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 4270209962Smm namewidth, 0, B_FALSE); 4271209962Smm 4272185029Spjd if (num_logs(nvroot) > 0) 4273213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 4274185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4275185029Spjd &l2cache, &nl2cache) == 0) 4276185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 4277185029Spjd 4278168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 4279168404Spjd &spares, &nspares) == 0) 4280168404Spjd print_spares(zhp, spares, nspares, namewidth); 4281168404Spjd 4282168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4283168404Spjd &nerr) == 0) { 4284168404Spjd nvlist_t *nverrlist = NULL; 4285168404Spjd 4286168404Spjd /* 4287168404Spjd * If the approximate error count is small, get a 4288168404Spjd * precise count by fetching the entire log and 4289168404Spjd * uniquifying the results. 4290168404Spjd */ 4291185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 4292168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 4293168404Spjd nvpair_t *elem; 4294168404Spjd 4295168404Spjd elem = NULL; 4296168404Spjd nerr = 0; 4297168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 4298168404Spjd elem)) != NULL) { 4299168404Spjd nerr++; 4300168404Spjd } 4301168404Spjd } 4302168404Spjd nvlist_free(nverrlist); 4303168404Spjd 4304168404Spjd (void) printf("\n"); 4305168404Spjd 4306168404Spjd if (nerr == 0) 4307168404Spjd (void) printf(gettext("errors: No known data " 4308168404Spjd "errors\n")); 4309168404Spjd else if (!cbp->cb_verbose) 4310168404Spjd (void) printf(gettext("errors: %llu data " 4311168404Spjd "errors, use '-v' for a list\n"), 4312168404Spjd (u_longlong_t)nerr); 4313168404Spjd else 4314168404Spjd print_error_log(zhp); 4315168404Spjd } 4316219089Spjd 4317219089Spjd if (cbp->cb_dedup_stats) 4318219089Spjd print_dedup_stats(config); 4319168404Spjd } else { 4320168404Spjd (void) printf(gettext("config: The configuration cannot be " 4321168404Spjd "determined.\n")); 4322168404Spjd } 4323168404Spjd 4324168404Spjd return (0); 4325168404Spjd} 4326168404Spjd 4327168404Spjd/* 4328219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4329168404Spjd * 4330168404Spjd * -v Display complete error logs 4331168404Spjd * -x Display only pools with potential problems 4332219089Spjd * -D Display dedup status (undocumented) 4333219089Spjd * -T Display a timestamp in date(1) or Unix format 4334168404Spjd * 4335168404Spjd * Describes the health status of all pools or some subset. 4336168404Spjd */ 4337168404Spjdint 4338168404Spjdzpool_do_status(int argc, char **argv) 4339168404Spjd{ 4340168404Spjd int c; 4341168404Spjd int ret; 4342219089Spjd unsigned long interval = 0, count = 0; 4343168404Spjd status_cbdata_t cb = { 0 }; 4344168404Spjd 4345168404Spjd /* check options */ 4346219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4347168404Spjd switch (c) { 4348168404Spjd case 'v': 4349168404Spjd cb.cb_verbose = B_TRUE; 4350168404Spjd break; 4351168404Spjd case 'x': 4352168404Spjd cb.cb_explain = B_TRUE; 4353168404Spjd break; 4354219089Spjd case 'D': 4355219089Spjd cb.cb_dedup_stats = B_TRUE; 4356219089Spjd break; 4357219089Spjd case 'T': 4358219089Spjd get_timestamp_arg(*optarg); 4359219089Spjd break; 4360168404Spjd case '?': 4361168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4362168404Spjd optopt); 4363168404Spjd usage(B_FALSE); 4364168404Spjd } 4365168404Spjd } 4366168404Spjd 4367168404Spjd argc -= optind; 4368168404Spjd argv += optind; 4369168404Spjd 4370219089Spjd get_interval_count(&argc, argv, &interval, &count); 4371168404Spjd 4372168404Spjd if (argc == 0) 4373168404Spjd cb.cb_allpools = B_TRUE; 4374168404Spjd 4375219089Spjd cb.cb_first = B_TRUE; 4376168404Spjd 4377219089Spjd for (;;) { 4378219089Spjd if (timestamp_fmt != NODATE) 4379219089Spjd print_timestamp(timestamp_fmt); 4380168404Spjd 4381219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 4382219089Spjd status_callback, &cb); 4383219089Spjd 4384219089Spjd if (argc == 0 && cb.cb_count == 0) 4385219089Spjd (void) printf(gettext("no pools available\n")); 4386219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 4387219089Spjd (void) printf(gettext("all pools are healthy\n")); 4388219089Spjd 4389219089Spjd if (ret != 0) 4390219089Spjd return (ret); 4391219089Spjd 4392219089Spjd if (interval == 0) 4393219089Spjd break; 4394219089Spjd 4395219089Spjd if (count != 0 && --count == 0) 4396219089Spjd break; 4397219089Spjd 4398219089Spjd (void) sleep(interval); 4399219089Spjd } 4400219089Spjd 4401219089Spjd return (0); 4402168404Spjd} 4403168404Spjd 4404168404Spjdtypedef struct upgrade_cbdata { 4405168404Spjd int cb_first; 4406212050Spjd char cb_poolname[ZPOOL_MAXNAMELEN]; 4407168404Spjd int cb_argc; 4408185029Spjd uint64_t cb_version; 4409168404Spjd char **cb_argv; 4410168404Spjd} upgrade_cbdata_t; 4411168404Spjd 4412238950Smm#ifdef __FreeBSD__ 4413168404Spjdstatic int 4414212050Spjdis_root_pool(zpool_handle_t *zhp) 4415212050Spjd{ 4416212050Spjd static struct statfs sfs; 4417212050Spjd static char *poolname = NULL; 4418212050Spjd static boolean_t stated = B_FALSE; 4419212050Spjd char *slash; 4420212050Spjd 4421212067Spjd if (!stated) { 4422212050Spjd stated = B_TRUE; 4423212050Spjd if (statfs("/", &sfs) == -1) { 4424212050Spjd (void) fprintf(stderr, 4425212050Spjd "Unable to stat root file system: %s.\n", 4426212050Spjd strerror(errno)); 4427212067Spjd return (0); 4428212050Spjd } 4429212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4430212067Spjd return (0); 4431212050Spjd poolname = sfs.f_mntfromname; 4432212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4433212050Spjd *slash = '\0'; 4434212050Spjd } 4435212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4436212050Spjd} 4437212050Spjd 4438238950Smmstatic void 4439238950Smmroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size) { 4440238950Smm 4441238950Smm if (poolname[0] == '\0' && is_root_pool(zhp)) 4442238950Smm (void) strlcpy(poolname, zpool_get_name(zhp), size); 4443238950Smm} 4444238950Smm#endif /* FreeBSD */ 4445238950Smm 4446212050Spjdstatic int 4447238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version) 4448238926Smm{ 4449238926Smm int ret; 4450238926Smm nvlist_t *config; 4451238926Smm uint64_t oldversion; 4452238926Smm 4453238926Smm config = zpool_get_config(zhp, NULL); 4454238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4455238926Smm &oldversion) == 0); 4456238926Smm 4457238926Smm assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 4458238926Smm assert(oldversion < version); 4459238926Smm 4460238926Smm ret = zpool_upgrade(zhp, version); 4461238926Smm if (ret != 0) 4462238926Smm return (ret); 4463238926Smm 4464238926Smm if (version >= SPA_VERSION_FEATURES) { 4465238926Smm (void) printf(gettext("Successfully upgraded " 4466238926Smm "'%s' from version %llu to feature flags.\n"), 4467238926Smm zpool_get_name(zhp), oldversion); 4468238926Smm } else { 4469238926Smm (void) printf(gettext("Successfully upgraded " 4470238926Smm "'%s' from version %llu to version %llu.\n"), 4471238926Smm zpool_get_name(zhp), oldversion, version); 4472238926Smm } 4473238926Smm 4474238926Smm return (0); 4475238926Smm} 4476238926Smm 4477238926Smmstatic int 4478238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp) 4479238926Smm{ 4480238926Smm int i, ret, count; 4481238926Smm boolean_t firstff = B_TRUE; 4482238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4483238926Smm 4484238926Smm count = 0; 4485238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4486238926Smm const char *fname = spa_feature_table[i].fi_uname; 4487238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4488238926Smm if (!nvlist_exists(enabled, fguid)) { 4489238926Smm char *propname; 4490238926Smm verify(-1 != asprintf(&propname, "feature@%s", fname)); 4491238926Smm ret = zpool_set_prop(zhp, propname, 4492238926Smm ZFS_FEATURE_ENABLED); 4493238926Smm if (ret != 0) { 4494238926Smm free(propname); 4495238926Smm return (ret); 4496238926Smm } 4497238926Smm count++; 4498238926Smm 4499238926Smm if (firstff) { 4500238926Smm (void) printf(gettext("Enabled the " 4501238926Smm "following features on '%s':\n"), 4502238926Smm zpool_get_name(zhp)); 4503238926Smm firstff = B_FALSE; 4504238926Smm } 4505238926Smm (void) printf(gettext(" %s\n"), fname); 4506238926Smm free(propname); 4507238926Smm } 4508238926Smm } 4509238926Smm 4510238926Smm if (countp != NULL) 4511238926Smm *countp = count; 4512238926Smm return (0); 4513238926Smm} 4514238926Smm 4515238926Smmstatic int 4516168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4517168404Spjd{ 4518168404Spjd upgrade_cbdata_t *cbp = arg; 4519168404Spjd nvlist_t *config; 4520168404Spjd uint64_t version; 4521238926Smm boolean_t printnl = B_FALSE; 4522238926Smm int ret; 4523168404Spjd 4524168404Spjd config = zpool_get_config(zhp, NULL); 4525168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4526168404Spjd &version) == 0); 4527168404Spjd 4528238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4529168404Spjd 4530238926Smm if (version < cbp->cb_version) { 4531238926Smm cbp->cb_first = B_FALSE; 4532238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4533238926Smm if (ret != 0) 4534238926Smm return (ret); 4535238926Smm#ifdef __FreeBSD__ 4536238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4537238950Smm sizeof(cbp->cb_poolname)); 4538238926Smm#endif /* ___FreeBSD__ */ 4539238926Smm printnl = B_TRUE; 4540238926Smm 4541238926Smm#ifdef illumos 4542238926Smm /* 4543238926Smm * If they did "zpool upgrade -a", then we could 4544238926Smm * be doing ioctls to different pools. We need 4545238926Smm * to log this history once to each pool, and bypass 4546238926Smm * the normal history logging that happens in main(). 4547238926Smm */ 4548238926Smm (void) zpool_log_history(g_zfs, history_str); 4549238926Smm log_history = B_FALSE; 4550238926Smm#endif 4551238926Smm } 4552238926Smm 4553238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4554238926Smm int count; 4555238926Smm ret = upgrade_enable_all(zhp, &count); 4556238926Smm if (ret != 0) 4557238926Smm return (ret); 4558238926Smm 4559238926Smm if (count > 0) { 4560168404Spjd cbp->cb_first = B_FALSE; 4561238926Smm printnl = B_TRUE; 4562168404Spjd } 4563238926Smm } 4564168404Spjd 4565238926Smm if (printnl) { 4566238926Smm (void) printf(gettext("\n")); 4567238926Smm } 4568238926Smm 4569238926Smm return (0); 4570238926Smm} 4571238926Smm 4572238926Smmstatic int 4573238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 4574238926Smm{ 4575238926Smm upgrade_cbdata_t *cbp = arg; 4576238926Smm nvlist_t *config; 4577238926Smm uint64_t version; 4578238926Smm 4579238926Smm config = zpool_get_config(zhp, NULL); 4580238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4581238926Smm &version) == 0); 4582238926Smm 4583238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4584238926Smm 4585238926Smm if (version < SPA_VERSION_FEATURES) { 4586168404Spjd if (cbp->cb_first) { 4587168404Spjd (void) printf(gettext("The following pools are " 4588238926Smm "formatted with legacy version numbers and can\n" 4589238926Smm "be upgraded to use feature flags. After " 4590238926Smm "being upgraded, these pools\nwill no " 4591238926Smm "longer be accessible by software that does not " 4592238926Smm "support feature\nflags.\n\n")); 4593168404Spjd (void) printf(gettext("VER POOL\n")); 4594168404Spjd (void) printf(gettext("--- ------------\n")); 4595168404Spjd cbp->cb_first = B_FALSE; 4596168404Spjd } 4597168404Spjd 4598168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4599168404Spjd zpool_get_name(zhp)); 4600168404Spjd } 4601168404Spjd 4602238926Smm return (0); 4603168404Spjd} 4604168404Spjd 4605238926Smmstatic int 4606238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 4607238926Smm{ 4608238926Smm upgrade_cbdata_t *cbp = arg; 4609238926Smm nvlist_t *config; 4610238926Smm uint64_t version; 4611238926Smm 4612238926Smm config = zpool_get_config(zhp, NULL); 4613238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4614238926Smm &version) == 0); 4615238926Smm 4616238926Smm if (version >= SPA_VERSION_FEATURES) { 4617238926Smm int i; 4618238926Smm boolean_t poolfirst = B_TRUE; 4619238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4620238926Smm 4621238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4622238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4623238926Smm const char *fname = spa_feature_table[i].fi_uname; 4624238926Smm if (!nvlist_exists(enabled, fguid)) { 4625238926Smm if (cbp->cb_first) { 4626238926Smm (void) printf(gettext("\nSome " 4627238926Smm "supported features are not " 4628238926Smm "enabled on the following pools. " 4629238926Smm "Once a\nfeature is enabled the " 4630238926Smm "pool may become incompatible with " 4631238926Smm "software\nthat does not support " 4632238926Smm "the feature. See " 4633243014Smm "zpool-features(7) for " 4634238926Smm "details.\n\n")); 4635238926Smm (void) printf(gettext("POOL " 4636238926Smm "FEATURE\n")); 4637238926Smm (void) printf(gettext("------" 4638238926Smm "---------\n")); 4639238926Smm cbp->cb_first = B_FALSE; 4640238926Smm } 4641238926Smm 4642238926Smm if (poolfirst) { 4643238926Smm (void) printf(gettext("%s\n"), 4644238926Smm zpool_get_name(zhp)); 4645238926Smm poolfirst = B_FALSE; 4646238926Smm } 4647238926Smm 4648238926Smm (void) printf(gettext(" %s\n"), fname); 4649238926Smm } 4650238926Smm } 4651238926Smm } 4652238926Smm 4653238926Smm return (0); 4654238926Smm} 4655238926Smm 4656168404Spjd/* ARGSUSED */ 4657168404Spjdstatic int 4658168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 4659168404Spjd{ 4660238926Smm boolean_t printnl = B_FALSE; 4661185029Spjd upgrade_cbdata_t *cbp = data; 4662185029Spjd uint64_t cur_version; 4663168404Spjd int ret; 4664168404Spjd 4665185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 4666185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 4667185029Spjd "Pool 'log' must be renamed using export and import" 4668185029Spjd " to upgrade.\n")); 4669185029Spjd return (1); 4670185029Spjd } 4671168404Spjd 4672185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4673185029Spjd if (cur_version > cbp->cb_version) { 4674168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 4675238926Smm "using more current version '%llu'.\n\n"), 4676185029Spjd zpool_get_name(zhp), cur_version); 4677185029Spjd return (0); 4678185029Spjd } 4679238926Smm 4680238926Smm if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 4681185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 4682238926Smm "using version %llu.\n\n"), zpool_get_name(zhp), 4683238926Smm cbp->cb_version); 4684168404Spjd return (0); 4685168404Spjd } 4686168404Spjd 4687238926Smm if (cur_version != cbp->cb_version) { 4688238926Smm printnl = B_TRUE; 4689238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4690238950Smm if (ret != 0) 4691238950Smm return (ret); 4692238926Smm#ifdef __FreeBSD__ 4693238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4694238950Smm sizeof(cbp->cb_poolname)); 4695238926Smm#endif /* ___FreeBSD__ */ 4696238926Smm } 4697168404Spjd 4698238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4699238926Smm int count = 0; 4700238926Smm ret = upgrade_enable_all(zhp, &count); 4701238926Smm if (ret != 0) 4702238926Smm return (ret); 4703238926Smm 4704238926Smm if (count != 0) { 4705238926Smm printnl = B_TRUE; 4706238950Smm#ifdef __FreeBSD__ 4707238951Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4708238951Smm sizeof(cbp->cb_poolname)); 4709238950Smm#endif /* __FreeBSD __*/ 4710238926Smm } else if (cur_version == SPA_VERSION) { 4711238926Smm (void) printf(gettext("Pool '%s' already has all " 4712238926Smm "supported features enabled.\n"), 4713238926Smm zpool_get_name(zhp)); 4714238926Smm } 4715168404Spjd } 4716168404Spjd 4717238926Smm if (printnl) { 4718238926Smm (void) printf(gettext("\n")); 4719238926Smm } 4720238926Smm 4721238926Smm return (0); 4722168404Spjd} 4723168404Spjd 4724168404Spjd/* 4725168404Spjd * zpool upgrade 4726168404Spjd * zpool upgrade -v 4727185029Spjd * zpool upgrade [-V version] <-a | pool ...> 4728168404Spjd * 4729168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 4730168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 4731168404Spjd * upgrade all pools. 4732168404Spjd */ 4733168404Spjdint 4734168404Spjdzpool_do_upgrade(int argc, char **argv) 4735168404Spjd{ 4736168404Spjd int c; 4737168404Spjd upgrade_cbdata_t cb = { 0 }; 4738168404Spjd int ret = 0; 4739168404Spjd boolean_t showversions = B_FALSE; 4740238926Smm boolean_t upgradeall = B_FALSE; 4741185029Spjd char *end; 4742168404Spjd 4743185029Spjd 4744168404Spjd /* check options */ 4745219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 4746168404Spjd switch (c) { 4747168404Spjd case 'a': 4748238926Smm upgradeall = B_TRUE; 4749168404Spjd break; 4750168404Spjd case 'v': 4751168404Spjd showversions = B_TRUE; 4752168404Spjd break; 4753185029Spjd case 'V': 4754185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 4755236884Smm if (*end != '\0' || 4756236884Smm !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 4757185029Spjd (void) fprintf(stderr, 4758185029Spjd gettext("invalid version '%s'\n"), optarg); 4759185029Spjd usage(B_FALSE); 4760185029Spjd } 4761185029Spjd break; 4762219089Spjd case ':': 4763219089Spjd (void) fprintf(stderr, gettext("missing argument for " 4764219089Spjd "'%c' option\n"), optopt); 4765219089Spjd usage(B_FALSE); 4766219089Spjd break; 4767168404Spjd case '?': 4768168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4769168404Spjd optopt); 4770168404Spjd usage(B_FALSE); 4771168404Spjd } 4772168404Spjd } 4773168404Spjd 4774168404Spjd cb.cb_argc = argc; 4775168404Spjd cb.cb_argv = argv; 4776168404Spjd argc -= optind; 4777168404Spjd argv += optind; 4778168404Spjd 4779185029Spjd if (cb.cb_version == 0) { 4780185029Spjd cb.cb_version = SPA_VERSION; 4781238926Smm } else if (!upgradeall && argc == 0) { 4782185029Spjd (void) fprintf(stderr, gettext("-V option is " 4783185029Spjd "incompatible with other arguments\n")); 4784185029Spjd usage(B_FALSE); 4785185029Spjd } 4786185029Spjd 4787168404Spjd if (showversions) { 4788238926Smm if (upgradeall || argc != 0) { 4789168404Spjd (void) fprintf(stderr, gettext("-v option is " 4790168404Spjd "incompatible with other arguments\n")); 4791168404Spjd usage(B_FALSE); 4792168404Spjd } 4793238926Smm } else if (upgradeall) { 4794168404Spjd if (argc != 0) { 4795185029Spjd (void) fprintf(stderr, gettext("-a option should not " 4796185029Spjd "be used along with a pool name\n")); 4797168404Spjd usage(B_FALSE); 4798168404Spjd } 4799168404Spjd } 4800168404Spjd 4801236884Smm (void) printf(gettext("This system supports ZFS pool feature " 4802236884Smm "flags.\n\n")); 4803168404Spjd if (showversions) { 4804238926Smm int i; 4805238926Smm 4806238926Smm (void) printf(gettext("The following features are " 4807168404Spjd "supported:\n\n")); 4808238926Smm (void) printf(gettext("FEAT DESCRIPTION\n")); 4809238926Smm (void) printf("----------------------------------------------" 4810238926Smm "---------------\n"); 4811238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4812238926Smm zfeature_info_t *fi = &spa_feature_table[i]; 4813238926Smm const char *ro = fi->fi_can_readonly ? 4814238926Smm " (read-only compatible)" : ""; 4815238926Smm 4816238926Smm (void) printf("%-37s%s\n", fi->fi_uname, ro); 4817238926Smm (void) printf(" %s\n", fi->fi_desc); 4818238926Smm } 4819238926Smm (void) printf("\n"); 4820238926Smm 4821238926Smm (void) printf(gettext("The following legacy versions are also " 4822238926Smm "supported:\n\n")); 4823168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 4824168404Spjd (void) printf("--- -----------------------------------------" 4825168404Spjd "---------------\n"); 4826168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 4827168404Spjd (void) printf(gettext(" 2 Ditto blocks " 4828168404Spjd "(replicated metadata)\n")); 4829168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 4830168404Spjd "RAID-Z\n")); 4831168404Spjd (void) printf(gettext(" 4 zpool history\n")); 4832168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 4833168404Spjd "algorithm\n")); 4834185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 4835185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 4836185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 4837185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 4838185029Spjd "properties\n")); 4839185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 4840185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 4841185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 4842185029Spjd (void) printf(gettext(" 13 snapused property\n")); 4843209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 4844209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 4845219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 4846219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 4847219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 4848219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 4849219089Spjd (void) printf(gettext(" 20 Compression using zle " 4850219089Spjd "(zero-length encoding)\n")); 4851219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 4852219089Spjd (void) printf(gettext(" 22 Received properties\n")); 4853219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 4854219089Spjd (void) printf(gettext(" 24 System attributes\n")); 4855219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 4856219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 4857219089Spjd "performance\n")); 4858219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 4859219089Spjd "performance\n")); 4860219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 4861219089Spjd (void) printf(gettext("\nFor more information on a particular " 4862219089Spjd "version, including supported releases,\n")); 4863219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 4864238926Smm } else if (argc == 0 && upgradeall) { 4865238926Smm cb.cb_first = B_TRUE; 4866168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4867238926Smm if (ret == 0 && cb.cb_first) { 4868238926Smm if (cb.cb_version == SPA_VERSION) { 4869238926Smm (void) printf(gettext("All pools are already " 4870238926Smm "formatted using feature flags.\n\n")); 4871238926Smm (void) printf(gettext("Every feature flags " 4872238926Smm "pool already has all supported features " 4873238926Smm "enabled.\n")); 4874238926Smm } else { 4875238926Smm (void) printf(gettext("All pools are already " 4876238926Smm "formatted with version %llu or higher.\n"), 4877238926Smm cb.cb_version); 4878168404Spjd } 4879168404Spjd } 4880238926Smm } else if (argc == 0) { 4881238926Smm cb.cb_first = B_TRUE; 4882238926Smm ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 4883238926Smm assert(ret == 0); 4884168404Spjd 4885238926Smm if (cb.cb_first) { 4886238926Smm (void) printf(gettext("All pools are formatted " 4887238926Smm "using feature flags.\n\n")); 4888238926Smm } else { 4889238926Smm (void) printf(gettext("\nUse 'zpool upgrade -v' " 4890238926Smm "for a list of available legacy versions.\n")); 4891168404Spjd } 4892238926Smm 4893238926Smm cb.cb_first = B_TRUE; 4894238926Smm ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 4895238926Smm assert(ret == 0); 4896238926Smm 4897238926Smm if (cb.cb_first) { 4898238926Smm (void) printf(gettext("Every feature flags pool has " 4899238926Smm "all supported features enabled.\n")); 4900238926Smm } else { 4901238926Smm (void) printf(gettext("\n")); 4902238926Smm } 4903168404Spjd } else { 4904168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, 4905168404Spjd upgrade_one, &cb); 4906168404Spjd } 4907168404Spjd 4908212050Spjd if (cb.cb_poolname[0] != '\0') { 4909212050Spjd (void) printf( 4910212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 4911212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 4912212050Spjd "the following command will do it:\n" 4913212050Spjd "\n" 4914212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 4915212050Spjd cb.cb_poolname); 4916212050Spjd } 4917212050Spjd 4918168404Spjd return (ret); 4919168404Spjd} 4920168404Spjd 4921185029Spjdtypedef struct hist_cbdata { 4922185029Spjd boolean_t first; 4923185029Spjd int longfmt; 4924185029Spjd int internal; 4925185029Spjd} hist_cbdata_t; 4926185029Spjd 4927168404Spjd/* 4928168404Spjd * Print out the command history for a specific pool. 4929168404Spjd */ 4930168404Spjdstatic int 4931168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 4932168404Spjd{ 4933168404Spjd nvlist_t *nvhis; 4934168404Spjd nvlist_t **records; 4935168404Spjd uint_t numrecords; 4936168404Spjd char *cmdstr; 4937185029Spjd char *pathstr; 4938168404Spjd uint64_t dst_time; 4939168404Spjd time_t tsec; 4940168404Spjd struct tm t; 4941168404Spjd char tbuf[30]; 4942168404Spjd int ret, i; 4943185029Spjd uint64_t who; 4944185029Spjd struct passwd *pwd; 4945185029Spjd char *hostname; 4946185029Spjd char *zonename; 4947185029Spjd char internalstr[MAXPATHLEN]; 4948185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 4949185029Spjd uint64_t txg; 4950185029Spjd uint64_t ievent; 4951168404Spjd 4952185029Spjd cb->first = B_FALSE; 4953168404Spjd 4954168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 4955168404Spjd 4956168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 4957168404Spjd return (ret); 4958168404Spjd 4959168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 4960168404Spjd &records, &numrecords) == 0); 4961168404Spjd for (i = 0; i < numrecords; i++) { 4962168404Spjd if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 4963185029Spjd &dst_time) != 0) 4964185029Spjd continue; 4965185029Spjd 4966185029Spjd /* is it an internal event or a standard event? */ 4967185029Spjd if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 4968185029Spjd &cmdstr) != 0) { 4969185029Spjd if (cb->internal == 0) 4970185029Spjd continue; 4971185029Spjd 4972185029Spjd if (nvlist_lookup_uint64(records[i], 4973185029Spjd ZPOOL_HIST_INT_EVENT, &ievent) != 0) 4974185029Spjd continue; 4975185029Spjd verify(nvlist_lookup_uint64(records[i], 4976185029Spjd ZPOOL_HIST_TXG, &txg) == 0); 4977185029Spjd verify(nvlist_lookup_string(records[i], 4978185029Spjd ZPOOL_HIST_INT_STR, &pathstr) == 0); 4979185029Spjd if (ievent >= LOG_END) 4980185029Spjd continue; 4981185029Spjd (void) snprintf(internalstr, 4982185029Spjd sizeof (internalstr), 4983185029Spjd "[internal %s txg:%lld] %s", 4984219089Spjd zfs_history_event_names[ievent], txg, 4985185029Spjd pathstr); 4986185029Spjd cmdstr = internalstr; 4987168404Spjd } 4988185029Spjd tsec = dst_time; 4989185029Spjd (void) localtime_r(&tsec, &t); 4990185029Spjd (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 4991185029Spjd (void) printf("%s %s", tbuf, cmdstr); 4992185029Spjd 4993185029Spjd if (!cb->longfmt) { 4994185029Spjd (void) printf("\n"); 4995185029Spjd continue; 4996185029Spjd } 4997185029Spjd (void) printf(" ["); 4998185029Spjd if (nvlist_lookup_uint64(records[i], 4999185029Spjd ZPOOL_HIST_WHO, &who) == 0) { 5000185029Spjd pwd = getpwuid((uid_t)who); 5001185029Spjd if (pwd) 5002185029Spjd (void) printf("user %s on", 5003185029Spjd pwd->pw_name); 5004185029Spjd else 5005185029Spjd (void) printf("user %d on", 5006185029Spjd (int)who); 5007185029Spjd } else { 5008185029Spjd (void) printf(gettext("no info]\n")); 5009185029Spjd continue; 5010185029Spjd } 5011185029Spjd if (nvlist_lookup_string(records[i], 5012185029Spjd ZPOOL_HIST_HOST, &hostname) == 0) { 5013185029Spjd (void) printf(" %s", hostname); 5014185029Spjd } 5015185029Spjd if (nvlist_lookup_string(records[i], 5016185029Spjd ZPOOL_HIST_ZONE, &zonename) == 0) { 5017185029Spjd (void) printf(":%s", zonename); 5018185029Spjd } 5019185029Spjd 5020185029Spjd (void) printf("]"); 5021185029Spjd (void) printf("\n"); 5022168404Spjd } 5023168404Spjd (void) printf("\n"); 5024168404Spjd nvlist_free(nvhis); 5025168404Spjd 5026168404Spjd return (ret); 5027168404Spjd} 5028168404Spjd 5029168404Spjd/* 5030168404Spjd * zpool history <pool> 5031168404Spjd * 5032168404Spjd * Displays the history of commands that modified pools. 5033168404Spjd */ 5034185029Spjd 5035185029Spjd 5036168404Spjdint 5037168404Spjdzpool_do_history(int argc, char **argv) 5038168404Spjd{ 5039185029Spjd hist_cbdata_t cbdata = { 0 }; 5040168404Spjd int ret; 5041185029Spjd int c; 5042168404Spjd 5043185029Spjd cbdata.first = B_TRUE; 5044185029Spjd /* check options */ 5045185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 5046185029Spjd switch (c) { 5047185029Spjd case 'l': 5048185029Spjd cbdata.longfmt = 1; 5049185029Spjd break; 5050185029Spjd case 'i': 5051185029Spjd cbdata.internal = 1; 5052185029Spjd break; 5053185029Spjd case '?': 5054185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5055185029Spjd optopt); 5056185029Spjd usage(B_FALSE); 5057185029Spjd } 5058185029Spjd } 5059168404Spjd argc -= optind; 5060168404Spjd argv += optind; 5061168404Spjd 5062168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 5063185029Spjd &cbdata); 5064168404Spjd 5065185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 5066168404Spjd (void) printf(gettext("no pools available\n")); 5067168404Spjd return (0); 5068168404Spjd } 5069168404Spjd 5070168404Spjd return (ret); 5071168404Spjd} 5072168404Spjd 5073168404Spjdstatic int 5074168404Spjdget_callback(zpool_handle_t *zhp, void *data) 5075168404Spjd{ 5076185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 5077168404Spjd char value[MAXNAMELEN]; 5078185029Spjd zprop_source_t srctype; 5079185029Spjd zprop_list_t *pl; 5080168404Spjd 5081168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 5082168404Spjd 5083168404Spjd /* 5084185029Spjd * Skip the special fake placeholder. This will also skip 5085185029Spjd * over the name property when 'all' is specified. 5086168404Spjd */ 5087185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 5088168404Spjd pl == cbp->cb_proplist) 5089168404Spjd continue; 5090168404Spjd 5091236884Smm if (pl->pl_prop == ZPROP_INVAL && 5092236884Smm (zpool_prop_feature(pl->pl_user_prop) || 5093236884Smm zpool_prop_unsupported(pl->pl_user_prop))) { 5094236884Smm srctype = ZPROP_SRC_LOCAL; 5095168404Spjd 5096236884Smm if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 5097236884Smm value, sizeof (value)) == 0) { 5098236884Smm zprop_print_one_property(zpool_get_name(zhp), 5099236884Smm cbp, pl->pl_user_prop, value, srctype, 5100236884Smm NULL, NULL); 5101236884Smm } 5102236884Smm } else { 5103236884Smm if (zpool_get_prop(zhp, pl->pl_prop, value, 5104236884Smm sizeof (value), &srctype) != 0) 5105236884Smm continue; 5106236884Smm 5107236884Smm zprop_print_one_property(zpool_get_name(zhp), cbp, 5108236884Smm zpool_prop_to_name(pl->pl_prop), value, srctype, 5109236884Smm NULL, NULL); 5110236884Smm } 5111168404Spjd } 5112168404Spjd return (0); 5113168404Spjd} 5114168404Spjd 5115168404Spjdint 5116168404Spjdzpool_do_get(int argc, char **argv) 5117168404Spjd{ 5118185029Spjd zprop_get_cbdata_t cb = { 0 }; 5119185029Spjd zprop_list_t fake_name = { 0 }; 5120168404Spjd int ret; 5121168404Spjd 5122236884Smm if (argc < 2) { 5123236884Smm (void) fprintf(stderr, gettext("missing property " 5124236884Smm "argument\n")); 5125168404Spjd usage(B_FALSE); 5126236884Smm } 5127168404Spjd 5128168404Spjd cb.cb_first = B_TRUE; 5129185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 5130168404Spjd cb.cb_columns[0] = GET_COL_NAME; 5131168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 5132168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 5133168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 5134185029Spjd cb.cb_type = ZFS_TYPE_POOL; 5135168404Spjd 5136236884Smm if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 5137185029Spjd ZFS_TYPE_POOL) != 0) 5138168404Spjd usage(B_FALSE); 5139168404Spjd 5140168404Spjd if (cb.cb_proplist != NULL) { 5141185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 5142168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 5143168404Spjd fake_name.pl_next = cb.cb_proplist; 5144168404Spjd cb.cb_proplist = &fake_name; 5145168404Spjd } 5146168404Spjd 5147168404Spjd ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 5148168404Spjd get_callback, &cb); 5149168404Spjd 5150168404Spjd if (cb.cb_proplist == &fake_name) 5151185029Spjd zprop_free_list(fake_name.pl_next); 5152168404Spjd else 5153185029Spjd zprop_free_list(cb.cb_proplist); 5154168404Spjd 5155168404Spjd return (ret); 5156168404Spjd} 5157168404Spjd 5158168404Spjdtypedef struct set_cbdata { 5159168404Spjd char *cb_propname; 5160168404Spjd char *cb_value; 5161168404Spjd boolean_t cb_any_successful; 5162168404Spjd} set_cbdata_t; 5163168404Spjd 5164168404Spjdint 5165168404Spjdset_callback(zpool_handle_t *zhp, void *data) 5166168404Spjd{ 5167168404Spjd int error; 5168168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 5169168404Spjd 5170168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 5171168404Spjd 5172168404Spjd if (!error) 5173168404Spjd cb->cb_any_successful = B_TRUE; 5174168404Spjd 5175168404Spjd return (error); 5176168404Spjd} 5177168404Spjd 5178168404Spjdint 5179168404Spjdzpool_do_set(int argc, char **argv) 5180168404Spjd{ 5181168404Spjd set_cbdata_t cb = { 0 }; 5182168404Spjd int error; 5183168404Spjd 5184168404Spjd if (argc > 1 && argv[1][0] == '-') { 5185168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5186168404Spjd argv[1][1]); 5187168404Spjd usage(B_FALSE); 5188168404Spjd } 5189168404Spjd 5190168404Spjd if (argc < 2) { 5191168404Spjd (void) fprintf(stderr, gettext("missing property=value " 5192168404Spjd "argument\n")); 5193168404Spjd usage(B_FALSE); 5194168404Spjd } 5195168404Spjd 5196168404Spjd if (argc < 3) { 5197168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 5198168404Spjd usage(B_FALSE); 5199168404Spjd } 5200168404Spjd 5201168404Spjd if (argc > 3) { 5202168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 5203168404Spjd usage(B_FALSE); 5204168404Spjd } 5205168404Spjd 5206168404Spjd cb.cb_propname = argv[1]; 5207168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 5208168404Spjd if (cb.cb_value == NULL) { 5209168404Spjd (void) fprintf(stderr, gettext("missing value in " 5210168404Spjd "property=value argument\n")); 5211168404Spjd usage(B_FALSE); 5212168404Spjd } 5213168404Spjd 5214168404Spjd *(cb.cb_value) = '\0'; 5215168404Spjd cb.cb_value++; 5216168404Spjd 5217168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 5218168404Spjd set_callback, &cb); 5219168404Spjd 5220168404Spjd return (error); 5221168404Spjd} 5222168404Spjd 5223168404Spjdstatic int 5224168404Spjdfind_command_idx(char *command, int *idx) 5225168404Spjd{ 5226168404Spjd int i; 5227168404Spjd 5228168404Spjd for (i = 0; i < NCOMMAND; i++) { 5229168404Spjd if (command_table[i].name == NULL) 5230168404Spjd continue; 5231168404Spjd 5232168404Spjd if (strcmp(command, command_table[i].name) == 0) { 5233168404Spjd *idx = i; 5234168404Spjd return (0); 5235168404Spjd } 5236168404Spjd } 5237168404Spjd return (1); 5238168404Spjd} 5239168404Spjd 5240168404Spjdint 5241168404Spjdmain(int argc, char **argv) 5242168404Spjd{ 5243168404Spjd int ret; 5244168404Spjd int i; 5245168404Spjd char *cmdname; 5246168404Spjd 5247168404Spjd (void) setlocale(LC_ALL, ""); 5248168404Spjd (void) textdomain(TEXT_DOMAIN); 5249168404Spjd 5250168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 5251168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 5252168404Spjd "initialize ZFS library\n")); 5253168404Spjd return (1); 5254168404Spjd } 5255168404Spjd 5256168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 5257168404Spjd 5258168404Spjd opterr = 0; 5259168404Spjd 5260168404Spjd /* 5261168404Spjd * Make sure the user has specified some command. 5262168404Spjd */ 5263168404Spjd if (argc < 2) { 5264168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 5265168404Spjd usage(B_FALSE); 5266168404Spjd } 5267168404Spjd 5268168404Spjd cmdname = argv[1]; 5269168404Spjd 5270168404Spjd /* 5271168404Spjd * Special case '-?' 5272168404Spjd */ 5273168404Spjd if (strcmp(cmdname, "-?") == 0) 5274168404Spjd usage(B_TRUE); 5275168404Spjd 5276185029Spjd zpool_set_history_str("zpool", argc, argv, history_str); 5277185029Spjd verify(zpool_stage_history(g_zfs, history_str) == 0); 5278185029Spjd 5279168404Spjd /* 5280168404Spjd * Run the appropriate command. 5281168404Spjd */ 5282168404Spjd if (find_command_idx(cmdname, &i) == 0) { 5283168404Spjd current_command = &command_table[i]; 5284168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 5285185029Spjd } else if (strchr(cmdname, '=')) { 5286185029Spjd verify(find_command_idx("set", &i) == 0); 5287185029Spjd current_command = &command_table[i]; 5288185029Spjd ret = command_table[i].func(argc, argv); 5289185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 5290185029Spjd /* 5291185029Spjd * 'freeze' is a vile debugging abomination, so we treat 5292185029Spjd * it as such. 5293185029Spjd */ 5294168404Spjd char buf[16384]; 5295168404Spjd int fd = open(ZFS_DEV, O_RDWR); 5296168404Spjd (void) strcpy((void *)buf, argv[2]); 5297168404Spjd return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 5298185029Spjd } else { 5299168404Spjd (void) fprintf(stderr, gettext("unrecognized " 5300168404Spjd "command '%s'\n"), cmdname); 5301168404Spjd usage(B_FALSE); 5302168404Spjd } 5303168404Spjd 5304168404Spjd libzfs_fini(g_zfs); 5305168404Spjd 5306168404Spjd /* 5307168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 5308168404Spjd * for the purposes of running ::findleaks. 5309168404Spjd */ 5310168404Spjd if (getenv("ZFS_ABORT") != NULL) { 5311168404Spjd (void) printf("dumping core by request\n"); 5312168404Spjd abort(); 5313168404Spjd } 5314168404Spjd 5315168404Spjd return (ret); 5316168404Spjd} 5317