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. 24288572Smav * Copyright (c) 2011, 2015 by Delphix. All rights reserved. 25236145Smm * Copyright (c) 2012 by Frederik Wessels. All rights reserved. 26236155Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 27254758Sdelphij * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved. 28297119Smav * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. 29299430Smav * Copyright 2016 Nexenta Systems, Inc. 30168404Spjd */ 31168404Spjd 32168404Spjd#include <solaris.h> 33168404Spjd#include <assert.h> 34168404Spjd#include <ctype.h> 35168404Spjd#include <dirent.h> 36168404Spjd#include <errno.h> 37168404Spjd#include <fcntl.h> 38168404Spjd#include <libgen.h> 39168404Spjd#include <libintl.h> 40168404Spjd#include <libuutil.h> 41168404Spjd#include <locale.h> 42168404Spjd#include <stdio.h> 43168404Spjd#include <stdlib.h> 44168404Spjd#include <string.h> 45168404Spjd#include <strings.h> 46168404Spjd#include <unistd.h> 47168404Spjd#include <priv.h> 48185029Spjd#include <pwd.h> 49185029Spjd#include <zone.h> 50168404Spjd#include <sys/time.h> 51236155Smm#include <zfs_prop.h> 52168404Spjd#include <sys/fs/zfs.h> 53168404Spjd#include <sys/stat.h> 54168404Spjd 55168404Spjd#include <libzfs.h> 56168404Spjd 57168404Spjd#include "zpool_util.h" 58185029Spjd#include "zfs_comutil.h" 59236884Smm#include "zfeature_common.h" 60168404Spjd 61219089Spjd#include "statcommon.h" 62219089Spjd 63168404Spjdstatic int zpool_do_create(int, char **); 64168404Spjdstatic int zpool_do_destroy(int, char **); 65168404Spjd 66168404Spjdstatic int zpool_do_add(int, char **); 67168404Spjdstatic int zpool_do_remove(int, char **); 68224171Sgibbsstatic int zpool_do_labelclear(int, char **); 69168404Spjd 70168404Spjdstatic int zpool_do_list(int, char **); 71168404Spjdstatic int zpool_do_iostat(int, char **); 72168404Spjdstatic int zpool_do_status(int, char **); 73168404Spjd 74168404Spjdstatic int zpool_do_online(int, char **); 75168404Spjdstatic int zpool_do_offline(int, char **); 76168404Spjdstatic int zpool_do_clear(int, char **); 77236155Smmstatic int zpool_do_reopen(int, char **); 78168404Spjd 79228103Smmstatic int zpool_do_reguid(int, char **); 80228103Smm 81168404Spjdstatic int zpool_do_attach(int, char **); 82168404Spjdstatic int zpool_do_detach(int, char **); 83168404Spjdstatic int zpool_do_replace(int, char **); 84219089Spjdstatic int zpool_do_split(int, char **); 85168404Spjd 86168404Spjdstatic int zpool_do_scrub(int, char **); 87168404Spjd 88168404Spjdstatic int zpool_do_import(int, char **); 89168404Spjdstatic int zpool_do_export(int, char **); 90168404Spjd 91168404Spjdstatic int zpool_do_upgrade(int, char **); 92168404Spjd 93168404Spjdstatic int zpool_do_history(int, char **); 94168404Spjd 95168404Spjdstatic int zpool_do_get(int, char **); 96168404Spjdstatic int zpool_do_set(int, char **); 97168404Spjd 98168404Spjd/* 99168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 100168404Spjd * debugging facilities. 101168404Spjd */ 102185029Spjd 103185029Spjd#ifdef DEBUG 104168404Spjdconst char * 105168404Spjd_umem_debug_init(void) 106168404Spjd{ 107168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 108168404Spjd} 109168404Spjd 110168404Spjdconst char * 111168404Spjd_umem_logging_init(void) 112168404Spjd{ 113168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 114168404Spjd} 115185029Spjd#endif 116168404Spjd 117168404Spjdtypedef enum { 118168404Spjd HELP_ADD, 119168404Spjd HELP_ATTACH, 120168404Spjd HELP_CLEAR, 121168404Spjd HELP_CREATE, 122168404Spjd HELP_DESTROY, 123168404Spjd HELP_DETACH, 124168404Spjd HELP_EXPORT, 125168404Spjd HELP_HISTORY, 126168404Spjd HELP_IMPORT, 127168404Spjd HELP_IOSTAT, 128224171Sgibbs HELP_LABELCLEAR, 129168404Spjd HELP_LIST, 130168404Spjd HELP_OFFLINE, 131168404Spjd HELP_ONLINE, 132168404Spjd HELP_REPLACE, 133168404Spjd HELP_REMOVE, 134168404Spjd HELP_SCRUB, 135168404Spjd HELP_STATUS, 136168404Spjd HELP_UPGRADE, 137168404Spjd HELP_GET, 138219089Spjd HELP_SET, 139228103Smm HELP_SPLIT, 140236155Smm HELP_REGUID, 141236155Smm HELP_REOPEN 142168404Spjd} zpool_help_t; 143168404Spjd 144168404Spjd 145168404Spjdtypedef struct zpool_command { 146168404Spjd const char *name; 147168404Spjd int (*func)(int, char **); 148168404Spjd zpool_help_t usage; 149168404Spjd} zpool_command_t; 150168404Spjd 151168404Spjd/* 152168404Spjd * Master command table. Each ZFS command has a name, associated function, and 153168404Spjd * usage message. The usage messages need to be internationalized, so we have 154168404Spjd * to have a function to return the usage message based on a command index. 155168404Spjd * 156168404Spjd * These commands are organized according to how they are displayed in the usage 157168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 158168404Spjd * the generic usage message. 159168404Spjd */ 160168404Spjdstatic zpool_command_t command_table[] = { 161168404Spjd { "create", zpool_do_create, HELP_CREATE }, 162168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 163168404Spjd { NULL }, 164168404Spjd { "add", zpool_do_add, HELP_ADD }, 165168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 166168404Spjd { NULL }, 167224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 168224171Sgibbs { NULL }, 169168404Spjd { "list", zpool_do_list, HELP_LIST }, 170168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 171168404Spjd { "status", zpool_do_status, HELP_STATUS }, 172168404Spjd { NULL }, 173168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 174168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 175168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 176236155Smm { "reopen", zpool_do_reopen, HELP_REOPEN }, 177168404Spjd { NULL }, 178168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 179168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 180168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 181219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 182168404Spjd { NULL }, 183168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 184168404Spjd { NULL }, 185168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 186168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 187168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 188228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 189168404Spjd { NULL }, 190168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 191168404Spjd { "get", zpool_do_get, HELP_GET }, 192168404Spjd { "set", zpool_do_set, HELP_SET }, 193168404Spjd}; 194168404Spjd 195168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 196168404Spjd 197248571Smmstatic zpool_command_t *current_command; 198185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 199248571Smmstatic boolean_t log_history = B_TRUE; 200219089Spjdstatic uint_t timestamp_fmt = NODATE; 201219089Spjd 202168404Spjdstatic const char * 203290765Smavget_usage(zpool_help_t idx) 204290765Smav{ 205168404Spjd switch (idx) { 206168404Spjd case HELP_ADD: 207168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 208168404Spjd case HELP_ATTACH: 209168404Spjd return (gettext("\tattach [-f] <pool> <device> " 210185029Spjd "<new-device>\n")); 211168404Spjd case HELP_CLEAR: 212219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 213168404Spjd case HELP_CREATE: 214236884Smm return (gettext("\tcreate [-fnd] [-o property=value] ... \n" 215333196Savg "\t [-O file-system-property=value] ...\n" 216333196Savg "\t [-m mountpoint] [-R root] [-t tempname] " 217333196Savg "<pool> <vdev> ...\n")); 218168404Spjd case HELP_DESTROY: 219168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 220168404Spjd case HELP_DETACH: 221168404Spjd return (gettext("\tdetach <pool> <device>\n")); 222168404Spjd case HELP_EXPORT: 223168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 224168404Spjd case HELP_HISTORY: 225185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 226168404Spjd case HELP_IMPORT: 227168404Spjd return (gettext("\timport [-d dir] [-D]\n" 228219089Spjd "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 229185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 230219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 231219089Spjd "[-R root] [-F [-n]] -a\n" 232185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 233219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 234333196Savg "[-R root] [-F [-n]] [-t]\n" 235219089Spjd "\t <pool | id> [newpool]\n")); 236168404Spjd case HELP_IOSTAT: 237219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 238168404Spjd "[count]]\n")); 239224171Sgibbs case HELP_LABELCLEAR: 240224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 241168404Spjd case HELP_LIST: 242264335Sdelphij return (gettext("\tlist [-Hpv] [-o property[,...]] " 243219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 244168404Spjd case HELP_OFFLINE: 245168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 246168404Spjd case HELP_ONLINE: 247228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 248168404Spjd case HELP_REPLACE: 249168404Spjd return (gettext("\treplace [-f] <pool> <device> " 250185029Spjd "[new-device]\n")); 251168404Spjd case HELP_REMOVE: 252185029Spjd return (gettext("\tremove <pool> <device> ...\n")); 253236155Smm case HELP_REOPEN: 254263393Sdelphij return (gettext("\treopen <pool>\n")); 255168404Spjd case HELP_SCRUB: 256168404Spjd return (gettext("\tscrub [-s] <pool> ...\n")); 257168404Spjd case HELP_STATUS: 258219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 259219089Spjd "[count]]\n")); 260168404Spjd case HELP_UPGRADE: 261228020Smm return (gettext("\tupgrade [-v]\n" 262185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 263168404Spjd case HELP_GET: 264264335Sdelphij return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] " 265264335Sdelphij "<\"all\" | property[,...]> <pool> ...\n")); 266168404Spjd case HELP_SET: 267168404Spjd return (gettext("\tset <property=value> <pool> \n")); 268219089Spjd case HELP_SPLIT: 269219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 270219089Spjd "\t [-o property=value] <pool> <newpool> " 271219089Spjd "[<device> ...]\n")); 272228103Smm case HELP_REGUID: 273228103Smm return (gettext("\treguid <pool>\n")); 274168404Spjd } 275168404Spjd 276168404Spjd abort(); 277168404Spjd /* NOTREACHED */ 278168404Spjd} 279168404Spjd 280168404Spjd 281168404Spjd/* 282168404Spjd * Callback routine that will print out a pool property value. 283168404Spjd */ 284185029Spjdstatic int 285185029Spjdprint_prop_cb(int prop, void *cb) 286168404Spjd{ 287168404Spjd FILE *fp = cb; 288168404Spjd 289219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 290168404Spjd 291185029Spjd if (zpool_prop_readonly(prop)) 292185029Spjd (void) fprintf(fp, " NO "); 293185029Spjd else 294219089Spjd (void) fprintf(fp, " YES "); 295185029Spjd 296168404Spjd if (zpool_prop_values(prop) == NULL) 297168404Spjd (void) fprintf(fp, "-\n"); 298168404Spjd else 299168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 300168404Spjd 301185029Spjd return (ZPROP_CONT); 302168404Spjd} 303168404Spjd 304168404Spjd/* 305168404Spjd * Display usage message. If we're inside a command, display only the usage for 306168404Spjd * that command. Otherwise, iterate over the entire command table and display 307168404Spjd * a complete usage message. 308168404Spjd */ 309168404Spjdvoid 310168404Spjdusage(boolean_t requested) 311168404Spjd{ 312168404Spjd FILE *fp = requested ? stdout : stderr; 313168404Spjd 314168404Spjd if (current_command == NULL) { 315168404Spjd int i; 316168404Spjd 317168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 318168404Spjd (void) fprintf(fp, 319168404Spjd gettext("where 'command' is one of the following:\n\n")); 320168404Spjd 321168404Spjd for (i = 0; i < NCOMMAND; i++) { 322168404Spjd if (command_table[i].name == NULL) 323168404Spjd (void) fprintf(fp, "\n"); 324168404Spjd else 325168404Spjd (void) fprintf(fp, "%s", 326168404Spjd get_usage(command_table[i].usage)); 327168404Spjd } 328168404Spjd } else { 329168404Spjd (void) fprintf(fp, gettext("usage:\n")); 330168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 331168404Spjd } 332168404Spjd 333168404Spjd if (current_command != NULL && 334168404Spjd ((strcmp(current_command->name, "set") == 0) || 335185029Spjd (strcmp(current_command->name, "get") == 0) || 336185029Spjd (strcmp(current_command->name, "list") == 0))) { 337168404Spjd 338168404Spjd (void) fprintf(fp, 339168404Spjd gettext("\nthe following properties are supported:\n")); 340168404Spjd 341219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 342185029Spjd "PROPERTY", "EDIT", "VALUES"); 343168404Spjd 344168404Spjd /* Iterate over all properties */ 345185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 346185029Spjd ZFS_TYPE_POOL); 347236884Smm 348236884Smm (void) fprintf(fp, "\t%-15s ", "feature@..."); 349236884Smm (void) fprintf(fp, "YES disabled | enabled | active\n"); 350236884Smm 351236884Smm (void) fprintf(fp, gettext("\nThe feature@ properties must be " 352243014Smm "appended with a feature name.\nSee zpool-features(7).\n")); 353168404Spjd } 354168404Spjd 355168404Spjd /* 356168404Spjd * See comments at end of main(). 357168404Spjd */ 358168404Spjd if (getenv("ZFS_ABORT") != NULL) { 359168404Spjd (void) printf("dumping core by request\n"); 360168404Spjd abort(); 361168404Spjd } 362168404Spjd 363168404Spjd exit(requested ? 0 : 2); 364168404Spjd} 365168404Spjd 366168404Spjdvoid 367185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 368185029Spjd boolean_t print_logs) 369168404Spjd{ 370168404Spjd nvlist_t **child; 371168404Spjd uint_t c, children; 372168404Spjd char *vname; 373168404Spjd 374168404Spjd if (name != NULL) 375168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 376168404Spjd 377168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 378168404Spjd &child, &children) != 0) 379168404Spjd return; 380168404Spjd 381168404Spjd for (c = 0; c < children; c++) { 382185029Spjd uint64_t is_log = B_FALSE; 383185029Spjd 384185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 385185029Spjd &is_log); 386185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 387185029Spjd continue; 388185029Spjd 389219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 390185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 391185029Spjd B_FALSE); 392168404Spjd free(vname); 393168404Spjd } 394168404Spjd} 395168404Spjd 396238926Smmstatic boolean_t 397238926Smmprop_list_contains_feature(nvlist_t *proplist) 398238926Smm{ 399238926Smm nvpair_t *nvp; 400238926Smm for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; 401238926Smm nvp = nvlist_next_nvpair(proplist, nvp)) { 402238926Smm if (zpool_prop_feature(nvpair_name(nvp))) 403238926Smm return (B_TRUE); 404238926Smm } 405238926Smm return (B_FALSE); 406238926Smm} 407238926Smm 408168404Spjd/* 409185029Spjd * Add a property pair (name, string-value) into a property nvlist. 410185029Spjd */ 411185029Spjdstatic int 412185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 413185029Spjd boolean_t poolprop) 414185029Spjd{ 415185029Spjd zpool_prop_t prop = ZPROP_INVAL; 416185029Spjd zfs_prop_t fprop; 417185029Spjd nvlist_t *proplist; 418185029Spjd const char *normnm; 419185029Spjd char *strval; 420185029Spjd 421185029Spjd if (*props == NULL && 422185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 423185029Spjd (void) fprintf(stderr, 424185029Spjd gettext("internal error: out of memory\n")); 425185029Spjd return (1); 426185029Spjd } 427185029Spjd 428185029Spjd proplist = *props; 429185029Spjd 430185029Spjd if (poolprop) { 431238926Smm const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); 432238926Smm 433236884Smm if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 434236884Smm !zpool_prop_feature(propname)) { 435185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 436185029Spjd "not a valid pool property\n"), propname); 437185029Spjd return (2); 438185029Spjd } 439238926Smm 440238926Smm /* 441238926Smm * feature@ properties and version should not be specified 442238926Smm * at the same time. 443238926Smm */ 444238926Smm if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && 445238926Smm nvlist_exists(proplist, vname)) || 446238926Smm (prop == ZPOOL_PROP_VERSION && 447238926Smm prop_list_contains_feature(proplist))) { 448238926Smm (void) fprintf(stderr, gettext("'feature@' and " 449238926Smm "'version' properties cannot be specified " 450238926Smm "together\n")); 451238926Smm return (2); 452238926Smm } 453238926Smm 454238926Smm 455236884Smm if (zpool_prop_feature(propname)) 456236884Smm normnm = propname; 457236884Smm else 458236884Smm normnm = zpool_prop_to_name(prop); 459185029Spjd } else { 460209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 461209962Smm normnm = zfs_prop_to_name(fprop); 462209962Smm } else { 463209962Smm normnm = propname; 464185029Spjd } 465185029Spjd } 466185029Spjd 467185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 468185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 469185029Spjd (void) fprintf(stderr, gettext("property '%s' " 470185029Spjd "specified multiple times\n"), propname); 471185029Spjd return (2); 472185029Spjd } 473185029Spjd 474185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 475185029Spjd (void) fprintf(stderr, gettext("internal " 476185029Spjd "error: out of memory\n")); 477185029Spjd return (1); 478185029Spjd } 479185029Spjd 480185029Spjd return (0); 481185029Spjd} 482185029Spjd 483185029Spjd/* 484333196Savg * Set a default property pair (name, string-value) in a property nvlist 485333196Savg */ 486333196Savgstatic int 487333196Savgadd_prop_list_default(const char *propname, char *propval, nvlist_t **props, 488333196Savg boolean_t poolprop) 489333196Savg{ 490333196Savg char *pval; 491333196Savg 492333196Savg if (nvlist_lookup_string(*props, propname, &pval) == 0) 493333196Savg return (0); 494333196Savg 495333196Savg return (add_prop_list(propname, propval, props, poolprop)); 496333196Savg} 497333196Savg 498333196Savg/* 499168404Spjd * zpool add [-fn] <pool> <vdev> ... 500168404Spjd * 501168404Spjd * -f Force addition of devices, even if they appear in use 502168404Spjd * -n Do not add the devices, but display the resulting layout if 503168404Spjd * they were to be added. 504168404Spjd * 505168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 506168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 507168404Spjd * libzfs. 508168404Spjd */ 509168404Spjdint 510168404Spjdzpool_do_add(int argc, char **argv) 511168404Spjd{ 512168404Spjd boolean_t force = B_FALSE; 513168404Spjd boolean_t dryrun = B_FALSE; 514168404Spjd int c; 515168404Spjd nvlist_t *nvroot; 516168404Spjd char *poolname; 517168404Spjd int ret; 518168404Spjd zpool_handle_t *zhp; 519168404Spjd nvlist_t *config; 520168404Spjd 521168404Spjd /* check options */ 522168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 523168404Spjd switch (c) { 524168404Spjd case 'f': 525168404Spjd force = B_TRUE; 526168404Spjd break; 527168404Spjd case 'n': 528168404Spjd dryrun = B_TRUE; 529168404Spjd break; 530168404Spjd case '?': 531168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 532168404Spjd optopt); 533168404Spjd usage(B_FALSE); 534168404Spjd } 535168404Spjd } 536168404Spjd 537168404Spjd argc -= optind; 538168404Spjd argv += optind; 539168404Spjd 540168404Spjd /* get pool name and check number of arguments */ 541168404Spjd if (argc < 1) { 542168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 543168404Spjd usage(B_FALSE); 544168404Spjd } 545168404Spjd if (argc < 2) { 546168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 547168404Spjd usage(B_FALSE); 548168404Spjd } 549168404Spjd 550168404Spjd poolname = argv[0]; 551168404Spjd 552168404Spjd argc--; 553168404Spjd argv++; 554168404Spjd 555168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 556168404Spjd return (1); 557168404Spjd 558168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 559168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 560168404Spjd poolname); 561168404Spjd zpool_close(zhp); 562168404Spjd return (1); 563168404Spjd } 564168404Spjd 565168404Spjd /* pass off to get_vdev_spec for processing */ 566185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 567185029Spjd argc, argv); 568168404Spjd if (nvroot == NULL) { 569168404Spjd zpool_close(zhp); 570168404Spjd return (1); 571168404Spjd } 572168404Spjd 573168404Spjd if (dryrun) { 574168404Spjd nvlist_t *poolnvroot; 575168404Spjd 576168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 577168404Spjd &poolnvroot) == 0); 578168404Spjd 579168404Spjd (void) printf(gettext("would update '%s' to the following " 580168404Spjd "configuration:\n"), zpool_get_name(zhp)); 581168404Spjd 582185029Spjd /* print original main pool and new tree */ 583185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 584185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 585168404Spjd 586185029Spjd /* Do the same for the logs */ 587185029Spjd if (num_logs(poolnvroot) > 0) { 588185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 589185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 590185029Spjd } else if (num_logs(nvroot) > 0) { 591185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 592185029Spjd } 593185029Spjd 594168404Spjd ret = 0; 595168404Spjd } else { 596168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 597168404Spjd } 598168404Spjd 599168404Spjd nvlist_free(nvroot); 600168404Spjd zpool_close(zhp); 601168404Spjd 602168404Spjd return (ret); 603168404Spjd} 604168404Spjd 605168404Spjd/* 606219089Spjd * zpool remove <pool> <vdev> ... 607168404Spjd * 608219089Spjd * Removes the given vdev from the pool. Currently, this supports removing 609219089Spjd * spares, cache, and log devices from the pool. 610168404Spjd */ 611168404Spjdint 612168404Spjdzpool_do_remove(int argc, char **argv) 613168404Spjd{ 614168404Spjd char *poolname; 615185029Spjd int i, ret = 0; 616168404Spjd zpool_handle_t *zhp; 617168404Spjd 618168404Spjd argc--; 619168404Spjd argv++; 620168404Spjd 621168404Spjd /* get pool name and check number of arguments */ 622168404Spjd if (argc < 1) { 623168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 624168404Spjd usage(B_FALSE); 625168404Spjd } 626168404Spjd if (argc < 2) { 627168404Spjd (void) fprintf(stderr, gettext("missing device\n")); 628168404Spjd usage(B_FALSE); 629168404Spjd } 630168404Spjd 631168404Spjd poolname = argv[0]; 632168404Spjd 633168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 634168404Spjd return (1); 635168404Spjd 636185029Spjd for (i = 1; i < argc; i++) { 637185029Spjd if (zpool_vdev_remove(zhp, argv[i]) != 0) 638185029Spjd ret = 1; 639168404Spjd } 640168404Spjd 641168404Spjd return (ret); 642168404Spjd} 643168404Spjd 644168404Spjd/* 645299430Smav * zpool labelclear [-f] <vdev> 646224171Sgibbs * 647299430Smav * -f Force clearing the label for the vdevs which are members of 648299430Smav * the exported or foreign pools. 649299430Smav * 650224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 651224171Sgibbs * on the device. 652224171Sgibbs */ 653224171Sgibbsint 654224171Sgibbszpool_do_labelclear(int argc, char **argv) 655224171Sgibbs{ 656299430Smav char vdev[MAXPATHLEN]; 657299430Smav char *name = NULL; 658299430Smav struct stat st; 659299430Smav int c, fd, ret = 0; 660299430Smav nvlist_t *config; 661224171Sgibbs pool_state_t state; 662224171Sgibbs boolean_t inuse = B_FALSE; 663224171Sgibbs boolean_t force = B_FALSE; 664224171Sgibbs 665224171Sgibbs /* check options */ 666224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 667224171Sgibbs switch (c) { 668224171Sgibbs case 'f': 669224171Sgibbs force = B_TRUE; 670224171Sgibbs break; 671224171Sgibbs default: 672224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 673224171Sgibbs optopt); 674224171Sgibbs usage(B_FALSE); 675224171Sgibbs } 676224171Sgibbs } 677224171Sgibbs 678224171Sgibbs argc -= optind; 679224171Sgibbs argv += optind; 680224171Sgibbs 681224171Sgibbs /* get vdev name */ 682224171Sgibbs if (argc < 1) { 683299430Smav (void) fprintf(stderr, gettext("missing vdev name\n")); 684224171Sgibbs usage(B_FALSE); 685224171Sgibbs } 686299430Smav if (argc > 1) { 687299430Smav (void) fprintf(stderr, gettext("too many arguments\n")); 688299430Smav usage(B_FALSE); 689299430Smav } 690224171Sgibbs 691299430Smav /* 692299430Smav * Check if we were given absolute path and use it as is. 693299430Smav * Otherwise if the provided vdev name doesn't point to a file, 694299430Smav * try prepending dsk path and appending s0. 695299430Smav */ 696299430Smav (void) strlcpy(vdev, argv[0], sizeof (vdev)); 697299430Smav if (vdev[0] != '/' && stat(vdev, &st) != 0) { 698299430Smav char *s; 699299430Smav 700299430Smav (void) snprintf(vdev, sizeof (vdev), "%s/%s", 701299430Smav#ifdef illumos 702299430Smav ZFS_DISK_ROOT, argv[0]); 703299430Smav if ((s = strrchr(argv[0], 's')) == NULL || 704299430Smav !isdigit(*(s + 1))) 705299430Smav (void) strlcat(vdev, "s0", sizeof (vdev)); 706299430Smav#else 707299430Smav "/dev", argv[0]); 708299430Smav#endif 709299430Smav if (stat(vdev, &st) != 0) { 710299430Smav (void) fprintf(stderr, gettext( 711299430Smav "failed to find device %s, try specifying absolute " 712299430Smav "path instead\n"), argv[0]); 713299430Smav return (1); 714299430Smav } 715299430Smav } 716299430Smav 717224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 718299430Smav (void) fprintf(stderr, gettext("failed to open %s: %s\n"), 719299430Smav vdev, strerror(errno)); 720299430Smav return (1); 721224171Sgibbs } 722224171Sgibbs 723324256Savg if (zpool_read_label(fd, &config) != 0) { 724224171Sgibbs (void) fprintf(stderr, 725299430Smav gettext("failed to read label from %s\n"), vdev); 726299430Smav return (1); 727299430Smav } 728299430Smav nvlist_free(config); 729224171Sgibbs 730299430Smav ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse); 731299430Smav if (ret != 0) { 732299430Smav (void) fprintf(stderr, 733299430Smav gettext("failed to check state for %s\n"), vdev); 734224171Sgibbs return (1); 735224171Sgibbs } 736224171Sgibbs 737299430Smav if (!inuse) 738299430Smav goto wipe_label; 739224171Sgibbs 740299430Smav switch (state) { 741299430Smav default: 742299430Smav case POOL_STATE_ACTIVE: 743299430Smav case POOL_STATE_SPARE: 744299430Smav case POOL_STATE_L2CACHE: 745299430Smav (void) fprintf(stderr, gettext( 746299430Smav "%s is a member (%s) of pool \"%s\"\n"), 747299430Smav vdev, zpool_pool_state_to_name(state), name); 748299430Smav ret = 1; 749299430Smav goto errout; 750224171Sgibbs 751299430Smav case POOL_STATE_EXPORTED: 752299430Smav if (force) 753299430Smav break; 754299430Smav (void) fprintf(stderr, gettext( 755299430Smav "use '-f' to override the following error:\n" 756299430Smav "%s is a member of exported pool \"%s\"\n"), 757299430Smav vdev, name); 758299430Smav ret = 1; 759299430Smav goto errout; 760224171Sgibbs 761299430Smav case POOL_STATE_POTENTIALLY_ACTIVE: 762299430Smav if (force) 763299430Smav break; 764299430Smav (void) fprintf(stderr, gettext( 765299430Smav "use '-f' to override the following error:\n" 766299430Smav "%s is a member of potentially active pool \"%s\"\n"), 767299430Smav vdev, name); 768299430Smav ret = 1; 769299430Smav goto errout; 770224171Sgibbs 771299430Smav case POOL_STATE_DESTROYED: 772299430Smav /* inuse should never be set for a destroyed pool */ 773299430Smav assert(0); 774299430Smav break; 775224171Sgibbs } 776224171Sgibbs 777224171Sgibbswipe_label: 778299430Smav ret = zpool_clear_label(fd); 779299430Smav if (ret != 0) { 780224171Sgibbs (void) fprintf(stderr, 781299430Smav gettext("failed to clear label for %s\n"), vdev); 782224171Sgibbs } 783224171Sgibbs 784224171Sgibbserrout: 785299430Smav free(name); 786299430Smav (void) close(fd); 787224171Sgibbs 788224171Sgibbs return (ret); 789224171Sgibbs} 790224171Sgibbs 791224171Sgibbs/* 792236884Smm * zpool create [-fnd] [-o property=value] ... 793185029Spjd * [-O file-system-property=value] ... 794333196Savg * [-R root] [-m mountpoint] [-t tempname] <pool> <dev> ... 795168404Spjd * 796168404Spjd * -f Force creation, even if devices appear in use 797168404Spjd * -n Do not create the pool, but display the resulting layout if it 798168404Spjd * were to be created. 799333196Savg * -R Create a pool under an alternate root 800333196Savg * -m Set default mountpoint for the root dataset. By default it's 801236884Smm * '/<pool>' 802333196Savg * -t Use the temporary name until the pool is exported. 803185029Spjd * -o Set property=value. 804236884Smm * -d Don't automatically enable all supported pool features 805236884Smm * (individual features can be enabled with -o). 806185029Spjd * -O Set fsproperty=value in the pool's root file system 807168404Spjd * 808168404Spjd * Creates the named pool according to the given vdev specification. The 809168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 810168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 811168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 812168404Spjd */ 813168404Spjdint 814168404Spjdzpool_do_create(int argc, char **argv) 815168404Spjd{ 816168404Spjd boolean_t force = B_FALSE; 817168404Spjd boolean_t dryrun = B_FALSE; 818236884Smm boolean_t enable_all_pool_feat = B_TRUE; 819168404Spjd int c; 820185029Spjd nvlist_t *nvroot = NULL; 821168404Spjd char *poolname; 822333196Savg char *tname = NULL; 823185029Spjd int ret = 1; 824168404Spjd char *altroot = NULL; 825168404Spjd char *mountpoint = NULL; 826185029Spjd nvlist_t *fsprops = NULL; 827185029Spjd nvlist_t *props = NULL; 828185029Spjd char *propval; 829168404Spjd 830168404Spjd /* check options */ 831333196Savg while ((c = getopt(argc, argv, ":fndR:m:o:O:t:")) != -1) { 832168404Spjd switch (c) { 833168404Spjd case 'f': 834168404Spjd force = B_TRUE; 835168404Spjd break; 836168404Spjd case 'n': 837168404Spjd dryrun = B_TRUE; 838168404Spjd break; 839236884Smm case 'd': 840236884Smm enable_all_pool_feat = B_FALSE; 841236884Smm break; 842168404Spjd case 'R': 843168404Spjd altroot = optarg; 844185029Spjd if (add_prop_list(zpool_prop_to_name( 845185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 846185029Spjd goto errout; 847333196Savg if (add_prop_list_default(zpool_prop_to_name( 848185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 849185029Spjd goto errout; 850168404Spjd break; 851168404Spjd case 'm': 852251634Sdelphij /* Equivalent to -O mountpoint=optarg */ 853168404Spjd mountpoint = optarg; 854168404Spjd break; 855185029Spjd case 'o': 856185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 857185029Spjd (void) fprintf(stderr, gettext("missing " 858185029Spjd "'=' for -o option\n")); 859185029Spjd goto errout; 860185029Spjd } 861185029Spjd *propval = '\0'; 862185029Spjd propval++; 863185029Spjd 864185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 865185029Spjd goto errout; 866236884Smm 867236884Smm /* 868236884Smm * If the user is creating a pool that doesn't support 869236884Smm * feature flags, don't enable any features. 870236884Smm */ 871236884Smm if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 872236884Smm char *end; 873236884Smm u_longlong_t ver; 874236884Smm 875236884Smm ver = strtoull(propval, &end, 10); 876236884Smm if (*end == '\0' && 877236884Smm ver < SPA_VERSION_FEATURES) { 878236884Smm enable_all_pool_feat = B_FALSE; 879236884Smm } 880236884Smm } 881279942Sdelphij if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) 882279942Sdelphij altroot = propval; 883185029Spjd break; 884185029Spjd case 'O': 885185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 886185029Spjd (void) fprintf(stderr, gettext("missing " 887185029Spjd "'=' for -O option\n")); 888185029Spjd goto errout; 889185029Spjd } 890185029Spjd *propval = '\0'; 891185029Spjd propval++; 892185029Spjd 893251634Sdelphij /* 894251634Sdelphij * Mountpoints are checked and then added later. 895251634Sdelphij * Uniquely among properties, they can be specified 896251634Sdelphij * more than once, to avoid conflict with -m. 897251634Sdelphij */ 898251634Sdelphij if (0 == strcmp(optarg, 899251634Sdelphij zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) { 900251634Sdelphij mountpoint = propval; 901251634Sdelphij } else if (add_prop_list(optarg, propval, &fsprops, 902251634Sdelphij B_FALSE)) { 903185029Spjd goto errout; 904251634Sdelphij } 905185029Spjd break; 906333196Savg case 't': 907333196Savg /* 908333196Savg * Sanity check temporary pool name. 909333196Savg */ 910333196Savg if (strchr(optarg, '/') != NULL) { 911333196Savg (void) fprintf(stderr, gettext("cannot create " 912333196Savg "'%s': invalid character '/' in temporary " 913333196Savg "name\n"), optarg); 914333196Savg (void) fprintf(stderr, gettext("use 'zfs " 915333196Savg "create' to create a dataset\n")); 916333196Savg goto errout; 917333196Savg } 918333196Savg 919333196Savg if (add_prop_list(zpool_prop_to_name( 920333196Savg ZPOOL_PROP_TNAME), optarg, &props, B_TRUE)) 921333196Savg goto errout; 922333196Savg if (add_prop_list_default(zpool_prop_to_name( 923333196Savg ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 924333196Savg goto errout; 925333196Savg tname = optarg; 926333196Savg break; 927168404Spjd case ':': 928168404Spjd (void) fprintf(stderr, gettext("missing argument for " 929168404Spjd "'%c' option\n"), optopt); 930185029Spjd goto badusage; 931168404Spjd case '?': 932168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 933168404Spjd optopt); 934185029Spjd goto badusage; 935168404Spjd } 936168404Spjd } 937168404Spjd 938168404Spjd argc -= optind; 939168404Spjd argv += optind; 940168404Spjd 941168404Spjd /* get pool name and check number of arguments */ 942168404Spjd if (argc < 1) { 943168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 944185029Spjd goto badusage; 945168404Spjd } 946168404Spjd if (argc < 2) { 947168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 948185029Spjd goto badusage; 949168404Spjd } 950168404Spjd 951168404Spjd poolname = argv[0]; 952168404Spjd 953168404Spjd /* 954168404Spjd * As a special case, check for use of '/' in the name, and direct the 955168404Spjd * user to use 'zfs create' instead. 956168404Spjd */ 957168404Spjd if (strchr(poolname, '/') != NULL) { 958168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 959168404Spjd "character '/' in pool name\n"), poolname); 960168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 961168404Spjd "create a dataset\n")); 962185029Spjd goto errout; 963168404Spjd } 964168404Spjd 965168404Spjd /* pass off to get_vdev_spec for bulk processing */ 966185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 967185029Spjd argc - 1, argv + 1); 968168404Spjd if (nvroot == NULL) 969185029Spjd goto errout; 970168404Spjd 971168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 972185029Spjd if (!zfs_allocatable_devs(nvroot)) { 973168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 974168404Spjd "specification: at least one toplevel vdev must be " 975168404Spjd "specified\n")); 976185029Spjd goto errout; 977168404Spjd } 978168404Spjd 979168404Spjd if (altroot != NULL && altroot[0] != '/') { 980168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 981168404Spjd "must be an absolute path\n"), altroot); 982185029Spjd goto errout; 983168404Spjd } 984168404Spjd 985168404Spjd /* 986168404Spjd * Check the validity of the mountpoint and direct the user to use the 987168404Spjd * '-m' mountpoint option if it looks like its in use. 988244857Spjd * Ignore the checks if the '-f' option is given. 989168404Spjd */ 990244857Spjd if (!force && (mountpoint == NULL || 991168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 992244857Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) { 993168404Spjd char buf[MAXPATHLEN]; 994185029Spjd DIR *dirp; 995168404Spjd 996168404Spjd if (mountpoint && mountpoint[0] != '/') { 997168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 998168404Spjd "'%s': must be an absolute path, 'legacy', or " 999168404Spjd "'none'\n"), mountpoint); 1000185029Spjd goto errout; 1001168404Spjd } 1002168404Spjd 1003168404Spjd if (mountpoint == NULL) { 1004168404Spjd if (altroot != NULL) 1005168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 1006168404Spjd altroot, poolname); 1007168404Spjd else 1008168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 1009168404Spjd poolname); 1010168404Spjd } else { 1011168404Spjd if (altroot != NULL) 1012168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 1013168404Spjd altroot, mountpoint); 1014168404Spjd else 1015168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 1016168404Spjd mountpoint); 1017168404Spjd } 1018168404Spjd 1019185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 1020185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 1021185029Spjd "%s\n"), buf, strerror(errno)); 1022185029Spjd (void) fprintf(stderr, gettext("use '-m' " 1023185029Spjd "option to provide a different default\n")); 1024185029Spjd goto errout; 1025185029Spjd } else if (dirp) { 1026185029Spjd int count = 0; 1027185029Spjd 1028185029Spjd while (count < 3 && readdir(dirp) != NULL) 1029185029Spjd count++; 1030185029Spjd (void) closedir(dirp); 1031185029Spjd 1032185029Spjd if (count > 2) { 1033168404Spjd (void) fprintf(stderr, gettext("mountpoint " 1034168404Spjd "'%s' exists and is not empty\n"), buf); 1035185029Spjd (void) fprintf(stderr, gettext("use '-m' " 1036185029Spjd "option to provide a " 1037185029Spjd "different default\n")); 1038185029Spjd goto errout; 1039185029Spjd } 1040168404Spjd } 1041168404Spjd } 1042168404Spjd 1043251634Sdelphij /* 1044251634Sdelphij * Now that the mountpoint's validity has been checked, ensure that 1045251634Sdelphij * the property is set appropriately prior to creating the pool. 1046251634Sdelphij */ 1047251634Sdelphij if (mountpoint != NULL) { 1048251634Sdelphij ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1049251634Sdelphij mountpoint, &fsprops, B_FALSE); 1050251634Sdelphij if (ret != 0) 1051251634Sdelphij goto errout; 1052251634Sdelphij } 1053251634Sdelphij 1054251634Sdelphij ret = 1; 1055168404Spjd if (dryrun) { 1056168404Spjd /* 1057168404Spjd * For a dry run invocation, print out a basic message and run 1058168404Spjd * through all the vdevs in the list and print out in an 1059168404Spjd * appropriate hierarchy. 1060168404Spjd */ 1061168404Spjd (void) printf(gettext("would create '%s' with the " 1062168404Spjd "following layout:\n\n"), poolname); 1063168404Spjd 1064185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 1065185029Spjd if (num_logs(nvroot) > 0) 1066185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 1067168404Spjd 1068168404Spjd ret = 0; 1069168404Spjd } else { 1070168404Spjd /* 1071168404Spjd * Hand off to libzfs. 1072168404Spjd */ 1073236884Smm if (enable_all_pool_feat) { 1074263390Sdelphij spa_feature_t i; 1075236884Smm for (i = 0; i < SPA_FEATURES; i++) { 1076236884Smm char propname[MAXPATHLEN]; 1077236884Smm zfeature_info_t *feat = &spa_feature_table[i]; 1078236884Smm 1079236884Smm (void) snprintf(propname, sizeof (propname), 1080236884Smm "feature@%s", feat->fi_uname); 1081236884Smm 1082236884Smm /* 1083236884Smm * Skip feature if user specified it manually 1084236884Smm * on the command line. 1085236884Smm */ 1086236884Smm if (nvlist_exists(props, propname)) 1087236884Smm continue; 1088236884Smm 1089251634Sdelphij ret = add_prop_list(propname, 1090251634Sdelphij ZFS_FEATURE_ENABLED, &props, B_TRUE); 1091251634Sdelphij if (ret != 0) 1092236884Smm goto errout; 1093236884Smm } 1094236884Smm } 1095251634Sdelphij 1096251634Sdelphij ret = 1; 1097185029Spjd if (zpool_create(g_zfs, poolname, 1098185029Spjd nvroot, props, fsprops) == 0) { 1099333196Savg zfs_handle_t *pool = zfs_open(g_zfs, 1100333196Savg tname ? tname : poolname, ZFS_TYPE_FILESYSTEM); 1101168404Spjd if (pool != NULL) { 1102168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 1103185029Spjd ret = zfs_shareall(pool); 1104168404Spjd zfs_close(pool); 1105168404Spjd } 1106168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 1107168404Spjd (void) fprintf(stderr, gettext("pool name may have " 1108168404Spjd "been omitted\n")); 1109168404Spjd } 1110168404Spjd } 1111168404Spjd 1112185029Spjderrout: 1113168404Spjd nvlist_free(nvroot); 1114185029Spjd nvlist_free(fsprops); 1115185029Spjd nvlist_free(props); 1116168404Spjd return (ret); 1117185029Spjdbadusage: 1118185029Spjd nvlist_free(fsprops); 1119185029Spjd nvlist_free(props); 1120185029Spjd usage(B_FALSE); 1121185029Spjd return (2); 1122168404Spjd} 1123168404Spjd 1124168404Spjd/* 1125168404Spjd * zpool destroy <pool> 1126168404Spjd * 1127168404Spjd * -f Forcefully unmount any datasets 1128168404Spjd * 1129168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 1130168404Spjd */ 1131168404Spjdint 1132168404Spjdzpool_do_destroy(int argc, char **argv) 1133168404Spjd{ 1134168404Spjd boolean_t force = B_FALSE; 1135168404Spjd int c; 1136168404Spjd char *pool; 1137168404Spjd zpool_handle_t *zhp; 1138168404Spjd int ret; 1139168404Spjd 1140168404Spjd /* check options */ 1141168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 1142168404Spjd switch (c) { 1143168404Spjd case 'f': 1144168404Spjd force = B_TRUE; 1145168404Spjd break; 1146168404Spjd case '?': 1147168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1148168404Spjd optopt); 1149168404Spjd usage(B_FALSE); 1150168404Spjd } 1151168404Spjd } 1152168404Spjd 1153168404Spjd argc -= optind; 1154168404Spjd argv += optind; 1155168404Spjd 1156168404Spjd /* check arguments */ 1157168404Spjd if (argc < 1) { 1158168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1159168404Spjd usage(B_FALSE); 1160168404Spjd } 1161168404Spjd if (argc > 1) { 1162168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1163168404Spjd usage(B_FALSE); 1164168404Spjd } 1165168404Spjd 1166168404Spjd pool = argv[0]; 1167168404Spjd 1168168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1169168404Spjd /* 1170168404Spjd * As a special case, check for use of '/' in the name, and 1171168404Spjd * direct the user to use 'zfs destroy' instead. 1172168404Spjd */ 1173168404Spjd if (strchr(pool, '/') != NULL) 1174168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1175168404Spjd "destroy a dataset\n")); 1176168404Spjd return (1); 1177168404Spjd } 1178168404Spjd 1179168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1180168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1181168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1182168404Spjd return (1); 1183168404Spjd } 1184168404Spjd 1185248571Smm /* The history must be logged as part of the export */ 1186248571Smm log_history = B_FALSE; 1187168404Spjd 1188248571Smm ret = (zpool_destroy(zhp, history_str) != 0); 1189248571Smm 1190168404Spjd zpool_close(zhp); 1191168404Spjd 1192168404Spjd return (ret); 1193168404Spjd} 1194168404Spjd 1195168404Spjd/* 1196168404Spjd * zpool export [-f] <pool> ... 1197168404Spjd * 1198168404Spjd * -f Forcefully unmount datasets 1199168404Spjd * 1200168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1201168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1202168404Spjd * then the datasets will be forcefully unmounted. 1203168404Spjd */ 1204168404Spjdint 1205168404Spjdzpool_do_export(int argc, char **argv) 1206168404Spjd{ 1207168404Spjd boolean_t force = B_FALSE; 1208207670Smm boolean_t hardforce = B_FALSE; 1209168404Spjd int c; 1210168404Spjd zpool_handle_t *zhp; 1211168404Spjd int ret; 1212168404Spjd int i; 1213168404Spjd 1214168404Spjd /* check options */ 1215207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1216168404Spjd switch (c) { 1217168404Spjd case 'f': 1218168404Spjd force = B_TRUE; 1219168404Spjd break; 1220207670Smm case 'F': 1221207670Smm hardforce = B_TRUE; 1222207670Smm break; 1223168404Spjd case '?': 1224168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1225168404Spjd optopt); 1226168404Spjd usage(B_FALSE); 1227168404Spjd } 1228168404Spjd } 1229168404Spjd 1230168404Spjd argc -= optind; 1231168404Spjd argv += optind; 1232168404Spjd 1233168404Spjd /* check arguments */ 1234168404Spjd if (argc < 1) { 1235168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1236168404Spjd usage(B_FALSE); 1237168404Spjd } 1238168404Spjd 1239168404Spjd ret = 0; 1240168404Spjd for (i = 0; i < argc; i++) { 1241168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1242168404Spjd ret = 1; 1243168404Spjd continue; 1244168404Spjd } 1245168404Spjd 1246168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1247168404Spjd ret = 1; 1248168404Spjd zpool_close(zhp); 1249168404Spjd continue; 1250168404Spjd } 1251168404Spjd 1252248571Smm /* The history must be logged as part of the export */ 1253248571Smm log_history = B_FALSE; 1254248571Smm 1255207670Smm if (hardforce) { 1256248571Smm if (zpool_export_force(zhp, history_str) != 0) 1257207670Smm ret = 1; 1258248571Smm } else if (zpool_export(zhp, force, history_str) != 0) { 1259168404Spjd ret = 1; 1260207670Smm } 1261168404Spjd 1262168404Spjd zpool_close(zhp); 1263168404Spjd } 1264168404Spjd 1265168404Spjd return (ret); 1266168404Spjd} 1267168404Spjd 1268168404Spjd/* 1269168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1270168404Spjd * name column. 1271168404Spjd */ 1272168404Spjdstatic int 1273168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1274168404Spjd{ 1275219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1276168404Spjd nvlist_t **child; 1277168404Spjd uint_t c, children; 1278168404Spjd int ret; 1279168404Spjd 1280168404Spjd if (strlen(name) + depth > max) 1281168404Spjd max = strlen(name) + depth; 1282168404Spjd 1283168404Spjd free(name); 1284168404Spjd 1285168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1286168404Spjd &child, &children) == 0) { 1287168404Spjd for (c = 0; c < children; c++) 1288168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1289168404Spjd max)) > max) 1290168404Spjd max = ret; 1291168404Spjd } 1292168404Spjd 1293185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1294185029Spjd &child, &children) == 0) { 1295185029Spjd for (c = 0; c < children; c++) 1296185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1297185029Spjd max)) > max) 1298185029Spjd max = ret; 1299185029Spjd } 1300185029Spjd 1301168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1302168404Spjd &child, &children) == 0) { 1303168404Spjd for (c = 0; c < children; c++) 1304168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1305168404Spjd max)) > max) 1306168404Spjd max = ret; 1307168404Spjd } 1308168404Spjd 1309168404Spjd 1310168404Spjd return (max); 1311168404Spjd} 1312168404Spjd 1313213197Smmtypedef struct spare_cbdata { 1314213197Smm uint64_t cb_guid; 1315213197Smm zpool_handle_t *cb_zhp; 1316213197Smm} spare_cbdata_t; 1317168404Spjd 1318213197Smmstatic boolean_t 1319213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1320213197Smm{ 1321213197Smm uint64_t guid; 1322213197Smm nvlist_t **child; 1323213197Smm uint_t c, children; 1324213197Smm 1325213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1326213197Smm search == guid) 1327213197Smm return (B_TRUE); 1328213197Smm 1329213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1330213197Smm &child, &children) == 0) { 1331213197Smm for (c = 0; c < children; c++) 1332213197Smm if (find_vdev(child[c], search)) 1333213197Smm return (B_TRUE); 1334213197Smm } 1335213197Smm 1336213197Smm return (B_FALSE); 1337213197Smm} 1338213197Smm 1339213197Smmstatic int 1340213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1341213197Smm{ 1342213197Smm spare_cbdata_t *cbp = data; 1343213197Smm nvlist_t *config, *nvroot; 1344213197Smm 1345213197Smm config = zpool_get_config(zhp, NULL); 1346213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1347213197Smm &nvroot) == 0); 1348213197Smm 1349213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1350213197Smm cbp->cb_zhp = zhp; 1351213197Smm return (1); 1352213197Smm } 1353213197Smm 1354213197Smm zpool_close(zhp); 1355213197Smm return (0); 1356213197Smm} 1357213197Smm 1358168404Spjd/* 1359213197Smm * Print out configuration state as requested by status_callback. 1360213197Smm */ 1361213197Smmvoid 1362213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1363213197Smm int namewidth, int depth, boolean_t isspare) 1364213197Smm{ 1365213197Smm nvlist_t **child; 1366254591Sgibbs uint_t c, vsc, children; 1367219089Spjd pool_scan_stat_t *ps = NULL; 1368213197Smm vdev_stat_t *vs; 1369219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1370213197Smm char *vname; 1371213197Smm uint64_t notpresent; 1372254591Sgibbs uint64_t ashift; 1373213197Smm spare_cbdata_t cb; 1374224169Sgibbs const char *state; 1375213197Smm 1376213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1377213197Smm &child, &children) != 0) 1378213197Smm children = 0; 1379213197Smm 1380219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1381254591Sgibbs (uint64_t **)&vs, &vsc) == 0); 1382219089Spjd 1383213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1384213197Smm if (isspare) { 1385213197Smm /* 1386213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1387213197Smm * online drives. 1388213197Smm */ 1389213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1390213197Smm state = "INUSE"; 1391213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1392213197Smm state = "AVAIL"; 1393213197Smm } 1394213197Smm 1395213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1396213197Smm name, state); 1397213197Smm 1398213197Smm if (!isspare) { 1399213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1400213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1401213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1402213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1403213197Smm } 1404213197Smm 1405213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1406224170Sgibbs ¬present) == 0 || 1407224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1408213197Smm char *path; 1409224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1410224170Sgibbs (void) printf(" was %s", path); 1411213197Smm } else if (vs->vs_aux != 0) { 1412213197Smm (void) printf(" "); 1413213197Smm 1414213197Smm switch (vs->vs_aux) { 1415213197Smm case VDEV_AUX_OPEN_FAILED: 1416213197Smm (void) printf(gettext("cannot open")); 1417213197Smm break; 1418213197Smm 1419213197Smm case VDEV_AUX_BAD_GUID_SUM: 1420213197Smm (void) printf(gettext("missing device")); 1421213197Smm break; 1422213197Smm 1423213197Smm case VDEV_AUX_NO_REPLICAS: 1424213197Smm (void) printf(gettext("insufficient replicas")); 1425213197Smm break; 1426213197Smm 1427213197Smm case VDEV_AUX_VERSION_NEWER: 1428213197Smm (void) printf(gettext("newer version")); 1429213197Smm break; 1430213197Smm 1431236884Smm case VDEV_AUX_UNSUP_FEAT: 1432236884Smm (void) printf(gettext("unsupported feature(s)")); 1433236884Smm break; 1434236884Smm 1435254591Sgibbs case VDEV_AUX_ASHIFT_TOO_BIG: 1436254591Sgibbs (void) printf(gettext("unsupported minimum blocksize")); 1437254591Sgibbs break; 1438254591Sgibbs 1439213197Smm case VDEV_AUX_SPARED: 1440213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1441213197Smm &cb.cb_guid) == 0); 1442213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1443213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1444213197Smm zpool_get_name(zhp)) == 0) 1445213197Smm (void) printf(gettext("currently in " 1446213197Smm "use")); 1447213197Smm else 1448213197Smm (void) printf(gettext("in use by " 1449213197Smm "pool '%s'"), 1450213197Smm zpool_get_name(cb.cb_zhp)); 1451213197Smm zpool_close(cb.cb_zhp); 1452213197Smm } else { 1453213197Smm (void) printf(gettext("currently in use")); 1454213197Smm } 1455213197Smm break; 1456213197Smm 1457213197Smm case VDEV_AUX_ERR_EXCEEDED: 1458213197Smm (void) printf(gettext("too many errors")); 1459213197Smm break; 1460213197Smm 1461213197Smm case VDEV_AUX_IO_FAILURE: 1462213197Smm (void) printf(gettext("experienced I/O failures")); 1463213197Smm break; 1464213197Smm 1465213197Smm case VDEV_AUX_BAD_LOG: 1466213197Smm (void) printf(gettext("bad intent log")); 1467213197Smm break; 1468213197Smm 1469219089Spjd case VDEV_AUX_EXTERNAL: 1470219089Spjd (void) printf(gettext("external device fault")); 1471219089Spjd break; 1472219089Spjd 1473219089Spjd case VDEV_AUX_SPLIT_POOL: 1474219089Spjd (void) printf(gettext("split into new pool")); 1475219089Spjd break; 1476219089Spjd 1477213197Smm default: 1478213197Smm (void) printf(gettext("corrupted data")); 1479213197Smm break; 1480213197Smm } 1481254591Sgibbs } else if (children == 0 && !isspare && 1482254591Sgibbs VDEV_STAT_VALID(vs_physical_ashift, vsc) && 1483254591Sgibbs vs->vs_configured_ashift < vs->vs_physical_ashift) { 1484254591Sgibbs (void) printf( 1485254591Sgibbs gettext(" block size: %dB configured, %dB native"), 1486254591Sgibbs 1 << vs->vs_configured_ashift, 1 << vs->vs_physical_ashift); 1487213197Smm } 1488213197Smm 1489219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1490219089Spjd (uint64_t **)&ps, &c); 1491219089Spjd 1492219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1493219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1494219089Spjd (void) printf(gettext(" (%s)"), 1495219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1496219089Spjd "resilvering" : "repairing"); 1497219089Spjd } 1498219089Spjd 1499213197Smm (void) printf("\n"); 1500213197Smm 1501213197Smm for (c = 0; c < children; c++) { 1502219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1503213197Smm 1504219089Spjd /* Don't print logs or holes here */ 1505213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1506219089Spjd &islog); 1507219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1508219089Spjd &ishole); 1509219089Spjd if (islog || ishole) 1510213197Smm continue; 1511219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1512213197Smm print_status_config(zhp, vname, child[c], 1513213197Smm namewidth, depth + 2, isspare); 1514213197Smm free(vname); 1515213197Smm } 1516213197Smm} 1517213197Smm 1518213197Smm 1519213197Smm/* 1520168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1521168404Spjd * pool, printing out the name and status for each one. 1522168404Spjd */ 1523168404Spjdvoid 1524213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1525168404Spjd{ 1526168404Spjd nvlist_t **child; 1527168404Spjd uint_t c, children; 1528168404Spjd vdev_stat_t *vs; 1529168404Spjd char *type, *vname; 1530168404Spjd 1531168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1532219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1533219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1534168404Spjd return; 1535168404Spjd 1536219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1537168404Spjd (uint64_t **)&vs, &c) == 0); 1538168404Spjd 1539168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1540185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1541168404Spjd 1542168404Spjd if (vs->vs_aux != 0) { 1543185029Spjd (void) printf(" "); 1544168404Spjd 1545168404Spjd switch (vs->vs_aux) { 1546168404Spjd case VDEV_AUX_OPEN_FAILED: 1547168404Spjd (void) printf(gettext("cannot open")); 1548168404Spjd break; 1549168404Spjd 1550168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1551168404Spjd (void) printf(gettext("missing device")); 1552168404Spjd break; 1553168404Spjd 1554168404Spjd case VDEV_AUX_NO_REPLICAS: 1555168404Spjd (void) printf(gettext("insufficient replicas")); 1556168404Spjd break; 1557168404Spjd 1558168404Spjd case VDEV_AUX_VERSION_NEWER: 1559168404Spjd (void) printf(gettext("newer version")); 1560168404Spjd break; 1561168404Spjd 1562236884Smm case VDEV_AUX_UNSUP_FEAT: 1563236884Smm (void) printf(gettext("unsupported feature(s)")); 1564236884Smm break; 1565236884Smm 1566185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1567185029Spjd (void) printf(gettext("too many errors")); 1568185029Spjd break; 1569185029Spjd 1570168404Spjd default: 1571168404Spjd (void) printf(gettext("corrupted data")); 1572168404Spjd break; 1573168404Spjd } 1574168404Spjd } 1575168404Spjd (void) printf("\n"); 1576168404Spjd 1577168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1578168404Spjd &child, &children) != 0) 1579168404Spjd return; 1580168404Spjd 1581168404Spjd for (c = 0; c < children; c++) { 1582185029Spjd uint64_t is_log = B_FALSE; 1583185029Spjd 1584185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1585185029Spjd &is_log); 1586213197Smm if (is_log) 1587185029Spjd continue; 1588185029Spjd 1589219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1590213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1591168404Spjd free(vname); 1592168404Spjd } 1593168404Spjd 1594185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1595185029Spjd &child, &children) == 0) { 1596185029Spjd (void) printf(gettext("\tcache\n")); 1597185029Spjd for (c = 0; c < children; c++) { 1598219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1599185029Spjd (void) printf("\t %s\n", vname); 1600185029Spjd free(vname); 1601185029Spjd } 1602185029Spjd } 1603185029Spjd 1604168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1605185029Spjd &child, &children) == 0) { 1606185029Spjd (void) printf(gettext("\tspares\n")); 1607185029Spjd for (c = 0; c < children; c++) { 1608219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1609185029Spjd (void) printf("\t %s\n", vname); 1610185029Spjd free(vname); 1611185029Spjd } 1612168404Spjd } 1613168404Spjd} 1614168404Spjd 1615168404Spjd/* 1616213197Smm * Print log vdevs. 1617213197Smm * Logs are recorded as top level vdevs in the main pool child array 1618213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1619213197Smm * print_import_config() to print the top level logs then any log 1620213197Smm * children (eg mirrored slogs) are printed recursively - which 1621213197Smm * works because only the top level vdev is marked "is_log" 1622213197Smm */ 1623213197Smmstatic void 1624213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1625213197Smm{ 1626213197Smm uint_t c, children; 1627213197Smm nvlist_t **child; 1628213197Smm 1629213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1630213197Smm &children) != 0) 1631213197Smm return; 1632213197Smm 1633213197Smm (void) printf(gettext("\tlogs\n")); 1634213197Smm 1635213197Smm for (c = 0; c < children; c++) { 1636213197Smm uint64_t is_log = B_FALSE; 1637213197Smm char *name; 1638213197Smm 1639213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1640213197Smm &is_log); 1641213197Smm if (!is_log) 1642213197Smm continue; 1643219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1644213197Smm if (verbose) 1645213197Smm print_status_config(zhp, name, child[c], namewidth, 1646213197Smm 2, B_FALSE); 1647213197Smm else 1648213197Smm print_import_config(name, child[c], namewidth, 2); 1649213197Smm free(name); 1650213197Smm } 1651213197Smm} 1652219089Spjd 1653213197Smm/* 1654168404Spjd * Display the status for the given pool. 1655168404Spjd */ 1656168404Spjdstatic void 1657168404Spjdshow_import(nvlist_t *config) 1658168404Spjd{ 1659168404Spjd uint64_t pool_state; 1660168404Spjd vdev_stat_t *vs; 1661168404Spjd char *name; 1662168404Spjd uint64_t guid; 1663168404Spjd char *msgid; 1664168404Spjd nvlist_t *nvroot; 1665168404Spjd int reason; 1666168404Spjd const char *health; 1667168404Spjd uint_t vsc; 1668168404Spjd int namewidth; 1669228103Smm char *comment; 1670168404Spjd 1671168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1672168404Spjd &name) == 0); 1673168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1674168404Spjd &guid) == 0); 1675168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1676168404Spjd &pool_state) == 0); 1677168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1678168404Spjd &nvroot) == 0); 1679168404Spjd 1680219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1681168404Spjd (uint64_t **)&vs, &vsc) == 0); 1682185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1683168404Spjd 1684168404Spjd reason = zpool_import_status(config, &msgid); 1685168404Spjd 1686228103Smm (void) printf(gettext(" pool: %s\n"), name); 1687228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1688228103Smm (void) printf(gettext(" state: %s"), health); 1689168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1690168404Spjd (void) printf(gettext(" (DESTROYED)")); 1691168404Spjd (void) printf("\n"); 1692168404Spjd 1693168404Spjd switch (reason) { 1694168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1695168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1696168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1697228103Smm (void) printf(gettext(" status: One or more devices are " 1698228103Smm "missing from the system.\n")); 1699168404Spjd break; 1700168404Spjd 1701168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1702168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1703228103Smm (void) printf(gettext(" status: One or more devices contains " 1704168404Spjd "corrupted data.\n")); 1705168404Spjd break; 1706168404Spjd 1707168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1708228103Smm (void) printf( 1709228103Smm gettext(" status: The pool data is corrupted.\n")); 1710168404Spjd break; 1711168404Spjd 1712168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1713228103Smm (void) printf(gettext(" status: One or more devices " 1714168404Spjd "are offlined.\n")); 1715168404Spjd break; 1716168404Spjd 1717168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1718228103Smm (void) printf(gettext(" status: The pool metadata is " 1719168404Spjd "corrupted.\n")); 1720168404Spjd break; 1721168404Spjd 1722168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1723238926Smm (void) printf(gettext(" status: The pool is formatted using a " 1724238926Smm "legacy on-disk version.\n")); 1725168404Spjd break; 1726168404Spjd 1727168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1728228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1729168404Spjd "incompatible version.\n")); 1730168404Spjd break; 1731168404Spjd 1732238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 1733238926Smm (void) printf(gettext(" status: Some supported features are " 1734238926Smm "not enabled on the pool.\n")); 1735238926Smm break; 1736238926Smm 1737236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1738236884Smm (void) printf(gettext("status: The pool uses the following " 1739236884Smm "feature(s) not supported on this sytem:\n")); 1740236884Smm zpool_print_unsup_feat(config); 1741236884Smm break; 1742236884Smm 1743236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1744236884Smm (void) printf(gettext("status: The pool can only be accessed " 1745236884Smm "in read-only mode on this system. It\n\tcannot be " 1746236884Smm "accessed in read-write mode because it uses the " 1747236884Smm "following\n\tfeature(s) not supported on this system:\n")); 1748236884Smm zpool_print_unsup_feat(config); 1749236884Smm break; 1750236884Smm 1751168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1752228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1753168498Spjd "another system.\n")); 1754168498Spjd break; 1755185029Spjd 1756185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1757185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1758228103Smm (void) printf(gettext(" status: One or more devices are " 1759185029Spjd "faulted.\n")); 1760185029Spjd break; 1761185029Spjd 1762185029Spjd case ZPOOL_STATUS_BAD_LOG: 1763228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1764185029Spjd "read.\n")); 1765185029Spjd break; 1766185029Spjd 1767219089Spjd case ZPOOL_STATUS_RESILVERING: 1768228103Smm (void) printf(gettext(" status: One or more devices were being " 1769219089Spjd "resilvered.\n")); 1770219089Spjd break; 1771219089Spjd 1772259784Sdelphij case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 1773259784Sdelphij (void) printf(gettext("status: One or more devices were " 1774259784Sdelphij "configured to use a non-native block size.\n" 1775259784Sdelphij "\tExpect reduced performance.\n")); 1776259784Sdelphij break; 1777259784Sdelphij 1778168404Spjd default: 1779168404Spjd /* 1780168404Spjd * No other status can be seen when importing pools. 1781168404Spjd */ 1782168404Spjd assert(reason == ZPOOL_STATUS_OK); 1783168404Spjd } 1784168404Spjd 1785168404Spjd /* 1786168404Spjd * Print out an action according to the overall state of the pool. 1787168404Spjd */ 1788168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1789238926Smm if (reason == ZPOOL_STATUS_VERSION_OLDER || 1790238926Smm reason == ZPOOL_STATUS_FEAT_DISABLED) { 1791228103Smm (void) printf(gettext(" action: The pool can be " 1792168404Spjd "imported using its name or numeric identifier, " 1793168404Spjd "though\n\tsome features will not be available " 1794168404Spjd "without an explicit 'zpool upgrade'.\n")); 1795238926Smm } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 1796228103Smm (void) printf(gettext(" action: The pool can be " 1797168498Spjd "imported using its name or numeric " 1798168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1799238926Smm } else { 1800228103Smm (void) printf(gettext(" action: The pool can be " 1801168404Spjd "imported using its name or numeric " 1802168404Spjd "identifier.\n")); 1803238926Smm } 1804168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1805228103Smm (void) printf(gettext(" action: The pool can be imported " 1806168404Spjd "despite missing or damaged devices. The\n\tfault " 1807168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1808168404Spjd } else { 1809168404Spjd switch (reason) { 1810168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1811228103Smm (void) printf(gettext(" action: The pool cannot be " 1812168404Spjd "imported. Access the pool on a system running " 1813168404Spjd "newer\n\tsoftware, or recreate the pool from " 1814168404Spjd "backup.\n")); 1815168404Spjd break; 1816236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1817236884Smm (void) printf(gettext("action: The pool cannot be " 1818236884Smm "imported. Access the pool on a system that " 1819236884Smm "supports\n\tthe required feature(s), or recreate " 1820236884Smm "the pool from backup.\n")); 1821236884Smm break; 1822236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1823236884Smm (void) printf(gettext("action: The pool cannot be " 1824236884Smm "imported in read-write mode. Import the pool " 1825236884Smm "with\n" 1826236884Smm "\t\"-o readonly=on\", access the pool on a system " 1827236884Smm "that supports the\n\trequired feature(s), or " 1828236884Smm "recreate the pool from backup.\n")); 1829236884Smm break; 1830168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1831168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1832168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1833228103Smm (void) printf(gettext(" action: The pool cannot be " 1834168404Spjd "imported. Attach the missing\n\tdevices and try " 1835168404Spjd "again.\n")); 1836168404Spjd break; 1837168404Spjd default: 1838228103Smm (void) printf(gettext(" action: The pool cannot be " 1839168404Spjd "imported due to damaged devices or data.\n")); 1840168404Spjd } 1841168404Spjd } 1842168404Spjd 1843228103Smm /* Print the comment attached to the pool. */ 1844228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 1845228103Smm (void) printf(gettext("comment: %s\n"), comment); 1846228103Smm 1847168404Spjd /* 1848168404Spjd * If the state is "closed" or "can't open", and the aux state 1849168404Spjd * is "corrupt data": 1850168404Spjd */ 1851168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1852168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1853168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1854168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1855168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1856168404Spjd "but can be imported using the '-Df' flags.\n")); 1857168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1858168404Spjd (void) printf(gettext("\tThe pool may be active on " 1859185029Spjd "another system, but can be imported using\n\t" 1860168404Spjd "the '-f' flag.\n")); 1861168404Spjd } 1862168404Spjd 1863168404Spjd if (msgid != NULL) 1864236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1865168404Spjd msgid); 1866168404Spjd 1867228103Smm (void) printf(gettext(" config:\n\n")); 1868168404Spjd 1869168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1870168404Spjd if (namewidth < 10) 1871168404Spjd namewidth = 10; 1872168404Spjd 1873213197Smm print_import_config(name, nvroot, namewidth, 0); 1874213197Smm if (num_logs(nvroot) > 0) 1875213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1876185029Spjd 1877168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1878168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1879168404Spjd "be part of this pool, though their\n\texact " 1880168404Spjd "configuration cannot be determined.\n")); 1881168404Spjd } 1882168404Spjd} 1883168404Spjd 1884168404Spjd/* 1885168404Spjd * Perform the import for the given configuration. This passes the heavy 1886185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1887185029Spjd * within the pool. 1888168404Spjd */ 1889168404Spjdstatic int 1890168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1891219089Spjd nvlist_t *props, int flags) 1892168404Spjd{ 1893168404Spjd zpool_handle_t *zhp; 1894168404Spjd char *name; 1895168404Spjd uint64_t state; 1896168404Spjd uint64_t version; 1897168404Spjd 1898168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1899168404Spjd &name) == 0); 1900168404Spjd 1901168404Spjd verify(nvlist_lookup_uint64(config, 1902168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1903168404Spjd verify(nvlist_lookup_uint64(config, 1904168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1905236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 1906168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1907236884Smm "is formatted using an unsupported ZFS version\n"), name); 1908168404Spjd return (1); 1909219089Spjd } else if (state != POOL_STATE_EXPORTED && 1910219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 1911168498Spjd uint64_t hostid; 1912168498Spjd 1913168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1914168498Spjd &hostid) == 0) { 1915168498Spjd if ((unsigned long)hostid != gethostid()) { 1916168498Spjd char *hostname; 1917168498Spjd uint64_t timestamp; 1918168498Spjd time_t t; 1919168498Spjd 1920168498Spjd verify(nvlist_lookup_string(config, 1921168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1922168498Spjd verify(nvlist_lookup_uint64(config, 1923168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1924168498Spjd t = timestamp; 1925168498Spjd (void) fprintf(stderr, gettext("cannot import " 1926168498Spjd "'%s': pool may be in use from other " 1927168498Spjd "system, it was last accessed by %s " 1928168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1929168498Spjd (unsigned long)hostid, 1930168498Spjd asctime(localtime(&t))); 1931168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1932168498Spjd "import anyway\n")); 1933168498Spjd return (1); 1934168498Spjd } 1935168498Spjd } else { 1936168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1937168498Spjd "pool may be in use from other system\n"), name); 1938168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1939168498Spjd "anyway\n")); 1940168498Spjd return (1); 1941168498Spjd } 1942168404Spjd } 1943168404Spjd 1944219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1945168404Spjd return (1); 1946168404Spjd 1947168404Spjd if (newname != NULL) 1948168404Spjd name = (char *)newname; 1949168404Spjd 1950209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 1951209962Smm return (1); 1952168404Spjd 1953209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1954219089Spjd !(flags & ZFS_IMPORT_ONLY) && 1955209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1956168404Spjd zpool_close(zhp); 1957168404Spjd return (1); 1958168404Spjd } 1959168404Spjd 1960168404Spjd zpool_close(zhp); 1961219089Spjd return (0); 1962168404Spjd} 1963168404Spjd 1964168404Spjd/* 1965168404Spjd * zpool import [-d dir] [-D] 1966185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1967185029Spjd * [-d dir | -c cachefile] [-f] -a 1968185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1969333196Savg * [-d dir | -c cachefile] [-f] [-n] [-F] [-t] 1970333196Savg * <pool | id> [newpool] 1971168404Spjd * 1972185029Spjd * -c Read pool information from a cachefile instead of searching 1973185029Spjd * devices. 1974185029Spjd * 1975168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1976168404Spjd * one directory can be specified using multiple '-d' options. 1977168404Spjd * 1978168404Spjd * -D Scan for previously destroyed pools or import all or only 1979168404Spjd * specified destroyed pools. 1980168404Spjd * 1981168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1982168404Spjd * the given root. The pool will remain exported when the machine 1983168404Spjd * is rebooted. 1984168404Spjd * 1985219089Spjd * -V Import even in the presence of faulted vdevs. This is an 1986185029Spjd * intentionally undocumented option for testing purposes, and 1987185029Spjd * treats the pool configuration as complete, leaving any bad 1988209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 1989209962Smm * import. 1990185029Spjd * 1991219089Spjd * -f Force import, even if it appears that the pool is active. 1992219089Spjd * 1993219089Spjd * -F Attempt rewind if necessary. 1994219089Spjd * 1995219089Spjd * -n See if rewind would work, but don't actually rewind. 1996219089Spjd * 1997219089Spjd * -N Import the pool but don't mount datasets. 1998219089Spjd * 1999333196Savg * -t Use newpool as a temporary pool name instead of renaming 2000333196Savg * the pool. 2001333196Savg * 2002219089Spjd * -T Specify a starting txg to use for import. This option is 2003219089Spjd * intentionally undocumented option for testing purposes. 2004219089Spjd * 2005168404Spjd * -a Import all pools found. 2006168404Spjd * 2007185029Spjd * -o Set property=value and/or temporary mount options (without '='). 2008185029Spjd * 2009168404Spjd * The import command scans for pools to import, and import pools based on pool 2010168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 2011168404Spjd */ 2012168404Spjdint 2013168404Spjdzpool_do_import(int argc, char **argv) 2014168404Spjd{ 2015168404Spjd char **searchdirs = NULL; 2016168404Spjd int nsearch = 0; 2017168404Spjd int c; 2018219089Spjd int err = 0; 2019185029Spjd nvlist_t *pools = NULL; 2020168404Spjd boolean_t do_all = B_FALSE; 2021168404Spjd boolean_t do_destroyed = B_FALSE; 2022168404Spjd char *mntopts = NULL; 2023168404Spjd nvpair_t *elem; 2024168404Spjd nvlist_t *config; 2025185029Spjd uint64_t searchguid = 0; 2026185029Spjd char *searchname = NULL; 2027185029Spjd char *propval; 2028168404Spjd nvlist_t *found_config; 2029219089Spjd nvlist_t *policy = NULL; 2030185029Spjd nvlist_t *props = NULL; 2031168404Spjd boolean_t first; 2032219089Spjd int flags = ZFS_IMPORT_NORMAL; 2033219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 2034219089Spjd boolean_t dryrun = B_FALSE; 2035219089Spjd boolean_t do_rewind = B_FALSE; 2036219089Spjd boolean_t xtreme_rewind = B_FALSE; 2037219089Spjd uint64_t pool_state, txg = -1ULL; 2038185029Spjd char *cachefile = NULL; 2039219089Spjd importargs_t idata = { 0 }; 2040219089Spjd char *endptr; 2041168404Spjd 2042168404Spjd /* check options */ 2043333196Savg while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:R:tT:VX")) != -1) { 2044168404Spjd switch (c) { 2045168404Spjd case 'a': 2046168404Spjd do_all = B_TRUE; 2047168404Spjd break; 2048185029Spjd case 'c': 2049185029Spjd cachefile = optarg; 2050185029Spjd break; 2051168404Spjd case 'd': 2052168404Spjd if (searchdirs == NULL) { 2053168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2054168404Spjd } else { 2055168404Spjd char **tmp = safe_malloc((nsearch + 1) * 2056168404Spjd sizeof (char *)); 2057168404Spjd bcopy(searchdirs, tmp, nsearch * 2058168404Spjd sizeof (char *)); 2059168404Spjd free(searchdirs); 2060168404Spjd searchdirs = tmp; 2061168404Spjd } 2062168404Spjd searchdirs[nsearch++] = optarg; 2063168404Spjd break; 2064168404Spjd case 'D': 2065168404Spjd do_destroyed = B_TRUE; 2066168404Spjd break; 2067168404Spjd case 'f': 2068219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 2069168404Spjd break; 2070185029Spjd case 'F': 2071219089Spjd do_rewind = B_TRUE; 2072185029Spjd break; 2073219089Spjd case 'm': 2074219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 2075219089Spjd break; 2076219089Spjd case 'n': 2077219089Spjd dryrun = B_TRUE; 2078219089Spjd break; 2079219089Spjd case 'N': 2080219089Spjd flags |= ZFS_IMPORT_ONLY; 2081219089Spjd break; 2082168404Spjd case 'o': 2083185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 2084185029Spjd *propval = '\0'; 2085185029Spjd propval++; 2086185029Spjd if (add_prop_list(optarg, propval, 2087185029Spjd &props, B_TRUE)) 2088185029Spjd goto error; 2089185029Spjd } else { 2090185029Spjd mntopts = optarg; 2091185029Spjd } 2092168404Spjd break; 2093168404Spjd case 'R': 2094185029Spjd if (add_prop_list(zpool_prop_to_name( 2095185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 2096185029Spjd goto error; 2097333196Savg if (add_prop_list_default(zpool_prop_to_name( 2098185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2099185029Spjd goto error; 2100168404Spjd break; 2101333196Savg case 't': 2102333196Savg flags |= ZFS_IMPORT_TEMP_NAME; 2103333196Savg if (add_prop_list_default(zpool_prop_to_name( 2104333196Savg ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2105333196Savg goto error; 2106333196Savg break; 2107219089Spjd case 'T': 2108219089Spjd errno = 0; 2109269219Sdelphij txg = strtoull(optarg, &endptr, 0); 2110219089Spjd if (errno != 0 || *endptr != '\0') { 2111219089Spjd (void) fprintf(stderr, 2112219089Spjd gettext("invalid txg value\n")); 2113219089Spjd usage(B_FALSE); 2114219089Spjd } 2115219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 2116219089Spjd break; 2117219089Spjd case 'V': 2118219089Spjd flags |= ZFS_IMPORT_VERBATIM; 2119219089Spjd break; 2120219089Spjd case 'X': 2121219089Spjd xtreme_rewind = B_TRUE; 2122219089Spjd break; 2123168404Spjd case ':': 2124168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2125168404Spjd "'%c' option\n"), optopt); 2126168404Spjd usage(B_FALSE); 2127168404Spjd break; 2128168404Spjd case '?': 2129168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2130168404Spjd optopt); 2131168404Spjd usage(B_FALSE); 2132168404Spjd } 2133168404Spjd } 2134168404Spjd 2135168404Spjd argc -= optind; 2136168404Spjd argv += optind; 2137168404Spjd 2138185029Spjd if (cachefile && nsearch != 0) { 2139185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 2140185029Spjd usage(B_FALSE); 2141185029Spjd } 2142185029Spjd 2143219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 2144219089Spjd (void) fprintf(stderr, 2145219089Spjd gettext("-n or -X only meaningful with -F\n")); 2146219089Spjd usage(B_FALSE); 2147219089Spjd } 2148219089Spjd if (dryrun) 2149219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 2150219089Spjd else if (do_rewind) 2151219089Spjd rewind_policy = ZPOOL_DO_REWIND; 2152219089Spjd if (xtreme_rewind) 2153219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 2154219089Spjd 2155219089Spjd /* In the future, we can capture further policy and include it here */ 2156219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2157219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 2158219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 2159219089Spjd goto error; 2160219089Spjd 2161168404Spjd if (searchdirs == NULL) { 2162168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2163235478Savg searchdirs[0] = "/dev"; 2164168404Spjd nsearch = 1; 2165168404Spjd } 2166168404Spjd 2167168404Spjd /* check argument count */ 2168168404Spjd if (do_all) { 2169168404Spjd if (argc != 0) { 2170168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2171168404Spjd usage(B_FALSE); 2172168404Spjd } 2173168404Spjd } else { 2174168404Spjd if (argc > 2) { 2175168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2176168404Spjd usage(B_FALSE); 2177168404Spjd } 2178168404Spjd 2179168404Spjd /* 2180168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 2181168404Spjd * here because otherwise any attempt to discover pools will 2182168404Spjd * silently fail. 2183168404Spjd */ 2184168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2185168404Spjd (void) fprintf(stderr, gettext("cannot " 2186168404Spjd "discover pools: permission denied\n")); 2187168404Spjd free(searchdirs); 2188219089Spjd nvlist_free(policy); 2189168404Spjd return (1); 2190168404Spjd } 2191168404Spjd } 2192168404Spjd 2193168404Spjd /* 2194168404Spjd * Depending on the arguments given, we do one of the following: 2195168404Spjd * 2196168404Spjd * <none> Iterate through all pools and display information about 2197168404Spjd * each one. 2198168404Spjd * 2199168404Spjd * -a Iterate through all pools and try to import each one. 2200168404Spjd * 2201168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 2202168404Spjd * name and import that one. 2203168404Spjd * 2204168404Spjd * -D Above options applies only to destroyed pools. 2205168404Spjd */ 2206168404Spjd if (argc != 0) { 2207168404Spjd char *endptr; 2208168404Spjd 2209168404Spjd errno = 0; 2210168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 2211254758Sdelphij if (errno != 0 || *endptr != '\0') { 2212168404Spjd searchname = argv[0]; 2213254758Sdelphij searchguid = 0; 2214254758Sdelphij } 2215168404Spjd found_config = NULL; 2216168404Spjd 2217185029Spjd /* 2218219089Spjd * User specified a name or guid. Ensure it's unique. 2219185029Spjd */ 2220219089Spjd idata.unique = B_TRUE; 2221185029Spjd } 2222185029Spjd 2223219089Spjd 2224219089Spjd idata.path = searchdirs; 2225219089Spjd idata.paths = nsearch; 2226219089Spjd idata.poolname = searchname; 2227219089Spjd idata.guid = searchguid; 2228219089Spjd idata.cachefile = cachefile; 2229219089Spjd 2230219089Spjd pools = zpool_search_import(g_zfs, &idata); 2231219089Spjd 2232219089Spjd if (pools != NULL && idata.exists && 2233219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2234219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2235219089Spjd "a pool with that name already exists\n"), 2236219089Spjd argv[0]); 2237333196Savg (void) fprintf(stderr, gettext("use the form 'zpool import " 2238333196Savg "[-t] <pool | id> <newpool>' to give it a new temporary " 2239333196Savg "or permanent name\n")); 2240219089Spjd err = 1; 2241219089Spjd } else if (pools == NULL && idata.exists) { 2242219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2243219089Spjd "a pool with that name is already created/imported,\n"), 2244219089Spjd argv[0]); 2245219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2246219089Spjd "with that name were found\n")); 2247219089Spjd err = 1; 2248219089Spjd } else if (pools == NULL) { 2249185029Spjd if (argc != 0) { 2250185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2251185029Spjd "no such pool available\n"), argv[0]); 2252185029Spjd } 2253219089Spjd err = 1; 2254219089Spjd } 2255219089Spjd 2256219089Spjd if (err == 1) { 2257185029Spjd free(searchdirs); 2258219089Spjd nvlist_free(policy); 2259185029Spjd return (1); 2260185029Spjd } 2261185029Spjd 2262185029Spjd /* 2263185029Spjd * At this point we have a list of import candidate configs. Even if 2264185029Spjd * we were searching by pool name or guid, we still need to 2265185029Spjd * post-process the list to deal with pool state and possible 2266185029Spjd * duplicate names. 2267185029Spjd */ 2268168404Spjd err = 0; 2269168404Spjd elem = NULL; 2270168404Spjd first = B_TRUE; 2271168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2272168404Spjd 2273168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2274168404Spjd 2275168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2276168404Spjd &pool_state) == 0); 2277168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2278168404Spjd continue; 2279168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2280168404Spjd continue; 2281168404Spjd 2282219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2283219089Spjd policy) == 0); 2284219089Spjd 2285168404Spjd if (argc == 0) { 2286168404Spjd if (first) 2287168404Spjd first = B_FALSE; 2288168404Spjd else if (!do_all) 2289168404Spjd (void) printf("\n"); 2290168404Spjd 2291219089Spjd if (do_all) { 2292168404Spjd err |= do_import(config, NULL, mntopts, 2293219089Spjd props, flags); 2294219089Spjd } else { 2295168404Spjd show_import(config); 2296219089Spjd } 2297168404Spjd } else if (searchname != NULL) { 2298168404Spjd char *name; 2299168404Spjd 2300168404Spjd /* 2301168404Spjd * We are searching for a pool based on name. 2302168404Spjd */ 2303168404Spjd verify(nvlist_lookup_string(config, 2304168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2305168404Spjd 2306168404Spjd if (strcmp(name, searchname) == 0) { 2307168404Spjd if (found_config != NULL) { 2308168404Spjd (void) fprintf(stderr, gettext( 2309168404Spjd "cannot import '%s': more than " 2310168404Spjd "one matching pool\n"), searchname); 2311168404Spjd (void) fprintf(stderr, gettext( 2312168404Spjd "import by numeric ID instead\n")); 2313168404Spjd err = B_TRUE; 2314168404Spjd } 2315168404Spjd found_config = config; 2316168404Spjd } 2317168404Spjd } else { 2318168404Spjd uint64_t guid; 2319168404Spjd 2320168404Spjd /* 2321168404Spjd * Search for a pool by guid. 2322168404Spjd */ 2323168404Spjd verify(nvlist_lookup_uint64(config, 2324168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2325168404Spjd 2326168404Spjd if (guid == searchguid) 2327168404Spjd found_config = config; 2328168404Spjd } 2329168404Spjd } 2330168404Spjd 2331168404Spjd /* 2332168404Spjd * If we were searching for a specific pool, verify that we found a 2333168404Spjd * pool, and then do the import. 2334168404Spjd */ 2335168404Spjd if (argc != 0 && err == 0) { 2336168404Spjd if (found_config == NULL) { 2337168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2338168404Spjd "no such pool available\n"), argv[0]); 2339168404Spjd err = B_TRUE; 2340168404Spjd } else { 2341168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2342219089Spjd argv[1], mntopts, props, flags); 2343168404Spjd } 2344168404Spjd } 2345168404Spjd 2346168404Spjd /* 2347168404Spjd * If we were just looking for pools, report an error if none were 2348168404Spjd * found. 2349168404Spjd */ 2350168404Spjd if (argc == 0 && first) 2351168404Spjd (void) fprintf(stderr, 2352168404Spjd gettext("no pools available to import\n")); 2353168404Spjd 2354185029Spjderror: 2355185029Spjd nvlist_free(props); 2356168404Spjd nvlist_free(pools); 2357219089Spjd nvlist_free(policy); 2358168404Spjd free(searchdirs); 2359168404Spjd 2360168404Spjd return (err ? 1 : 0); 2361168404Spjd} 2362168404Spjd 2363168404Spjdtypedef struct iostat_cbdata { 2364236155Smm boolean_t cb_verbose; 2365236155Smm int cb_namewidth; 2366236155Smm int cb_iteration; 2367168404Spjd zpool_list_t *cb_list; 2368168404Spjd} iostat_cbdata_t; 2369168404Spjd 2370168404Spjdstatic void 2371168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2372168404Spjd{ 2373168404Spjd int i = 0; 2374168404Spjd 2375168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2376168404Spjd (void) printf("-"); 2377168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2378168404Spjd} 2379168404Spjd 2380168404Spjdstatic void 2381168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2382168404Spjd{ 2383168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2384168404Spjd cb->cb_namewidth, ""); 2385219089Spjd (void) printf("%-*s alloc free read write read write\n", 2386168404Spjd cb->cb_namewidth, "pool"); 2387168404Spjd print_iostat_separator(cb); 2388168404Spjd} 2389168404Spjd 2390168404Spjd/* 2391168404Spjd * Display a single statistic. 2392168404Spjd */ 2393185029Spjdstatic void 2394168404Spjdprint_one_stat(uint64_t value) 2395168404Spjd{ 2396168404Spjd char buf[64]; 2397168404Spjd 2398168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2399168404Spjd (void) printf(" %5s", buf); 2400168404Spjd} 2401168404Spjd 2402168404Spjd/* 2403168404Spjd * Print out all the statistics for the given vdev. This can either be the 2404168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2405168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2406168404Spjd */ 2407168404Spjdvoid 2408168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2409168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2410168404Spjd{ 2411168404Spjd nvlist_t **oldchild, **newchild; 2412168404Spjd uint_t c, children; 2413168404Spjd vdev_stat_t *oldvs, *newvs; 2414168404Spjd vdev_stat_t zerovs = { 0 }; 2415168404Spjd uint64_t tdelta; 2416168404Spjd double scale; 2417168404Spjd char *vname; 2418168404Spjd 2419168404Spjd if (oldnv != NULL) { 2420219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2421219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2422168404Spjd } else { 2423168404Spjd oldvs = &zerovs; 2424168404Spjd } 2425168404Spjd 2426219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2427168404Spjd (uint64_t **)&newvs, &c) == 0); 2428168404Spjd 2429168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2430168404Spjd (void) printf("%*s%s", depth, "", name); 2431168404Spjd else 2432168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2433168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2434168404Spjd 2435168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2436168404Spjd 2437168404Spjd if (tdelta == 0) 2438168404Spjd scale = 1.0; 2439168404Spjd else 2440168404Spjd scale = (double)NANOSEC / tdelta; 2441168404Spjd 2442168404Spjd /* only toplevel vdevs have capacity stats */ 2443168404Spjd if (newvs->vs_space == 0) { 2444168404Spjd (void) printf(" - -"); 2445168404Spjd } else { 2446168404Spjd print_one_stat(newvs->vs_alloc); 2447168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2448168404Spjd } 2449168404Spjd 2450168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2451168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2452168404Spjd 2453168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2454168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2455168404Spjd 2456168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2457168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2458168404Spjd 2459168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2460168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2461168404Spjd 2462168404Spjd (void) printf("\n"); 2463168404Spjd 2464168404Spjd if (!cb->cb_verbose) 2465168404Spjd return; 2466168404Spjd 2467168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2468168404Spjd &newchild, &children) != 0) 2469168404Spjd return; 2470168404Spjd 2471168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2472168404Spjd &oldchild, &c) != 0) 2473168404Spjd return; 2474168404Spjd 2475168404Spjd for (c = 0; c < children; c++) { 2476227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2477219089Spjd 2478227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2479227497Smm &ishole); 2480227497Smm 2481227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2482227497Smm &islog); 2483227497Smm 2484227497Smm if (ishole || islog) 2485219089Spjd continue; 2486219089Spjd 2487219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2488168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2489168404Spjd newchild[c], cb, depth + 2); 2490168404Spjd free(vname); 2491168404Spjd } 2492185029Spjd 2493185029Spjd /* 2494227497Smm * Log device section 2495227497Smm */ 2496227497Smm 2497227497Smm if (num_logs(newnv) > 0) { 2498227497Smm (void) printf("%-*s - - - - - " 2499227497Smm "-\n", cb->cb_namewidth, "logs"); 2500227497Smm 2501227497Smm for (c = 0; c < children; c++) { 2502227497Smm uint64_t islog = B_FALSE; 2503227497Smm (void) nvlist_lookup_uint64(newchild[c], 2504227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2505227497Smm 2506227497Smm if (islog) { 2507227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2508227497Smm B_FALSE); 2509227497Smm print_vdev_stats(zhp, vname, oldnv ? 2510227497Smm oldchild[c] : NULL, newchild[c], 2511227497Smm cb, depth + 2); 2512227497Smm free(vname); 2513227497Smm } 2514227497Smm } 2515227497Smm 2516227497Smm } 2517227497Smm 2518227497Smm /* 2519185029Spjd * Include level 2 ARC devices in iostat output 2520185029Spjd */ 2521185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2522185029Spjd &newchild, &children) != 0) 2523185029Spjd return; 2524185029Spjd 2525185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2526185029Spjd &oldchild, &c) != 0) 2527185029Spjd return; 2528185029Spjd 2529185029Spjd if (children > 0) { 2530185029Spjd (void) printf("%-*s - - - - - " 2531185029Spjd "-\n", cb->cb_namewidth, "cache"); 2532185029Spjd for (c = 0; c < children; c++) { 2533219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2534219089Spjd B_FALSE); 2535185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2536185029Spjd newchild[c], cb, depth + 2); 2537185029Spjd free(vname); 2538185029Spjd } 2539185029Spjd } 2540168404Spjd} 2541168404Spjd 2542168404Spjdstatic int 2543168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2544168404Spjd{ 2545168404Spjd iostat_cbdata_t *cb = data; 2546168404Spjd boolean_t missing; 2547168404Spjd 2548168404Spjd /* 2549168404Spjd * If the pool has disappeared, remove it from the list and continue. 2550168404Spjd */ 2551168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2552168404Spjd return (-1); 2553168404Spjd 2554168404Spjd if (missing) 2555168404Spjd pool_list_remove(cb->cb_list, zhp); 2556168404Spjd 2557168404Spjd return (0); 2558168404Spjd} 2559168404Spjd 2560168404Spjd/* 2561168404Spjd * Callback to print out the iostats for the given pool. 2562168404Spjd */ 2563168404Spjdint 2564168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2565168404Spjd{ 2566168404Spjd iostat_cbdata_t *cb = data; 2567168404Spjd nvlist_t *oldconfig, *newconfig; 2568168404Spjd nvlist_t *oldnvroot, *newnvroot; 2569168404Spjd 2570168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2571168404Spjd 2572168404Spjd if (cb->cb_iteration == 1) 2573168404Spjd oldconfig = NULL; 2574168404Spjd 2575168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2576168404Spjd &newnvroot) == 0); 2577168404Spjd 2578168404Spjd if (oldconfig == NULL) 2579168404Spjd oldnvroot = NULL; 2580168404Spjd else 2581168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2582168404Spjd &oldnvroot) == 0); 2583168404Spjd 2584168404Spjd /* 2585168404Spjd * Print out the statistics for the pool. 2586168404Spjd */ 2587168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2588168404Spjd 2589168404Spjd if (cb->cb_verbose) 2590168404Spjd print_iostat_separator(cb); 2591168404Spjd 2592168404Spjd return (0); 2593168404Spjd} 2594168404Spjd 2595168404Spjdint 2596168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2597168404Spjd{ 2598168404Spjd iostat_cbdata_t *cb = data; 2599168404Spjd nvlist_t *config, *nvroot; 2600168404Spjd 2601168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2602168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2603168404Spjd &nvroot) == 0); 2604168404Spjd if (!cb->cb_verbose) 2605168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2606168404Spjd else 2607236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2608236145Smm cb->cb_namewidth); 2609168404Spjd } 2610168404Spjd 2611168404Spjd /* 2612168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2613168404Spjd * maximum we can have and still fit in 80 columns. 2614168404Spjd */ 2615168404Spjd if (cb->cb_namewidth < 10) 2616168404Spjd cb->cb_namewidth = 10; 2617168404Spjd if (cb->cb_namewidth > 38) 2618168404Spjd cb->cb_namewidth = 38; 2619168404Spjd 2620168404Spjd return (0); 2621168404Spjd} 2622168404Spjd 2623168404Spjd/* 2624219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2625168404Spjd */ 2626219089Spjdstatic void 2627219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2628219089Spjd unsigned long *cnt) 2629168404Spjd{ 2630168404Spjd unsigned long interval = 0, count = 0; 2631219089Spjd int argc = *argcp, errno; 2632168404Spjd 2633168404Spjd /* 2634168404Spjd * Determine if the last argument is an integer or a pool name 2635168404Spjd */ 2636168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2637168404Spjd char *end; 2638168404Spjd 2639168404Spjd errno = 0; 2640168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2641168404Spjd 2642168404Spjd if (*end == '\0' && errno == 0) { 2643168404Spjd if (interval == 0) { 2644168404Spjd (void) fprintf(stderr, gettext("interval " 2645168404Spjd "cannot be zero\n")); 2646168404Spjd usage(B_FALSE); 2647168404Spjd } 2648168404Spjd /* 2649168404Spjd * Ignore the last parameter 2650168404Spjd */ 2651168404Spjd argc--; 2652168404Spjd } else { 2653168404Spjd /* 2654168404Spjd * If this is not a valid number, just plow on. The 2655168404Spjd * user will get a more informative error message later 2656168404Spjd * on. 2657168404Spjd */ 2658168404Spjd interval = 0; 2659168404Spjd } 2660168404Spjd } 2661168404Spjd 2662168404Spjd /* 2663168404Spjd * If the last argument is also an integer, then we have both a count 2664219089Spjd * and an interval. 2665168404Spjd */ 2666168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2667168404Spjd char *end; 2668168404Spjd 2669168404Spjd errno = 0; 2670168404Spjd count = interval; 2671168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2672168404Spjd 2673168404Spjd if (*end == '\0' && errno == 0) { 2674168404Spjd if (interval == 0) { 2675168404Spjd (void) fprintf(stderr, gettext("interval " 2676168404Spjd "cannot be zero\n")); 2677168404Spjd usage(B_FALSE); 2678168404Spjd } 2679168404Spjd 2680168404Spjd /* 2681168404Spjd * Ignore the last parameter 2682168404Spjd */ 2683168404Spjd argc--; 2684168404Spjd } else { 2685168404Spjd interval = 0; 2686168404Spjd } 2687168404Spjd } 2688168404Spjd 2689219089Spjd *iv = interval; 2690219089Spjd *cnt = count; 2691219089Spjd *argcp = argc; 2692219089Spjd} 2693219089Spjd 2694219089Spjdstatic void 2695219089Spjdget_timestamp_arg(char c) 2696219089Spjd{ 2697219089Spjd if (c == 'u') 2698219089Spjd timestamp_fmt = UDATE; 2699219089Spjd else if (c == 'd') 2700219089Spjd timestamp_fmt = DDATE; 2701219089Spjd else 2702219089Spjd usage(B_FALSE); 2703219089Spjd} 2704219089Spjd 2705219089Spjd/* 2706219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2707219089Spjd * 2708219089Spjd * -v Display statistics for individual vdevs 2709219089Spjd * -T Display a timestamp in date(1) or Unix format 2710219089Spjd * 2711219089Spjd * This command can be tricky because we want to be able to deal with pool 2712219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2713219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2714219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2715219089Spjd * changes are all handled within libzfs. 2716219089Spjd */ 2717219089Spjdint 2718219089Spjdzpool_do_iostat(int argc, char **argv) 2719219089Spjd{ 2720219089Spjd int c; 2721219089Spjd int ret; 2722219089Spjd int npools; 2723219089Spjd unsigned long interval = 0, count = 0; 2724219089Spjd zpool_list_t *list; 2725219089Spjd boolean_t verbose = B_FALSE; 2726219089Spjd iostat_cbdata_t cb; 2727219089Spjd 2728219089Spjd /* check options */ 2729219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2730219089Spjd switch (c) { 2731219089Spjd case 'T': 2732219089Spjd get_timestamp_arg(*optarg); 2733219089Spjd break; 2734219089Spjd case 'v': 2735219089Spjd verbose = B_TRUE; 2736219089Spjd break; 2737219089Spjd case '?': 2738219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2739219089Spjd optopt); 2740219089Spjd usage(B_FALSE); 2741219089Spjd } 2742219089Spjd } 2743219089Spjd 2744219089Spjd argc -= optind; 2745219089Spjd argv += optind; 2746219089Spjd 2747219089Spjd get_interval_count(&argc, argv, &interval, &count); 2748219089Spjd 2749168404Spjd /* 2750168404Spjd * Construct the list of all interesting pools. 2751168404Spjd */ 2752168404Spjd ret = 0; 2753168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2754168404Spjd return (1); 2755168404Spjd 2756168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2757168404Spjd pool_list_free(list); 2758168404Spjd return (1); 2759168404Spjd } 2760168404Spjd 2761168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2762168404Spjd pool_list_free(list); 2763168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2764168404Spjd return (1); 2765168404Spjd } 2766168404Spjd 2767168404Spjd /* 2768168404Spjd * Enter the main iostat loop. 2769168404Spjd */ 2770168404Spjd cb.cb_list = list; 2771168404Spjd cb.cb_verbose = verbose; 2772168404Spjd cb.cb_iteration = 0; 2773168404Spjd cb.cb_namewidth = 0; 2774168404Spjd 2775168404Spjd for (;;) { 2776168404Spjd pool_list_update(list); 2777168404Spjd 2778168404Spjd if ((npools = pool_list_count(list)) == 0) 2779168404Spjd break; 2780168404Spjd 2781168404Spjd /* 2782168404Spjd * Refresh all statistics. This is done as an explicit step 2783168404Spjd * before calculating the maximum name width, so that any 2784168404Spjd * configuration changes are properly accounted for. 2785168404Spjd */ 2786168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2787168404Spjd 2788168404Spjd /* 2789168404Spjd * Iterate over all pools to determine the maximum width 2790168404Spjd * for the pool / device name column across all pools. 2791168404Spjd */ 2792168404Spjd cb.cb_namewidth = 0; 2793168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2794168404Spjd 2795219089Spjd if (timestamp_fmt != NODATE) 2796219089Spjd print_timestamp(timestamp_fmt); 2797219089Spjd 2798168404Spjd /* 2799168404Spjd * If it's the first time, or verbose mode, print the header. 2800168404Spjd */ 2801168404Spjd if (++cb.cb_iteration == 1 || verbose) 2802168404Spjd print_iostat_header(&cb); 2803168404Spjd 2804168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2805168404Spjd 2806168404Spjd /* 2807168404Spjd * If there's more than one pool, and we're not in verbose mode 2808168404Spjd * (which prints a separator for us), then print a separator. 2809168404Spjd */ 2810168404Spjd if (npools > 1 && !verbose) 2811168404Spjd print_iostat_separator(&cb); 2812168404Spjd 2813168404Spjd if (verbose) 2814168404Spjd (void) printf("\n"); 2815168404Spjd 2816168404Spjd /* 2817168404Spjd * Flush the output so that redirection to a file isn't buffered 2818168404Spjd * indefinitely. 2819168404Spjd */ 2820168404Spjd (void) fflush(stdout); 2821168404Spjd 2822168404Spjd if (interval == 0) 2823168404Spjd break; 2824168404Spjd 2825168404Spjd if (count != 0 && --count == 0) 2826168404Spjd break; 2827168404Spjd 2828168404Spjd (void) sleep(interval); 2829168404Spjd } 2830168404Spjd 2831168404Spjd pool_list_free(list); 2832168404Spjd 2833168404Spjd return (ret); 2834168404Spjd} 2835168404Spjd 2836168404Spjdtypedef struct list_cbdata { 2837236155Smm boolean_t cb_verbose; 2838236155Smm int cb_namewidth; 2839168404Spjd boolean_t cb_scripted; 2840185029Spjd zprop_list_t *cb_proplist; 2841264335Sdelphij boolean_t cb_literal; 2842168404Spjd} list_cbdata_t; 2843168404Spjd 2844168404Spjd/* 2845168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2846168404Spjd */ 2847185029Spjdstatic void 2848236155Smmprint_header(list_cbdata_t *cb) 2849168404Spjd{ 2850236155Smm zprop_list_t *pl = cb->cb_proplist; 2851236884Smm char headerbuf[ZPOOL_MAXPROPLEN]; 2852185029Spjd const char *header; 2853185029Spjd boolean_t first = B_TRUE; 2854185029Spjd boolean_t right_justify; 2855236155Smm size_t width = 0; 2856168404Spjd 2857185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2858236155Smm width = pl->pl_width; 2859236155Smm if (first && cb->cb_verbose) { 2860236155Smm /* 2861236155Smm * Reset the width to accommodate the verbose listing 2862236155Smm * of devices. 2863236155Smm */ 2864236155Smm width = cb->cb_namewidth; 2865236155Smm } 2866236155Smm 2867185029Spjd if (!first) 2868168404Spjd (void) printf(" "); 2869168404Spjd else 2870185029Spjd first = B_FALSE; 2871168404Spjd 2872236884Smm right_justify = B_FALSE; 2873236884Smm if (pl->pl_prop != ZPROP_INVAL) { 2874236884Smm header = zpool_prop_column_name(pl->pl_prop); 2875236884Smm right_justify = zpool_prop_align_right(pl->pl_prop); 2876236884Smm } else { 2877236884Smm int i; 2878185029Spjd 2879236884Smm for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2880236884Smm headerbuf[i] = toupper(pl->pl_user_prop[i]); 2881236884Smm headerbuf[i] = '\0'; 2882236884Smm header = headerbuf; 2883236884Smm } 2884236884Smm 2885185029Spjd if (pl->pl_next == NULL && !right_justify) 2886185029Spjd (void) printf("%s", header); 2887185029Spjd else if (right_justify) 2888236155Smm (void) printf("%*s", width, header); 2889185029Spjd else 2890236155Smm (void) printf("%-*s", width, header); 2891236155Smm 2892168404Spjd } 2893168404Spjd 2894168404Spjd (void) printf("\n"); 2895168404Spjd} 2896168404Spjd 2897185029Spjd/* 2898185029Spjd * Given a pool and a list of properties, print out all the properties according 2899185029Spjd * to the described layout. 2900185029Spjd */ 2901185029Spjdstatic void 2902236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 2903168404Spjd{ 2904236155Smm zprop_list_t *pl = cb->cb_proplist; 2905185029Spjd boolean_t first = B_TRUE; 2906185029Spjd char property[ZPOOL_MAXPROPLEN]; 2907185029Spjd char *propstr; 2908185029Spjd boolean_t right_justify; 2909236155Smm size_t width; 2910168404Spjd 2911185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2912236155Smm 2913236155Smm width = pl->pl_width; 2914236155Smm if (first && cb->cb_verbose) { 2915236155Smm /* 2916236155Smm * Reset the width to accommodate the verbose listing 2917236155Smm * of devices. 2918236155Smm */ 2919236155Smm width = cb->cb_namewidth; 2920236155Smm } 2921236155Smm 2922185029Spjd if (!first) { 2923236155Smm if (cb->cb_scripted) 2924168404Spjd (void) printf("\t"); 2925168404Spjd else 2926168404Spjd (void) printf(" "); 2927185029Spjd } else { 2928185029Spjd first = B_FALSE; 2929168404Spjd } 2930168404Spjd 2931185029Spjd right_justify = B_FALSE; 2932185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2933273058Sdelphij if (zpool_get_prop(zhp, pl->pl_prop, property, 2934264335Sdelphij sizeof (property), NULL, cb->cb_literal) != 0) 2935185029Spjd propstr = "-"; 2936168404Spjd else 2937185029Spjd propstr = property; 2938168404Spjd 2939185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2940236884Smm } else if ((zpool_prop_feature(pl->pl_user_prop) || 2941236884Smm zpool_prop_unsupported(pl->pl_user_prop)) && 2942236884Smm zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 2943236884Smm sizeof (property)) == 0) { 2944236884Smm propstr = property; 2945185029Spjd } else { 2946185029Spjd propstr = "-"; 2947185029Spjd } 2948168404Spjd 2949168404Spjd 2950185029Spjd /* 2951185029Spjd * If this is being called in scripted mode, or if this is the 2952185029Spjd * last column and it is left-justified, don't include a width 2953185029Spjd * format specifier. 2954185029Spjd */ 2955236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 2956185029Spjd (void) printf("%s", propstr); 2957185029Spjd else if (right_justify) 2958185029Spjd (void) printf("%*s", width, propstr); 2959185029Spjd else 2960185029Spjd (void) printf("%-*s", width, propstr); 2961185029Spjd } 2962168404Spjd 2963185029Spjd (void) printf("\n"); 2964185029Spjd} 2965168404Spjd 2966236155Smmstatic void 2967273058Sdelphijprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, 2968273058Sdelphij boolean_t valid) 2969236155Smm{ 2970236155Smm char propval[64]; 2971236155Smm boolean_t fixed; 2972236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 2973236155Smm 2974273058Sdelphij switch (prop) { 2975273058Sdelphij case ZPOOL_PROP_EXPANDSZ: 2976273058Sdelphij if (value == 0) 2977273058Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 2978273058Sdelphij else 2979273058Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 2980273058Sdelphij break; 2981273058Sdelphij case ZPOOL_PROP_FRAGMENTATION: 2982273058Sdelphij if (value == ZFS_FRAG_INVALID) { 2983273058Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 2984273058Sdelphij } else { 2985273058Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", 2986273058Sdelphij value); 2987273058Sdelphij } 2988273058Sdelphij break; 2989273058Sdelphij case ZPOOL_PROP_CAPACITY: 2990269773Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", value); 2991273058Sdelphij break; 2992273058Sdelphij default: 2993269773Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 2994273058Sdelphij } 2995236155Smm 2996273058Sdelphij if (!valid) 2997273058Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 2998273058Sdelphij 2999236155Smm if (scripted) 3000236155Smm (void) printf("\t%s", propval); 3001236155Smm else 3002236155Smm (void) printf(" %*s", width, propval); 3003236155Smm} 3004236155Smm 3005236155Smmvoid 3006236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 3007236155Smm list_cbdata_t *cb, int depth) 3008236155Smm{ 3009236155Smm nvlist_t **child; 3010236155Smm vdev_stat_t *vs; 3011236155Smm uint_t c, children; 3012236155Smm char *vname; 3013236155Smm boolean_t scripted = cb->cb_scripted; 3014290764Smav uint64_t islog = B_FALSE; 3015290764Smav boolean_t haslog = B_FALSE; 3016290764Smav char *dashes = "%-*s - - - - - -\n"; 3017236155Smm 3018236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 3019236155Smm (uint64_t **)&vs, &c) == 0); 3020236155Smm 3021236155Smm if (name != NULL) { 3022273058Sdelphij boolean_t toplevel = (vs->vs_space != 0); 3023273058Sdelphij uint64_t cap; 3024273058Sdelphij 3025236155Smm if (scripted) 3026236155Smm (void) printf("\t%s", name); 3027236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 3028236155Smm (void) printf("%*s%s", depth, "", name); 3029236155Smm else 3030236155Smm (void) printf("%*s%s%*s", depth, "", name, 3031236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 3032236155Smm 3033273058Sdelphij /* 3034273058Sdelphij * Print the properties for the individual vdevs. Some 3035273058Sdelphij * properties are only applicable to toplevel vdevs. The 3036273058Sdelphij * 'toplevel' boolean value is passed to the print_one_column() 3037273058Sdelphij * to indicate that the value is valid. 3038273058Sdelphij */ 3039273058Sdelphij print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted, 3040273058Sdelphij toplevel); 3041273058Sdelphij print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted, 3042273058Sdelphij toplevel); 3043273058Sdelphij print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, 3044273058Sdelphij scripted, toplevel); 3045273058Sdelphij print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted, 3046273058Sdelphij B_TRUE); 3047273058Sdelphij print_one_column(ZPOOL_PROP_FRAGMENTATION, 3048273058Sdelphij vs->vs_fragmentation, scripted, 3049273058Sdelphij (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel)); 3050273058Sdelphij cap = (vs->vs_space == 0) ? 0 : 3051273058Sdelphij (vs->vs_alloc * 100 / vs->vs_space); 3052273058Sdelphij print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel); 3053236155Smm (void) printf("\n"); 3054236155Smm } 3055236155Smm 3056236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 3057236155Smm &child, &children) != 0) 3058236155Smm return; 3059236155Smm 3060236155Smm for (c = 0; c < children; c++) { 3061236155Smm uint64_t ishole = B_FALSE; 3062236155Smm 3063236155Smm if (nvlist_lookup_uint64(child[c], 3064236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 3065236155Smm continue; 3066236155Smm 3067290764Smav if (nvlist_lookup_uint64(child[c], 3068290764Smav ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) { 3069290764Smav haslog = B_TRUE; 3070290764Smav continue; 3071290764Smav } 3072290764Smav 3073236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3074236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3075236155Smm free(vname); 3076236155Smm } 3077236155Smm 3078290764Smav if (haslog == B_TRUE) { 3079290764Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3080290764Smav (void) printf(dashes, cb->cb_namewidth, "log"); 3081290764Smav for (c = 0; c < children; c++) { 3082290764Smav if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3083290764Smav &islog) != 0 || !islog) 3084290764Smav continue; 3085290764Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3086290764Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3087290764Smav free(vname); 3088290764Smav } 3089290764Smav } 3090290764Smav 3091236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 3092290764Smav &child, &children) == 0 && children > 0) { 3093290764Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3094290764Smav (void) printf(dashes, cb->cb_namewidth, "cache"); 3095290764Smav for (c = 0; c < children; c++) { 3096290764Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3097290764Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3098290764Smav free(vname); 3099290764Smav } 3100290764Smav } 3101236155Smm 3102290764Smav if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child, 3103290764Smav &children) == 0 && children > 0) { 3104290764Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3105290764Smav (void) printf(dashes, cb->cb_namewidth, "spare"); 3106236155Smm for (c = 0; c < children; c++) { 3107290764Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3108236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3109236155Smm free(vname); 3110236155Smm } 3111236155Smm } 3112236155Smm} 3113236155Smm 3114236155Smm 3115185029Spjd/* 3116185029Spjd * Generic callback function to list a pool. 3117185029Spjd */ 3118185029Spjdint 3119185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 3120185029Spjd{ 3121185029Spjd list_cbdata_t *cbp = data; 3122236155Smm nvlist_t *config; 3123236155Smm nvlist_t *nvroot; 3124168404Spjd 3125236155Smm config = zpool_get_config(zhp, NULL); 3126168404Spjd 3127236155Smm print_pool(zhp, cbp); 3128236155Smm if (!cbp->cb_verbose) 3129236155Smm return (0); 3130168404Spjd 3131236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3132236155Smm &nvroot) == 0); 3133236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 3134236155Smm 3135168404Spjd return (0); 3136168404Spjd} 3137168404Spjd 3138168404Spjd/* 3139264335Sdelphij * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 3140168404Spjd * 3141185029Spjd * -H Scripted mode. Don't display headers, and separate properties 3142185029Spjd * by a single tab. 3143185029Spjd * -o List of properties to display. Defaults to 3144273058Sdelphij * "name,size,allocated,free,expandsize,fragmentation,capacity," 3145273058Sdelphij * "dedupratio,health,altroot" 3146264335Sdelphij * -p Diplay values in parsable (exact) format. 3147219089Spjd * -T Display a timestamp in date(1) or Unix format 3148168404Spjd * 3149168404Spjd * List all pools in the system, whether or not they're healthy. Output space 3150168404Spjd * statistics for each one, as well as health status summary. 3151168404Spjd */ 3152168404Spjdint 3153168404Spjdzpool_do_list(int argc, char **argv) 3154168404Spjd{ 3155168404Spjd int c; 3156168404Spjd int ret; 3157168404Spjd list_cbdata_t cb = { 0 }; 3158185029Spjd static char default_props[] = 3159273058Sdelphij "name,size,allocated,free,expandsize,fragmentation,capacity," 3160269773Sdelphij "dedupratio,health,altroot"; 3161185029Spjd char *props = default_props; 3162219089Spjd unsigned long interval = 0, count = 0; 3163236155Smm zpool_list_t *list; 3164236155Smm boolean_t first = B_TRUE; 3165168404Spjd 3166168404Spjd /* check options */ 3167264335Sdelphij while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) { 3168168404Spjd switch (c) { 3169168404Spjd case 'H': 3170168404Spjd cb.cb_scripted = B_TRUE; 3171168404Spjd break; 3172168404Spjd case 'o': 3173185029Spjd props = optarg; 3174168404Spjd break; 3175264335Sdelphij case 'p': 3176264335Sdelphij cb.cb_literal = B_TRUE; 3177264335Sdelphij break; 3178219089Spjd case 'T': 3179219089Spjd get_timestamp_arg(*optarg); 3180219089Spjd break; 3181236155Smm case 'v': 3182236155Smm cb.cb_verbose = B_TRUE; 3183236155Smm break; 3184168404Spjd case ':': 3185168404Spjd (void) fprintf(stderr, gettext("missing argument for " 3186168404Spjd "'%c' option\n"), optopt); 3187168404Spjd usage(B_FALSE); 3188168404Spjd break; 3189168404Spjd case '?': 3190168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3191168404Spjd optopt); 3192168404Spjd usage(B_FALSE); 3193168404Spjd } 3194168404Spjd } 3195168404Spjd 3196168404Spjd argc -= optind; 3197168404Spjd argv += optind; 3198168404Spjd 3199219089Spjd get_interval_count(&argc, argv, &interval, &count); 3200219089Spjd 3201185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3202185029Spjd usage(B_FALSE); 3203168404Spjd 3204219089Spjd for (;;) { 3205269004Sdelphij if ((list = pool_list_get(argc, argv, &cb.cb_proplist, 3206269004Sdelphij &ret)) == NULL) 3207269004Sdelphij return (1); 3208168404Spjd 3209236155Smm if (pool_list_count(list) == 0) 3210236155Smm break; 3211236155Smm 3212236155Smm cb.cb_namewidth = 0; 3213236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3214236155Smm 3215219089Spjd if (timestamp_fmt != NODATE) 3216219089Spjd print_timestamp(timestamp_fmt); 3217168404Spjd 3218236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 3219236155Smm print_header(&cb); 3220236155Smm first = B_FALSE; 3221219089Spjd } 3222236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 3223219089Spjd 3224219089Spjd if (interval == 0) 3225219089Spjd break; 3226219089Spjd 3227219089Spjd if (count != 0 && --count == 0) 3228219089Spjd break; 3229219089Spjd 3230269004Sdelphij pool_list_free(list); 3231219089Spjd (void) sleep(interval); 3232168404Spjd } 3233168404Spjd 3234269004Sdelphij if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3235269004Sdelphij (void) printf(gettext("no pools available\n")); 3236269004Sdelphij ret = 0; 3237269004Sdelphij } 3238269004Sdelphij 3239269004Sdelphij pool_list_free(list); 3240219089Spjd zprop_free_list(cb.cb_proplist); 3241168404Spjd return (ret); 3242168404Spjd} 3243168404Spjd 3244168404Spjdstatic int 3245168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 3246168404Spjd{ 3247168404Spjd boolean_t force = B_FALSE; 3248168404Spjd int c; 3249168404Spjd nvlist_t *nvroot; 3250168404Spjd char *poolname, *old_disk, *new_disk; 3251168404Spjd zpool_handle_t *zhp; 3252168404Spjd int ret; 3253168404Spjd 3254168404Spjd /* check options */ 3255168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3256168404Spjd switch (c) { 3257168404Spjd case 'f': 3258168404Spjd force = B_TRUE; 3259168404Spjd break; 3260168404Spjd case '?': 3261168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3262168404Spjd optopt); 3263168404Spjd usage(B_FALSE); 3264168404Spjd } 3265168404Spjd } 3266168404Spjd 3267168404Spjd argc -= optind; 3268168404Spjd argv += optind; 3269168404Spjd 3270168404Spjd /* get pool name and check number of arguments */ 3271168404Spjd if (argc < 1) { 3272168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3273168404Spjd usage(B_FALSE); 3274168404Spjd } 3275168404Spjd 3276168404Spjd poolname = argv[0]; 3277168404Spjd 3278168404Spjd if (argc < 2) { 3279168404Spjd (void) fprintf(stderr, 3280168404Spjd gettext("missing <device> specification\n")); 3281168404Spjd usage(B_FALSE); 3282168404Spjd } 3283168404Spjd 3284168404Spjd old_disk = argv[1]; 3285168404Spjd 3286168404Spjd if (argc < 3) { 3287168404Spjd if (!replacing) { 3288168404Spjd (void) fprintf(stderr, 3289168404Spjd gettext("missing <new_device> specification\n")); 3290168404Spjd usage(B_FALSE); 3291168404Spjd } 3292168404Spjd new_disk = old_disk; 3293168404Spjd argc -= 1; 3294168404Spjd argv += 1; 3295168404Spjd } else { 3296168404Spjd new_disk = argv[2]; 3297168404Spjd argc -= 2; 3298168404Spjd argv += 2; 3299168404Spjd } 3300168404Spjd 3301168404Spjd if (argc > 1) { 3302168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3303168404Spjd usage(B_FALSE); 3304168404Spjd } 3305168404Spjd 3306168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3307168404Spjd return (1); 3308168404Spjd 3309185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3310168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3311168404Spjd poolname); 3312168404Spjd zpool_close(zhp); 3313168404Spjd return (1); 3314168404Spjd } 3315168404Spjd 3316185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3317185029Spjd argc, argv); 3318168404Spjd if (nvroot == NULL) { 3319168404Spjd zpool_close(zhp); 3320168404Spjd return (1); 3321168404Spjd } 3322168404Spjd 3323168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3324168404Spjd 3325168404Spjd nvlist_free(nvroot); 3326168404Spjd zpool_close(zhp); 3327168404Spjd 3328168404Spjd return (ret); 3329168404Spjd} 3330168404Spjd 3331168404Spjd/* 3332168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3333168404Spjd * 3334168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3335168404Spjd * 3336168404Spjd * Replace <device> with <new_device>. 3337168404Spjd */ 3338168404Spjd/* ARGSUSED */ 3339168404Spjdint 3340168404Spjdzpool_do_replace(int argc, char **argv) 3341168404Spjd{ 3342168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3343168404Spjd} 3344168404Spjd 3345168404Spjd/* 3346168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3347168404Spjd * 3348168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3349168404Spjd * 3350168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3351168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3352168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3353168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3354168404Spjd */ 3355168404Spjdint 3356168404Spjdzpool_do_attach(int argc, char **argv) 3357168404Spjd{ 3358168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3359168404Spjd} 3360168404Spjd 3361168404Spjd/* 3362168404Spjd * zpool detach [-f] <pool> <device> 3363168404Spjd * 3364168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3365168404Spjd * (not supported yet) 3366168404Spjd * 3367168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3368168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3369168404Spjd * has the only valid copy of some data. 3370168404Spjd */ 3371168404Spjd/* ARGSUSED */ 3372168404Spjdint 3373168404Spjdzpool_do_detach(int argc, char **argv) 3374168404Spjd{ 3375168404Spjd int c; 3376168404Spjd char *poolname, *path; 3377168404Spjd zpool_handle_t *zhp; 3378168404Spjd int ret; 3379168404Spjd 3380168404Spjd /* check options */ 3381168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3382168404Spjd switch (c) { 3383168404Spjd case 'f': 3384168404Spjd case '?': 3385168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3386168404Spjd optopt); 3387168404Spjd usage(B_FALSE); 3388168404Spjd } 3389168404Spjd } 3390168404Spjd 3391168404Spjd argc -= optind; 3392168404Spjd argv += optind; 3393168404Spjd 3394168404Spjd /* get pool name and check number of arguments */ 3395168404Spjd if (argc < 1) { 3396168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3397168404Spjd usage(B_FALSE); 3398168404Spjd } 3399168404Spjd 3400168404Spjd if (argc < 2) { 3401168404Spjd (void) fprintf(stderr, 3402168404Spjd gettext("missing <device> specification\n")); 3403168404Spjd usage(B_FALSE); 3404168404Spjd } 3405168404Spjd 3406168404Spjd poolname = argv[0]; 3407168404Spjd path = argv[1]; 3408168404Spjd 3409168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3410168404Spjd return (1); 3411168404Spjd 3412168404Spjd ret = zpool_vdev_detach(zhp, path); 3413168404Spjd 3414168404Spjd zpool_close(zhp); 3415168404Spjd 3416168404Spjd return (ret); 3417168404Spjd} 3418168404Spjd 3419168404Spjd/* 3420219089Spjd * zpool split [-n] [-o prop=val] ... 3421219089Spjd * [-o mntopt] ... 3422219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3423219089Spjd * 3424219089Spjd * -n Do not split the pool, but display the resulting layout if 3425219089Spjd * it were to be split. 3426219089Spjd * -o Set property=value, or set mount options. 3427219089Spjd * -R Mount the split-off pool under an alternate root. 3428219089Spjd * 3429219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3430219089Spjd * off may be listed, provided that no more than one device is specified 3431219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3432219089Spjd * state unless -R is specified. 3433219089Spjd * 3434219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3435219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3436219089Spjd * undergoing a resilvering operation. 3437219089Spjd */ 3438219089Spjdint 3439219089Spjdzpool_do_split(int argc, char **argv) 3440219089Spjd{ 3441219089Spjd char *srcpool, *newpool, *propval; 3442219089Spjd char *mntopts = NULL; 3443219089Spjd splitflags_t flags; 3444219089Spjd int c, ret = 0; 3445219089Spjd zpool_handle_t *zhp; 3446219089Spjd nvlist_t *config, *props = NULL; 3447219089Spjd 3448219089Spjd flags.dryrun = B_FALSE; 3449219089Spjd flags.import = B_FALSE; 3450219089Spjd 3451219089Spjd /* check options */ 3452219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3453219089Spjd switch (c) { 3454219089Spjd case 'R': 3455219089Spjd flags.import = B_TRUE; 3456219089Spjd if (add_prop_list( 3457219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3458219089Spjd &props, B_TRUE) != 0) { 3459297115Smav nvlist_free(props); 3460219089Spjd usage(B_FALSE); 3461219089Spjd } 3462219089Spjd break; 3463219089Spjd case 'n': 3464219089Spjd flags.dryrun = B_TRUE; 3465219089Spjd break; 3466219089Spjd case 'o': 3467219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3468219089Spjd *propval = '\0'; 3469219089Spjd propval++; 3470219089Spjd if (add_prop_list(optarg, propval, 3471219089Spjd &props, B_TRUE) != 0) { 3472297115Smav nvlist_free(props); 3473219089Spjd usage(B_FALSE); 3474219089Spjd } 3475219089Spjd } else { 3476219089Spjd mntopts = optarg; 3477219089Spjd } 3478219089Spjd break; 3479219089Spjd case ':': 3480219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3481219089Spjd "'%c' option\n"), optopt); 3482219089Spjd usage(B_FALSE); 3483219089Spjd break; 3484219089Spjd case '?': 3485219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3486219089Spjd optopt); 3487219089Spjd usage(B_FALSE); 3488219089Spjd break; 3489219089Spjd } 3490219089Spjd } 3491219089Spjd 3492219089Spjd if (!flags.import && mntopts != NULL) { 3493219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3494219089Spjd "valid when importing the pool\n")); 3495219089Spjd usage(B_FALSE); 3496219089Spjd } 3497219089Spjd 3498219089Spjd argc -= optind; 3499219089Spjd argv += optind; 3500219089Spjd 3501219089Spjd if (argc < 1) { 3502219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3503219089Spjd usage(B_FALSE); 3504219089Spjd } 3505219089Spjd if (argc < 2) { 3506219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3507219089Spjd usage(B_FALSE); 3508219089Spjd } 3509219089Spjd 3510219089Spjd srcpool = argv[0]; 3511219089Spjd newpool = argv[1]; 3512219089Spjd 3513219089Spjd argc -= 2; 3514219089Spjd argv += 2; 3515219089Spjd 3516219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3517219089Spjd return (1); 3518219089Spjd 3519219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3520219089Spjd if (config == NULL) { 3521219089Spjd ret = 1; 3522219089Spjd } else { 3523219089Spjd if (flags.dryrun) { 3524219089Spjd (void) printf(gettext("would create '%s' with the " 3525219089Spjd "following layout:\n\n"), newpool); 3526219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3527219089Spjd } 3528219089Spjd nvlist_free(config); 3529219089Spjd } 3530219089Spjd 3531219089Spjd zpool_close(zhp); 3532219089Spjd 3533219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3534219089Spjd return (ret); 3535219089Spjd 3536219089Spjd /* 3537219089Spjd * The split was successful. Now we need to open the new 3538219089Spjd * pool and import it. 3539219089Spjd */ 3540219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3541219089Spjd return (1); 3542219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3543219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3544219089Spjd ret = 1; 3545240415Smm (void) fprintf(stderr, gettext("Split was successful, but " 3546219089Spjd "the datasets could not all be mounted\n")); 3547219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3548219089Spjd "different altroot\n"), "zpool import"); 3549219089Spjd } 3550219089Spjd zpool_close(zhp); 3551219089Spjd 3552219089Spjd return (ret); 3553219089Spjd} 3554219089Spjd 3555219089Spjd 3556219089Spjd 3557219089Spjd/* 3558168404Spjd * zpool online <pool> <device> ... 3559168404Spjd */ 3560168404Spjdint 3561168404Spjdzpool_do_online(int argc, char **argv) 3562168404Spjd{ 3563168404Spjd int c, i; 3564168404Spjd char *poolname; 3565168404Spjd zpool_handle_t *zhp; 3566168404Spjd int ret = 0; 3567185029Spjd vdev_state_t newstate; 3568219089Spjd int flags = 0; 3569168404Spjd 3570168404Spjd /* check options */ 3571219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3572168404Spjd switch (c) { 3573219089Spjd case 'e': 3574219089Spjd flags |= ZFS_ONLINE_EXPAND; 3575219089Spjd break; 3576168404Spjd case 't': 3577168404Spjd case '?': 3578168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3579168404Spjd optopt); 3580168404Spjd usage(B_FALSE); 3581168404Spjd } 3582168404Spjd } 3583168404Spjd 3584168404Spjd argc -= optind; 3585168404Spjd argv += optind; 3586168404Spjd 3587168404Spjd /* get pool name and check number of arguments */ 3588168404Spjd if (argc < 1) { 3589168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3590168404Spjd usage(B_FALSE); 3591168404Spjd } 3592168404Spjd if (argc < 2) { 3593168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3594168404Spjd usage(B_FALSE); 3595168404Spjd } 3596168404Spjd 3597168404Spjd poolname = argv[0]; 3598168404Spjd 3599168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3600168404Spjd return (1); 3601168404Spjd 3602185029Spjd for (i = 1; i < argc; i++) { 3603219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3604185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3605185029Spjd (void) printf(gettext("warning: device '%s' " 3606185029Spjd "onlined, but remains in faulted state\n"), 3607185029Spjd argv[i]); 3608185029Spjd if (newstate == VDEV_STATE_FAULTED) 3609185029Spjd (void) printf(gettext("use 'zpool " 3610185029Spjd "clear' to restore a faulted " 3611185029Spjd "device\n")); 3612185029Spjd else 3613185029Spjd (void) printf(gettext("use 'zpool " 3614185029Spjd "replace' to replace devices " 3615185029Spjd "that are no longer present\n")); 3616185029Spjd } 3617185029Spjd } else { 3618168404Spjd ret = 1; 3619185029Spjd } 3620185029Spjd } 3621168404Spjd 3622168404Spjd zpool_close(zhp); 3623168404Spjd 3624168404Spjd return (ret); 3625168404Spjd} 3626168404Spjd 3627168404Spjd/* 3628168404Spjd * zpool offline [-ft] <pool> <device> ... 3629168404Spjd * 3630168404Spjd * -f Force the device into the offline state, even if doing 3631168404Spjd * so would appear to compromise pool availability. 3632168404Spjd * (not supported yet) 3633168404Spjd * 3634168404Spjd * -t Only take the device off-line temporarily. The offline 3635168404Spjd * state will not be persistent across reboots. 3636168404Spjd */ 3637168404Spjd/* ARGSUSED */ 3638168404Spjdint 3639168404Spjdzpool_do_offline(int argc, char **argv) 3640168404Spjd{ 3641168404Spjd int c, i; 3642168404Spjd char *poolname; 3643168404Spjd zpool_handle_t *zhp; 3644168404Spjd int ret = 0; 3645168404Spjd boolean_t istmp = B_FALSE; 3646168404Spjd 3647168404Spjd /* check options */ 3648168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3649168404Spjd switch (c) { 3650168404Spjd case 't': 3651168404Spjd istmp = B_TRUE; 3652168404Spjd break; 3653168404Spjd case 'f': 3654168404Spjd case '?': 3655168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3656168404Spjd optopt); 3657168404Spjd usage(B_FALSE); 3658168404Spjd } 3659168404Spjd } 3660168404Spjd 3661168404Spjd argc -= optind; 3662168404Spjd argv += optind; 3663168404Spjd 3664168404Spjd /* get pool name and check number of arguments */ 3665168404Spjd if (argc < 1) { 3666168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3667168404Spjd usage(B_FALSE); 3668168404Spjd } 3669168404Spjd if (argc < 2) { 3670168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3671168404Spjd usage(B_FALSE); 3672168404Spjd } 3673168404Spjd 3674168404Spjd poolname = argv[0]; 3675168404Spjd 3676168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3677168404Spjd return (1); 3678168404Spjd 3679185029Spjd for (i = 1; i < argc; i++) { 3680185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3681168404Spjd ret = 1; 3682185029Spjd } 3683168404Spjd 3684168404Spjd zpool_close(zhp); 3685168404Spjd 3686168404Spjd return (ret); 3687168404Spjd} 3688168404Spjd 3689168404Spjd/* 3690168404Spjd * zpool clear <pool> [device] 3691168404Spjd * 3692168404Spjd * Clear all errors associated with a pool or a particular device. 3693168404Spjd */ 3694168404Spjdint 3695168404Spjdzpool_do_clear(int argc, char **argv) 3696168404Spjd{ 3697219089Spjd int c; 3698168404Spjd int ret = 0; 3699219089Spjd boolean_t dryrun = B_FALSE; 3700219089Spjd boolean_t do_rewind = B_FALSE; 3701219089Spjd boolean_t xtreme_rewind = B_FALSE; 3702219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3703219089Spjd nvlist_t *policy = NULL; 3704168404Spjd zpool_handle_t *zhp; 3705168404Spjd char *pool, *device; 3706168404Spjd 3707219089Spjd /* check options */ 3708219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3709219089Spjd switch (c) { 3710219089Spjd case 'F': 3711219089Spjd do_rewind = B_TRUE; 3712219089Spjd break; 3713219089Spjd case 'n': 3714219089Spjd dryrun = B_TRUE; 3715219089Spjd break; 3716219089Spjd case 'X': 3717219089Spjd xtreme_rewind = B_TRUE; 3718219089Spjd break; 3719219089Spjd case '?': 3720219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3721219089Spjd optopt); 3722219089Spjd usage(B_FALSE); 3723219089Spjd } 3724219089Spjd } 3725219089Spjd 3726219089Spjd argc -= optind; 3727219089Spjd argv += optind; 3728219089Spjd 3729219089Spjd if (argc < 1) { 3730168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3731168404Spjd usage(B_FALSE); 3732168404Spjd } 3733168404Spjd 3734219089Spjd if (argc > 2) { 3735168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3736168404Spjd usage(B_FALSE); 3737168404Spjd } 3738168404Spjd 3739219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3740219089Spjd (void) fprintf(stderr, 3741219089Spjd gettext("-n or -X only meaningful with -F\n")); 3742219089Spjd usage(B_FALSE); 3743219089Spjd } 3744219089Spjd if (dryrun) 3745219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3746219089Spjd else if (do_rewind) 3747219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3748219089Spjd if (xtreme_rewind) 3749219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3750168404Spjd 3751219089Spjd /* In future, further rewind policy choices can be passed along here */ 3752219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3753219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3754168404Spjd return (1); 3755168404Spjd 3756219089Spjd pool = argv[0]; 3757219089Spjd device = argc == 2 ? argv[1] : NULL; 3758219089Spjd 3759219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3760219089Spjd nvlist_free(policy); 3761219089Spjd return (1); 3762219089Spjd } 3763219089Spjd 3764219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3765168404Spjd ret = 1; 3766168404Spjd 3767168404Spjd zpool_close(zhp); 3768168404Spjd 3769219089Spjd nvlist_free(policy); 3770219089Spjd 3771168404Spjd return (ret); 3772168404Spjd} 3773168404Spjd 3774228103Smm/* 3775228103Smm * zpool reguid <pool> 3776228103Smm */ 3777228103Smmint 3778228103Smmzpool_do_reguid(int argc, char **argv) 3779228103Smm{ 3780228103Smm int c; 3781228103Smm char *poolname; 3782228103Smm zpool_handle_t *zhp; 3783228103Smm int ret = 0; 3784228103Smm 3785228103Smm /* check options */ 3786228103Smm while ((c = getopt(argc, argv, "")) != -1) { 3787228103Smm switch (c) { 3788228103Smm case '?': 3789228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3790228103Smm optopt); 3791228103Smm usage(B_FALSE); 3792228103Smm } 3793228103Smm } 3794228103Smm 3795228103Smm argc -= optind; 3796228103Smm argv += optind; 3797228103Smm 3798228103Smm /* get pool name and check number of arguments */ 3799228103Smm if (argc < 1) { 3800228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 3801228103Smm usage(B_FALSE); 3802228103Smm } 3803228103Smm 3804228103Smm if (argc > 1) { 3805228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 3806228103Smm usage(B_FALSE); 3807228103Smm } 3808228103Smm 3809228103Smm poolname = argv[0]; 3810228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3811228103Smm return (1); 3812228103Smm 3813228103Smm ret = zpool_reguid(zhp); 3814228103Smm 3815228103Smm zpool_close(zhp); 3816228103Smm return (ret); 3817228103Smm} 3818228103Smm 3819228103Smm 3820236155Smm/* 3821236155Smm * zpool reopen <pool> 3822236155Smm * 3823236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 3824236155Smm */ 3825236155Smmint 3826236155Smmzpool_do_reopen(int argc, char **argv) 3827236155Smm{ 3828263393Sdelphij int c; 3829236155Smm int ret = 0; 3830236155Smm zpool_handle_t *zhp; 3831236155Smm char *pool; 3832236155Smm 3833263393Sdelphij /* check options */ 3834263393Sdelphij while ((c = getopt(argc, argv, "")) != -1) { 3835263393Sdelphij switch (c) { 3836263393Sdelphij case '?': 3837263393Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3838263393Sdelphij optopt); 3839263393Sdelphij usage(B_FALSE); 3840263393Sdelphij } 3841263393Sdelphij } 3842263393Sdelphij 3843236155Smm argc--; 3844236155Smm argv++; 3845236155Smm 3846263393Sdelphij if (argc < 1) { 3847263393Sdelphij (void) fprintf(stderr, gettext("missing pool name\n")); 3848263393Sdelphij usage(B_FALSE); 3849263393Sdelphij } 3850236155Smm 3851263393Sdelphij if (argc > 1) { 3852263393Sdelphij (void) fprintf(stderr, gettext("too many arguments\n")); 3853263393Sdelphij usage(B_FALSE); 3854263393Sdelphij } 3855263393Sdelphij 3856236155Smm pool = argv[0]; 3857236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 3858236155Smm return (1); 3859236155Smm 3860236155Smm ret = zpool_reopen(zhp); 3861236155Smm zpool_close(zhp); 3862236155Smm return (ret); 3863236155Smm} 3864236155Smm 3865168404Spjdtypedef struct scrub_cbdata { 3866168404Spjd int cb_type; 3867168404Spjd int cb_argc; 3868168404Spjd char **cb_argv; 3869168404Spjd} scrub_cbdata_t; 3870168404Spjd 3871168404Spjdint 3872168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3873168404Spjd{ 3874168404Spjd scrub_cbdata_t *cb = data; 3875168404Spjd int err; 3876168404Spjd 3877168404Spjd /* 3878168404Spjd * Ignore faulted pools. 3879168404Spjd */ 3880168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3881168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3882168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 3883168404Spjd return (1); 3884168404Spjd } 3885168404Spjd 3886219089Spjd err = zpool_scan(zhp, cb->cb_type); 3887168404Spjd 3888168404Spjd return (err != 0); 3889168404Spjd} 3890168404Spjd 3891168404Spjd/* 3892168404Spjd * zpool scrub [-s] <pool> ... 3893168404Spjd * 3894168404Spjd * -s Stop. Stops any in-progress scrub. 3895168404Spjd */ 3896168404Spjdint 3897168404Spjdzpool_do_scrub(int argc, char **argv) 3898168404Spjd{ 3899168404Spjd int c; 3900168404Spjd scrub_cbdata_t cb; 3901168404Spjd 3902219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 3903168404Spjd 3904168404Spjd /* check options */ 3905168404Spjd while ((c = getopt(argc, argv, "s")) != -1) { 3906168404Spjd switch (c) { 3907168404Spjd case 's': 3908219089Spjd cb.cb_type = POOL_SCAN_NONE; 3909168404Spjd break; 3910168404Spjd case '?': 3911168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3912168404Spjd optopt); 3913168404Spjd usage(B_FALSE); 3914168404Spjd } 3915168404Spjd } 3916168404Spjd 3917168404Spjd cb.cb_argc = argc; 3918168404Spjd cb.cb_argv = argv; 3919168404Spjd argc -= optind; 3920168404Spjd argv += optind; 3921168404Spjd 3922168404Spjd if (argc < 1) { 3923168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3924168404Spjd usage(B_FALSE); 3925168404Spjd } 3926168404Spjd 3927168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3928168404Spjd} 3929168404Spjd 3930168404Spjdtypedef struct status_cbdata { 3931168404Spjd int cb_count; 3932168404Spjd boolean_t cb_allpools; 3933168404Spjd boolean_t cb_verbose; 3934168404Spjd boolean_t cb_explain; 3935168404Spjd boolean_t cb_first; 3936219089Spjd boolean_t cb_dedup_stats; 3937168404Spjd} status_cbdata_t; 3938168404Spjd 3939168404Spjd/* 3940168404Spjd * Print out detailed scrub status. 3941168404Spjd */ 3942168404Spjdvoid 3943219089Spjdprint_scan_status(pool_scan_stat_t *ps) 3944168404Spjd{ 3945219089Spjd time_t start, end; 3946219089Spjd uint64_t elapsed, mins_left, hours_left; 3947219089Spjd uint64_t pass_exam, examined, total; 3948219089Spjd uint_t rate; 3949168404Spjd double fraction_done; 3950219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3951168404Spjd 3952226583Spjd (void) printf(gettext(" scan: ")); 3953168404Spjd 3954219089Spjd /* If there's never been a scan, there's not much to say. */ 3955219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 3956219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 3957168404Spjd (void) printf(gettext("none requested\n")); 3958168404Spjd return; 3959168404Spjd } 3960168404Spjd 3961219089Spjd start = ps->pss_start_time; 3962219089Spjd end = ps->pss_end_time; 3963219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3964168404Spjd 3965219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 3966219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 3967219089Spjd /* 3968219089Spjd * Scan is finished or canceled. 3969219089Spjd */ 3970219089Spjd if (ps->pss_state == DSS_FINISHED) { 3971219089Spjd uint64_t minutes_taken = (end - start) / 60; 3972297119Smav char *fmt = NULL; 3973168404Spjd 3974219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3975219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 3976219089Spjd "%llu errors on %s"); 3977219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3978219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 3979219089Spjd "%llu errors on %s"); 3980219089Spjd } 3981219089Spjd /* LINTED */ 3982219089Spjd (void) printf(fmt, processed_buf, 3983185029Spjd (u_longlong_t)(minutes_taken / 60), 3984185029Spjd (uint_t)(minutes_taken % 60), 3985219089Spjd (u_longlong_t)ps->pss_errors, 3986219089Spjd ctime((time_t *)&end)); 3987168404Spjd return; 3988219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 3989219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3990219089Spjd (void) printf(gettext("scrub canceled on %s"), 3991219089Spjd ctime(&end)); 3992219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3993219089Spjd (void) printf(gettext("resilver canceled on %s"), 3994219089Spjd ctime(&end)); 3995219089Spjd } 3996219089Spjd return; 3997168404Spjd } 3998168404Spjd 3999219089Spjd assert(ps->pss_state == DSS_SCANNING); 4000168404Spjd 4001219089Spjd /* 4002219089Spjd * Scan is in progress. 4003219089Spjd */ 4004219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4005219089Spjd (void) printf(gettext("scrub in progress since %s"), 4006219089Spjd ctime(&start)); 4007219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4008219089Spjd (void) printf(gettext("resilver in progress since %s"), 4009219089Spjd ctime(&start)); 4010219089Spjd } 4011219089Spjd 4012219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 4013219089Spjd total = ps->pss_to_examine; 4014168404Spjd fraction_done = (double)examined / total; 4015168404Spjd 4016219089Spjd /* elapsed time for this pass */ 4017219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 4018219089Spjd elapsed = elapsed ? elapsed : 1; 4019219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 4020219089Spjd rate = pass_exam / elapsed; 4021219089Spjd rate = rate ? rate : 1; 4022219089Spjd mins_left = ((total - examined) / rate) / 60; 4023219089Spjd hours_left = mins_left / 60; 4024219089Spjd 4025219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 4026219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 4027219089Spjd zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 4028219089Spjd 4029219089Spjd /* 4030219089Spjd * do not print estimated time if hours_left is more than 30 days 4031219089Spjd */ 4032226583Spjd (void) printf(gettext(" %s scanned out of %s at %s/s"), 4033219089Spjd examined_buf, total_buf, rate_buf); 4034219089Spjd if (hours_left < (30 * 24)) { 4035219089Spjd (void) printf(gettext(", %lluh%um to go\n"), 4036219089Spjd (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 4037219089Spjd } else { 4038219089Spjd (void) printf(gettext( 4039219089Spjd ", (scan is slow, no estimated time)\n")); 4040219089Spjd } 4041219089Spjd 4042219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 4043226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 4044219089Spjd processed_buf, 100 * fraction_done); 4045219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 4046226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 4047219089Spjd processed_buf, 100 * fraction_done); 4048219089Spjd } 4049168404Spjd} 4050168404Spjd 4051168404Spjdstatic void 4052168404Spjdprint_error_log(zpool_handle_t *zhp) 4053168404Spjd{ 4054185029Spjd nvlist_t *nverrlist = NULL; 4055168404Spjd nvpair_t *elem; 4056168404Spjd char *pathname; 4057168404Spjd size_t len = MAXPATHLEN * 2; 4058168404Spjd 4059168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 4060168404Spjd (void) printf("errors: List of errors unavailable " 4061168404Spjd "(insufficient privileges)\n"); 4062168404Spjd return; 4063168404Spjd } 4064168404Spjd 4065168404Spjd (void) printf("errors: Permanent errors have been " 4066168404Spjd "detected in the following files:\n\n"); 4067168404Spjd 4068168404Spjd pathname = safe_malloc(len); 4069168404Spjd elem = NULL; 4070168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 4071168404Spjd nvlist_t *nv; 4072168404Spjd uint64_t dsobj, obj; 4073168404Spjd 4074168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 4075168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 4076168404Spjd &dsobj) == 0); 4077168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 4078168404Spjd &obj) == 0); 4079168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 4080168404Spjd (void) printf("%7s %s\n", "", pathname); 4081168404Spjd } 4082168404Spjd free(pathname); 4083168404Spjd nvlist_free(nverrlist); 4084168404Spjd} 4085168404Spjd 4086168404Spjdstatic void 4087168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 4088168404Spjd int namewidth) 4089168404Spjd{ 4090168404Spjd uint_t i; 4091168404Spjd char *name; 4092168404Spjd 4093168404Spjd if (nspares == 0) 4094168404Spjd return; 4095168404Spjd 4096168404Spjd (void) printf(gettext("\tspares\n")); 4097168404Spjd 4098168404Spjd for (i = 0; i < nspares; i++) { 4099219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 4100168404Spjd print_status_config(zhp, name, spares[i], 4101209962Smm namewidth, 2, B_TRUE); 4102168404Spjd free(name); 4103168404Spjd } 4104168404Spjd} 4105168404Spjd 4106185029Spjdstatic void 4107185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 4108185029Spjd int namewidth) 4109185029Spjd{ 4110185029Spjd uint_t i; 4111185029Spjd char *name; 4112185029Spjd 4113185029Spjd if (nl2cache == 0) 4114185029Spjd return; 4115185029Spjd 4116185029Spjd (void) printf(gettext("\tcache\n")); 4117185029Spjd 4118185029Spjd for (i = 0; i < nl2cache; i++) { 4119219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 4120185029Spjd print_status_config(zhp, name, l2cache[i], 4121209962Smm namewidth, 2, B_FALSE); 4122185029Spjd free(name); 4123185029Spjd } 4124185029Spjd} 4125185029Spjd 4126219089Spjdstatic void 4127219089Spjdprint_dedup_stats(nvlist_t *config) 4128219089Spjd{ 4129219089Spjd ddt_histogram_t *ddh; 4130219089Spjd ddt_stat_t *dds; 4131219089Spjd ddt_object_t *ddo; 4132219089Spjd uint_t c; 4133219089Spjd 4134219089Spjd /* 4135219089Spjd * If the pool was faulted then we may not have been able to 4136253441Sdelphij * obtain the config. Otherwise, if we have anything in the dedup 4137219089Spjd * table continue processing the stats. 4138219089Spjd */ 4139219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 4140227497Smm (uint64_t **)&ddo, &c) != 0) 4141219089Spjd return; 4142219089Spjd 4143219089Spjd (void) printf("\n"); 4144227497Smm (void) printf(gettext(" dedup: ")); 4145227497Smm if (ddo->ddo_count == 0) { 4146227497Smm (void) printf(gettext("no DDT entries\n")); 4147227497Smm return; 4148227497Smm } 4149227497Smm 4150219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 4151219089Spjd (u_longlong_t)ddo->ddo_count, 4152219089Spjd (u_longlong_t)ddo->ddo_dspace, 4153219089Spjd (u_longlong_t)ddo->ddo_mspace); 4154219089Spjd 4155219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 4156219089Spjd (uint64_t **)&dds, &c) == 0); 4157219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 4158219089Spjd (uint64_t **)&ddh, &c) == 0); 4159219089Spjd zpool_dump_ddt(dds, ddh); 4160219089Spjd} 4161219089Spjd 4162168404Spjd/* 4163168404Spjd * Display a summary of pool status. Displays a summary such as: 4164168404Spjd * 4165168404Spjd * pool: tank 4166168404Spjd * status: DEGRADED 4167168404Spjd * reason: One or more devices ... 4168236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 4169168404Spjd * config: 4170168404Spjd * mirror DEGRADED 4171168404Spjd * c1t0d0 OK 4172168404Spjd * c2t0d0 UNAVAIL 4173168404Spjd * 4174168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 4175168404Spjd * option is specified, then we print out error rate information as well. 4176168404Spjd */ 4177168404Spjdint 4178168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 4179168404Spjd{ 4180168404Spjd status_cbdata_t *cbp = data; 4181168404Spjd nvlist_t *config, *nvroot; 4182168404Spjd char *msgid; 4183168404Spjd int reason; 4184168404Spjd const char *health; 4185168404Spjd uint_t c; 4186168404Spjd vdev_stat_t *vs; 4187168404Spjd 4188168404Spjd config = zpool_get_config(zhp, NULL); 4189168404Spjd reason = zpool_get_status(zhp, &msgid); 4190168404Spjd 4191168404Spjd cbp->cb_count++; 4192168404Spjd 4193168404Spjd /* 4194168404Spjd * If we were given 'zpool status -x', only report those pools with 4195168404Spjd * problems. 4196168404Spjd */ 4197248267Smm if (cbp->cb_explain && 4198248267Smm (reason == ZPOOL_STATUS_OK || 4199248267Smm reason == ZPOOL_STATUS_VERSION_OLDER || 4200269735Sdelphij reason == ZPOOL_STATUS_NON_NATIVE_ASHIFT || 4201248267Smm reason == ZPOOL_STATUS_FEAT_DISABLED)) { 4202168404Spjd if (!cbp->cb_allpools) { 4203168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 4204168404Spjd zpool_get_name(zhp)); 4205168404Spjd if (cbp->cb_first) 4206168404Spjd cbp->cb_first = B_FALSE; 4207168404Spjd } 4208168404Spjd return (0); 4209168404Spjd } 4210168404Spjd 4211168404Spjd if (cbp->cb_first) 4212168404Spjd cbp->cb_first = B_FALSE; 4213168404Spjd else 4214168404Spjd (void) printf("\n"); 4215168404Spjd 4216168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 4217168404Spjd &nvroot) == 0); 4218219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 4219168404Spjd (uint64_t **)&vs, &c) == 0); 4220185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4221168404Spjd 4222168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4223168404Spjd (void) printf(gettext(" state: %s\n"), health); 4224168404Spjd 4225168404Spjd switch (reason) { 4226168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 4227168404Spjd (void) printf(gettext("status: One or more devices could not " 4228168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 4229168404Spjd "continue functioning in a degraded state.\n")); 4230168404Spjd (void) printf(gettext("action: Attach the missing device and " 4231168404Spjd "online it using 'zpool online'.\n")); 4232168404Spjd break; 4233168404Spjd 4234168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 4235168404Spjd (void) printf(gettext("status: One or more devices could not " 4236168404Spjd "be opened. There are insufficient\n\treplicas for the " 4237168404Spjd "pool to continue functioning.\n")); 4238168404Spjd (void) printf(gettext("action: Attach the missing device and " 4239168404Spjd "online it using 'zpool online'.\n")); 4240168404Spjd break; 4241168404Spjd 4242168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 4243168404Spjd (void) printf(gettext("status: One or more devices could not " 4244168404Spjd "be used because the label is missing or\n\tinvalid. " 4245168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 4246168404Spjd "functioning in a degraded state.\n")); 4247168404Spjd (void) printf(gettext("action: Replace the device using " 4248168404Spjd "'zpool replace'.\n")); 4249168404Spjd break; 4250168404Spjd 4251168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4252168404Spjd (void) printf(gettext("status: One or more devices could not " 4253168404Spjd "be used because the label is missing \n\tor invalid. " 4254168404Spjd "There are insufficient replicas for the pool to " 4255168404Spjd "continue\n\tfunctioning.\n")); 4256219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4257219089Spjd zpool_get_name(zhp), reason, config); 4258168404Spjd break; 4259168404Spjd 4260168404Spjd case ZPOOL_STATUS_FAILING_DEV: 4261168404Spjd (void) printf(gettext("status: One or more devices has " 4262168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 4263168404Spjd "made to correct the error. Applications are " 4264168404Spjd "unaffected.\n")); 4265168404Spjd (void) printf(gettext("action: Determine if the device needs " 4266168404Spjd "to be replaced, and clear the errors\n\tusing " 4267168404Spjd "'zpool clear' or replace the device with 'zpool " 4268168404Spjd "replace'.\n")); 4269168404Spjd break; 4270168404Spjd 4271168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 4272168404Spjd (void) printf(gettext("status: One or more devices has " 4273168404Spjd "been taken offline by the administrator.\n\tSufficient " 4274168404Spjd "replicas exist for the pool to continue functioning in " 4275168404Spjd "a\n\tdegraded state.\n")); 4276168404Spjd (void) printf(gettext("action: Online the device using " 4277168404Spjd "'zpool online' or replace the device with\n\t'zpool " 4278168404Spjd "replace'.\n")); 4279168404Spjd break; 4280168404Spjd 4281219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 4282219089Spjd (void) printf(gettext("status: One or more devices has " 4283219089Spjd "been removed by the administrator.\n\tSufficient " 4284219089Spjd "replicas exist for the pool to continue functioning in " 4285219089Spjd "a\n\tdegraded state.\n")); 4286219089Spjd (void) printf(gettext("action: Online the device using " 4287219089Spjd "'zpool online' or replace the device with\n\t'zpool " 4288219089Spjd "replace'.\n")); 4289219089Spjd break; 4290219089Spjd 4291168404Spjd case ZPOOL_STATUS_RESILVERING: 4292168404Spjd (void) printf(gettext("status: One or more devices is " 4293168404Spjd "currently being resilvered. The pool will\n\tcontinue " 4294168404Spjd "to function, possibly in a degraded state.\n")); 4295168404Spjd (void) printf(gettext("action: Wait for the resilver to " 4296168404Spjd "complete.\n")); 4297168404Spjd break; 4298168404Spjd 4299168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 4300168404Spjd (void) printf(gettext("status: One or more devices has " 4301168404Spjd "experienced an error resulting in data\n\tcorruption. " 4302168404Spjd "Applications may be affected.\n")); 4303168404Spjd (void) printf(gettext("action: Restore the file in question " 4304168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 4305168404Spjd "backup.\n")); 4306168404Spjd break; 4307168404Spjd 4308168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4309168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4310168404Spjd "and the pool cannot be opened.\n")); 4311219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4312219089Spjd zpool_get_name(zhp), reason, config); 4313168404Spjd break; 4314168404Spjd 4315168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4316238926Smm (void) printf(gettext("status: The pool is formatted using a " 4317238926Smm "legacy on-disk format. The pool can\n\tstill be used, " 4318238926Smm "but some features are unavailable.\n")); 4319168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4320168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 4321238926Smm "be accessible on software that does not support feature\n" 4322238926Smm "\tflags.\n")); 4323168404Spjd break; 4324168404Spjd 4325168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 4326168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 4327168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 4328168404Spjd "be accessed on this system.\n")); 4329168404Spjd (void) printf(gettext("action: Access the pool from a system " 4330168404Spjd "running more recent software, or\n\trestore the pool from " 4331168404Spjd "backup.\n")); 4332168404Spjd break; 4333168404Spjd 4334238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 4335238926Smm (void) printf(gettext("status: Some supported features are not " 4336238926Smm "enabled on the pool. The pool can\n\tstill be used, but " 4337238926Smm "some features are unavailable.\n")); 4338238926Smm (void) printf(gettext("action: Enable all features using " 4339238926Smm "'zpool upgrade'. Once this is done,\n\tthe pool may no " 4340238926Smm "longer be accessible by software that does not support\n\t" 4341243014Smm "the features. See zpool-features(7) for details.\n")); 4342238926Smm break; 4343238926Smm 4344236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 4345236884Smm (void) printf(gettext("status: The pool cannot be accessed on " 4346236884Smm "this system because it uses the\n\tfollowing feature(s) " 4347236884Smm "not supported on this system:\n")); 4348236884Smm zpool_print_unsup_feat(config); 4349236884Smm (void) printf("\n"); 4350236884Smm (void) printf(gettext("action: Access the pool from a system " 4351236884Smm "that supports the required feature(s),\n\tor restore the " 4352236884Smm "pool from backup.\n")); 4353236884Smm break; 4354236884Smm 4355236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4356236884Smm (void) printf(gettext("status: The pool can only be accessed " 4357236884Smm "in read-only mode on this system. It\n\tcannot be " 4358236884Smm "accessed in read-write mode because it uses the " 4359236884Smm "following\n\tfeature(s) not supported on this system:\n")); 4360236884Smm zpool_print_unsup_feat(config); 4361236884Smm (void) printf("\n"); 4362236884Smm (void) printf(gettext("action: The pool cannot be accessed in " 4363236884Smm "read-write mode. Import the pool with\n" 4364236884Smm "\t\"-o readonly=on\", access the pool from a system that " 4365236884Smm "supports the\n\trequired feature(s), or restore the " 4366236884Smm "pool from backup.\n")); 4367236884Smm break; 4368236884Smm 4369185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 4370185029Spjd (void) printf(gettext("status: One or more devices are " 4371185029Spjd "faulted in response to persistent errors.\n\tSufficient " 4372185029Spjd "replicas exist for the pool to continue functioning " 4373185029Spjd "in a\n\tdegraded state.\n")); 4374185029Spjd (void) printf(gettext("action: Replace the faulted device, " 4375185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 4376185029Spjd break; 4377185029Spjd 4378185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 4379185029Spjd (void) printf(gettext("status: One or more devices are " 4380185029Spjd "faulted in response to persistent errors. There are " 4381185029Spjd "insufficient replicas for the pool to\n\tcontinue " 4382185029Spjd "functioning.\n")); 4383185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 4384185029Spjd "from a backup source. Manually marking the device\n" 4385185029Spjd "\trepaired using 'zpool clear' may allow some data " 4386185029Spjd "to be recovered.\n")); 4387185029Spjd break; 4388185029Spjd 4389185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 4390185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 4391185029Spjd (void) printf(gettext("status: One or more devices are " 4392185029Spjd "faulted in response to IO failures.\n")); 4393185029Spjd (void) printf(gettext("action: Make sure the affected devices " 4394185029Spjd "are connected, then run 'zpool clear'.\n")); 4395185029Spjd break; 4396185029Spjd 4397185029Spjd case ZPOOL_STATUS_BAD_LOG: 4398185029Spjd (void) printf(gettext("status: An intent log record " 4399185029Spjd "could not be read.\n" 4400185029Spjd "\tWaiting for adminstrator intervention to fix the " 4401185029Spjd "faulted pool.\n")); 4402185029Spjd (void) printf(gettext("action: Either restore the affected " 4403185029Spjd "device(s) and run 'zpool online',\n" 4404185029Spjd "\tor ignore the intent log records by running " 4405185029Spjd "'zpool clear'.\n")); 4406185029Spjd break; 4407185029Spjd 4408254591Sgibbs case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 4409254591Sgibbs (void) printf(gettext("status: One or more devices are " 4410254591Sgibbs "configured to use a non-native block size.\n" 4411254591Sgibbs "\tExpect reduced performance.\n")); 4412254591Sgibbs (void) printf(gettext("action: Replace affected devices with " 4413254591Sgibbs "devices that support the\n\tconfigured block size, or " 4414254591Sgibbs "migrate data to a properly configured\n\tpool.\n")); 4415254591Sgibbs break; 4416254591Sgibbs 4417168404Spjd default: 4418168404Spjd /* 4419168404Spjd * The remaining errors can't actually be generated, yet. 4420168404Spjd */ 4421168404Spjd assert(reason == ZPOOL_STATUS_OK); 4422168404Spjd } 4423168404Spjd 4424168404Spjd if (msgid != NULL) 4425236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4426168404Spjd msgid); 4427168404Spjd 4428168404Spjd if (config != NULL) { 4429168404Spjd int namewidth; 4430168404Spjd uint64_t nerr; 4431185029Spjd nvlist_t **spares, **l2cache; 4432185029Spjd uint_t nspares, nl2cache; 4433219089Spjd pool_scan_stat_t *ps = NULL; 4434168404Spjd 4435219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 4436219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 4437219089Spjd print_scan_status(ps); 4438168404Spjd 4439168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 4440168404Spjd if (namewidth < 10) 4441168404Spjd namewidth = 10; 4442168404Spjd 4443168404Spjd (void) printf(gettext("config:\n\n")); 4444168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4445168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4446168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 4447209962Smm namewidth, 0, B_FALSE); 4448209962Smm 4449185029Spjd if (num_logs(nvroot) > 0) 4450213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 4451185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4452185029Spjd &l2cache, &nl2cache) == 0) 4453185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 4454185029Spjd 4455168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 4456168404Spjd &spares, &nspares) == 0) 4457168404Spjd print_spares(zhp, spares, nspares, namewidth); 4458168404Spjd 4459168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4460168404Spjd &nerr) == 0) { 4461168404Spjd nvlist_t *nverrlist = NULL; 4462168404Spjd 4463168404Spjd /* 4464168404Spjd * If the approximate error count is small, get a 4465168404Spjd * precise count by fetching the entire log and 4466168404Spjd * uniquifying the results. 4467168404Spjd */ 4468185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 4469168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 4470168404Spjd nvpair_t *elem; 4471168404Spjd 4472168404Spjd elem = NULL; 4473168404Spjd nerr = 0; 4474168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 4475168404Spjd elem)) != NULL) { 4476168404Spjd nerr++; 4477168404Spjd } 4478168404Spjd } 4479168404Spjd nvlist_free(nverrlist); 4480168404Spjd 4481168404Spjd (void) printf("\n"); 4482168404Spjd 4483168404Spjd if (nerr == 0) 4484168404Spjd (void) printf(gettext("errors: No known data " 4485168404Spjd "errors\n")); 4486168404Spjd else if (!cbp->cb_verbose) 4487168404Spjd (void) printf(gettext("errors: %llu data " 4488168404Spjd "errors, use '-v' for a list\n"), 4489168404Spjd (u_longlong_t)nerr); 4490168404Spjd else 4491168404Spjd print_error_log(zhp); 4492168404Spjd } 4493219089Spjd 4494219089Spjd if (cbp->cb_dedup_stats) 4495219089Spjd print_dedup_stats(config); 4496168404Spjd } else { 4497168404Spjd (void) printf(gettext("config: The configuration cannot be " 4498168404Spjd "determined.\n")); 4499168404Spjd } 4500168404Spjd 4501168404Spjd return (0); 4502168404Spjd} 4503168404Spjd 4504168404Spjd/* 4505219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4506168404Spjd * 4507168404Spjd * -v Display complete error logs 4508168404Spjd * -x Display only pools with potential problems 4509219089Spjd * -D Display dedup status (undocumented) 4510219089Spjd * -T Display a timestamp in date(1) or Unix format 4511168404Spjd * 4512168404Spjd * Describes the health status of all pools or some subset. 4513168404Spjd */ 4514168404Spjdint 4515168404Spjdzpool_do_status(int argc, char **argv) 4516168404Spjd{ 4517168404Spjd int c; 4518168404Spjd int ret; 4519219089Spjd unsigned long interval = 0, count = 0; 4520168404Spjd status_cbdata_t cb = { 0 }; 4521168404Spjd 4522168404Spjd /* check options */ 4523219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4524168404Spjd switch (c) { 4525168404Spjd case 'v': 4526168404Spjd cb.cb_verbose = B_TRUE; 4527168404Spjd break; 4528168404Spjd case 'x': 4529168404Spjd cb.cb_explain = B_TRUE; 4530168404Spjd break; 4531219089Spjd case 'D': 4532219089Spjd cb.cb_dedup_stats = B_TRUE; 4533219089Spjd break; 4534219089Spjd case 'T': 4535219089Spjd get_timestamp_arg(*optarg); 4536219089Spjd break; 4537168404Spjd case '?': 4538168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4539168404Spjd optopt); 4540168404Spjd usage(B_FALSE); 4541168404Spjd } 4542168404Spjd } 4543168404Spjd 4544168404Spjd argc -= optind; 4545168404Spjd argv += optind; 4546168404Spjd 4547219089Spjd get_interval_count(&argc, argv, &interval, &count); 4548168404Spjd 4549168404Spjd if (argc == 0) 4550168404Spjd cb.cb_allpools = B_TRUE; 4551168404Spjd 4552219089Spjd cb.cb_first = B_TRUE; 4553168404Spjd 4554219089Spjd for (;;) { 4555219089Spjd if (timestamp_fmt != NODATE) 4556219089Spjd print_timestamp(timestamp_fmt); 4557168404Spjd 4558219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 4559219089Spjd status_callback, &cb); 4560219089Spjd 4561219089Spjd if (argc == 0 && cb.cb_count == 0) 4562219089Spjd (void) printf(gettext("no pools available\n")); 4563219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 4564219089Spjd (void) printf(gettext("all pools are healthy\n")); 4565219089Spjd 4566219089Spjd if (ret != 0) 4567219089Spjd return (ret); 4568219089Spjd 4569219089Spjd if (interval == 0) 4570219089Spjd break; 4571219089Spjd 4572219089Spjd if (count != 0 && --count == 0) 4573219089Spjd break; 4574219089Spjd 4575219089Spjd (void) sleep(interval); 4576219089Spjd } 4577219089Spjd 4578219089Spjd return (0); 4579168404Spjd} 4580168404Spjd 4581168404Spjdtypedef struct upgrade_cbdata { 4582277757Ssmh boolean_t cb_first; 4583277757Ssmh boolean_t cb_unavail; 4584307122Smav char cb_poolname[ZFS_MAX_DATASET_NAME_LEN]; 4585277757Ssmh int cb_argc; 4586277757Ssmh uint64_t cb_version; 4587277757Ssmh char **cb_argv; 4588168404Spjd} upgrade_cbdata_t; 4589168404Spjd 4590238950Smm#ifdef __FreeBSD__ 4591168404Spjdstatic int 4592212050Spjdis_root_pool(zpool_handle_t *zhp) 4593212050Spjd{ 4594212050Spjd static struct statfs sfs; 4595212050Spjd static char *poolname = NULL; 4596212050Spjd static boolean_t stated = B_FALSE; 4597212050Spjd char *slash; 4598212050Spjd 4599212067Spjd if (!stated) { 4600212050Spjd stated = B_TRUE; 4601212050Spjd if (statfs("/", &sfs) == -1) { 4602212050Spjd (void) fprintf(stderr, 4603212050Spjd "Unable to stat root file system: %s.\n", 4604212050Spjd strerror(errno)); 4605212067Spjd return (0); 4606212050Spjd } 4607212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4608212067Spjd return (0); 4609212050Spjd poolname = sfs.f_mntfromname; 4610212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4611212050Spjd *slash = '\0'; 4612212050Spjd } 4613212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4614212050Spjd} 4615212050Spjd 4616238950Smmstatic void 4617272063Ssmhroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size) 4618272063Ssmh{ 4619238950Smm 4620238950Smm if (poolname[0] == '\0' && is_root_pool(zhp)) 4621238950Smm (void) strlcpy(poolname, zpool_get_name(zhp), size); 4622238950Smm} 4623238950Smm#endif /* FreeBSD */ 4624238950Smm 4625212050Spjdstatic int 4626238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version) 4627238926Smm{ 4628238926Smm int ret; 4629238926Smm nvlist_t *config; 4630238926Smm uint64_t oldversion; 4631238926Smm 4632238926Smm config = zpool_get_config(zhp, NULL); 4633238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4634238926Smm &oldversion) == 0); 4635238926Smm 4636238926Smm assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 4637238926Smm assert(oldversion < version); 4638238926Smm 4639238926Smm ret = zpool_upgrade(zhp, version); 4640238926Smm if (ret != 0) 4641238926Smm return (ret); 4642238926Smm 4643238926Smm if (version >= SPA_VERSION_FEATURES) { 4644238926Smm (void) printf(gettext("Successfully upgraded " 4645238926Smm "'%s' from version %llu to feature flags.\n"), 4646238926Smm zpool_get_name(zhp), oldversion); 4647238926Smm } else { 4648238926Smm (void) printf(gettext("Successfully upgraded " 4649238926Smm "'%s' from version %llu to version %llu.\n"), 4650238926Smm zpool_get_name(zhp), oldversion, version); 4651238926Smm } 4652238926Smm 4653238926Smm return (0); 4654238926Smm} 4655238926Smm 4656238926Smmstatic int 4657238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp) 4658238926Smm{ 4659238926Smm int i, ret, count; 4660238926Smm boolean_t firstff = B_TRUE; 4661238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4662238926Smm 4663238926Smm count = 0; 4664238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4665238926Smm const char *fname = spa_feature_table[i].fi_uname; 4666238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4667238926Smm if (!nvlist_exists(enabled, fguid)) { 4668238926Smm char *propname; 4669238926Smm verify(-1 != asprintf(&propname, "feature@%s", fname)); 4670238926Smm ret = zpool_set_prop(zhp, propname, 4671238926Smm ZFS_FEATURE_ENABLED); 4672238926Smm if (ret != 0) { 4673238926Smm free(propname); 4674238926Smm return (ret); 4675238926Smm } 4676238926Smm count++; 4677238926Smm 4678238926Smm if (firstff) { 4679238926Smm (void) printf(gettext("Enabled the " 4680238926Smm "following features on '%s':\n"), 4681238926Smm zpool_get_name(zhp)); 4682238926Smm firstff = B_FALSE; 4683238926Smm } 4684238926Smm (void) printf(gettext(" %s\n"), fname); 4685238926Smm free(propname); 4686238926Smm } 4687238926Smm } 4688238926Smm 4689238926Smm if (countp != NULL) 4690238926Smm *countp = count; 4691238926Smm return (0); 4692238926Smm} 4693238926Smm 4694238926Smmstatic int 4695168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4696168404Spjd{ 4697168404Spjd upgrade_cbdata_t *cbp = arg; 4698168404Spjd nvlist_t *config; 4699168404Spjd uint64_t version; 4700238926Smm boolean_t printnl = B_FALSE; 4701238926Smm int ret; 4702168404Spjd 4703277628Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4704277628Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 4705277757Ssmh "currently unavailable.\n\n"), zpool_get_name(zhp)); 4706277757Ssmh cbp->cb_unavail = B_TRUE; 4707277628Ssmh /* Allow iteration to continue. */ 4708277628Ssmh return (0); 4709277628Ssmh } 4710277628Ssmh 4711168404Spjd config = zpool_get_config(zhp, NULL); 4712168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4713168404Spjd &version) == 0); 4714168404Spjd 4715238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4716168404Spjd 4717238926Smm if (version < cbp->cb_version) { 4718238926Smm cbp->cb_first = B_FALSE; 4719238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4720238926Smm if (ret != 0) 4721238926Smm return (ret); 4722238926Smm#ifdef __FreeBSD__ 4723238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4724238950Smm sizeof(cbp->cb_poolname)); 4725272063Ssmh#endif /* __FreeBSD__ */ 4726238926Smm printnl = B_TRUE; 4727238926Smm 4728238926Smm#ifdef illumos 4729238926Smm /* 4730238926Smm * If they did "zpool upgrade -a", then we could 4731238926Smm * be doing ioctls to different pools. We need 4732238926Smm * to log this history once to each pool, and bypass 4733238926Smm * the normal history logging that happens in main(). 4734238926Smm */ 4735238926Smm (void) zpool_log_history(g_zfs, history_str); 4736238926Smm log_history = B_FALSE; 4737238926Smm#endif 4738238926Smm } 4739238926Smm 4740238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4741238926Smm int count; 4742238926Smm ret = upgrade_enable_all(zhp, &count); 4743238926Smm if (ret != 0) 4744238926Smm return (ret); 4745238926Smm 4746238926Smm if (count > 0) { 4747168404Spjd cbp->cb_first = B_FALSE; 4748238926Smm printnl = B_TRUE; 4749272063Ssmh#ifdef __FreeBSD__ 4750272063Ssmh root_pool_upgrade_check(zhp, cbp->cb_poolname, 4751272063Ssmh sizeof(cbp->cb_poolname)); 4752272063Ssmh#endif /* __FreeBSD__ */ 4753248571Smm /* 4754248571Smm * If they did "zpool upgrade -a", then we could 4755248571Smm * be doing ioctls to different pools. We need 4756248571Smm * to log this history once to each pool, and bypass 4757248571Smm * the normal history logging that happens in main(). 4758248571Smm */ 4759248571Smm (void) zpool_log_history(g_zfs, history_str); 4760248571Smm log_history = B_FALSE; 4761168404Spjd } 4762238926Smm } 4763168404Spjd 4764238926Smm if (printnl) { 4765238926Smm (void) printf(gettext("\n")); 4766238926Smm } 4767238926Smm 4768238926Smm return (0); 4769238926Smm} 4770238926Smm 4771238926Smmstatic int 4772277757Ssmhupgrade_list_unavail(zpool_handle_t *zhp, void *arg) 4773277757Ssmh{ 4774277757Ssmh upgrade_cbdata_t *cbp = arg; 4775277757Ssmh 4776277757Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4777277757Ssmh if (cbp->cb_first) { 4778277757Ssmh (void) fprintf(stderr, gettext("The following pools " 4779277757Ssmh "are unavailable and cannot be upgraded as this " 4780277757Ssmh "time.\n\n")); 4781277757Ssmh (void) fprintf(stderr, gettext("POOL\n")); 4782277757Ssmh (void) fprintf(stderr, gettext("------------\n")); 4783277757Ssmh cbp->cb_first = B_FALSE; 4784277757Ssmh } 4785277757Ssmh (void) printf(gettext("%s\n"), zpool_get_name(zhp)); 4786277757Ssmh cbp->cb_unavail = B_TRUE; 4787277757Ssmh } 4788277757Ssmh return (0); 4789277757Ssmh} 4790277757Ssmh 4791277757Ssmhstatic int 4792238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 4793238926Smm{ 4794238926Smm upgrade_cbdata_t *cbp = arg; 4795238926Smm nvlist_t *config; 4796238926Smm uint64_t version; 4797238926Smm 4798277757Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4799277757Ssmh /* 4800277757Ssmh * This will have been reported by upgrade_list_unavail so 4801277757Ssmh * just allow iteration to continue. 4802277757Ssmh */ 4803277757Ssmh cbp->cb_unavail = B_TRUE; 4804277757Ssmh return (0); 4805277757Ssmh } 4806277757Ssmh 4807238926Smm config = zpool_get_config(zhp, NULL); 4808238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4809238926Smm &version) == 0); 4810238926Smm 4811238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4812238926Smm 4813238926Smm if (version < SPA_VERSION_FEATURES) { 4814168404Spjd if (cbp->cb_first) { 4815168404Spjd (void) printf(gettext("The following pools are " 4816238926Smm "formatted with legacy version numbers and can\n" 4817238926Smm "be upgraded to use feature flags. After " 4818238926Smm "being upgraded, these pools\nwill no " 4819238926Smm "longer be accessible by software that does not " 4820238926Smm "support feature\nflags.\n\n")); 4821168404Spjd (void) printf(gettext("VER POOL\n")); 4822168404Spjd (void) printf(gettext("--- ------------\n")); 4823168404Spjd cbp->cb_first = B_FALSE; 4824168404Spjd } 4825168404Spjd 4826168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4827168404Spjd zpool_get_name(zhp)); 4828168404Spjd } 4829168404Spjd 4830238926Smm return (0); 4831168404Spjd} 4832168404Spjd 4833238926Smmstatic int 4834238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 4835238926Smm{ 4836238926Smm upgrade_cbdata_t *cbp = arg; 4837238926Smm nvlist_t *config; 4838238926Smm uint64_t version; 4839238926Smm 4840277628Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4841277757Ssmh /* 4842277757Ssmh * This will have been reported by upgrade_list_unavail so 4843277757Ssmh * just allow iteration to continue. 4844277757Ssmh */ 4845277757Ssmh cbp->cb_unavail = B_TRUE; 4846277628Ssmh return (0); 4847277628Ssmh } 4848277628Ssmh 4849238926Smm config = zpool_get_config(zhp, NULL); 4850238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4851238926Smm &version) == 0); 4852238926Smm 4853238926Smm if (version >= SPA_VERSION_FEATURES) { 4854238926Smm int i; 4855238926Smm boolean_t poolfirst = B_TRUE; 4856238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4857238926Smm 4858238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4859238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4860238926Smm const char *fname = spa_feature_table[i].fi_uname; 4861238926Smm if (!nvlist_exists(enabled, fguid)) { 4862238926Smm if (cbp->cb_first) { 4863238926Smm (void) printf(gettext("\nSome " 4864238926Smm "supported features are not " 4865238926Smm "enabled on the following pools. " 4866238926Smm "Once a\nfeature is enabled the " 4867238926Smm "pool may become incompatible with " 4868238926Smm "software\nthat does not support " 4869238926Smm "the feature. See " 4870243014Smm "zpool-features(7) for " 4871238926Smm "details.\n\n")); 4872238926Smm (void) printf(gettext("POOL " 4873238926Smm "FEATURE\n")); 4874238926Smm (void) printf(gettext("------" 4875238926Smm "---------\n")); 4876238926Smm cbp->cb_first = B_FALSE; 4877238926Smm } 4878238926Smm 4879238926Smm if (poolfirst) { 4880238926Smm (void) printf(gettext("%s\n"), 4881238926Smm zpool_get_name(zhp)); 4882238926Smm poolfirst = B_FALSE; 4883238926Smm } 4884238926Smm 4885238926Smm (void) printf(gettext(" %s\n"), fname); 4886238926Smm } 4887238926Smm } 4888238926Smm } 4889238926Smm 4890238926Smm return (0); 4891238926Smm} 4892238926Smm 4893168404Spjd/* ARGSUSED */ 4894168404Spjdstatic int 4895168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 4896168404Spjd{ 4897238926Smm boolean_t printnl = B_FALSE; 4898185029Spjd upgrade_cbdata_t *cbp = data; 4899185029Spjd uint64_t cur_version; 4900168404Spjd int ret; 4901168404Spjd 4902277757Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4903277757Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 4904277757Ssmh "is currently unavailable.\n\n"), zpool_get_name(zhp)); 4905277757Ssmh cbp->cb_unavail = B_TRUE; 4906277757Ssmh return (1); 4907277757Ssmh } 4908277757Ssmh 4909185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 4910185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 4911185029Spjd "Pool 'log' must be renamed using export and import" 4912277757Ssmh " to upgrade.\n\n")); 4913185029Spjd return (1); 4914185029Spjd } 4915168404Spjd 4916185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4917185029Spjd if (cur_version > cbp->cb_version) { 4918168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 4919238926Smm "using more current version '%llu'.\n\n"), 4920185029Spjd zpool_get_name(zhp), cur_version); 4921185029Spjd return (0); 4922185029Spjd } 4923238926Smm 4924238926Smm if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 4925185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 4926238926Smm "using version %llu.\n\n"), zpool_get_name(zhp), 4927238926Smm cbp->cb_version); 4928168404Spjd return (0); 4929168404Spjd } 4930168404Spjd 4931238926Smm if (cur_version != cbp->cb_version) { 4932238926Smm printnl = B_TRUE; 4933238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4934238950Smm if (ret != 0) 4935238950Smm return (ret); 4936238926Smm#ifdef __FreeBSD__ 4937238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4938238950Smm sizeof(cbp->cb_poolname)); 4939272063Ssmh#endif /* __FreeBSD__ */ 4940238926Smm } 4941168404Spjd 4942238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4943238926Smm int count = 0; 4944238926Smm ret = upgrade_enable_all(zhp, &count); 4945238926Smm if (ret != 0) 4946238926Smm return (ret); 4947238926Smm 4948238926Smm if (count != 0) { 4949238926Smm printnl = B_TRUE; 4950238950Smm#ifdef __FreeBSD__ 4951238951Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4952238951Smm sizeof(cbp->cb_poolname)); 4953238950Smm#endif /* __FreeBSD __*/ 4954238926Smm } else if (cur_version == SPA_VERSION) { 4955238926Smm (void) printf(gettext("Pool '%s' already has all " 4956277757Ssmh "supported features enabled.\n\n"), 4957238926Smm zpool_get_name(zhp)); 4958238926Smm } 4959168404Spjd } 4960168404Spjd 4961238926Smm if (printnl) { 4962238926Smm (void) printf(gettext("\n")); 4963238926Smm } 4964238926Smm 4965238926Smm return (0); 4966168404Spjd} 4967168404Spjd 4968168404Spjd/* 4969168404Spjd * zpool upgrade 4970168404Spjd * zpool upgrade -v 4971185029Spjd * zpool upgrade [-V version] <-a | pool ...> 4972168404Spjd * 4973168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 4974168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 4975168404Spjd * upgrade all pools. 4976168404Spjd */ 4977168404Spjdint 4978168404Spjdzpool_do_upgrade(int argc, char **argv) 4979168404Spjd{ 4980168404Spjd int c; 4981168404Spjd upgrade_cbdata_t cb = { 0 }; 4982168404Spjd int ret = 0; 4983168404Spjd boolean_t showversions = B_FALSE; 4984238926Smm boolean_t upgradeall = B_FALSE; 4985185029Spjd char *end; 4986168404Spjd 4987185029Spjd 4988168404Spjd /* check options */ 4989219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 4990168404Spjd switch (c) { 4991168404Spjd case 'a': 4992238926Smm upgradeall = B_TRUE; 4993168404Spjd break; 4994168404Spjd case 'v': 4995168404Spjd showversions = B_TRUE; 4996168404Spjd break; 4997185029Spjd case 'V': 4998185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 4999236884Smm if (*end != '\0' || 5000236884Smm !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 5001185029Spjd (void) fprintf(stderr, 5002185029Spjd gettext("invalid version '%s'\n"), optarg); 5003185029Spjd usage(B_FALSE); 5004185029Spjd } 5005185029Spjd break; 5006219089Spjd case ':': 5007219089Spjd (void) fprintf(stderr, gettext("missing argument for " 5008219089Spjd "'%c' option\n"), optopt); 5009219089Spjd usage(B_FALSE); 5010219089Spjd break; 5011168404Spjd case '?': 5012168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5013168404Spjd optopt); 5014168404Spjd usage(B_FALSE); 5015168404Spjd } 5016168404Spjd } 5017168404Spjd 5018168404Spjd cb.cb_argc = argc; 5019168404Spjd cb.cb_argv = argv; 5020168404Spjd argc -= optind; 5021168404Spjd argv += optind; 5022168404Spjd 5023185029Spjd if (cb.cb_version == 0) { 5024185029Spjd cb.cb_version = SPA_VERSION; 5025238926Smm } else if (!upgradeall && argc == 0) { 5026185029Spjd (void) fprintf(stderr, gettext("-V option is " 5027185029Spjd "incompatible with other arguments\n")); 5028185029Spjd usage(B_FALSE); 5029185029Spjd } 5030185029Spjd 5031168404Spjd if (showversions) { 5032238926Smm if (upgradeall || argc != 0) { 5033168404Spjd (void) fprintf(stderr, gettext("-v option is " 5034168404Spjd "incompatible with other arguments\n")); 5035168404Spjd usage(B_FALSE); 5036168404Spjd } 5037238926Smm } else if (upgradeall) { 5038168404Spjd if (argc != 0) { 5039185029Spjd (void) fprintf(stderr, gettext("-a option should not " 5040185029Spjd "be used along with a pool name\n")); 5041168404Spjd usage(B_FALSE); 5042168404Spjd } 5043168404Spjd } 5044168404Spjd 5045236884Smm (void) printf(gettext("This system supports ZFS pool feature " 5046236884Smm "flags.\n\n")); 5047168404Spjd if (showversions) { 5048238926Smm int i; 5049238926Smm 5050238926Smm (void) printf(gettext("The following features are " 5051168404Spjd "supported:\n\n")); 5052238926Smm (void) printf(gettext("FEAT DESCRIPTION\n")); 5053238926Smm (void) printf("----------------------------------------------" 5054238926Smm "---------------\n"); 5055238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5056238926Smm zfeature_info_t *fi = &spa_feature_table[i]; 5057288572Smav const char *ro = 5058288572Smav (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ? 5059238926Smm " (read-only compatible)" : ""; 5060238926Smm 5061238926Smm (void) printf("%-37s%s\n", fi->fi_uname, ro); 5062238926Smm (void) printf(" %s\n", fi->fi_desc); 5063238926Smm } 5064238926Smm (void) printf("\n"); 5065238926Smm 5066238926Smm (void) printf(gettext("The following legacy versions are also " 5067238926Smm "supported:\n\n")); 5068168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 5069168404Spjd (void) printf("--- -----------------------------------------" 5070168404Spjd "---------------\n"); 5071168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 5072168404Spjd (void) printf(gettext(" 2 Ditto blocks " 5073168404Spjd "(replicated metadata)\n")); 5074168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 5075168404Spjd "RAID-Z\n")); 5076168404Spjd (void) printf(gettext(" 4 zpool history\n")); 5077168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 5078168404Spjd "algorithm\n")); 5079185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 5080185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 5081185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 5082185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 5083185029Spjd "properties\n")); 5084185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 5085185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 5086185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 5087185029Spjd (void) printf(gettext(" 13 snapused property\n")); 5088209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 5089209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 5090219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 5091219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 5092219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 5093219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 5094219089Spjd (void) printf(gettext(" 20 Compression using zle " 5095219089Spjd "(zero-length encoding)\n")); 5096219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 5097219089Spjd (void) printf(gettext(" 22 Received properties\n")); 5098219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 5099219089Spjd (void) printf(gettext(" 24 System attributes\n")); 5100219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 5101219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 5102219089Spjd "performance\n")); 5103219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 5104219089Spjd "performance\n")); 5105219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 5106219089Spjd (void) printf(gettext("\nFor more information on a particular " 5107219089Spjd "version, including supported releases,\n")); 5108219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 5109238926Smm } else if (argc == 0 && upgradeall) { 5110238926Smm cb.cb_first = B_TRUE; 5111168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 5112238926Smm if (ret == 0 && cb.cb_first) { 5113238926Smm if (cb.cb_version == SPA_VERSION) { 5114277757Ssmh (void) printf(gettext("All %spools are already " 5115277757Ssmh "formatted using feature flags.\n\n"), 5116277757Ssmh cb.cb_unavail ? gettext("available ") : ""); 5117277757Ssmh (void) printf(gettext("Every %sfeature flags " 5118238926Smm "pool already has all supported features " 5119277757Ssmh "enabled.\n"), 5120277757Ssmh cb.cb_unavail ? gettext("available ") : ""); 5121238926Smm } else { 5122238926Smm (void) printf(gettext("All pools are already " 5123238926Smm "formatted with version %llu or higher.\n"), 5124238926Smm cb.cb_version); 5125168404Spjd } 5126168404Spjd } 5127238926Smm } else if (argc == 0) { 5128238926Smm cb.cb_first = B_TRUE; 5129277757Ssmh ret = zpool_iter(g_zfs, upgrade_list_unavail, &cb); 5130277757Ssmh assert(ret == 0); 5131277757Ssmh 5132277757Ssmh if (!cb.cb_first) { 5133277757Ssmh (void) fprintf(stderr, "\n"); 5134277757Ssmh } 5135277757Ssmh 5136277757Ssmh cb.cb_first = B_TRUE; 5137238926Smm ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 5138238926Smm assert(ret == 0); 5139168404Spjd 5140238926Smm if (cb.cb_first) { 5141277757Ssmh (void) printf(gettext("All %spools are formatted using " 5142277757Ssmh "feature flags.\n\n"), cb.cb_unavail ? 5143277757Ssmh gettext("available ") : ""); 5144238926Smm } else { 5145238926Smm (void) printf(gettext("\nUse 'zpool upgrade -v' " 5146238926Smm "for a list of available legacy versions.\n")); 5147168404Spjd } 5148238926Smm 5149238926Smm cb.cb_first = B_TRUE; 5150238926Smm ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 5151238926Smm assert(ret == 0); 5152238926Smm 5153238926Smm if (cb.cb_first) { 5154277757Ssmh (void) printf(gettext("Every %sfeature flags pool has " 5155277757Ssmh "all supported features enabled.\n"), 5156277757Ssmh cb.cb_unavail ? gettext("available ") : ""); 5157238926Smm } else { 5158238926Smm (void) printf(gettext("\n")); 5159238926Smm } 5160168404Spjd } else { 5161277757Ssmh ret = for_each_pool(argc, argv, B_TRUE, NULL, 5162168404Spjd upgrade_one, &cb); 5163168404Spjd } 5164168404Spjd 5165212050Spjd if (cb.cb_poolname[0] != '\0') { 5166212050Spjd (void) printf( 5167212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 5168212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 5169212050Spjd "the following command will do it:\n" 5170212050Spjd "\n" 5171212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 5172212050Spjd cb.cb_poolname); 5173212050Spjd } 5174212050Spjd 5175168404Spjd return (ret); 5176168404Spjd} 5177168404Spjd 5178185029Spjdtypedef struct hist_cbdata { 5179185029Spjd boolean_t first; 5180248571Smm boolean_t longfmt; 5181248571Smm boolean_t internal; 5182185029Spjd} hist_cbdata_t; 5183185029Spjd 5184168404Spjd/* 5185168404Spjd * Print out the command history for a specific pool. 5186168404Spjd */ 5187168404Spjdstatic int 5188168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 5189168404Spjd{ 5190168404Spjd nvlist_t *nvhis; 5191168404Spjd nvlist_t **records; 5192168404Spjd uint_t numrecords; 5193168404Spjd int ret, i; 5194185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 5195168404Spjd 5196185029Spjd cb->first = B_FALSE; 5197168404Spjd 5198168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 5199168404Spjd 5200168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 5201168404Spjd return (ret); 5202168404Spjd 5203168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 5204168404Spjd &records, &numrecords) == 0); 5205168404Spjd for (i = 0; i < numrecords; i++) { 5206248571Smm nvlist_t *rec = records[i]; 5207248571Smm char tbuf[30] = ""; 5208185029Spjd 5209248571Smm if (nvlist_exists(rec, ZPOOL_HIST_TIME)) { 5210248571Smm time_t tsec; 5211248571Smm struct tm t; 5212185029Spjd 5213248571Smm tsec = fnvlist_lookup_uint64(records[i], 5214248571Smm ZPOOL_HIST_TIME); 5215248571Smm (void) localtime_r(&tsec, &t); 5216248571Smm (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 5217248571Smm } 5218248571Smm 5219248571Smm if (nvlist_exists(rec, ZPOOL_HIST_CMD)) { 5220248571Smm (void) printf("%s %s", tbuf, 5221248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_CMD)); 5222248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) { 5223248571Smm int ievent = 5224248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT); 5225248571Smm if (!cb->internal) 5226185029Spjd continue; 5227248571Smm if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) { 5228248571Smm (void) printf("%s unrecognized record:\n", 5229248571Smm tbuf); 5230248571Smm dump_nvlist(rec, 4); 5231185029Spjd continue; 5232248571Smm } 5233248571Smm (void) printf("%s [internal %s txg:%lld] %s", tbuf, 5234248571Smm zfs_history_event_names[ievent], 5235248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5236248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR)); 5237248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) { 5238248571Smm if (!cb->internal) 5239248571Smm continue; 5240248571Smm (void) printf("%s [txg:%lld] %s", tbuf, 5241248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5242248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME)); 5243248571Smm if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) { 5244248571Smm (void) printf(" %s (%llu)", 5245248571Smm fnvlist_lookup_string(rec, 5246248571Smm ZPOOL_HIST_DSNAME), 5247248571Smm fnvlist_lookup_uint64(rec, 5248248571Smm ZPOOL_HIST_DSID)); 5249248571Smm } 5250248571Smm (void) printf(" %s", fnvlist_lookup_string(rec, 5251248571Smm ZPOOL_HIST_INT_STR)); 5252248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) { 5253248571Smm if (!cb->internal) 5254248571Smm continue; 5255248571Smm (void) printf("%s ioctl %s\n", tbuf, 5256248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL)); 5257248571Smm if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) { 5258248571Smm (void) printf(" input:\n"); 5259248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5260248571Smm ZPOOL_HIST_INPUT_NVL), 8); 5261248571Smm } 5262248571Smm if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) { 5263248571Smm (void) printf(" output:\n"); 5264248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5265248571Smm ZPOOL_HIST_OUTPUT_NVL), 8); 5266248571Smm } 5267248571Smm } else { 5268248571Smm if (!cb->internal) 5269248571Smm continue; 5270248571Smm (void) printf("%s unrecognized record:\n", tbuf); 5271248571Smm dump_nvlist(rec, 4); 5272168404Spjd } 5273185029Spjd 5274185029Spjd if (!cb->longfmt) { 5275185029Spjd (void) printf("\n"); 5276185029Spjd continue; 5277185029Spjd } 5278185029Spjd (void) printf(" ["); 5279248571Smm if (nvlist_exists(rec, ZPOOL_HIST_WHO)) { 5280248571Smm uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO); 5281248571Smm struct passwd *pwd = getpwuid(who); 5282248571Smm (void) printf("user %d ", (int)who); 5283248571Smm if (pwd != NULL) 5284248571Smm (void) printf("(%s) ", pwd->pw_name); 5285185029Spjd } 5286248571Smm if (nvlist_exists(rec, ZPOOL_HIST_HOST)) { 5287248571Smm (void) printf("on %s", 5288248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_HOST)); 5289185029Spjd } 5290248571Smm if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) { 5291248571Smm (void) printf(":%s", 5292248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE)); 5293185029Spjd } 5294185029Spjd (void) printf("]"); 5295185029Spjd (void) printf("\n"); 5296168404Spjd } 5297168404Spjd (void) printf("\n"); 5298168404Spjd nvlist_free(nvhis); 5299168404Spjd 5300168404Spjd return (ret); 5301168404Spjd} 5302168404Spjd 5303168404Spjd/* 5304168404Spjd * zpool history <pool> 5305168404Spjd * 5306168404Spjd * Displays the history of commands that modified pools. 5307168404Spjd */ 5308168404Spjdint 5309168404Spjdzpool_do_history(int argc, char **argv) 5310168404Spjd{ 5311185029Spjd hist_cbdata_t cbdata = { 0 }; 5312168404Spjd int ret; 5313185029Spjd int c; 5314168404Spjd 5315185029Spjd cbdata.first = B_TRUE; 5316185029Spjd /* check options */ 5317185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 5318185029Spjd switch (c) { 5319185029Spjd case 'l': 5320248571Smm cbdata.longfmt = B_TRUE; 5321185029Spjd break; 5322185029Spjd case 'i': 5323248571Smm cbdata.internal = B_TRUE; 5324185029Spjd break; 5325185029Spjd case '?': 5326185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5327185029Spjd optopt); 5328185029Spjd usage(B_FALSE); 5329185029Spjd } 5330185029Spjd } 5331168404Spjd argc -= optind; 5332168404Spjd argv += optind; 5333168404Spjd 5334168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 5335185029Spjd &cbdata); 5336168404Spjd 5337185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 5338168404Spjd (void) printf(gettext("no pools available\n")); 5339168404Spjd return (0); 5340168404Spjd } 5341168404Spjd 5342168404Spjd return (ret); 5343168404Spjd} 5344168404Spjd 5345168404Spjdstatic int 5346168404Spjdget_callback(zpool_handle_t *zhp, void *data) 5347168404Spjd{ 5348185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 5349168404Spjd char value[MAXNAMELEN]; 5350185029Spjd zprop_source_t srctype; 5351185029Spjd zprop_list_t *pl; 5352168404Spjd 5353168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 5354168404Spjd 5355168404Spjd /* 5356185029Spjd * Skip the special fake placeholder. This will also skip 5357185029Spjd * over the name property when 'all' is specified. 5358168404Spjd */ 5359185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 5360168404Spjd pl == cbp->cb_proplist) 5361168404Spjd continue; 5362168404Spjd 5363236884Smm if (pl->pl_prop == ZPROP_INVAL && 5364236884Smm (zpool_prop_feature(pl->pl_user_prop) || 5365236884Smm zpool_prop_unsupported(pl->pl_user_prop))) { 5366236884Smm srctype = ZPROP_SRC_LOCAL; 5367168404Spjd 5368236884Smm if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 5369236884Smm value, sizeof (value)) == 0) { 5370236884Smm zprop_print_one_property(zpool_get_name(zhp), 5371236884Smm cbp, pl->pl_user_prop, value, srctype, 5372236884Smm NULL, NULL); 5373236884Smm } 5374236884Smm } else { 5375236884Smm if (zpool_get_prop(zhp, pl->pl_prop, value, 5376264335Sdelphij sizeof (value), &srctype, cbp->cb_literal) != 0) 5377236884Smm continue; 5378236884Smm 5379236884Smm zprop_print_one_property(zpool_get_name(zhp), cbp, 5380236884Smm zpool_prop_to_name(pl->pl_prop), value, srctype, 5381236884Smm NULL, NULL); 5382236884Smm } 5383168404Spjd } 5384168404Spjd return (0); 5385168404Spjd} 5386168404Spjd 5387264335Sdelphij/* 5388264335Sdelphij * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ... 5389264335Sdelphij * 5390264335Sdelphij * -H Scripted mode. Don't display headers, and separate properties 5391264335Sdelphij * by a single tab. 5392264335Sdelphij * -o List of columns to display. Defaults to 5393264335Sdelphij * "name,property,value,source". 5394264335Sdelphij * -p Diplay values in parsable (exact) format. 5395264335Sdelphij * 5396264335Sdelphij * Get properties of pools in the system. Output space statistics 5397264335Sdelphij * for each one as well as other attributes. 5398264335Sdelphij */ 5399168404Spjdint 5400168404Spjdzpool_do_get(int argc, char **argv) 5401168404Spjd{ 5402185029Spjd zprop_get_cbdata_t cb = { 0 }; 5403185029Spjd zprop_list_t fake_name = { 0 }; 5404168404Spjd int ret; 5405264335Sdelphij int c, i; 5406264335Sdelphij char *value; 5407168404Spjd 5408264335Sdelphij cb.cb_first = B_TRUE; 5409168404Spjd 5410264335Sdelphij /* 5411264335Sdelphij * Set up default columns and sources. 5412264335Sdelphij */ 5413185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 5414168404Spjd cb.cb_columns[0] = GET_COL_NAME; 5415168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 5416168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 5417168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 5418185029Spjd cb.cb_type = ZFS_TYPE_POOL; 5419168404Spjd 5420264335Sdelphij /* check options */ 5421264335Sdelphij while ((c = getopt(argc, argv, ":Hpo:")) != -1) { 5422264335Sdelphij switch (c) { 5423264335Sdelphij case 'p': 5424264335Sdelphij cb.cb_literal = B_TRUE; 5425264335Sdelphij break; 5426264335Sdelphij case 'H': 5427264335Sdelphij cb.cb_scripted = B_TRUE; 5428264335Sdelphij break; 5429264335Sdelphij case 'o': 5430264335Sdelphij bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 5431264335Sdelphij i = 0; 5432264335Sdelphij while (*optarg != '\0') { 5433264335Sdelphij static char *col_subopts[] = 5434264335Sdelphij { "name", "property", "value", "source", 5435264335Sdelphij "all", NULL }; 5436264335Sdelphij 5437264335Sdelphij if (i == ZFS_GET_NCOLS) { 5438264335Sdelphij (void) fprintf(stderr, gettext("too " 5439264335Sdelphij "many fields given to -o " 5440264335Sdelphij "option\n")); 5441264335Sdelphij usage(B_FALSE); 5442264335Sdelphij } 5443264335Sdelphij 5444264335Sdelphij switch (getsubopt(&optarg, col_subopts, 5445264335Sdelphij &value)) { 5446264335Sdelphij case 0: 5447264335Sdelphij cb.cb_columns[i++] = GET_COL_NAME; 5448264335Sdelphij break; 5449264335Sdelphij case 1: 5450264335Sdelphij cb.cb_columns[i++] = GET_COL_PROPERTY; 5451264335Sdelphij break; 5452264335Sdelphij case 2: 5453264335Sdelphij cb.cb_columns[i++] = GET_COL_VALUE; 5454264335Sdelphij break; 5455264335Sdelphij case 3: 5456264335Sdelphij cb.cb_columns[i++] = GET_COL_SOURCE; 5457264335Sdelphij break; 5458264335Sdelphij case 4: 5459264335Sdelphij if (i > 0) { 5460264335Sdelphij (void) fprintf(stderr, 5461264335Sdelphij gettext("\"all\" conflicts " 5462264335Sdelphij "with specific fields " 5463264335Sdelphij "given to -o option\n")); 5464264335Sdelphij usage(B_FALSE); 5465264335Sdelphij } 5466264335Sdelphij cb.cb_columns[0] = GET_COL_NAME; 5467264335Sdelphij cb.cb_columns[1] = GET_COL_PROPERTY; 5468264335Sdelphij cb.cb_columns[2] = GET_COL_VALUE; 5469264335Sdelphij cb.cb_columns[3] = GET_COL_SOURCE; 5470264335Sdelphij i = ZFS_GET_NCOLS; 5471264335Sdelphij break; 5472264335Sdelphij default: 5473264335Sdelphij (void) fprintf(stderr, 5474264335Sdelphij gettext("invalid column name " 5475296436Sdim "'%s'\n"), suboptarg); 5476264335Sdelphij usage(B_FALSE); 5477264335Sdelphij } 5478264335Sdelphij } 5479264335Sdelphij break; 5480264335Sdelphij case '?': 5481264335Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5482264335Sdelphij optopt); 5483264335Sdelphij usage(B_FALSE); 5484264335Sdelphij } 5485264335Sdelphij } 5486264335Sdelphij 5487264335Sdelphij argc -= optind; 5488264335Sdelphij argv += optind; 5489264335Sdelphij 5490264335Sdelphij if (argc < 1) { 5491264335Sdelphij (void) fprintf(stderr, gettext("missing property " 5492264335Sdelphij "argument\n")); 5493264335Sdelphij usage(B_FALSE); 5494264335Sdelphij } 5495264335Sdelphij 5496264335Sdelphij if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, 5497185029Spjd ZFS_TYPE_POOL) != 0) 5498168404Spjd usage(B_FALSE); 5499168404Spjd 5500264335Sdelphij argc--; 5501264335Sdelphij argv++; 5502264335Sdelphij 5503168404Spjd if (cb.cb_proplist != NULL) { 5504185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 5505168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 5506168404Spjd fake_name.pl_next = cb.cb_proplist; 5507168404Spjd cb.cb_proplist = &fake_name; 5508168404Spjd } 5509168404Spjd 5510264335Sdelphij ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 5511168404Spjd get_callback, &cb); 5512168404Spjd 5513168404Spjd if (cb.cb_proplist == &fake_name) 5514185029Spjd zprop_free_list(fake_name.pl_next); 5515168404Spjd else 5516185029Spjd zprop_free_list(cb.cb_proplist); 5517168404Spjd 5518168404Spjd return (ret); 5519168404Spjd} 5520168404Spjd 5521168404Spjdtypedef struct set_cbdata { 5522168404Spjd char *cb_propname; 5523168404Spjd char *cb_value; 5524168404Spjd boolean_t cb_any_successful; 5525168404Spjd} set_cbdata_t; 5526168404Spjd 5527168404Spjdint 5528168404Spjdset_callback(zpool_handle_t *zhp, void *data) 5529168404Spjd{ 5530168404Spjd int error; 5531168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 5532168404Spjd 5533168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 5534168404Spjd 5535168404Spjd if (!error) 5536168404Spjd cb->cb_any_successful = B_TRUE; 5537168404Spjd 5538168404Spjd return (error); 5539168404Spjd} 5540168404Spjd 5541168404Spjdint 5542168404Spjdzpool_do_set(int argc, char **argv) 5543168404Spjd{ 5544168404Spjd set_cbdata_t cb = { 0 }; 5545168404Spjd int error; 5546168404Spjd 5547168404Spjd if (argc > 1 && argv[1][0] == '-') { 5548168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5549168404Spjd argv[1][1]); 5550168404Spjd usage(B_FALSE); 5551168404Spjd } 5552168404Spjd 5553168404Spjd if (argc < 2) { 5554168404Spjd (void) fprintf(stderr, gettext("missing property=value " 5555168404Spjd "argument\n")); 5556168404Spjd usage(B_FALSE); 5557168404Spjd } 5558168404Spjd 5559168404Spjd if (argc < 3) { 5560168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 5561168404Spjd usage(B_FALSE); 5562168404Spjd } 5563168404Spjd 5564168404Spjd if (argc > 3) { 5565168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 5566168404Spjd usage(B_FALSE); 5567168404Spjd } 5568168404Spjd 5569168404Spjd cb.cb_propname = argv[1]; 5570168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 5571168404Spjd if (cb.cb_value == NULL) { 5572168404Spjd (void) fprintf(stderr, gettext("missing value in " 5573168404Spjd "property=value argument\n")); 5574168404Spjd usage(B_FALSE); 5575168404Spjd } 5576168404Spjd 5577168404Spjd *(cb.cb_value) = '\0'; 5578168404Spjd cb.cb_value++; 5579168404Spjd 5580168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 5581168404Spjd set_callback, &cb); 5582168404Spjd 5583168404Spjd return (error); 5584168404Spjd} 5585168404Spjd 5586168404Spjdstatic int 5587168404Spjdfind_command_idx(char *command, int *idx) 5588168404Spjd{ 5589168404Spjd int i; 5590168404Spjd 5591168404Spjd for (i = 0; i < NCOMMAND; i++) { 5592168404Spjd if (command_table[i].name == NULL) 5593168404Spjd continue; 5594168404Spjd 5595168404Spjd if (strcmp(command, command_table[i].name) == 0) { 5596168404Spjd *idx = i; 5597168404Spjd return (0); 5598168404Spjd } 5599168404Spjd } 5600168404Spjd return (1); 5601168404Spjd} 5602168404Spjd 5603168404Spjdint 5604168404Spjdmain(int argc, char **argv) 5605168404Spjd{ 5606297119Smav int ret = 0; 5607168404Spjd int i; 5608168404Spjd char *cmdname; 5609168404Spjd 5610168404Spjd (void) setlocale(LC_ALL, ""); 5611168404Spjd (void) textdomain(TEXT_DOMAIN); 5612168404Spjd 5613168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 5614168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 5615168404Spjd "initialize ZFS library\n")); 5616168404Spjd return (1); 5617168404Spjd } 5618168404Spjd 5619168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 5620168404Spjd 5621168404Spjd opterr = 0; 5622168404Spjd 5623168404Spjd /* 5624168404Spjd * Make sure the user has specified some command. 5625168404Spjd */ 5626168404Spjd if (argc < 2) { 5627168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 5628168404Spjd usage(B_FALSE); 5629168404Spjd } 5630168404Spjd 5631168404Spjd cmdname = argv[1]; 5632168404Spjd 5633168404Spjd /* 5634168404Spjd * Special case '-?' 5635168404Spjd */ 5636168404Spjd if (strcmp(cmdname, "-?") == 0) 5637168404Spjd usage(B_TRUE); 5638168404Spjd 5639248571Smm zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); 5640185029Spjd 5641168404Spjd /* 5642168404Spjd * Run the appropriate command. 5643168404Spjd */ 5644168404Spjd if (find_command_idx(cmdname, &i) == 0) { 5645168404Spjd current_command = &command_table[i]; 5646168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 5647185029Spjd } else if (strchr(cmdname, '=')) { 5648185029Spjd verify(find_command_idx("set", &i) == 0); 5649185029Spjd current_command = &command_table[i]; 5650185029Spjd ret = command_table[i].func(argc, argv); 5651185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 5652185029Spjd /* 5653185029Spjd * 'freeze' is a vile debugging abomination, so we treat 5654185029Spjd * it as such. 5655185029Spjd */ 5656252059Ssmh zfs_cmd_t zc = { 0 }; 5657252059Ssmh (void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name)); 5658252059Ssmh return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc)); 5659185029Spjd } else { 5660168404Spjd (void) fprintf(stderr, gettext("unrecognized " 5661168404Spjd "command '%s'\n"), cmdname); 5662168404Spjd usage(B_FALSE); 5663168404Spjd } 5664168404Spjd 5665248571Smm if (ret == 0 && log_history) 5666248571Smm (void) zpool_log_history(g_zfs, history_str); 5667248571Smm 5668168404Spjd libzfs_fini(g_zfs); 5669168404Spjd 5670168404Spjd /* 5671168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 5672168404Spjd * for the purposes of running ::findleaks. 5673168404Spjd */ 5674168404Spjd if (getenv("ZFS_ABORT") != NULL) { 5675168404Spjd (void) printf("dumping core by request\n"); 5676168404Spjd abort(); 5677168404Spjd } 5678168404Spjd 5679168404Spjd return (ret); 5680168404Spjd} 5681