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. 24332525Smav * Copyright (c) 2011, 2018 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. 28296537Smav * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. 29297763Smav * Copyright 2016 Nexenta Systems, Inc. 30324010Savg * Copyright (c) 2017 Datto Inc. 31168404Spjd */ 32168404Spjd 33168404Spjd#include <solaris.h> 34168404Spjd#include <assert.h> 35168404Spjd#include <ctype.h> 36168404Spjd#include <dirent.h> 37168404Spjd#include <errno.h> 38168404Spjd#include <fcntl.h> 39332547Smav#include <getopt.h> 40168404Spjd#include <libgen.h> 41168404Spjd#include <libintl.h> 42168404Spjd#include <libuutil.h> 43168404Spjd#include <locale.h> 44168404Spjd#include <stdio.h> 45168404Spjd#include <stdlib.h> 46168404Spjd#include <string.h> 47168404Spjd#include <strings.h> 48168404Spjd#include <unistd.h> 49168404Spjd#include <priv.h> 50185029Spjd#include <pwd.h> 51185029Spjd#include <zone.h> 52168404Spjd#include <sys/time.h> 53236155Smm#include <zfs_prop.h> 54168404Spjd#include <sys/fs/zfs.h> 55168404Spjd#include <sys/stat.h> 56168404Spjd 57168404Spjd#include <libzfs.h> 58168404Spjd 59168404Spjd#include "zpool_util.h" 60185029Spjd#include "zfs_comutil.h" 61236884Smm#include "zfeature_common.h" 62168404Spjd 63219089Spjd#include "statcommon.h" 64219089Spjd 65359754Skevanslibzfs_handle_t *g_zfs; 66359754Skevans 67168404Spjdstatic int zpool_do_create(int, char **); 68168404Spjdstatic int zpool_do_destroy(int, char **); 69168404Spjd 70168404Spjdstatic int zpool_do_add(int, char **); 71168404Spjdstatic int zpool_do_remove(int, char **); 72224171Sgibbsstatic int zpool_do_labelclear(int, char **); 73168404Spjd 74332547Smavstatic int zpool_do_checkpoint(int, char **); 75332547Smav 76168404Spjdstatic int zpool_do_list(int, char **); 77168404Spjdstatic int zpool_do_iostat(int, char **); 78168404Spjdstatic int zpool_do_status(int, char **); 79168404Spjd 80168404Spjdstatic int zpool_do_online(int, char **); 81168404Spjdstatic int zpool_do_offline(int, char **); 82168404Spjdstatic int zpool_do_clear(int, char **); 83236155Smmstatic int zpool_do_reopen(int, char **); 84168404Spjd 85228103Smmstatic int zpool_do_reguid(int, char **); 86228103Smm 87168404Spjdstatic int zpool_do_attach(int, char **); 88168404Spjdstatic int zpool_do_detach(int, char **); 89168404Spjdstatic int zpool_do_replace(int, char **); 90219089Spjdstatic int zpool_do_split(int, char **); 91168404Spjd 92339111Smavstatic int zpool_do_initialize(int, char **); 93168404Spjdstatic int zpool_do_scrub(int, char **); 94168404Spjd 95168404Spjdstatic int zpool_do_import(int, char **); 96168404Spjdstatic int zpool_do_export(int, char **); 97168404Spjd 98168404Spjdstatic int zpool_do_upgrade(int, char **); 99168404Spjd 100168404Spjdstatic int zpool_do_history(int, char **); 101168404Spjd 102168404Spjdstatic int zpool_do_get(int, char **); 103168404Spjdstatic int zpool_do_set(int, char **); 104168404Spjd 105168404Spjd/* 106168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 107168404Spjd * debugging facilities. 108168404Spjd */ 109185029Spjd 110185029Spjd#ifdef DEBUG 111168404Spjdconst char * 112168404Spjd_umem_debug_init(void) 113168404Spjd{ 114168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 115168404Spjd} 116168404Spjd 117168404Spjdconst char * 118168404Spjd_umem_logging_init(void) 119168404Spjd{ 120168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 121168404Spjd} 122185029Spjd#endif 123168404Spjd 124168404Spjdtypedef enum { 125168404Spjd HELP_ADD, 126168404Spjd HELP_ATTACH, 127168404Spjd HELP_CLEAR, 128168404Spjd HELP_CREATE, 129332547Smav HELP_CHECKPOINT, 130168404Spjd HELP_DESTROY, 131168404Spjd HELP_DETACH, 132168404Spjd HELP_EXPORT, 133168404Spjd HELP_HISTORY, 134168404Spjd HELP_IMPORT, 135168404Spjd HELP_IOSTAT, 136224171Sgibbs HELP_LABELCLEAR, 137168404Spjd HELP_LIST, 138168404Spjd HELP_OFFLINE, 139168404Spjd HELP_ONLINE, 140168404Spjd HELP_REPLACE, 141168404Spjd HELP_REMOVE, 142339111Smav HELP_INITIALIZE, 143168404Spjd HELP_SCRUB, 144168404Spjd HELP_STATUS, 145168404Spjd HELP_UPGRADE, 146168404Spjd HELP_GET, 147219089Spjd HELP_SET, 148228103Smm HELP_SPLIT, 149236155Smm HELP_REGUID, 150236155Smm HELP_REOPEN 151168404Spjd} zpool_help_t; 152168404Spjd 153168404Spjd 154168404Spjdtypedef struct zpool_command { 155168404Spjd const char *name; 156168404Spjd int (*func)(int, char **); 157168404Spjd zpool_help_t usage; 158168404Spjd} zpool_command_t; 159168404Spjd 160168404Spjd/* 161168404Spjd * Master command table. Each ZFS command has a name, associated function, and 162168404Spjd * usage message. The usage messages need to be internationalized, so we have 163168404Spjd * to have a function to return the usage message based on a command index. 164168404Spjd * 165168404Spjd * These commands are organized according to how they are displayed in the usage 166168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 167168404Spjd * the generic usage message. 168168404Spjd */ 169168404Spjdstatic zpool_command_t command_table[] = { 170168404Spjd { "create", zpool_do_create, HELP_CREATE }, 171168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 172168404Spjd { NULL }, 173168404Spjd { "add", zpool_do_add, HELP_ADD }, 174168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 175168404Spjd { NULL }, 176224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 177224171Sgibbs { NULL }, 178332547Smav { "checkpoint", zpool_do_checkpoint, HELP_CHECKPOINT }, 179332547Smav { NULL }, 180168404Spjd { "list", zpool_do_list, HELP_LIST }, 181168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 182168404Spjd { "status", zpool_do_status, HELP_STATUS }, 183168404Spjd { NULL }, 184168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 185168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 186168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 187236155Smm { "reopen", zpool_do_reopen, HELP_REOPEN }, 188168404Spjd { NULL }, 189168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 190168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 191168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 192219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 193168404Spjd { NULL }, 194339111Smav { "initialize", zpool_do_initialize, HELP_INITIALIZE }, 195168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 196168404Spjd { NULL }, 197168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 198168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 199168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 200228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 201168404Spjd { NULL }, 202168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 203168404Spjd { "get", zpool_do_get, HELP_GET }, 204168404Spjd { "set", zpool_do_set, HELP_SET }, 205168404Spjd}; 206168404Spjd 207168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 208168404Spjd 209248571Smmstatic zpool_command_t *current_command; 210185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 211248571Smmstatic boolean_t log_history = B_TRUE; 212219089Spjdstatic uint_t timestamp_fmt = NODATE; 213219089Spjd 214168404Spjdstatic const char * 215289562Smavget_usage(zpool_help_t idx) 216289562Smav{ 217168404Spjd switch (idx) { 218168404Spjd case HELP_ADD: 219168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 220168404Spjd case HELP_ATTACH: 221168404Spjd return (gettext("\tattach [-f] <pool> <device> " 222185029Spjd "<new-device>\n")); 223168404Spjd case HELP_CLEAR: 224219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 225168404Spjd case HELP_CREATE: 226331395Smav return (gettext("\tcreate [-fnd] [-B] " 227331395Smav "[-o property=value] ... \n" 228333194Savg "\t [-O file-system-property=value] ...\n" 229333194Savg "\t [-m mountpoint] [-R root] [-t tempname] " 230333194Savg "<pool> <vdev> ...\n")); 231332547Smav case HELP_CHECKPOINT: 232332547Smav return (gettext("\tcheckpoint [--discard] <pool> ...\n")); 233168404Spjd case HELP_DESTROY: 234168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 235168404Spjd case HELP_DETACH: 236168404Spjd return (gettext("\tdetach <pool> <device>\n")); 237168404Spjd case HELP_EXPORT: 238168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 239168404Spjd case HELP_HISTORY: 240185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 241168404Spjd case HELP_IMPORT: 242168404Spjd return (gettext("\timport [-d dir] [-D]\n" 243185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 244219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 245219089Spjd "[-R root] [-F [-n]] -a\n" 246185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 247219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 248333194Savg "[-R root] [-F [-n]] [-t]\n" 249332547Smav "\t [--rewind-to-checkpoint] <pool | id> [newpool]\n")); 250168404Spjd case HELP_IOSTAT: 251219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 252168404Spjd "[count]]\n")); 253224171Sgibbs case HELP_LABELCLEAR: 254224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 255168404Spjd case HELP_LIST: 256263889Sdelphij return (gettext("\tlist [-Hpv] [-o property[,...]] " 257219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 258168404Spjd case HELP_OFFLINE: 259168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 260168404Spjd case HELP_ONLINE: 261228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 262168404Spjd case HELP_REPLACE: 263168404Spjd return (gettext("\treplace [-f] <pool> <device> " 264185029Spjd "[new-device]\n")); 265168404Spjd case HELP_REMOVE: 266332525Smav return (gettext("\tremove [-nps] <pool> <device> ...\n")); 267236155Smm case HELP_REOPEN: 268260138Sdelphij return (gettext("\treopen <pool>\n")); 269339111Smav case HELP_INITIALIZE: 270339111Smav return (gettext("\tinitialize [-cs] <pool> [<device> ...]\n")); 271168404Spjd case HELP_SCRUB: 272324010Savg return (gettext("\tscrub [-s | -p] <pool> ...\n")); 273168404Spjd case HELP_STATUS: 274219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 275219089Spjd "[count]]\n")); 276168404Spjd case HELP_UPGRADE: 277228020Smm return (gettext("\tupgrade [-v]\n" 278185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 279168404Spjd case HELP_GET: 280263889Sdelphij return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] " 281263889Sdelphij "<\"all\" | property[,...]> <pool> ...\n")); 282168404Spjd case HELP_SET: 283168404Spjd return (gettext("\tset <property=value> <pool> \n")); 284219089Spjd case HELP_SPLIT: 285219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 286219089Spjd "\t [-o property=value] <pool> <newpool> " 287219089Spjd "[<device> ...]\n")); 288228103Smm case HELP_REGUID: 289228103Smm return (gettext("\treguid <pool>\n")); 290168404Spjd } 291168404Spjd 292168404Spjd abort(); 293168404Spjd /* NOTREACHED */ 294168404Spjd} 295168404Spjd 296168404Spjd 297168404Spjd/* 298168404Spjd * Callback routine that will print out a pool property value. 299168404Spjd */ 300185029Spjdstatic int 301185029Spjdprint_prop_cb(int prop, void *cb) 302168404Spjd{ 303168404Spjd FILE *fp = cb; 304168404Spjd 305219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 306168404Spjd 307185029Spjd if (zpool_prop_readonly(prop)) 308185029Spjd (void) fprintf(fp, " NO "); 309185029Spjd else 310219089Spjd (void) fprintf(fp, " YES "); 311185029Spjd 312168404Spjd if (zpool_prop_values(prop) == NULL) 313168404Spjd (void) fprintf(fp, "-\n"); 314168404Spjd else 315168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 316168404Spjd 317185029Spjd return (ZPROP_CONT); 318168404Spjd} 319168404Spjd 320168404Spjd/* 321168404Spjd * Display usage message. If we're inside a command, display only the usage for 322168404Spjd * that command. Otherwise, iterate over the entire command table and display 323168404Spjd * a complete usage message. 324168404Spjd */ 325168404Spjdvoid 326168404Spjdusage(boolean_t requested) 327168404Spjd{ 328168404Spjd FILE *fp = requested ? stdout : stderr; 329168404Spjd 330168404Spjd if (current_command == NULL) { 331168404Spjd int i; 332168404Spjd 333168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 334168404Spjd (void) fprintf(fp, 335168404Spjd gettext("where 'command' is one of the following:\n\n")); 336168404Spjd 337168404Spjd for (i = 0; i < NCOMMAND; i++) { 338168404Spjd if (command_table[i].name == NULL) 339168404Spjd (void) fprintf(fp, "\n"); 340168404Spjd else 341168404Spjd (void) fprintf(fp, "%s", 342168404Spjd get_usage(command_table[i].usage)); 343168404Spjd } 344168404Spjd } else { 345168404Spjd (void) fprintf(fp, gettext("usage:\n")); 346168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 347168404Spjd } 348168404Spjd 349168404Spjd if (current_command != NULL && 350168404Spjd ((strcmp(current_command->name, "set") == 0) || 351185029Spjd (strcmp(current_command->name, "get") == 0) || 352185029Spjd (strcmp(current_command->name, "list") == 0))) { 353168404Spjd 354168404Spjd (void) fprintf(fp, 355168404Spjd gettext("\nthe following properties are supported:\n")); 356168404Spjd 357219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 358185029Spjd "PROPERTY", "EDIT", "VALUES"); 359168404Spjd 360168404Spjd /* Iterate over all properties */ 361185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 362185029Spjd ZFS_TYPE_POOL); 363236884Smm 364236884Smm (void) fprintf(fp, "\t%-15s ", "feature@..."); 365236884Smm (void) fprintf(fp, "YES disabled | enabled | active\n"); 366236884Smm 367236884Smm (void) fprintf(fp, gettext("\nThe feature@ properties must be " 368243014Smm "appended with a feature name.\nSee zpool-features(7).\n")); 369168404Spjd } 370168404Spjd 371168404Spjd /* 372168404Spjd * See comments at end of main(). 373168404Spjd */ 374168404Spjd if (getenv("ZFS_ABORT") != NULL) { 375168404Spjd (void) printf("dumping core by request\n"); 376168404Spjd abort(); 377168404Spjd } 378168404Spjd 379168404Spjd exit(requested ? 0 : 2); 380168404Spjd} 381168404Spjd 382168404Spjdvoid 383185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 384185029Spjd boolean_t print_logs) 385168404Spjd{ 386168404Spjd nvlist_t **child; 387168404Spjd uint_t c, children; 388168404Spjd char *vname; 389168404Spjd 390168404Spjd if (name != NULL) 391168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 392168404Spjd 393168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 394168404Spjd &child, &children) != 0) 395168404Spjd return; 396168404Spjd 397168404Spjd for (c = 0; c < children; c++) { 398185029Spjd uint64_t is_log = B_FALSE; 399185029Spjd 400185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 401185029Spjd &is_log); 402185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 403185029Spjd continue; 404185029Spjd 405219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 406185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 407185029Spjd B_FALSE); 408168404Spjd free(vname); 409168404Spjd } 410168404Spjd} 411168404Spjd 412238926Smmstatic boolean_t 413238926Smmprop_list_contains_feature(nvlist_t *proplist) 414238926Smm{ 415238926Smm nvpair_t *nvp; 416238926Smm for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; 417238926Smm nvp = nvlist_next_nvpair(proplist, nvp)) { 418238926Smm if (zpool_prop_feature(nvpair_name(nvp))) 419238926Smm return (B_TRUE); 420238926Smm } 421238926Smm return (B_FALSE); 422238926Smm} 423238926Smm 424168404Spjd/* 425185029Spjd * Add a property pair (name, string-value) into a property nvlist. 426185029Spjd */ 427185029Spjdstatic int 428185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 429185029Spjd boolean_t poolprop) 430185029Spjd{ 431185029Spjd zpool_prop_t prop = ZPROP_INVAL; 432185029Spjd zfs_prop_t fprop; 433185029Spjd nvlist_t *proplist; 434185029Spjd const char *normnm; 435185029Spjd char *strval; 436185029Spjd 437185029Spjd if (*props == NULL && 438185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 439185029Spjd (void) fprintf(stderr, 440185029Spjd gettext("internal error: out of memory\n")); 441185029Spjd return (1); 442185029Spjd } 443185029Spjd 444185029Spjd proplist = *props; 445185029Spjd 446185029Spjd if (poolprop) { 447238926Smm const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); 448238926Smm 449236884Smm if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 450236884Smm !zpool_prop_feature(propname)) { 451185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 452185029Spjd "not a valid pool property\n"), propname); 453185029Spjd return (2); 454185029Spjd } 455238926Smm 456238926Smm /* 457238926Smm * feature@ properties and version should not be specified 458238926Smm * at the same time. 459238926Smm */ 460329493Smav if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) && 461238926Smm nvlist_exists(proplist, vname)) || 462238926Smm (prop == ZPOOL_PROP_VERSION && 463238926Smm prop_list_contains_feature(proplist))) { 464238926Smm (void) fprintf(stderr, gettext("'feature@' and " 465238926Smm "'version' properties cannot be specified " 466238926Smm "together\n")); 467238926Smm return (2); 468238926Smm } 469238926Smm 470238926Smm 471236884Smm if (zpool_prop_feature(propname)) 472236884Smm normnm = propname; 473236884Smm else 474236884Smm normnm = zpool_prop_to_name(prop); 475185029Spjd } else { 476209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 477209962Smm normnm = zfs_prop_to_name(fprop); 478209962Smm } else { 479209962Smm normnm = propname; 480185029Spjd } 481185029Spjd } 482185029Spjd 483185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 484185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 485185029Spjd (void) fprintf(stderr, gettext("property '%s' " 486185029Spjd "specified multiple times\n"), propname); 487185029Spjd return (2); 488185029Spjd } 489185029Spjd 490185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 491185029Spjd (void) fprintf(stderr, gettext("internal " 492185029Spjd "error: out of memory\n")); 493185029Spjd return (1); 494185029Spjd } 495185029Spjd 496185029Spjd return (0); 497185029Spjd} 498185029Spjd 499185029Spjd/* 500333194Savg * Set a default property pair (name, string-value) in a property nvlist 501333194Savg */ 502333194Savgstatic int 503333194Savgadd_prop_list_default(const char *propname, char *propval, nvlist_t **props, 504333194Savg boolean_t poolprop) 505333194Savg{ 506333194Savg char *pval; 507333194Savg 508333194Savg if (nvlist_lookup_string(*props, propname, &pval) == 0) 509333194Savg return (0); 510333194Savg 511333194Savg return (add_prop_list(propname, propval, props, poolprop)); 512333194Savg} 513333194Savg 514333194Savg/* 515168404Spjd * zpool add [-fn] <pool> <vdev> ... 516168404Spjd * 517168404Spjd * -f Force addition of devices, even if they appear in use 518168404Spjd * -n Do not add the devices, but display the resulting layout if 519168404Spjd * they were to be added. 520168404Spjd * 521168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 522168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 523168404Spjd * libzfs. 524168404Spjd */ 525168404Spjdint 526168404Spjdzpool_do_add(int argc, char **argv) 527168404Spjd{ 528168404Spjd boolean_t force = B_FALSE; 529168404Spjd boolean_t dryrun = B_FALSE; 530168404Spjd int c; 531168404Spjd nvlist_t *nvroot; 532168404Spjd char *poolname; 533331395Smav zpool_boot_label_t boot_type; 534331395Smav uint64_t boot_size; 535168404Spjd int ret; 536168404Spjd zpool_handle_t *zhp; 537168404Spjd nvlist_t *config; 538168404Spjd 539168404Spjd /* check options */ 540168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 541168404Spjd switch (c) { 542168404Spjd case 'f': 543168404Spjd force = B_TRUE; 544168404Spjd break; 545168404Spjd case 'n': 546168404Spjd dryrun = B_TRUE; 547168404Spjd break; 548168404Spjd case '?': 549168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 550168404Spjd optopt); 551168404Spjd usage(B_FALSE); 552168404Spjd } 553168404Spjd } 554168404Spjd 555168404Spjd argc -= optind; 556168404Spjd argv += optind; 557168404Spjd 558168404Spjd /* get pool name and check number of arguments */ 559168404Spjd if (argc < 1) { 560168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 561168404Spjd usage(B_FALSE); 562168404Spjd } 563168404Spjd if (argc < 2) { 564168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 565168404Spjd usage(B_FALSE); 566168404Spjd } 567168404Spjd 568168404Spjd poolname = argv[0]; 569168404Spjd 570168404Spjd argc--; 571168404Spjd argv++; 572168404Spjd 573168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 574168404Spjd return (1); 575168404Spjd 576168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 577168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 578168404Spjd poolname); 579168404Spjd zpool_close(zhp); 580168404Spjd return (1); 581168404Spjd } 582168404Spjd 583331395Smav if (zpool_is_bootable(zhp)) 584331395Smav boot_type = ZPOOL_COPY_BOOT_LABEL; 585331395Smav else 586331395Smav boot_type = ZPOOL_NO_BOOT_LABEL; 587331395Smav 588168404Spjd /* pass off to get_vdev_spec for processing */ 589331395Smav boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL); 590185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 591331395Smav boot_type, boot_size, argc, argv); 592168404Spjd if (nvroot == NULL) { 593168404Spjd zpool_close(zhp); 594168404Spjd return (1); 595168404Spjd } 596168404Spjd 597168404Spjd if (dryrun) { 598168404Spjd nvlist_t *poolnvroot; 599168404Spjd 600168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 601168404Spjd &poolnvroot) == 0); 602168404Spjd 603168404Spjd (void) printf(gettext("would update '%s' to the following " 604168404Spjd "configuration:\n"), zpool_get_name(zhp)); 605168404Spjd 606185029Spjd /* print original main pool and new tree */ 607185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 608185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 609168404Spjd 610185029Spjd /* Do the same for the logs */ 611185029Spjd if (num_logs(poolnvroot) > 0) { 612185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 613185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 614185029Spjd } else if (num_logs(nvroot) > 0) { 615185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 616185029Spjd } 617185029Spjd 618168404Spjd ret = 0; 619168404Spjd } else { 620168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 621168404Spjd } 622168404Spjd 623168404Spjd nvlist_free(nvroot); 624168404Spjd zpool_close(zhp); 625168404Spjd 626168404Spjd return (ret); 627168404Spjd} 628168404Spjd 629168404Spjd/* 630219089Spjd * zpool remove <pool> <vdev> ... 631168404Spjd * 632332525Smav * Removes the given vdev from the pool. 633168404Spjd */ 634168404Spjdint 635168404Spjdzpool_do_remove(int argc, char **argv) 636168404Spjd{ 637168404Spjd char *poolname; 638185029Spjd int i, ret = 0; 639168404Spjd zpool_handle_t *zhp; 640332525Smav boolean_t stop = B_FALSE; 641332525Smav boolean_t noop = B_FALSE; 642332525Smav boolean_t parsable = B_FALSE; 643332525Smav char c; 644168404Spjd 645332525Smav /* check options */ 646332525Smav while ((c = getopt(argc, argv, "nps")) != -1) { 647332525Smav switch (c) { 648332525Smav case 'n': 649332525Smav noop = B_TRUE; 650332525Smav break; 651332525Smav case 'p': 652332525Smav parsable = B_TRUE; 653332525Smav break; 654332525Smav case 's': 655332525Smav stop = B_TRUE; 656332525Smav break; 657332525Smav case '?': 658332525Smav (void) fprintf(stderr, gettext("invalid option '%c'\n"), 659332525Smav optopt); 660332525Smav usage(B_FALSE); 661332525Smav } 662332525Smav } 663168404Spjd 664332525Smav argc -= optind; 665332525Smav argv += optind; 666332525Smav 667168404Spjd /* get pool name and check number of arguments */ 668168404Spjd if (argc < 1) { 669168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 670168404Spjd usage(B_FALSE); 671168404Spjd } 672168404Spjd 673168404Spjd poolname = argv[0]; 674168404Spjd 675168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 676168404Spjd return (1); 677168404Spjd 678332525Smav if (stop && noop) { 679332525Smav (void) fprintf(stderr, gettext("stop request ignored\n")); 680332525Smav return (0); 681332525Smav } 682332525Smav 683332525Smav if (stop) { 684332525Smav if (argc > 1) { 685332525Smav (void) fprintf(stderr, gettext("too many arguments\n")); 686332525Smav usage(B_FALSE); 687332525Smav } 688332525Smav if (zpool_vdev_remove_cancel(zhp) != 0) 689185029Spjd ret = 1; 690332525Smav } else { 691332525Smav if (argc < 2) { 692332525Smav (void) fprintf(stderr, gettext("missing device\n")); 693332525Smav usage(B_FALSE); 694332525Smav } 695332525Smav 696332525Smav for (i = 1; i < argc; i++) { 697332525Smav if (noop) { 698332525Smav uint64_t size; 699332525Smav 700332525Smav if (zpool_vdev_indirect_size(zhp, argv[i], 701332525Smav &size) != 0) { 702332525Smav ret = 1; 703332525Smav break; 704332525Smav } 705332525Smav if (parsable) { 706332525Smav (void) printf("%s %llu\n", 707332525Smav argv[i], size); 708332525Smav } else { 709332525Smav char valstr[32]; 710332525Smav zfs_nicenum(size, valstr, 711332525Smav sizeof (valstr)); 712332525Smav (void) printf("Memory that will be " 713332525Smav "used after removing %s: %s\n", 714332525Smav argv[i], valstr); 715332525Smav } 716332525Smav } else { 717332525Smav if (zpool_vdev_remove(zhp, argv[i]) != 0) 718332525Smav ret = 1; 719332525Smav } 720332525Smav } 721168404Spjd } 722168404Spjd 723168404Spjd return (ret); 724168404Spjd} 725168404Spjd 726168404Spjd/* 727297763Smav * zpool labelclear [-f] <vdev> 728224171Sgibbs * 729297763Smav * -f Force clearing the label for the vdevs which are members of 730297763Smav * the exported or foreign pools. 731297763Smav * 732224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 733224171Sgibbs * on the device. 734224171Sgibbs */ 735224171Sgibbsint 736224171Sgibbszpool_do_labelclear(int argc, char **argv) 737224171Sgibbs{ 738297763Smav char vdev[MAXPATHLEN]; 739297763Smav char *name = NULL; 740297763Smav struct stat st; 741297763Smav int c, fd, ret = 0; 742297763Smav nvlist_t *config; 743224171Sgibbs pool_state_t state; 744224171Sgibbs boolean_t inuse = B_FALSE; 745224171Sgibbs boolean_t force = B_FALSE; 746224171Sgibbs 747224171Sgibbs /* check options */ 748224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 749224171Sgibbs switch (c) { 750224171Sgibbs case 'f': 751224171Sgibbs force = B_TRUE; 752224171Sgibbs break; 753224171Sgibbs default: 754224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 755224171Sgibbs optopt); 756224171Sgibbs usage(B_FALSE); 757224171Sgibbs } 758224171Sgibbs } 759224171Sgibbs 760224171Sgibbs argc -= optind; 761224171Sgibbs argv += optind; 762224171Sgibbs 763224171Sgibbs /* get vdev name */ 764224171Sgibbs if (argc < 1) { 765297763Smav (void) fprintf(stderr, gettext("missing vdev name\n")); 766224171Sgibbs usage(B_FALSE); 767224171Sgibbs } 768297763Smav if (argc > 1) { 769297763Smav (void) fprintf(stderr, gettext("too many arguments\n")); 770297763Smav usage(B_FALSE); 771297763Smav } 772224171Sgibbs 773297763Smav /* 774297763Smav * Check if we were given absolute path and use it as is. 775297763Smav * Otherwise if the provided vdev name doesn't point to a file, 776297763Smav * try prepending dsk path and appending s0. 777297763Smav */ 778297763Smav (void) strlcpy(vdev, argv[0], sizeof (vdev)); 779297763Smav if (vdev[0] != '/' && stat(vdev, &st) != 0) { 780297763Smav char *s; 781297763Smav 782297763Smav (void) snprintf(vdev, sizeof (vdev), "%s/%s", 783297763Smav#ifdef illumos 784297763Smav ZFS_DISK_ROOT, argv[0]); 785297763Smav if ((s = strrchr(argv[0], 's')) == NULL || 786297763Smav !isdigit(*(s + 1))) 787297763Smav (void) strlcat(vdev, "s0", sizeof (vdev)); 788297763Smav#else 789297763Smav "/dev", argv[0]); 790297763Smav#endif 791297763Smav if (stat(vdev, &st) != 0) { 792297763Smav (void) fprintf(stderr, gettext( 793297763Smav "failed to find device %s, try specifying absolute " 794297763Smav "path instead\n"), argv[0]); 795297763Smav return (1); 796297763Smav } 797297763Smav } 798297763Smav 799224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 800297763Smav (void) fprintf(stderr, gettext("failed to open %s: %s\n"), 801297763Smav vdev, strerror(errno)); 802297763Smav return (1); 803224171Sgibbs } 804224171Sgibbs 805324255Savg if (zpool_read_label(fd, &config) != 0) { 806224171Sgibbs (void) fprintf(stderr, 807297763Smav gettext("failed to read label from %s\n"), vdev); 808297763Smav return (1); 809297763Smav } 810297763Smav nvlist_free(config); 811224171Sgibbs 812297763Smav ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse); 813297763Smav if (ret != 0) { 814297763Smav (void) fprintf(stderr, 815297763Smav gettext("failed to check state for %s\n"), vdev); 816224171Sgibbs return (1); 817224171Sgibbs } 818224171Sgibbs 819297763Smav if (!inuse) 820297763Smav goto wipe_label; 821224171Sgibbs 822297763Smav switch (state) { 823297763Smav default: 824297763Smav case POOL_STATE_ACTIVE: 825297763Smav case POOL_STATE_SPARE: 826297763Smav case POOL_STATE_L2CACHE: 827297763Smav (void) fprintf(stderr, gettext( 828297763Smav "%s is a member (%s) of pool \"%s\"\n"), 829297763Smav vdev, zpool_pool_state_to_name(state), name); 830297763Smav ret = 1; 831297763Smav goto errout; 832224171Sgibbs 833297763Smav case POOL_STATE_EXPORTED: 834297763Smav if (force) 835297763Smav break; 836297763Smav (void) fprintf(stderr, gettext( 837297763Smav "use '-f' to override the following error:\n" 838297763Smav "%s is a member of exported pool \"%s\"\n"), 839297763Smav vdev, name); 840297763Smav ret = 1; 841297763Smav goto errout; 842224171Sgibbs 843297763Smav case POOL_STATE_POTENTIALLY_ACTIVE: 844297763Smav if (force) 845297763Smav break; 846297763Smav (void) fprintf(stderr, gettext( 847297763Smav "use '-f' to override the following error:\n" 848297763Smav "%s is a member of potentially active pool \"%s\"\n"), 849297763Smav vdev, name); 850297763Smav ret = 1; 851297763Smav goto errout; 852224171Sgibbs 853297763Smav case POOL_STATE_DESTROYED: 854297763Smav /* inuse should never be set for a destroyed pool */ 855297763Smav assert(0); 856297763Smav break; 857224171Sgibbs } 858224171Sgibbs 859224171Sgibbswipe_label: 860297763Smav ret = zpool_clear_label(fd); 861297763Smav if (ret != 0) { 862224171Sgibbs (void) fprintf(stderr, 863297763Smav gettext("failed to clear label for %s\n"), vdev); 864224171Sgibbs } 865224171Sgibbs 866224171Sgibbserrout: 867297763Smav free(name); 868297763Smav (void) close(fd); 869224171Sgibbs 870224171Sgibbs return (ret); 871224171Sgibbs} 872224171Sgibbs 873224171Sgibbs/* 874331395Smav * zpool create [-fnd] [-B] [-o property=value] ... 875185029Spjd * [-O file-system-property=value] ... 876333194Savg * [-R root] [-m mountpoint] [-t tempname] <pool> <dev> ... 877168404Spjd * 878331395Smav * -B Create boot partition. 879168404Spjd * -f Force creation, even if devices appear in use 880168404Spjd * -n Do not create the pool, but display the resulting layout if it 881168404Spjd * were to be created. 882333194Savg * -R Create a pool under an alternate root 883333194Savg * -m Set default mountpoint for the root dataset. By default it's 884236884Smm * '/<pool>' 885333194Savg * -t Use the temporary name until the pool is exported. 886185029Spjd * -o Set property=value. 887236884Smm * -d Don't automatically enable all supported pool features 888236884Smm * (individual features can be enabled with -o). 889185029Spjd * -O Set fsproperty=value in the pool's root file system 890168404Spjd * 891168404Spjd * Creates the named pool according to the given vdev specification. The 892168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 893168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 894168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 895168404Spjd */ 896331395Smav 897331395Smav#define SYSTEM256 (256 * 1024 * 1024) 898168404Spjdint 899168404Spjdzpool_do_create(int argc, char **argv) 900168404Spjd{ 901168404Spjd boolean_t force = B_FALSE; 902168404Spjd boolean_t dryrun = B_FALSE; 903236884Smm boolean_t enable_all_pool_feat = B_TRUE; 904331395Smav zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL; 905331395Smav uint64_t boot_size = 0; 906168404Spjd int c; 907185029Spjd nvlist_t *nvroot = NULL; 908168404Spjd char *poolname; 909333194Savg char *tname = NULL; 910185029Spjd int ret = 1; 911168404Spjd char *altroot = NULL; 912168404Spjd char *mountpoint = NULL; 913185029Spjd nvlist_t *fsprops = NULL; 914185029Spjd nvlist_t *props = NULL; 915185029Spjd char *propval; 916168404Spjd 917168404Spjd /* check options */ 918333194Savg while ((c = getopt(argc, argv, ":fndBR:m:o:O:t:")) != -1) { 919168404Spjd switch (c) { 920168404Spjd case 'f': 921168404Spjd force = B_TRUE; 922168404Spjd break; 923168404Spjd case 'n': 924168404Spjd dryrun = B_TRUE; 925168404Spjd break; 926236884Smm case 'd': 927236884Smm enable_all_pool_feat = B_FALSE; 928236884Smm break; 929331395Smav case 'B': 930331395Smav#ifdef illumos 931331395Smav /* 932331395Smav * We should create the system partition. 933331395Smav * Also make sure the size is set. 934331395Smav */ 935331395Smav boot_type = ZPOOL_CREATE_BOOT_LABEL; 936331395Smav if (boot_size == 0) 937331395Smav boot_size = SYSTEM256; 938331395Smav break; 939331395Smav#else 940331395Smav (void) fprintf(stderr, 941331395Smav gettext("option '%c' is not supported\n"), 942331395Smav optopt); 943331395Smav goto badusage; 944331395Smav#endif 945168404Spjd case 'R': 946168404Spjd altroot = optarg; 947185029Spjd if (add_prop_list(zpool_prop_to_name( 948185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 949185029Spjd goto errout; 950333194Savg if (add_prop_list_default(zpool_prop_to_name( 951185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 952185029Spjd goto errout; 953168404Spjd break; 954168404Spjd case 'm': 955251634Sdelphij /* Equivalent to -O mountpoint=optarg */ 956168404Spjd mountpoint = optarg; 957168404Spjd break; 958185029Spjd case 'o': 959185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 960185029Spjd (void) fprintf(stderr, gettext("missing " 961185029Spjd "'=' for -o option\n")); 962185029Spjd goto errout; 963185029Spjd } 964185029Spjd *propval = '\0'; 965185029Spjd propval++; 966185029Spjd 967185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 968185029Spjd goto errout; 969236884Smm 970236884Smm /* 971331395Smav * Get bootsize value for make_root_vdev(). 972331395Smav */ 973331395Smav if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) { 974331395Smav if (zfs_nicestrtonum(g_zfs, propval, 975331395Smav &boot_size) < 0 || boot_size == 0) { 976331395Smav (void) fprintf(stderr, 977331395Smav gettext("bad boot partition size " 978331395Smav "'%s': %s\n"), propval, 979331395Smav libzfs_error_description(g_zfs)); 980331395Smav goto errout; 981331395Smav } 982331395Smav } 983331395Smav 984331395Smav /* 985236884Smm * If the user is creating a pool that doesn't support 986236884Smm * feature flags, don't enable any features. 987236884Smm */ 988236884Smm if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 989236884Smm char *end; 990236884Smm u_longlong_t ver; 991236884Smm 992236884Smm ver = strtoull(propval, &end, 10); 993236884Smm if (*end == '\0' && 994236884Smm ver < SPA_VERSION_FEATURES) { 995236884Smm enable_all_pool_feat = B_FALSE; 996236884Smm } 997236884Smm } 998279366Sdelphij if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) 999279366Sdelphij altroot = propval; 1000185029Spjd break; 1001185029Spjd case 'O': 1002185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 1003185029Spjd (void) fprintf(stderr, gettext("missing " 1004185029Spjd "'=' for -O option\n")); 1005185029Spjd goto errout; 1006185029Spjd } 1007185029Spjd *propval = '\0'; 1008185029Spjd propval++; 1009185029Spjd 1010251634Sdelphij /* 1011251634Sdelphij * Mountpoints are checked and then added later. 1012251634Sdelphij * Uniquely among properties, they can be specified 1013251634Sdelphij * more than once, to avoid conflict with -m. 1014251634Sdelphij */ 1015251634Sdelphij if (0 == strcmp(optarg, 1016251634Sdelphij zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) { 1017251634Sdelphij mountpoint = propval; 1018251634Sdelphij } else if (add_prop_list(optarg, propval, &fsprops, 1019251634Sdelphij B_FALSE)) { 1020185029Spjd goto errout; 1021251634Sdelphij } 1022185029Spjd break; 1023333194Savg case 't': 1024333194Savg /* 1025333194Savg * Sanity check temporary pool name. 1026333194Savg */ 1027333194Savg if (strchr(optarg, '/') != NULL) { 1028333194Savg (void) fprintf(stderr, gettext("cannot create " 1029333194Savg "'%s': invalid character '/' in temporary " 1030333194Savg "name\n"), optarg); 1031333194Savg (void) fprintf(stderr, gettext("use 'zfs " 1032333194Savg "create' to create a dataset\n")); 1033333194Savg goto errout; 1034333194Savg } 1035333194Savg 1036333194Savg if (add_prop_list(zpool_prop_to_name( 1037333194Savg ZPOOL_PROP_TNAME), optarg, &props, B_TRUE)) 1038333194Savg goto errout; 1039333194Savg if (add_prop_list_default(zpool_prop_to_name( 1040333194Savg ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1041333194Savg goto errout; 1042333194Savg tname = optarg; 1043333194Savg break; 1044168404Spjd case ':': 1045168404Spjd (void) fprintf(stderr, gettext("missing argument for " 1046168404Spjd "'%c' option\n"), optopt); 1047185029Spjd goto badusage; 1048168404Spjd case '?': 1049168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1050168404Spjd optopt); 1051185029Spjd goto badusage; 1052168404Spjd } 1053168404Spjd } 1054168404Spjd 1055168404Spjd argc -= optind; 1056168404Spjd argv += optind; 1057168404Spjd 1058168404Spjd /* get pool name and check number of arguments */ 1059168404Spjd if (argc < 1) { 1060168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 1061185029Spjd goto badusage; 1062168404Spjd } 1063168404Spjd if (argc < 2) { 1064168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 1065185029Spjd goto badusage; 1066168404Spjd } 1067168404Spjd 1068168404Spjd poolname = argv[0]; 1069168404Spjd 1070168404Spjd /* 1071168404Spjd * As a special case, check for use of '/' in the name, and direct the 1072168404Spjd * user to use 'zfs create' instead. 1073168404Spjd */ 1074168404Spjd if (strchr(poolname, '/') != NULL) { 1075168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 1076168404Spjd "character '/' in pool name\n"), poolname); 1077168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 1078168404Spjd "create a dataset\n")); 1079185029Spjd goto errout; 1080168404Spjd } 1081168404Spjd 1082331395Smav /* 1083331395Smav * Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used, 1084331395Smav * and not set otherwise. 1085331395Smav */ 1086331395Smav if (boot_type == ZPOOL_CREATE_BOOT_LABEL) { 1087331395Smav const char *propname; 1088331395Smav char *strptr, *buf = NULL; 1089331395Smav int rv; 1090331395Smav 1091331395Smav propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE); 1092331395Smav if (nvlist_lookup_string(props, propname, &strptr) != 0) { 1093331395Smav (void) asprintf(&buf, "%" PRIu64, boot_size); 1094331395Smav if (buf == NULL) { 1095331395Smav (void) fprintf(stderr, 1096331395Smav gettext("internal error: out of memory\n")); 1097331395Smav goto errout; 1098331395Smav } 1099331395Smav rv = add_prop_list(propname, buf, &props, B_TRUE); 1100331395Smav free(buf); 1101331395Smav if (rv != 0) 1102331395Smav goto errout; 1103331395Smav } 1104331395Smav } else { 1105331395Smav const char *propname; 1106331395Smav char *strptr; 1107331395Smav 1108331395Smav propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE); 1109331395Smav if (nvlist_lookup_string(props, propname, &strptr) == 0) { 1110331395Smav (void) fprintf(stderr, gettext("error: setting boot " 1111331395Smav "partition size requires option '-B'\n")); 1112331395Smav goto errout; 1113331395Smav } 1114331395Smav } 1115331395Smav 1116168404Spjd /* pass off to get_vdev_spec for bulk processing */ 1117185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 1118331395Smav boot_type, boot_size, argc - 1, argv + 1); 1119168404Spjd if (nvroot == NULL) 1120185029Spjd goto errout; 1121168404Spjd 1122168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 1123185029Spjd if (!zfs_allocatable_devs(nvroot)) { 1124168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 1125168404Spjd "specification: at least one toplevel vdev must be " 1126168404Spjd "specified\n")); 1127185029Spjd goto errout; 1128168404Spjd } 1129168404Spjd 1130168404Spjd if (altroot != NULL && altroot[0] != '/') { 1131168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 1132168404Spjd "must be an absolute path\n"), altroot); 1133185029Spjd goto errout; 1134168404Spjd } 1135168404Spjd 1136168404Spjd /* 1137168404Spjd * Check the validity of the mountpoint and direct the user to use the 1138168404Spjd * '-m' mountpoint option if it looks like its in use. 1139244857Spjd * Ignore the checks if the '-f' option is given. 1140168404Spjd */ 1141244857Spjd if (!force && (mountpoint == NULL || 1142168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 1143244857Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) { 1144168404Spjd char buf[MAXPATHLEN]; 1145185029Spjd DIR *dirp; 1146168404Spjd 1147168404Spjd if (mountpoint && mountpoint[0] != '/') { 1148168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 1149168404Spjd "'%s': must be an absolute path, 'legacy', or " 1150168404Spjd "'none'\n"), mountpoint); 1151185029Spjd goto errout; 1152168404Spjd } 1153168404Spjd 1154168404Spjd if (mountpoint == NULL) { 1155168404Spjd if (altroot != NULL) 1156168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 1157168404Spjd altroot, poolname); 1158168404Spjd else 1159168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 1160168404Spjd poolname); 1161168404Spjd } else { 1162168404Spjd if (altroot != NULL) 1163168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 1164168404Spjd altroot, mountpoint); 1165168404Spjd else 1166168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 1167168404Spjd mountpoint); 1168168404Spjd } 1169168404Spjd 1170185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 1171185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 1172185029Spjd "%s\n"), buf, strerror(errno)); 1173185029Spjd (void) fprintf(stderr, gettext("use '-m' " 1174185029Spjd "option to provide a different default\n")); 1175185029Spjd goto errout; 1176185029Spjd } else if (dirp) { 1177185029Spjd int count = 0; 1178185029Spjd 1179185029Spjd while (count < 3 && readdir(dirp) != NULL) 1180185029Spjd count++; 1181185029Spjd (void) closedir(dirp); 1182185029Spjd 1183185029Spjd if (count > 2) { 1184168404Spjd (void) fprintf(stderr, gettext("mountpoint " 1185168404Spjd "'%s' exists and is not empty\n"), buf); 1186185029Spjd (void) fprintf(stderr, gettext("use '-m' " 1187185029Spjd "option to provide a " 1188185029Spjd "different default\n")); 1189185029Spjd goto errout; 1190185029Spjd } 1191168404Spjd } 1192168404Spjd } 1193168404Spjd 1194251634Sdelphij /* 1195251634Sdelphij * Now that the mountpoint's validity has been checked, ensure that 1196251634Sdelphij * the property is set appropriately prior to creating the pool. 1197251634Sdelphij */ 1198251634Sdelphij if (mountpoint != NULL) { 1199251634Sdelphij ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1200251634Sdelphij mountpoint, &fsprops, B_FALSE); 1201251634Sdelphij if (ret != 0) 1202251634Sdelphij goto errout; 1203251634Sdelphij } 1204251634Sdelphij 1205251634Sdelphij ret = 1; 1206168404Spjd if (dryrun) { 1207168404Spjd /* 1208168404Spjd * For a dry run invocation, print out a basic message and run 1209168404Spjd * through all the vdevs in the list and print out in an 1210168404Spjd * appropriate hierarchy. 1211168404Spjd */ 1212168404Spjd (void) printf(gettext("would create '%s' with the " 1213168404Spjd "following layout:\n\n"), poolname); 1214168404Spjd 1215185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 1216185029Spjd if (num_logs(nvroot) > 0) 1217185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 1218168404Spjd 1219168404Spjd ret = 0; 1220168404Spjd } else { 1221168404Spjd /* 1222168404Spjd * Hand off to libzfs. 1223168404Spjd */ 1224236884Smm if (enable_all_pool_feat) { 1225259813Sdelphij spa_feature_t i; 1226236884Smm for (i = 0; i < SPA_FEATURES; i++) { 1227236884Smm char propname[MAXPATHLEN]; 1228236884Smm zfeature_info_t *feat = &spa_feature_table[i]; 1229236884Smm 1230236884Smm (void) snprintf(propname, sizeof (propname), 1231236884Smm "feature@%s", feat->fi_uname); 1232236884Smm 1233236884Smm /* 1234236884Smm * Skip feature if user specified it manually 1235236884Smm * on the command line. 1236236884Smm */ 1237236884Smm if (nvlist_exists(props, propname)) 1238236884Smm continue; 1239236884Smm 1240251634Sdelphij ret = add_prop_list(propname, 1241251634Sdelphij ZFS_FEATURE_ENABLED, &props, B_TRUE); 1242251634Sdelphij if (ret != 0) 1243236884Smm goto errout; 1244236884Smm } 1245236884Smm } 1246251634Sdelphij 1247251634Sdelphij ret = 1; 1248185029Spjd if (zpool_create(g_zfs, poolname, 1249185029Spjd nvroot, props, fsprops) == 0) { 1250333194Savg zfs_handle_t *pool = zfs_open(g_zfs, 1251333194Savg tname ? tname : poolname, ZFS_TYPE_FILESYSTEM); 1252168404Spjd if (pool != NULL) { 1253168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 1254185029Spjd ret = zfs_shareall(pool); 1255168404Spjd zfs_close(pool); 1256168404Spjd } 1257168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 1258168404Spjd (void) fprintf(stderr, gettext("pool name may have " 1259168404Spjd "been omitted\n")); 1260168404Spjd } 1261168404Spjd } 1262168404Spjd 1263185029Spjderrout: 1264168404Spjd nvlist_free(nvroot); 1265185029Spjd nvlist_free(fsprops); 1266185029Spjd nvlist_free(props); 1267168404Spjd return (ret); 1268185029Spjdbadusage: 1269185029Spjd nvlist_free(fsprops); 1270185029Spjd nvlist_free(props); 1271185029Spjd usage(B_FALSE); 1272185029Spjd return (2); 1273168404Spjd} 1274168404Spjd 1275168404Spjd/* 1276168404Spjd * zpool destroy <pool> 1277168404Spjd * 1278342941Savg * -f Forcefully unmount any datasets 1279168404Spjd * 1280168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 1281168404Spjd */ 1282168404Spjdint 1283168404Spjdzpool_do_destroy(int argc, char **argv) 1284168404Spjd{ 1285168404Spjd boolean_t force = B_FALSE; 1286168404Spjd int c; 1287168404Spjd char *pool; 1288168404Spjd zpool_handle_t *zhp; 1289168404Spjd int ret; 1290168404Spjd 1291168404Spjd /* check options */ 1292168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 1293168404Spjd switch (c) { 1294168404Spjd case 'f': 1295168404Spjd force = B_TRUE; 1296168404Spjd break; 1297168404Spjd case '?': 1298168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1299168404Spjd optopt); 1300168404Spjd usage(B_FALSE); 1301168404Spjd } 1302168404Spjd } 1303168404Spjd 1304168404Spjd argc -= optind; 1305168404Spjd argv += optind; 1306168404Spjd 1307168404Spjd /* check arguments */ 1308168404Spjd if (argc < 1) { 1309168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1310168404Spjd usage(B_FALSE); 1311168404Spjd } 1312168404Spjd if (argc > 1) { 1313168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1314168404Spjd usage(B_FALSE); 1315168404Spjd } 1316168404Spjd 1317168404Spjd pool = argv[0]; 1318168404Spjd 1319168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1320168404Spjd /* 1321168404Spjd * As a special case, check for use of '/' in the name, and 1322168404Spjd * direct the user to use 'zfs destroy' instead. 1323168404Spjd */ 1324168404Spjd if (strchr(pool, '/') != NULL) 1325168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1326168404Spjd "destroy a dataset\n")); 1327168404Spjd return (1); 1328168404Spjd } 1329168404Spjd 1330168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1331168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1332168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1333168404Spjd return (1); 1334168404Spjd } 1335168404Spjd 1336248571Smm /* The history must be logged as part of the export */ 1337248571Smm log_history = B_FALSE; 1338168404Spjd 1339248571Smm ret = (zpool_destroy(zhp, history_str) != 0); 1340248571Smm 1341168404Spjd zpool_close(zhp); 1342168404Spjd 1343168404Spjd return (ret); 1344168404Spjd} 1345168404Spjd 1346168404Spjd/* 1347168404Spjd * zpool export [-f] <pool> ... 1348168404Spjd * 1349168404Spjd * -f Forcefully unmount datasets 1350168404Spjd * 1351168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1352168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1353168404Spjd * then the datasets will be forcefully unmounted. 1354168404Spjd */ 1355168404Spjdint 1356168404Spjdzpool_do_export(int argc, char **argv) 1357168404Spjd{ 1358168404Spjd boolean_t force = B_FALSE; 1359207670Smm boolean_t hardforce = B_FALSE; 1360168404Spjd int c; 1361168404Spjd zpool_handle_t *zhp; 1362168404Spjd int ret; 1363168404Spjd int i; 1364168404Spjd 1365168404Spjd /* check options */ 1366207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1367168404Spjd switch (c) { 1368168404Spjd case 'f': 1369168404Spjd force = B_TRUE; 1370168404Spjd break; 1371207670Smm case 'F': 1372207670Smm hardforce = B_TRUE; 1373207670Smm break; 1374168404Spjd case '?': 1375168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1376168404Spjd optopt); 1377168404Spjd usage(B_FALSE); 1378168404Spjd } 1379168404Spjd } 1380168404Spjd 1381168404Spjd argc -= optind; 1382168404Spjd argv += optind; 1383168404Spjd 1384168404Spjd /* check arguments */ 1385168404Spjd if (argc < 1) { 1386168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1387168404Spjd usage(B_FALSE); 1388168404Spjd } 1389168404Spjd 1390168404Spjd ret = 0; 1391168404Spjd for (i = 0; i < argc; i++) { 1392168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1393168404Spjd ret = 1; 1394168404Spjd continue; 1395168404Spjd } 1396168404Spjd 1397168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1398168404Spjd ret = 1; 1399168404Spjd zpool_close(zhp); 1400168404Spjd continue; 1401168404Spjd } 1402168404Spjd 1403248571Smm /* The history must be logged as part of the export */ 1404248571Smm log_history = B_FALSE; 1405248571Smm 1406207670Smm if (hardforce) { 1407248571Smm if (zpool_export_force(zhp, history_str) != 0) 1408207670Smm ret = 1; 1409248571Smm } else if (zpool_export(zhp, force, history_str) != 0) { 1410168404Spjd ret = 1; 1411207670Smm } 1412168404Spjd 1413168404Spjd zpool_close(zhp); 1414168404Spjd } 1415168404Spjd 1416168404Spjd return (ret); 1417168404Spjd} 1418168404Spjd 1419168404Spjd/* 1420168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1421168404Spjd * name column. 1422168404Spjd */ 1423168404Spjdstatic int 1424168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1425168404Spjd{ 1426219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1427168404Spjd nvlist_t **child; 1428168404Spjd uint_t c, children; 1429168404Spjd int ret; 1430168404Spjd 1431168404Spjd if (strlen(name) + depth > max) 1432168404Spjd max = strlen(name) + depth; 1433168404Spjd 1434168404Spjd free(name); 1435168404Spjd 1436168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1437168404Spjd &child, &children) == 0) { 1438168404Spjd for (c = 0; c < children; c++) 1439168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1440168404Spjd max)) > max) 1441168404Spjd max = ret; 1442168404Spjd } 1443168404Spjd 1444185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1445185029Spjd &child, &children) == 0) { 1446185029Spjd for (c = 0; c < children; c++) 1447185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1448185029Spjd max)) > max) 1449185029Spjd max = ret; 1450185029Spjd } 1451185029Spjd 1452168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1453168404Spjd &child, &children) == 0) { 1454168404Spjd for (c = 0; c < children; c++) 1455168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1456168404Spjd max)) > max) 1457168404Spjd max = ret; 1458168404Spjd } 1459168404Spjd 1460168404Spjd 1461168404Spjd return (max); 1462168404Spjd} 1463168404Spjd 1464213197Smmtypedef struct spare_cbdata { 1465213197Smm uint64_t cb_guid; 1466213197Smm zpool_handle_t *cb_zhp; 1467213197Smm} spare_cbdata_t; 1468168404Spjd 1469213197Smmstatic boolean_t 1470213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1471213197Smm{ 1472213197Smm uint64_t guid; 1473213197Smm nvlist_t **child; 1474213197Smm uint_t c, children; 1475213197Smm 1476213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1477213197Smm search == guid) 1478213197Smm return (B_TRUE); 1479213197Smm 1480213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1481213197Smm &child, &children) == 0) { 1482213197Smm for (c = 0; c < children; c++) 1483213197Smm if (find_vdev(child[c], search)) 1484213197Smm return (B_TRUE); 1485213197Smm } 1486213197Smm 1487213197Smm return (B_FALSE); 1488213197Smm} 1489213197Smm 1490213197Smmstatic int 1491213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1492213197Smm{ 1493213197Smm spare_cbdata_t *cbp = data; 1494213197Smm nvlist_t *config, *nvroot; 1495213197Smm 1496213197Smm config = zpool_get_config(zhp, NULL); 1497213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1498213197Smm &nvroot) == 0); 1499213197Smm 1500213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1501213197Smm cbp->cb_zhp = zhp; 1502213197Smm return (1); 1503213197Smm } 1504213197Smm 1505213197Smm zpool_close(zhp); 1506213197Smm return (0); 1507213197Smm} 1508213197Smm 1509168404Spjd/* 1510213197Smm * Print out configuration state as requested by status_callback. 1511213197Smm */ 1512213197Smmvoid 1513213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1514213197Smm int namewidth, int depth, boolean_t isspare) 1515213197Smm{ 1516213197Smm nvlist_t **child; 1517254591Sgibbs uint_t c, vsc, children; 1518219089Spjd pool_scan_stat_t *ps = NULL; 1519213197Smm vdev_stat_t *vs; 1520219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1521213197Smm char *vname; 1522213197Smm uint64_t notpresent; 1523254591Sgibbs uint64_t ashift; 1524213197Smm spare_cbdata_t cb; 1525224169Sgibbs const char *state; 1526332525Smav char *type; 1527213197Smm 1528213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1529213197Smm &child, &children) != 0) 1530213197Smm children = 0; 1531213197Smm 1532219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1533254591Sgibbs (uint64_t **)&vs, &vsc) == 0); 1534219089Spjd 1535332525Smav verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1536332525Smav 1537332525Smav if (strcmp(type, VDEV_TYPE_INDIRECT) == 0) 1538332525Smav return; 1539332525Smav 1540213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1541213197Smm if (isspare) { 1542213197Smm /* 1543213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1544213197Smm * online drives. 1545213197Smm */ 1546213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1547213197Smm state = "INUSE"; 1548213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1549213197Smm state = "AVAIL"; 1550213197Smm } 1551213197Smm 1552213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1553213197Smm name, state); 1554213197Smm 1555213197Smm if (!isspare) { 1556213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1557213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1558213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1559213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1560213197Smm } 1561213197Smm 1562213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1563224170Sgibbs ¬present) == 0 || 1564224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1565213197Smm char *path; 1566224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1567224170Sgibbs (void) printf(" was %s", path); 1568213197Smm } else if (vs->vs_aux != 0) { 1569213197Smm (void) printf(" "); 1570213197Smm 1571213197Smm switch (vs->vs_aux) { 1572213197Smm case VDEV_AUX_OPEN_FAILED: 1573213197Smm (void) printf(gettext("cannot open")); 1574213197Smm break; 1575213197Smm 1576213197Smm case VDEV_AUX_BAD_GUID_SUM: 1577213197Smm (void) printf(gettext("missing device")); 1578213197Smm break; 1579213197Smm 1580213197Smm case VDEV_AUX_NO_REPLICAS: 1581213197Smm (void) printf(gettext("insufficient replicas")); 1582213197Smm break; 1583213197Smm 1584213197Smm case VDEV_AUX_VERSION_NEWER: 1585213197Smm (void) printf(gettext("newer version")); 1586213197Smm break; 1587213197Smm 1588236884Smm case VDEV_AUX_UNSUP_FEAT: 1589236884Smm (void) printf(gettext("unsupported feature(s)")); 1590236884Smm break; 1591236884Smm 1592254591Sgibbs case VDEV_AUX_ASHIFT_TOO_BIG: 1593254591Sgibbs (void) printf(gettext("unsupported minimum blocksize")); 1594254591Sgibbs break; 1595254591Sgibbs 1596213197Smm case VDEV_AUX_SPARED: 1597213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1598213197Smm &cb.cb_guid) == 0); 1599213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1600213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1601213197Smm zpool_get_name(zhp)) == 0) 1602213197Smm (void) printf(gettext("currently in " 1603213197Smm "use")); 1604213197Smm else 1605213197Smm (void) printf(gettext("in use by " 1606213197Smm "pool '%s'"), 1607213197Smm zpool_get_name(cb.cb_zhp)); 1608213197Smm zpool_close(cb.cb_zhp); 1609213197Smm } else { 1610213197Smm (void) printf(gettext("currently in use")); 1611213197Smm } 1612213197Smm break; 1613213197Smm 1614213197Smm case VDEV_AUX_ERR_EXCEEDED: 1615213197Smm (void) printf(gettext("too many errors")); 1616213197Smm break; 1617213197Smm 1618213197Smm case VDEV_AUX_IO_FAILURE: 1619213197Smm (void) printf(gettext("experienced I/O failures")); 1620213197Smm break; 1621213197Smm 1622213197Smm case VDEV_AUX_BAD_LOG: 1623213197Smm (void) printf(gettext("bad intent log")); 1624213197Smm break; 1625213197Smm 1626219089Spjd case VDEV_AUX_EXTERNAL: 1627219089Spjd (void) printf(gettext("external device fault")); 1628219089Spjd break; 1629219089Spjd 1630219089Spjd case VDEV_AUX_SPLIT_POOL: 1631219089Spjd (void) printf(gettext("split into new pool")); 1632219089Spjd break; 1633219089Spjd 1634332536Smav case VDEV_AUX_CHILDREN_OFFLINE: 1635332536Smav (void) printf(gettext("all children offline")); 1636332536Smav break; 1637332536Smav 1638213197Smm default: 1639213197Smm (void) printf(gettext("corrupted data")); 1640213197Smm break; 1641213197Smm } 1642254591Sgibbs } else if (children == 0 && !isspare && 1643254591Sgibbs VDEV_STAT_VALID(vs_physical_ashift, vsc) && 1644254591Sgibbs vs->vs_configured_ashift < vs->vs_physical_ashift) { 1645254591Sgibbs (void) printf( 1646254591Sgibbs gettext(" block size: %dB configured, %dB native"), 1647254591Sgibbs 1 << vs->vs_configured_ashift, 1 << vs->vs_physical_ashift); 1648213197Smm } 1649213197Smm 1650219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1651219089Spjd (uint64_t **)&ps, &c); 1652219089Spjd 1653339034Ssef if (ps != NULL && ps->pss_state == DSS_SCANNING && 1654219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1655219089Spjd (void) printf(gettext(" (%s)"), 1656219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1657219089Spjd "resilvering" : "repairing"); 1658219089Spjd } 1659219089Spjd 1660339111Smav if ((vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE || 1661339111Smav vs->vs_initialize_state == VDEV_INITIALIZE_SUSPENDED || 1662339111Smav vs->vs_initialize_state == VDEV_INITIALIZE_COMPLETE) && 1663339111Smav !vs->vs_scan_removing) { 1664339111Smav char zbuf[1024]; 1665339111Smav char tbuf[256]; 1666339111Smav struct tm zaction_ts; 1667339111Smav 1668339111Smav time_t t = vs->vs_initialize_action_time; 1669339111Smav int initialize_pct = 100; 1670339111Smav if (vs->vs_initialize_state != VDEV_INITIALIZE_COMPLETE) { 1671339111Smav initialize_pct = (vs->vs_initialize_bytes_done * 100 / 1672339111Smav (vs->vs_initialize_bytes_est + 1)); 1673339111Smav } 1674339111Smav 1675339111Smav (void) localtime_r(&t, &zaction_ts); 1676339111Smav (void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts); 1677339111Smav 1678339111Smav switch (vs->vs_initialize_state) { 1679339111Smav case VDEV_INITIALIZE_SUSPENDED: 1680339111Smav (void) snprintf(zbuf, sizeof (zbuf), 1681339111Smav ", suspended, started at %s", tbuf); 1682339111Smav break; 1683339111Smav case VDEV_INITIALIZE_ACTIVE: 1684339111Smav (void) snprintf(zbuf, sizeof (zbuf), 1685339111Smav ", started at %s", tbuf); 1686339111Smav break; 1687339111Smav case VDEV_INITIALIZE_COMPLETE: 1688339111Smav (void) snprintf(zbuf, sizeof (zbuf), 1689339111Smav ", completed at %s", tbuf); 1690339111Smav break; 1691339111Smav } 1692339111Smav 1693339111Smav (void) printf(gettext(" (%d%% initialized%s)"), 1694339111Smav initialize_pct, zbuf); 1695339111Smav } 1696339111Smav 1697213197Smm (void) printf("\n"); 1698213197Smm 1699213197Smm for (c = 0; c < children; c++) { 1700219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1701213197Smm 1702219089Spjd /* Don't print logs or holes here */ 1703213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1704219089Spjd &islog); 1705219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1706219089Spjd &ishole); 1707219089Spjd if (islog || ishole) 1708213197Smm continue; 1709219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1710213197Smm print_status_config(zhp, vname, child[c], 1711213197Smm namewidth, depth + 2, isspare); 1712213197Smm free(vname); 1713213197Smm } 1714213197Smm} 1715213197Smm 1716213197Smm 1717213197Smm/* 1718168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1719168404Spjd * pool, printing out the name and status for each one. 1720168404Spjd */ 1721168404Spjdvoid 1722213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1723168404Spjd{ 1724168404Spjd nvlist_t **child; 1725168404Spjd uint_t c, children; 1726168404Spjd vdev_stat_t *vs; 1727168404Spjd char *type, *vname; 1728168404Spjd 1729168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1730219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1731219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1732168404Spjd return; 1733168404Spjd 1734219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1735168404Spjd (uint64_t **)&vs, &c) == 0); 1736168404Spjd 1737168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1738185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1739168404Spjd 1740168404Spjd if (vs->vs_aux != 0) { 1741185029Spjd (void) printf(" "); 1742168404Spjd 1743168404Spjd switch (vs->vs_aux) { 1744168404Spjd case VDEV_AUX_OPEN_FAILED: 1745168404Spjd (void) printf(gettext("cannot open")); 1746168404Spjd break; 1747168404Spjd 1748168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1749168404Spjd (void) printf(gettext("missing device")); 1750168404Spjd break; 1751168404Spjd 1752168404Spjd case VDEV_AUX_NO_REPLICAS: 1753168404Spjd (void) printf(gettext("insufficient replicas")); 1754168404Spjd break; 1755168404Spjd 1756168404Spjd case VDEV_AUX_VERSION_NEWER: 1757168404Spjd (void) printf(gettext("newer version")); 1758168404Spjd break; 1759168404Spjd 1760236884Smm case VDEV_AUX_UNSUP_FEAT: 1761236884Smm (void) printf(gettext("unsupported feature(s)")); 1762236884Smm break; 1763236884Smm 1764185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1765185029Spjd (void) printf(gettext("too many errors")); 1766185029Spjd break; 1767185029Spjd 1768332536Smav case VDEV_AUX_CHILDREN_OFFLINE: 1769332536Smav (void) printf(gettext("all children offline")); 1770332536Smav break; 1771332536Smav 1772168404Spjd default: 1773168404Spjd (void) printf(gettext("corrupted data")); 1774168404Spjd break; 1775168404Spjd } 1776168404Spjd } 1777168404Spjd (void) printf("\n"); 1778168404Spjd 1779168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1780168404Spjd &child, &children) != 0) 1781168404Spjd return; 1782168404Spjd 1783168404Spjd for (c = 0; c < children; c++) { 1784185029Spjd uint64_t is_log = B_FALSE; 1785185029Spjd 1786185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1787185029Spjd &is_log); 1788213197Smm if (is_log) 1789185029Spjd continue; 1790185029Spjd 1791219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1792213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1793168404Spjd free(vname); 1794168404Spjd } 1795168404Spjd 1796185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1797185029Spjd &child, &children) == 0) { 1798185029Spjd (void) printf(gettext("\tcache\n")); 1799185029Spjd for (c = 0; c < children; c++) { 1800219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1801185029Spjd (void) printf("\t %s\n", vname); 1802185029Spjd free(vname); 1803185029Spjd } 1804185029Spjd } 1805185029Spjd 1806168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1807185029Spjd &child, &children) == 0) { 1808185029Spjd (void) printf(gettext("\tspares\n")); 1809185029Spjd for (c = 0; c < children; c++) { 1810219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1811185029Spjd (void) printf("\t %s\n", vname); 1812185029Spjd free(vname); 1813185029Spjd } 1814168404Spjd } 1815168404Spjd} 1816168404Spjd 1817168404Spjd/* 1818213197Smm * Print log vdevs. 1819213197Smm * Logs are recorded as top level vdevs in the main pool child array 1820213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1821213197Smm * print_import_config() to print the top level logs then any log 1822213197Smm * children (eg mirrored slogs) are printed recursively - which 1823213197Smm * works because only the top level vdev is marked "is_log" 1824213197Smm */ 1825213197Smmstatic void 1826213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1827213197Smm{ 1828213197Smm uint_t c, children; 1829213197Smm nvlist_t **child; 1830213197Smm 1831213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1832213197Smm &children) != 0) 1833213197Smm return; 1834213197Smm 1835213197Smm (void) printf(gettext("\tlogs\n")); 1836213197Smm 1837213197Smm for (c = 0; c < children; c++) { 1838213197Smm uint64_t is_log = B_FALSE; 1839213197Smm char *name; 1840213197Smm 1841213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1842213197Smm &is_log); 1843213197Smm if (!is_log) 1844213197Smm continue; 1845219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1846213197Smm if (verbose) 1847213197Smm print_status_config(zhp, name, child[c], namewidth, 1848213197Smm 2, B_FALSE); 1849213197Smm else 1850213197Smm print_import_config(name, child[c], namewidth, 2); 1851213197Smm free(name); 1852213197Smm } 1853213197Smm} 1854219089Spjd 1855213197Smm/* 1856168404Spjd * Display the status for the given pool. 1857168404Spjd */ 1858168404Spjdstatic void 1859168404Spjdshow_import(nvlist_t *config) 1860168404Spjd{ 1861168404Spjd uint64_t pool_state; 1862168404Spjd vdev_stat_t *vs; 1863168404Spjd char *name; 1864168404Spjd uint64_t guid; 1865168404Spjd char *msgid; 1866168404Spjd nvlist_t *nvroot; 1867168404Spjd int reason; 1868168404Spjd const char *health; 1869168404Spjd uint_t vsc; 1870168404Spjd int namewidth; 1871228103Smm char *comment; 1872168404Spjd 1873168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1874168404Spjd &name) == 0); 1875168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1876168404Spjd &guid) == 0); 1877168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1878168404Spjd &pool_state) == 0); 1879168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1880168404Spjd &nvroot) == 0); 1881168404Spjd 1882219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1883168404Spjd (uint64_t **)&vs, &vsc) == 0); 1884185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1885168404Spjd 1886168404Spjd reason = zpool_import_status(config, &msgid); 1887168404Spjd 1888228103Smm (void) printf(gettext(" pool: %s\n"), name); 1889228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1890228103Smm (void) printf(gettext(" state: %s"), health); 1891168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1892168404Spjd (void) printf(gettext(" (DESTROYED)")); 1893168404Spjd (void) printf("\n"); 1894168404Spjd 1895168404Spjd switch (reason) { 1896168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1897168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1898168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1899228103Smm (void) printf(gettext(" status: One or more devices are " 1900228103Smm "missing from the system.\n")); 1901168404Spjd break; 1902168404Spjd 1903168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1904168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1905228103Smm (void) printf(gettext(" status: One or more devices contains " 1906168404Spjd "corrupted data.\n")); 1907168404Spjd break; 1908168404Spjd 1909168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1910228103Smm (void) printf( 1911228103Smm gettext(" status: The pool data is corrupted.\n")); 1912168404Spjd break; 1913168404Spjd 1914168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1915228103Smm (void) printf(gettext(" status: One or more devices " 1916168404Spjd "are offlined.\n")); 1917168404Spjd break; 1918168404Spjd 1919168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1920228103Smm (void) printf(gettext(" status: The pool metadata is " 1921168404Spjd "corrupted.\n")); 1922168404Spjd break; 1923168404Spjd 1924168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1925238926Smm (void) printf(gettext(" status: The pool is formatted using a " 1926238926Smm "legacy on-disk version.\n")); 1927168404Spjd break; 1928168404Spjd 1929168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1930228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1931168404Spjd "incompatible version.\n")); 1932168404Spjd break; 1933168404Spjd 1934238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 1935238926Smm (void) printf(gettext(" status: Some supported features are " 1936238926Smm "not enabled on the pool.\n")); 1937238926Smm break; 1938238926Smm 1939236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1940236884Smm (void) printf(gettext("status: The pool uses the following " 1941332542Smav "feature(s) not supported on this system:\n")); 1942236884Smm zpool_print_unsup_feat(config); 1943236884Smm break; 1944236884Smm 1945236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1946236884Smm (void) printf(gettext("status: The pool can only be accessed " 1947236884Smm "in read-only mode on this system. It\n\tcannot be " 1948236884Smm "accessed in read-write mode because it uses the " 1949236884Smm "following\n\tfeature(s) not supported on this system:\n")); 1950236884Smm zpool_print_unsup_feat(config); 1951236884Smm break; 1952236884Smm 1953168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1954228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1955168498Spjd "another system.\n")); 1956168498Spjd break; 1957185029Spjd 1958185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1959185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1960228103Smm (void) printf(gettext(" status: One or more devices are " 1961185029Spjd "faulted.\n")); 1962185029Spjd break; 1963185029Spjd 1964185029Spjd case ZPOOL_STATUS_BAD_LOG: 1965228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1966185029Spjd "read.\n")); 1967185029Spjd break; 1968185029Spjd 1969219089Spjd case ZPOOL_STATUS_RESILVERING: 1970228103Smm (void) printf(gettext(" status: One or more devices were being " 1971219089Spjd "resilvered.\n")); 1972219089Spjd break; 1973219089Spjd 1974259131Sdelphij case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 1975259131Sdelphij (void) printf(gettext("status: One or more devices were " 1976259131Sdelphij "configured to use a non-native block size.\n" 1977259131Sdelphij "\tExpect reduced performance.\n")); 1978259131Sdelphij break; 1979259131Sdelphij 1980168404Spjd default: 1981168404Spjd /* 1982168404Spjd * No other status can be seen when importing pools. 1983168404Spjd */ 1984168404Spjd assert(reason == ZPOOL_STATUS_OK); 1985168404Spjd } 1986168404Spjd 1987168404Spjd /* 1988168404Spjd * Print out an action according to the overall state of the pool. 1989168404Spjd */ 1990168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1991238926Smm if (reason == ZPOOL_STATUS_VERSION_OLDER || 1992238926Smm reason == ZPOOL_STATUS_FEAT_DISABLED) { 1993228103Smm (void) printf(gettext(" action: The pool can be " 1994168404Spjd "imported using its name or numeric identifier, " 1995168404Spjd "though\n\tsome features will not be available " 1996168404Spjd "without an explicit 'zpool upgrade'.\n")); 1997238926Smm } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 1998228103Smm (void) printf(gettext(" action: The pool can be " 1999168498Spjd "imported using its name or numeric " 2000168498Spjd "identifier and\n\tthe '-f' flag.\n")); 2001238926Smm } else { 2002228103Smm (void) printf(gettext(" action: The pool can be " 2003168404Spjd "imported using its name or numeric " 2004168404Spjd "identifier.\n")); 2005238926Smm } 2006168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 2007228103Smm (void) printf(gettext(" action: The pool can be imported " 2008168404Spjd "despite missing or damaged devices. The\n\tfault " 2009168404Spjd "tolerance of the pool may be compromised if imported.\n")); 2010168404Spjd } else { 2011168404Spjd switch (reason) { 2012168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 2013228103Smm (void) printf(gettext(" action: The pool cannot be " 2014168404Spjd "imported. Access the pool on a system running " 2015168404Spjd "newer\n\tsoftware, or recreate the pool from " 2016168404Spjd "backup.\n")); 2017168404Spjd break; 2018236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 2019236884Smm (void) printf(gettext("action: The pool cannot be " 2020236884Smm "imported. Access the pool on a system that " 2021236884Smm "supports\n\tthe required feature(s), or recreate " 2022236884Smm "the pool from backup.\n")); 2023236884Smm break; 2024236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 2025236884Smm (void) printf(gettext("action: The pool cannot be " 2026236884Smm "imported in read-write mode. Import the pool " 2027236884Smm "with\n" 2028236884Smm "\t\"-o readonly=on\", access the pool on a system " 2029236884Smm "that supports the\n\trequired feature(s), or " 2030236884Smm "recreate the pool from backup.\n")); 2031236884Smm break; 2032168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 2033168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 2034168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 2035228103Smm (void) printf(gettext(" action: The pool cannot be " 2036168404Spjd "imported. Attach the missing\n\tdevices and try " 2037168404Spjd "again.\n")); 2038168404Spjd break; 2039168404Spjd default: 2040228103Smm (void) printf(gettext(" action: The pool cannot be " 2041168404Spjd "imported due to damaged devices or data.\n")); 2042168404Spjd } 2043168404Spjd } 2044168404Spjd 2045228103Smm /* Print the comment attached to the pool. */ 2046228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 2047228103Smm (void) printf(gettext("comment: %s\n"), comment); 2048228103Smm 2049168404Spjd /* 2050168404Spjd * If the state is "closed" or "can't open", and the aux state 2051168404Spjd * is "corrupt data": 2052168404Spjd */ 2053168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 2054168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 2055168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 2056168404Spjd if (pool_state == POOL_STATE_DESTROYED) 2057168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 2058168404Spjd "but can be imported using the '-Df' flags.\n")); 2059168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 2060168404Spjd (void) printf(gettext("\tThe pool may be active on " 2061185029Spjd "another system, but can be imported using\n\t" 2062168404Spjd "the '-f' flag.\n")); 2063168404Spjd } 2064168404Spjd 2065168404Spjd if (msgid != NULL) 2066236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 2067168404Spjd msgid); 2068168404Spjd 2069228103Smm (void) printf(gettext(" config:\n\n")); 2070168404Spjd 2071168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 2072168404Spjd if (namewidth < 10) 2073168404Spjd namewidth = 10; 2074168404Spjd 2075213197Smm print_import_config(name, nvroot, namewidth, 0); 2076213197Smm if (num_logs(nvroot) > 0) 2077213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 2078185029Spjd 2079168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 2080168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 2081168404Spjd "be part of this pool, though their\n\texact " 2082168404Spjd "configuration cannot be determined.\n")); 2083168404Spjd } 2084168404Spjd} 2085168404Spjd 2086168404Spjd/* 2087168404Spjd * Perform the import for the given configuration. This passes the heavy 2088185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 2089185029Spjd * within the pool. 2090168404Spjd */ 2091168404Spjdstatic int 2092168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 2093219089Spjd nvlist_t *props, int flags) 2094168404Spjd{ 2095168404Spjd zpool_handle_t *zhp; 2096168404Spjd char *name; 2097168404Spjd uint64_t state; 2098168404Spjd uint64_t version; 2099168404Spjd 2100168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 2101168404Spjd &name) == 0); 2102168404Spjd 2103168404Spjd verify(nvlist_lookup_uint64(config, 2104168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 2105168404Spjd verify(nvlist_lookup_uint64(config, 2106168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 2107236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 2108168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 2109236884Smm "is formatted using an unsupported ZFS version\n"), name); 2110168404Spjd return (1); 2111219089Spjd } else if (state != POOL_STATE_EXPORTED && 2112219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 2113168498Spjd uint64_t hostid; 2114168498Spjd 2115168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 2116168498Spjd &hostid) == 0) { 2117168498Spjd if ((unsigned long)hostid != gethostid()) { 2118168498Spjd char *hostname; 2119168498Spjd uint64_t timestamp; 2120168498Spjd time_t t; 2121168498Spjd 2122168498Spjd verify(nvlist_lookup_string(config, 2123168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 2124168498Spjd verify(nvlist_lookup_uint64(config, 2125168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 2126168498Spjd t = timestamp; 2127168498Spjd (void) fprintf(stderr, gettext("cannot import " 2128168498Spjd "'%s': pool may be in use from other " 2129168498Spjd "system, it was last accessed by %s " 2130168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 2131168498Spjd (unsigned long)hostid, 2132168498Spjd asctime(localtime(&t))); 2133168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 2134168498Spjd "import anyway\n")); 2135168498Spjd return (1); 2136168498Spjd } 2137168498Spjd } else { 2138168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2139168498Spjd "pool may be in use from other system\n"), name); 2140168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 2141168498Spjd "anyway\n")); 2142168498Spjd return (1); 2143168498Spjd } 2144168404Spjd } 2145168404Spjd 2146219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 2147168404Spjd return (1); 2148168404Spjd 2149168404Spjd if (newname != NULL) 2150168404Spjd name = (char *)newname; 2151168404Spjd 2152209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 2153209962Smm return (1); 2154168404Spjd 2155209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 2156219089Spjd !(flags & ZFS_IMPORT_ONLY) && 2157209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 2158168404Spjd zpool_close(zhp); 2159168404Spjd return (1); 2160168404Spjd } 2161168404Spjd 2162168404Spjd zpool_close(zhp); 2163219089Spjd return (0); 2164168404Spjd} 2165168404Spjd 2166168404Spjd/* 2167332547Smav * zpool checkpoint <pool> 2168332547Smav * checkpoint --discard <pool> 2169332547Smav * 2170342941Savg * -d Discard the checkpoint from a checkpointed 2171342941Savg * --discard pool. 2172332547Smav * 2173332547Smav * Checkpoints the specified pool, by taking a "snapshot" of its 2174332547Smav * current state. A pool can only have one checkpoint at a time. 2175332547Smav */ 2176332547Smavint 2177332547Smavzpool_do_checkpoint(int argc, char **argv) 2178332547Smav{ 2179332547Smav boolean_t discard; 2180332547Smav char *pool; 2181332547Smav zpool_handle_t *zhp; 2182332547Smav int c, err; 2183332547Smav 2184332547Smav struct option long_options[] = { 2185332547Smav {"discard", no_argument, NULL, 'd'}, 2186332547Smav {0, 0, 0, 0} 2187332547Smav }; 2188332547Smav 2189332547Smav discard = B_FALSE; 2190332547Smav while ((c = getopt_long(argc, argv, ":d", long_options, NULL)) != -1) { 2191332547Smav switch (c) { 2192332547Smav case 'd': 2193332547Smav discard = B_TRUE; 2194332547Smav break; 2195332547Smav case '?': 2196332547Smav (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2197332547Smav optopt); 2198332547Smav usage(B_FALSE); 2199332547Smav } 2200332547Smav } 2201332547Smav 2202332547Smav argc -= optind; 2203332547Smav argv += optind; 2204332547Smav 2205332547Smav if (argc < 1) { 2206332547Smav (void) fprintf(stderr, gettext("missing pool argument\n")); 2207332547Smav usage(B_FALSE); 2208332547Smav } 2209332547Smav 2210332547Smav if (argc > 1) { 2211332547Smav (void) fprintf(stderr, gettext("too many arguments\n")); 2212332547Smav usage(B_FALSE); 2213332547Smav } 2214332547Smav 2215332547Smav pool = argv[0]; 2216332547Smav 2217332547Smav if ((zhp = zpool_open(g_zfs, pool)) == NULL) { 2218332547Smav /* As a special case, check for use of '/' in the name */ 2219332547Smav if (strchr(pool, '/') != NULL) 2220332547Smav (void) fprintf(stderr, gettext("'zpool checkpoint' " 2221332547Smav "doesn't work on datasets. To save the state " 2222332547Smav "of a dataset from a specific point in time " 2223332547Smav "please use 'zfs snapshot'\n")); 2224332547Smav return (1); 2225332547Smav } 2226332547Smav 2227332547Smav if (discard) 2228332547Smav err = (zpool_discard_checkpoint(zhp) != 0); 2229332547Smav else 2230332547Smav err = (zpool_checkpoint(zhp) != 0); 2231332547Smav 2232332547Smav zpool_close(zhp); 2233332547Smav 2234332547Smav return (err); 2235332547Smav} 2236332547Smav 2237332547Smav#define CHECKPOINT_OPT 1024 2238332547Smav 2239332547Smav/* 2240168404Spjd * zpool import [-d dir] [-D] 2241185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 2242185029Spjd * [-d dir | -c cachefile] [-f] -a 2243185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 2244333194Savg * [-d dir | -c cachefile] [-f] [-n] [-F] [-t] 2245333194Savg * <pool | id> [newpool] 2246168404Spjd * 2247342941Savg * -c Read pool information from a cachefile instead of searching 2248185029Spjd * devices. 2249185029Spjd * 2250342941Savg * -d Scan in a specific directory, other than /dev/dsk. More than 2251168404Spjd * one directory can be specified using multiple '-d' options. 2252168404Spjd * 2253342941Savg * -D Scan for previously destroyed pools or import all or only 2254342941Savg * specified destroyed pools. 2255168404Spjd * 2256342941Savg * -R Temporarily import the pool, with all mountpoints relative to 2257168404Spjd * the given root. The pool will remain exported when the machine 2258168404Spjd * is rebooted. 2259168404Spjd * 2260342941Savg * -V Import even in the presence of faulted vdevs. This is an 2261342941Savg * intentionally undocumented option for testing purposes, and 2262342941Savg * treats the pool configuration as complete, leaving any bad 2263209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 2264209962Smm * import. 2265185029Spjd * 2266342941Savg * -f Force import, even if it appears that the pool is active. 2267219089Spjd * 2268342941Savg * -F Attempt rewind if necessary. 2269219089Spjd * 2270342941Savg * -n See if rewind would work, but don't actually rewind. 2271219089Spjd * 2272342941Savg * -N Import the pool but don't mount datasets. 2273219089Spjd * 2274342941Savg * -t Use newpool as a temporary pool name instead of renaming 2275342941Savg * the pool. 2276333194Savg * 2277342941Savg * -T Specify a starting txg to use for import. This option is 2278342941Savg * intentionally undocumented option for testing purposes. 2279219089Spjd * 2280342941Savg * -a Import all pools found. 2281168404Spjd * 2282342941Savg * -o Set property=value and/or temporary mount options (without '='). 2283185029Spjd * 2284342941Savg * --rewind-to-checkpoint 2285342941Savg * Import the pool and revert back to the checkpoint. 2286332547Smav * 2287168404Spjd * The import command scans for pools to import, and import pools based on pool 2288168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 2289168404Spjd */ 2290168404Spjdint 2291168404Spjdzpool_do_import(int argc, char **argv) 2292168404Spjd{ 2293168404Spjd char **searchdirs = NULL; 2294168404Spjd int nsearch = 0; 2295168404Spjd int c; 2296219089Spjd int err = 0; 2297185029Spjd nvlist_t *pools = NULL; 2298168404Spjd boolean_t do_all = B_FALSE; 2299168404Spjd boolean_t do_destroyed = B_FALSE; 2300168404Spjd char *mntopts = NULL; 2301168404Spjd nvpair_t *elem; 2302168404Spjd nvlist_t *config; 2303185029Spjd uint64_t searchguid = 0; 2304185029Spjd char *searchname = NULL; 2305185029Spjd char *propval; 2306168404Spjd nvlist_t *found_config; 2307219089Spjd nvlist_t *policy = NULL; 2308185029Spjd nvlist_t *props = NULL; 2309168404Spjd boolean_t first; 2310219089Spjd int flags = ZFS_IMPORT_NORMAL; 2311219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 2312219089Spjd boolean_t dryrun = B_FALSE; 2313219089Spjd boolean_t do_rewind = B_FALSE; 2314219089Spjd boolean_t xtreme_rewind = B_FALSE; 2315219089Spjd uint64_t pool_state, txg = -1ULL; 2316185029Spjd char *cachefile = NULL; 2317219089Spjd importargs_t idata = { 0 }; 2318219089Spjd char *endptr; 2319168404Spjd 2320332547Smav 2321332547Smav struct option long_options[] = { 2322332547Smav {"rewind-to-checkpoint", no_argument, NULL, CHECKPOINT_OPT}, 2323332547Smav {0, 0, 0, 0} 2324332547Smav }; 2325332547Smav 2326168404Spjd /* check options */ 2327333194Savg while ((c = getopt_long(argc, argv, ":aCc:d:DEfFmnNo:rR:tT:VX", 2328332547Smav long_options, NULL)) != -1) { 2329168404Spjd switch (c) { 2330168404Spjd case 'a': 2331168404Spjd do_all = B_TRUE; 2332168404Spjd break; 2333185029Spjd case 'c': 2334185029Spjd cachefile = optarg; 2335185029Spjd break; 2336168404Spjd case 'd': 2337168404Spjd if (searchdirs == NULL) { 2338168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2339168404Spjd } else { 2340168404Spjd char **tmp = safe_malloc((nsearch + 1) * 2341168404Spjd sizeof (char *)); 2342168404Spjd bcopy(searchdirs, tmp, nsearch * 2343168404Spjd sizeof (char *)); 2344168404Spjd free(searchdirs); 2345168404Spjd searchdirs = tmp; 2346168404Spjd } 2347168404Spjd searchdirs[nsearch++] = optarg; 2348168404Spjd break; 2349168404Spjd case 'D': 2350168404Spjd do_destroyed = B_TRUE; 2351168404Spjd break; 2352168404Spjd case 'f': 2353219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 2354168404Spjd break; 2355185029Spjd case 'F': 2356219089Spjd do_rewind = B_TRUE; 2357185029Spjd break; 2358219089Spjd case 'm': 2359219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 2360219089Spjd break; 2361219089Spjd case 'n': 2362219089Spjd dryrun = B_TRUE; 2363219089Spjd break; 2364219089Spjd case 'N': 2365219089Spjd flags |= ZFS_IMPORT_ONLY; 2366219089Spjd break; 2367168404Spjd case 'o': 2368185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 2369185029Spjd *propval = '\0'; 2370185029Spjd propval++; 2371185029Spjd if (add_prop_list(optarg, propval, 2372185029Spjd &props, B_TRUE)) 2373185029Spjd goto error; 2374185029Spjd } else { 2375185029Spjd mntopts = optarg; 2376185029Spjd } 2377168404Spjd break; 2378168404Spjd case 'R': 2379185029Spjd if (add_prop_list(zpool_prop_to_name( 2380185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 2381185029Spjd goto error; 2382333194Savg if (add_prop_list_default(zpool_prop_to_name( 2383185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2384185029Spjd goto error; 2385168404Spjd break; 2386333194Savg case 't': 2387333194Savg flags |= ZFS_IMPORT_TEMP_NAME; 2388333194Savg if (add_prop_list_default(zpool_prop_to_name( 2389333194Savg ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2390333194Savg goto error; 2391333194Savg break; 2392219089Spjd case 'T': 2393219089Spjd errno = 0; 2394268720Sdelphij txg = strtoull(optarg, &endptr, 0); 2395219089Spjd if (errno != 0 || *endptr != '\0') { 2396219089Spjd (void) fprintf(stderr, 2397219089Spjd gettext("invalid txg value\n")); 2398219089Spjd usage(B_FALSE); 2399219089Spjd } 2400219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 2401219089Spjd break; 2402219089Spjd case 'V': 2403219089Spjd flags |= ZFS_IMPORT_VERBATIM; 2404219089Spjd break; 2405219089Spjd case 'X': 2406219089Spjd xtreme_rewind = B_TRUE; 2407219089Spjd break; 2408332547Smav case CHECKPOINT_OPT: 2409332547Smav flags |= ZFS_IMPORT_CHECKPOINT; 2410332547Smav break; 2411168404Spjd case ':': 2412168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2413168404Spjd "'%c' option\n"), optopt); 2414168404Spjd usage(B_FALSE); 2415168404Spjd break; 2416168404Spjd case '?': 2417168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2418168404Spjd optopt); 2419168404Spjd usage(B_FALSE); 2420168404Spjd } 2421168404Spjd } 2422168404Spjd 2423168404Spjd argc -= optind; 2424168404Spjd argv += optind; 2425168404Spjd 2426185029Spjd if (cachefile && nsearch != 0) { 2427185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 2428185029Spjd usage(B_FALSE); 2429185029Spjd } 2430185029Spjd 2431219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 2432219089Spjd (void) fprintf(stderr, 2433219089Spjd gettext("-n or -X only meaningful with -F\n")); 2434219089Spjd usage(B_FALSE); 2435219089Spjd } 2436219089Spjd if (dryrun) 2437219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 2438219089Spjd else if (do_rewind) 2439219089Spjd rewind_policy = ZPOOL_DO_REWIND; 2440219089Spjd if (xtreme_rewind) 2441219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 2442219089Spjd 2443219089Spjd /* In the future, we can capture further policy and include it here */ 2444219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2445332550Smav nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, txg) != 0 || 2446332550Smav nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, 2447332550Smav rewind_policy) != 0) 2448219089Spjd goto error; 2449219089Spjd 2450168404Spjd if (searchdirs == NULL) { 2451168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2452235478Savg searchdirs[0] = "/dev"; 2453168404Spjd nsearch = 1; 2454168404Spjd } 2455168404Spjd 2456168404Spjd /* check argument count */ 2457168404Spjd if (do_all) { 2458168404Spjd if (argc != 0) { 2459168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2460168404Spjd usage(B_FALSE); 2461168404Spjd } 2462168404Spjd } else { 2463168404Spjd if (argc > 2) { 2464168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2465168404Spjd usage(B_FALSE); 2466168404Spjd } 2467168404Spjd 2468168404Spjd /* 2469168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 2470168404Spjd * here because otherwise any attempt to discover pools will 2471168404Spjd * silently fail. 2472168404Spjd */ 2473168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2474168404Spjd (void) fprintf(stderr, gettext("cannot " 2475168404Spjd "discover pools: permission denied\n")); 2476168404Spjd free(searchdirs); 2477219089Spjd nvlist_free(policy); 2478168404Spjd return (1); 2479168404Spjd } 2480168404Spjd } 2481168404Spjd 2482168404Spjd /* 2483168404Spjd * Depending on the arguments given, we do one of the following: 2484168404Spjd * 2485168404Spjd * <none> Iterate through all pools and display information about 2486168404Spjd * each one. 2487168404Spjd * 2488168404Spjd * -a Iterate through all pools and try to import each one. 2489168404Spjd * 2490168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 2491168404Spjd * name and import that one. 2492168404Spjd * 2493168404Spjd * -D Above options applies only to destroyed pools. 2494168404Spjd */ 2495168404Spjd if (argc != 0) { 2496168404Spjd char *endptr; 2497168404Spjd 2498168404Spjd errno = 0; 2499168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 2500254758Sdelphij if (errno != 0 || *endptr != '\0') { 2501168404Spjd searchname = argv[0]; 2502254758Sdelphij searchguid = 0; 2503254758Sdelphij } 2504168404Spjd found_config = NULL; 2505168404Spjd 2506185029Spjd /* 2507219089Spjd * User specified a name or guid. Ensure it's unique. 2508185029Spjd */ 2509219089Spjd idata.unique = B_TRUE; 2510185029Spjd } 2511185029Spjd 2512219089Spjd 2513219089Spjd idata.path = searchdirs; 2514219089Spjd idata.paths = nsearch; 2515219089Spjd idata.poolname = searchname; 2516219089Spjd idata.guid = searchguid; 2517219089Spjd idata.cachefile = cachefile; 2518332536Smav idata.policy = policy; 2519219089Spjd 2520219089Spjd pools = zpool_search_import(g_zfs, &idata); 2521219089Spjd 2522219089Spjd if (pools != NULL && idata.exists && 2523219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2524219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2525219089Spjd "a pool with that name already exists\n"), 2526219089Spjd argv[0]); 2527333194Savg (void) fprintf(stderr, gettext("use the form 'zpool import " 2528333194Savg "[-t] <pool | id> <newpool>' to give it a new temporary " 2529333194Savg "or permanent name\n")); 2530219089Spjd err = 1; 2531219089Spjd } else if (pools == NULL && idata.exists) { 2532219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2533219089Spjd "a pool with that name is already created/imported,\n"), 2534219089Spjd argv[0]); 2535219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2536219089Spjd "with that name were found\n")); 2537219089Spjd err = 1; 2538219089Spjd } else if (pools == NULL) { 2539185029Spjd if (argc != 0) { 2540185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2541185029Spjd "no such pool available\n"), argv[0]); 2542185029Spjd } 2543219089Spjd err = 1; 2544219089Spjd } 2545219089Spjd 2546219089Spjd if (err == 1) { 2547185029Spjd free(searchdirs); 2548219089Spjd nvlist_free(policy); 2549185029Spjd return (1); 2550185029Spjd } 2551185029Spjd 2552185029Spjd /* 2553185029Spjd * At this point we have a list of import candidate configs. Even if 2554185029Spjd * we were searching by pool name or guid, we still need to 2555185029Spjd * post-process the list to deal with pool state and possible 2556185029Spjd * duplicate names. 2557185029Spjd */ 2558168404Spjd err = 0; 2559168404Spjd elem = NULL; 2560168404Spjd first = B_TRUE; 2561168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2562168404Spjd 2563168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2564168404Spjd 2565168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2566168404Spjd &pool_state) == 0); 2567168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2568168404Spjd continue; 2569168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2570168404Spjd continue; 2571168404Spjd 2572332550Smav verify(nvlist_add_nvlist(config, ZPOOL_LOAD_POLICY, 2573219089Spjd policy) == 0); 2574219089Spjd 2575168404Spjd if (argc == 0) { 2576168404Spjd if (first) 2577168404Spjd first = B_FALSE; 2578168404Spjd else if (!do_all) 2579168404Spjd (void) printf("\n"); 2580168404Spjd 2581219089Spjd if (do_all) { 2582168404Spjd err |= do_import(config, NULL, mntopts, 2583219089Spjd props, flags); 2584219089Spjd } else { 2585168404Spjd show_import(config); 2586219089Spjd } 2587168404Spjd } else if (searchname != NULL) { 2588168404Spjd char *name; 2589168404Spjd 2590168404Spjd /* 2591168404Spjd * We are searching for a pool based on name. 2592168404Spjd */ 2593168404Spjd verify(nvlist_lookup_string(config, 2594168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2595168404Spjd 2596168404Spjd if (strcmp(name, searchname) == 0) { 2597168404Spjd if (found_config != NULL) { 2598168404Spjd (void) fprintf(stderr, gettext( 2599168404Spjd "cannot import '%s': more than " 2600168404Spjd "one matching pool\n"), searchname); 2601168404Spjd (void) fprintf(stderr, gettext( 2602168404Spjd "import by numeric ID instead\n")); 2603168404Spjd err = B_TRUE; 2604168404Spjd } 2605168404Spjd found_config = config; 2606168404Spjd } 2607168404Spjd } else { 2608168404Spjd uint64_t guid; 2609168404Spjd 2610168404Spjd /* 2611168404Spjd * Search for a pool by guid. 2612168404Spjd */ 2613168404Spjd verify(nvlist_lookup_uint64(config, 2614168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2615168404Spjd 2616168404Spjd if (guid == searchguid) 2617168404Spjd found_config = config; 2618168404Spjd } 2619168404Spjd } 2620168404Spjd 2621168404Spjd /* 2622168404Spjd * If we were searching for a specific pool, verify that we found a 2623168404Spjd * pool, and then do the import. 2624168404Spjd */ 2625168404Spjd if (argc != 0 && err == 0) { 2626168404Spjd if (found_config == NULL) { 2627168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2628168404Spjd "no such pool available\n"), argv[0]); 2629168404Spjd err = B_TRUE; 2630168404Spjd } else { 2631168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2632219089Spjd argv[1], mntopts, props, flags); 2633168404Spjd } 2634168404Spjd } 2635168404Spjd 2636168404Spjd /* 2637168404Spjd * If we were just looking for pools, report an error if none were 2638168404Spjd * found. 2639168404Spjd */ 2640168404Spjd if (argc == 0 && first) 2641168404Spjd (void) fprintf(stderr, 2642168404Spjd gettext("no pools available to import\n")); 2643168404Spjd 2644185029Spjderror: 2645185029Spjd nvlist_free(props); 2646168404Spjd nvlist_free(pools); 2647219089Spjd nvlist_free(policy); 2648168404Spjd free(searchdirs); 2649168404Spjd 2650168404Spjd return (err ? 1 : 0); 2651168404Spjd} 2652168404Spjd 2653168404Spjdtypedef struct iostat_cbdata { 2654236155Smm boolean_t cb_verbose; 2655236155Smm int cb_namewidth; 2656236155Smm int cb_iteration; 2657168404Spjd zpool_list_t *cb_list; 2658168404Spjd} iostat_cbdata_t; 2659168404Spjd 2660168404Spjdstatic void 2661168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2662168404Spjd{ 2663168404Spjd int i = 0; 2664168404Spjd 2665168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2666168404Spjd (void) printf("-"); 2667168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2668168404Spjd} 2669168404Spjd 2670168404Spjdstatic void 2671168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2672168404Spjd{ 2673168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2674168404Spjd cb->cb_namewidth, ""); 2675219089Spjd (void) printf("%-*s alloc free read write read write\n", 2676168404Spjd cb->cb_namewidth, "pool"); 2677168404Spjd print_iostat_separator(cb); 2678168404Spjd} 2679168404Spjd 2680168404Spjd/* 2681168404Spjd * Display a single statistic. 2682168404Spjd */ 2683185029Spjdstatic void 2684168404Spjdprint_one_stat(uint64_t value) 2685168404Spjd{ 2686168404Spjd char buf[64]; 2687168404Spjd 2688168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2689168404Spjd (void) printf(" %5s", buf); 2690168404Spjd} 2691168404Spjd 2692168404Spjd/* 2693168404Spjd * Print out all the statistics for the given vdev. This can either be the 2694168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2695168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2696168404Spjd */ 2697168404Spjdvoid 2698168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2699168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2700168404Spjd{ 2701168404Spjd nvlist_t **oldchild, **newchild; 2702168404Spjd uint_t c, children; 2703168404Spjd vdev_stat_t *oldvs, *newvs; 2704168404Spjd vdev_stat_t zerovs = { 0 }; 2705168404Spjd uint64_t tdelta; 2706168404Spjd double scale; 2707168404Spjd char *vname; 2708168404Spjd 2709332525Smav if (strcmp(name, VDEV_TYPE_INDIRECT) == 0) 2710332525Smav return; 2711332525Smav 2712168404Spjd if (oldnv != NULL) { 2713219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2714219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2715168404Spjd } else { 2716168404Spjd oldvs = &zerovs; 2717168404Spjd } 2718168404Spjd 2719219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2720168404Spjd (uint64_t **)&newvs, &c) == 0); 2721168404Spjd 2722168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2723168404Spjd (void) printf("%*s%s", depth, "", name); 2724168404Spjd else 2725168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2726168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2727168404Spjd 2728168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2729168404Spjd 2730168404Spjd if (tdelta == 0) 2731168404Spjd scale = 1.0; 2732168404Spjd else 2733168404Spjd scale = (double)NANOSEC / tdelta; 2734168404Spjd 2735168404Spjd /* only toplevel vdevs have capacity stats */ 2736168404Spjd if (newvs->vs_space == 0) { 2737168404Spjd (void) printf(" - -"); 2738168404Spjd } else { 2739168404Spjd print_one_stat(newvs->vs_alloc); 2740168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2741168404Spjd } 2742168404Spjd 2743168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2744168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2745168404Spjd 2746168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2747168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2748168404Spjd 2749168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2750168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2751168404Spjd 2752168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2753168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2754168404Spjd 2755168404Spjd (void) printf("\n"); 2756168404Spjd 2757168404Spjd if (!cb->cb_verbose) 2758168404Spjd return; 2759168404Spjd 2760168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2761168404Spjd &newchild, &children) != 0) 2762168404Spjd return; 2763168404Spjd 2764168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2765168404Spjd &oldchild, &c) != 0) 2766168404Spjd return; 2767168404Spjd 2768168404Spjd for (c = 0; c < children; c++) { 2769227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2770219089Spjd 2771227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2772227497Smm &ishole); 2773227497Smm 2774227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2775227497Smm &islog); 2776227497Smm 2777227497Smm if (ishole || islog) 2778219089Spjd continue; 2779219089Spjd 2780219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2781168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2782168404Spjd newchild[c], cb, depth + 2); 2783168404Spjd free(vname); 2784168404Spjd } 2785185029Spjd 2786185029Spjd /* 2787227497Smm * Log device section 2788227497Smm */ 2789227497Smm 2790227497Smm if (num_logs(newnv) > 0) { 2791227497Smm (void) printf("%-*s - - - - - " 2792227497Smm "-\n", cb->cb_namewidth, "logs"); 2793227497Smm 2794227497Smm for (c = 0; c < children; c++) { 2795227497Smm uint64_t islog = B_FALSE; 2796227497Smm (void) nvlist_lookup_uint64(newchild[c], 2797227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2798227497Smm 2799227497Smm if (islog) { 2800227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2801227497Smm B_FALSE); 2802227497Smm print_vdev_stats(zhp, vname, oldnv ? 2803227497Smm oldchild[c] : NULL, newchild[c], 2804227497Smm cb, depth + 2); 2805227497Smm free(vname); 2806227497Smm } 2807227497Smm } 2808227497Smm 2809227497Smm } 2810227497Smm 2811227497Smm /* 2812185029Spjd * Include level 2 ARC devices in iostat output 2813185029Spjd */ 2814185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2815185029Spjd &newchild, &children) != 0) 2816185029Spjd return; 2817185029Spjd 2818185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2819185029Spjd &oldchild, &c) != 0) 2820185029Spjd return; 2821185029Spjd 2822185029Spjd if (children > 0) { 2823185029Spjd (void) printf("%-*s - - - - - " 2824185029Spjd "-\n", cb->cb_namewidth, "cache"); 2825185029Spjd for (c = 0; c < children; c++) { 2826219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2827219089Spjd B_FALSE); 2828185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2829185029Spjd newchild[c], cb, depth + 2); 2830185029Spjd free(vname); 2831185029Spjd } 2832185029Spjd } 2833168404Spjd} 2834168404Spjd 2835168404Spjdstatic int 2836168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2837168404Spjd{ 2838168404Spjd iostat_cbdata_t *cb = data; 2839168404Spjd boolean_t missing; 2840168404Spjd 2841168404Spjd /* 2842168404Spjd * If the pool has disappeared, remove it from the list and continue. 2843168404Spjd */ 2844168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2845168404Spjd return (-1); 2846168404Spjd 2847168404Spjd if (missing) 2848168404Spjd pool_list_remove(cb->cb_list, zhp); 2849168404Spjd 2850168404Spjd return (0); 2851168404Spjd} 2852168404Spjd 2853168404Spjd/* 2854168404Spjd * Callback to print out the iostats for the given pool. 2855168404Spjd */ 2856168404Spjdint 2857168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2858168404Spjd{ 2859168404Spjd iostat_cbdata_t *cb = data; 2860168404Spjd nvlist_t *oldconfig, *newconfig; 2861168404Spjd nvlist_t *oldnvroot, *newnvroot; 2862168404Spjd 2863168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2864168404Spjd 2865168404Spjd if (cb->cb_iteration == 1) 2866168404Spjd oldconfig = NULL; 2867168404Spjd 2868168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2869168404Spjd &newnvroot) == 0); 2870168404Spjd 2871168404Spjd if (oldconfig == NULL) 2872168404Spjd oldnvroot = NULL; 2873168404Spjd else 2874168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2875168404Spjd &oldnvroot) == 0); 2876168404Spjd 2877168404Spjd /* 2878168404Spjd * Print out the statistics for the pool. 2879168404Spjd */ 2880168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2881168404Spjd 2882168404Spjd if (cb->cb_verbose) 2883168404Spjd print_iostat_separator(cb); 2884168404Spjd 2885168404Spjd return (0); 2886168404Spjd} 2887168404Spjd 2888168404Spjdint 2889168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2890168404Spjd{ 2891168404Spjd iostat_cbdata_t *cb = data; 2892168404Spjd nvlist_t *config, *nvroot; 2893168404Spjd 2894168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2895168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2896168404Spjd &nvroot) == 0); 2897168404Spjd if (!cb->cb_verbose) 2898168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2899168404Spjd else 2900236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2901236145Smm cb->cb_namewidth); 2902168404Spjd } 2903168404Spjd 2904168404Spjd /* 2905168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2906168404Spjd * maximum we can have and still fit in 80 columns. 2907168404Spjd */ 2908168404Spjd if (cb->cb_namewidth < 10) 2909168404Spjd cb->cb_namewidth = 10; 2910168404Spjd if (cb->cb_namewidth > 38) 2911168404Spjd cb->cb_namewidth = 38; 2912168404Spjd 2913168404Spjd return (0); 2914168404Spjd} 2915168404Spjd 2916168404Spjd/* 2917219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2918168404Spjd */ 2919219089Spjdstatic void 2920219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2921219089Spjd unsigned long *cnt) 2922168404Spjd{ 2923168404Spjd unsigned long interval = 0, count = 0; 2924219089Spjd int argc = *argcp, errno; 2925168404Spjd 2926168404Spjd /* 2927168404Spjd * Determine if the last argument is an integer or a pool name 2928168404Spjd */ 2929168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2930168404Spjd char *end; 2931168404Spjd 2932168404Spjd errno = 0; 2933168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2934168404Spjd 2935168404Spjd if (*end == '\0' && errno == 0) { 2936168404Spjd if (interval == 0) { 2937168404Spjd (void) fprintf(stderr, gettext("interval " 2938168404Spjd "cannot be zero\n")); 2939168404Spjd usage(B_FALSE); 2940168404Spjd } 2941168404Spjd /* 2942168404Spjd * Ignore the last parameter 2943168404Spjd */ 2944168404Spjd argc--; 2945168404Spjd } else { 2946168404Spjd /* 2947168404Spjd * If this is not a valid number, just plow on. The 2948168404Spjd * user will get a more informative error message later 2949168404Spjd * on. 2950168404Spjd */ 2951168404Spjd interval = 0; 2952168404Spjd } 2953168404Spjd } 2954168404Spjd 2955168404Spjd /* 2956168404Spjd * If the last argument is also an integer, then we have both a count 2957219089Spjd * and an interval. 2958168404Spjd */ 2959168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2960168404Spjd char *end; 2961168404Spjd 2962168404Spjd errno = 0; 2963168404Spjd count = interval; 2964168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2965168404Spjd 2966168404Spjd if (*end == '\0' && errno == 0) { 2967168404Spjd if (interval == 0) { 2968168404Spjd (void) fprintf(stderr, gettext("interval " 2969168404Spjd "cannot be zero\n")); 2970168404Spjd usage(B_FALSE); 2971168404Spjd } 2972168404Spjd 2973168404Spjd /* 2974168404Spjd * Ignore the last parameter 2975168404Spjd */ 2976168404Spjd argc--; 2977168404Spjd } else { 2978168404Spjd interval = 0; 2979168404Spjd } 2980168404Spjd } 2981168404Spjd 2982219089Spjd *iv = interval; 2983219089Spjd *cnt = count; 2984219089Spjd *argcp = argc; 2985219089Spjd} 2986219089Spjd 2987219089Spjdstatic void 2988219089Spjdget_timestamp_arg(char c) 2989219089Spjd{ 2990219089Spjd if (c == 'u') 2991219089Spjd timestamp_fmt = UDATE; 2992219089Spjd else if (c == 'd') 2993219089Spjd timestamp_fmt = DDATE; 2994219089Spjd else 2995219089Spjd usage(B_FALSE); 2996219089Spjd} 2997219089Spjd 2998219089Spjd/* 2999219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 3000219089Spjd * 3001219089Spjd * -v Display statistics for individual vdevs 3002219089Spjd * -T Display a timestamp in date(1) or Unix format 3003219089Spjd * 3004219089Spjd * This command can be tricky because we want to be able to deal with pool 3005219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 3006219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 3007219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 3008219089Spjd * changes are all handled within libzfs. 3009219089Spjd */ 3010219089Spjdint 3011219089Spjdzpool_do_iostat(int argc, char **argv) 3012219089Spjd{ 3013219089Spjd int c; 3014219089Spjd int ret; 3015219089Spjd int npools; 3016219089Spjd unsigned long interval = 0, count = 0; 3017219089Spjd zpool_list_t *list; 3018219089Spjd boolean_t verbose = B_FALSE; 3019219089Spjd iostat_cbdata_t cb; 3020219089Spjd 3021219089Spjd /* check options */ 3022219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 3023219089Spjd switch (c) { 3024219089Spjd case 'T': 3025219089Spjd get_timestamp_arg(*optarg); 3026219089Spjd break; 3027219089Spjd case 'v': 3028219089Spjd verbose = B_TRUE; 3029219089Spjd break; 3030219089Spjd case '?': 3031219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3032219089Spjd optopt); 3033219089Spjd usage(B_FALSE); 3034219089Spjd } 3035219089Spjd } 3036219089Spjd 3037219089Spjd argc -= optind; 3038219089Spjd argv += optind; 3039219089Spjd 3040219089Spjd get_interval_count(&argc, argv, &interval, &count); 3041219089Spjd 3042168404Spjd /* 3043168404Spjd * Construct the list of all interesting pools. 3044168404Spjd */ 3045168404Spjd ret = 0; 3046168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 3047168404Spjd return (1); 3048168404Spjd 3049168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 3050168404Spjd pool_list_free(list); 3051168404Spjd return (1); 3052168404Spjd } 3053168404Spjd 3054168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 3055168404Spjd pool_list_free(list); 3056168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 3057168404Spjd return (1); 3058168404Spjd } 3059168404Spjd 3060168404Spjd /* 3061168404Spjd * Enter the main iostat loop. 3062168404Spjd */ 3063168404Spjd cb.cb_list = list; 3064168404Spjd cb.cb_verbose = verbose; 3065168404Spjd cb.cb_iteration = 0; 3066168404Spjd cb.cb_namewidth = 0; 3067168404Spjd 3068168404Spjd for (;;) { 3069168404Spjd pool_list_update(list); 3070168404Spjd 3071168404Spjd if ((npools = pool_list_count(list)) == 0) 3072168404Spjd break; 3073168404Spjd 3074168404Spjd /* 3075168404Spjd * Refresh all statistics. This is done as an explicit step 3076168404Spjd * before calculating the maximum name width, so that any 3077168404Spjd * configuration changes are properly accounted for. 3078168404Spjd */ 3079168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 3080168404Spjd 3081168404Spjd /* 3082168404Spjd * Iterate over all pools to determine the maximum width 3083168404Spjd * for the pool / device name column across all pools. 3084168404Spjd */ 3085168404Spjd cb.cb_namewidth = 0; 3086168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3087168404Spjd 3088219089Spjd if (timestamp_fmt != NODATE) 3089219089Spjd print_timestamp(timestamp_fmt); 3090219089Spjd 3091168404Spjd /* 3092168404Spjd * If it's the first time, or verbose mode, print the header. 3093168404Spjd */ 3094168404Spjd if (++cb.cb_iteration == 1 || verbose) 3095168404Spjd print_iostat_header(&cb); 3096168404Spjd 3097168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 3098168404Spjd 3099168404Spjd /* 3100168404Spjd * If there's more than one pool, and we're not in verbose mode 3101168404Spjd * (which prints a separator for us), then print a separator. 3102168404Spjd */ 3103168404Spjd if (npools > 1 && !verbose) 3104168404Spjd print_iostat_separator(&cb); 3105168404Spjd 3106168404Spjd if (verbose) 3107168404Spjd (void) printf("\n"); 3108168404Spjd 3109168404Spjd /* 3110168404Spjd * Flush the output so that redirection to a file isn't buffered 3111168404Spjd * indefinitely. 3112168404Spjd */ 3113168404Spjd (void) fflush(stdout); 3114168404Spjd 3115168404Spjd if (interval == 0) 3116168404Spjd break; 3117168404Spjd 3118168404Spjd if (count != 0 && --count == 0) 3119168404Spjd break; 3120168404Spjd 3121168404Spjd (void) sleep(interval); 3122168404Spjd } 3123168404Spjd 3124168404Spjd pool_list_free(list); 3125168404Spjd 3126168404Spjd return (ret); 3127168404Spjd} 3128168404Spjd 3129168404Spjdtypedef struct list_cbdata { 3130236155Smm boolean_t cb_verbose; 3131236155Smm int cb_namewidth; 3132168404Spjd boolean_t cb_scripted; 3133185029Spjd zprop_list_t *cb_proplist; 3134263889Sdelphij boolean_t cb_literal; 3135168404Spjd} list_cbdata_t; 3136168404Spjd 3137168404Spjd/* 3138168404Spjd * Given a list of columns to display, output appropriate headers for each one. 3139168404Spjd */ 3140185029Spjdstatic void 3141236155Smmprint_header(list_cbdata_t *cb) 3142168404Spjd{ 3143236155Smm zprop_list_t *pl = cb->cb_proplist; 3144236884Smm char headerbuf[ZPOOL_MAXPROPLEN]; 3145185029Spjd const char *header; 3146185029Spjd boolean_t first = B_TRUE; 3147185029Spjd boolean_t right_justify; 3148236155Smm size_t width = 0; 3149168404Spjd 3150185029Spjd for (; pl != NULL; pl = pl->pl_next) { 3151236155Smm width = pl->pl_width; 3152236155Smm if (first && cb->cb_verbose) { 3153236155Smm /* 3154236155Smm * Reset the width to accommodate the verbose listing 3155236155Smm * of devices. 3156236155Smm */ 3157236155Smm width = cb->cb_namewidth; 3158236155Smm } 3159236155Smm 3160185029Spjd if (!first) 3161168404Spjd (void) printf(" "); 3162168404Spjd else 3163185029Spjd first = B_FALSE; 3164168404Spjd 3165236884Smm right_justify = B_FALSE; 3166236884Smm if (pl->pl_prop != ZPROP_INVAL) { 3167236884Smm header = zpool_prop_column_name(pl->pl_prop); 3168236884Smm right_justify = zpool_prop_align_right(pl->pl_prop); 3169236884Smm } else { 3170236884Smm int i; 3171185029Spjd 3172236884Smm for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 3173236884Smm headerbuf[i] = toupper(pl->pl_user_prop[i]); 3174236884Smm headerbuf[i] = '\0'; 3175236884Smm header = headerbuf; 3176236884Smm } 3177236884Smm 3178185029Spjd if (pl->pl_next == NULL && !right_justify) 3179185029Spjd (void) printf("%s", header); 3180185029Spjd else if (right_justify) 3181236155Smm (void) printf("%*s", width, header); 3182185029Spjd else 3183236155Smm (void) printf("%-*s", width, header); 3184236155Smm 3185168404Spjd } 3186168404Spjd 3187168404Spjd (void) printf("\n"); 3188168404Spjd} 3189168404Spjd 3190185029Spjd/* 3191185029Spjd * Given a pool and a list of properties, print out all the properties according 3192185029Spjd * to the described layout. 3193185029Spjd */ 3194185029Spjdstatic void 3195236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 3196168404Spjd{ 3197236155Smm zprop_list_t *pl = cb->cb_proplist; 3198185029Spjd boolean_t first = B_TRUE; 3199185029Spjd char property[ZPOOL_MAXPROPLEN]; 3200185029Spjd char *propstr; 3201185029Spjd boolean_t right_justify; 3202236155Smm size_t width; 3203168404Spjd 3204185029Spjd for (; pl != NULL; pl = pl->pl_next) { 3205236155Smm 3206236155Smm width = pl->pl_width; 3207236155Smm if (first && cb->cb_verbose) { 3208236155Smm /* 3209236155Smm * Reset the width to accommodate the verbose listing 3210236155Smm * of devices. 3211236155Smm */ 3212236155Smm width = cb->cb_namewidth; 3213236155Smm } 3214236155Smm 3215185029Spjd if (!first) { 3216236155Smm if (cb->cb_scripted) 3217168404Spjd (void) printf("\t"); 3218168404Spjd else 3219168404Spjd (void) printf(" "); 3220185029Spjd } else { 3221185029Spjd first = B_FALSE; 3222168404Spjd } 3223168404Spjd 3224185029Spjd right_justify = B_FALSE; 3225185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 3226272502Sdelphij if (zpool_get_prop(zhp, pl->pl_prop, property, 3227263889Sdelphij sizeof (property), NULL, cb->cb_literal) != 0) 3228185029Spjd propstr = "-"; 3229168404Spjd else 3230185029Spjd propstr = property; 3231168404Spjd 3232185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 3233236884Smm } else if ((zpool_prop_feature(pl->pl_user_prop) || 3234236884Smm zpool_prop_unsupported(pl->pl_user_prop)) && 3235236884Smm zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 3236236884Smm sizeof (property)) == 0) { 3237236884Smm propstr = property; 3238185029Spjd } else { 3239185029Spjd propstr = "-"; 3240185029Spjd } 3241168404Spjd 3242168404Spjd 3243185029Spjd /* 3244185029Spjd * If this is being called in scripted mode, or if this is the 3245185029Spjd * last column and it is left-justified, don't include a width 3246185029Spjd * format specifier. 3247185029Spjd */ 3248236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 3249185029Spjd (void) printf("%s", propstr); 3250185029Spjd else if (right_justify) 3251185029Spjd (void) printf("%*s", width, propstr); 3252185029Spjd else 3253185029Spjd (void) printf("%-*s", width, propstr); 3254185029Spjd } 3255168404Spjd 3256185029Spjd (void) printf("\n"); 3257185029Spjd} 3258168404Spjd 3259236155Smmstatic void 3260272502Sdelphijprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, 3261272502Sdelphij boolean_t valid) 3262236155Smm{ 3263236155Smm char propval[64]; 3264236155Smm boolean_t fixed; 3265236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 3266236155Smm 3267272502Sdelphij switch (prop) { 3268272502Sdelphij case ZPOOL_PROP_EXPANDSZ: 3269332547Smav case ZPOOL_PROP_CHECKPOINT: 3270272502Sdelphij if (value == 0) 3271272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 3272272502Sdelphij else 3273272502Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 3274272502Sdelphij break; 3275272502Sdelphij case ZPOOL_PROP_FRAGMENTATION: 3276272502Sdelphij if (value == ZFS_FRAG_INVALID) { 3277272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 3278272502Sdelphij } else { 3279272502Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", 3280272502Sdelphij value); 3281272502Sdelphij } 3282272502Sdelphij break; 3283272502Sdelphij case ZPOOL_PROP_CAPACITY: 3284269118Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", value); 3285272502Sdelphij break; 3286272502Sdelphij default: 3287269118Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 3288272502Sdelphij } 3289236155Smm 3290272502Sdelphij if (!valid) 3291272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 3292272502Sdelphij 3293236155Smm if (scripted) 3294236155Smm (void) printf("\t%s", propval); 3295236155Smm else 3296236155Smm (void) printf(" %*s", width, propval); 3297236155Smm} 3298236155Smm 3299236155Smmvoid 3300236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 3301236155Smm list_cbdata_t *cb, int depth) 3302236155Smm{ 3303236155Smm nvlist_t **child; 3304236155Smm vdev_stat_t *vs; 3305236155Smm uint_t c, children; 3306236155Smm char *vname; 3307236155Smm boolean_t scripted = cb->cb_scripted; 3308289536Smav uint64_t islog = B_FALSE; 3309289536Smav boolean_t haslog = B_FALSE; 3310289536Smav char *dashes = "%-*s - - - - - -\n"; 3311236155Smm 3312236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 3313236155Smm (uint64_t **)&vs, &c) == 0); 3314236155Smm 3315236155Smm if (name != NULL) { 3316272502Sdelphij boolean_t toplevel = (vs->vs_space != 0); 3317272502Sdelphij uint64_t cap; 3318272502Sdelphij 3319332525Smav if (strcmp(name, VDEV_TYPE_INDIRECT) == 0) 3320332525Smav return; 3321332525Smav 3322236155Smm if (scripted) 3323236155Smm (void) printf("\t%s", name); 3324236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 3325236155Smm (void) printf("%*s%s", depth, "", name); 3326236155Smm else 3327236155Smm (void) printf("%*s%s%*s", depth, "", name, 3328236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 3329236155Smm 3330272502Sdelphij /* 3331272502Sdelphij * Print the properties for the individual vdevs. Some 3332272502Sdelphij * properties are only applicable to toplevel vdevs. The 3333272502Sdelphij * 'toplevel' boolean value is passed to the print_one_column() 3334272502Sdelphij * to indicate that the value is valid. 3335272502Sdelphij */ 3336272502Sdelphij print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted, 3337272502Sdelphij toplevel); 3338272502Sdelphij print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted, 3339272502Sdelphij toplevel); 3340272502Sdelphij print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, 3341272502Sdelphij scripted, toplevel); 3342332547Smav print_one_column(ZPOOL_PROP_CHECKPOINT, 3343332547Smav vs->vs_checkpoint_space, scripted, toplevel); 3344272502Sdelphij print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted, 3345272502Sdelphij B_TRUE); 3346272502Sdelphij print_one_column(ZPOOL_PROP_FRAGMENTATION, 3347272502Sdelphij vs->vs_fragmentation, scripted, 3348272502Sdelphij (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel)); 3349272502Sdelphij cap = (vs->vs_space == 0) ? 0 : 3350272502Sdelphij (vs->vs_alloc * 100 / vs->vs_space); 3351272502Sdelphij print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel); 3352236155Smm (void) printf("\n"); 3353236155Smm } 3354236155Smm 3355236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 3356236155Smm &child, &children) != 0) 3357236155Smm return; 3358236155Smm 3359236155Smm for (c = 0; c < children; c++) { 3360236155Smm uint64_t ishole = B_FALSE; 3361236155Smm 3362236155Smm if (nvlist_lookup_uint64(child[c], 3363236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 3364236155Smm continue; 3365236155Smm 3366289536Smav if (nvlist_lookup_uint64(child[c], 3367289536Smav ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) { 3368289536Smav haslog = B_TRUE; 3369289536Smav continue; 3370289536Smav } 3371289536Smav 3372236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3373236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3374236155Smm free(vname); 3375236155Smm } 3376236155Smm 3377289536Smav if (haslog == B_TRUE) { 3378289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3379289536Smav (void) printf(dashes, cb->cb_namewidth, "log"); 3380289536Smav for (c = 0; c < children; c++) { 3381289536Smav if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3382289536Smav &islog) != 0 || !islog) 3383289536Smav continue; 3384289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3385289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3386289536Smav free(vname); 3387289536Smav } 3388289536Smav } 3389289536Smav 3390236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 3391289536Smav &child, &children) == 0 && children > 0) { 3392289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3393289536Smav (void) printf(dashes, cb->cb_namewidth, "cache"); 3394289536Smav for (c = 0; c < children; c++) { 3395289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3396289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3397289536Smav free(vname); 3398289536Smav } 3399289536Smav } 3400236155Smm 3401289536Smav if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child, 3402289536Smav &children) == 0 && children > 0) { 3403289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3404289536Smav (void) printf(dashes, cb->cb_namewidth, "spare"); 3405236155Smm for (c = 0; c < children; c++) { 3406289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3407236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3408236155Smm free(vname); 3409236155Smm } 3410236155Smm } 3411236155Smm} 3412236155Smm 3413236155Smm 3414185029Spjd/* 3415185029Spjd * Generic callback function to list a pool. 3416185029Spjd */ 3417185029Spjdint 3418185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 3419185029Spjd{ 3420185029Spjd list_cbdata_t *cbp = data; 3421236155Smm nvlist_t *config; 3422236155Smm nvlist_t *nvroot; 3423168404Spjd 3424236155Smm config = zpool_get_config(zhp, NULL); 3425168404Spjd 3426236155Smm print_pool(zhp, cbp); 3427236155Smm if (!cbp->cb_verbose) 3428236155Smm return (0); 3429168404Spjd 3430236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3431236155Smm &nvroot) == 0); 3432236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 3433236155Smm 3434168404Spjd return (0); 3435168404Spjd} 3436168404Spjd 3437168404Spjd/* 3438263889Sdelphij * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 3439168404Spjd * 3440185029Spjd * -H Scripted mode. Don't display headers, and separate properties 3441185029Spjd * by a single tab. 3442185029Spjd * -o List of properties to display. Defaults to 3443272502Sdelphij * "name,size,allocated,free,expandsize,fragmentation,capacity," 3444272502Sdelphij * "dedupratio,health,altroot" 3445342941Savg * -p Diplay values in parsable (exact) format. 3446219089Spjd * -T Display a timestamp in date(1) or Unix format 3447168404Spjd * 3448168404Spjd * List all pools in the system, whether or not they're healthy. Output space 3449168404Spjd * statistics for each one, as well as health status summary. 3450168404Spjd */ 3451168404Spjdint 3452168404Spjdzpool_do_list(int argc, char **argv) 3453168404Spjd{ 3454168404Spjd int c; 3455168404Spjd int ret; 3456168404Spjd list_cbdata_t cb = { 0 }; 3457185029Spjd static char default_props[] = 3458332547Smav "name,size,allocated,free,checkpoint,expandsize,fragmentation," 3459332547Smav "capacity,dedupratio,health,altroot"; 3460185029Spjd char *props = default_props; 3461219089Spjd unsigned long interval = 0, count = 0; 3462236155Smm zpool_list_t *list; 3463236155Smm boolean_t first = B_TRUE; 3464168404Spjd 3465168404Spjd /* check options */ 3466263889Sdelphij while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) { 3467168404Spjd switch (c) { 3468168404Spjd case 'H': 3469168404Spjd cb.cb_scripted = B_TRUE; 3470168404Spjd break; 3471168404Spjd case 'o': 3472185029Spjd props = optarg; 3473168404Spjd break; 3474263889Sdelphij case 'p': 3475263889Sdelphij cb.cb_literal = B_TRUE; 3476263889Sdelphij break; 3477219089Spjd case 'T': 3478219089Spjd get_timestamp_arg(*optarg); 3479219089Spjd break; 3480236155Smm case 'v': 3481236155Smm cb.cb_verbose = B_TRUE; 3482236155Smm break; 3483168404Spjd case ':': 3484168404Spjd (void) fprintf(stderr, gettext("missing argument for " 3485168404Spjd "'%c' option\n"), optopt); 3486168404Spjd usage(B_FALSE); 3487168404Spjd break; 3488168404Spjd case '?': 3489168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3490168404Spjd optopt); 3491168404Spjd usage(B_FALSE); 3492168404Spjd } 3493168404Spjd } 3494168404Spjd 3495168404Spjd argc -= optind; 3496168404Spjd argv += optind; 3497168404Spjd 3498219089Spjd get_interval_count(&argc, argv, &interval, &count); 3499219089Spjd 3500185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3501185029Spjd usage(B_FALSE); 3502168404Spjd 3503219089Spjd for (;;) { 3504268470Sdelphij if ((list = pool_list_get(argc, argv, &cb.cb_proplist, 3505268470Sdelphij &ret)) == NULL) 3506268470Sdelphij return (1); 3507168404Spjd 3508236155Smm if (pool_list_count(list) == 0) 3509236155Smm break; 3510236155Smm 3511236155Smm cb.cb_namewidth = 0; 3512236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3513236155Smm 3514219089Spjd if (timestamp_fmt != NODATE) 3515219089Spjd print_timestamp(timestamp_fmt); 3516168404Spjd 3517236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 3518236155Smm print_header(&cb); 3519236155Smm first = B_FALSE; 3520219089Spjd } 3521236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 3522219089Spjd 3523219089Spjd if (interval == 0) 3524219089Spjd break; 3525219089Spjd 3526219089Spjd if (count != 0 && --count == 0) 3527219089Spjd break; 3528219089Spjd 3529268470Sdelphij pool_list_free(list); 3530219089Spjd (void) sleep(interval); 3531168404Spjd } 3532168404Spjd 3533268470Sdelphij if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3534268470Sdelphij (void) printf(gettext("no pools available\n")); 3535268470Sdelphij ret = 0; 3536268470Sdelphij } 3537268470Sdelphij 3538268470Sdelphij pool_list_free(list); 3539219089Spjd zprop_free_list(cb.cb_proplist); 3540168404Spjd return (ret); 3541168404Spjd} 3542168404Spjd 3543168404Spjdstatic int 3544168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 3545168404Spjd{ 3546168404Spjd boolean_t force = B_FALSE; 3547168404Spjd int c; 3548168404Spjd nvlist_t *nvroot; 3549168404Spjd char *poolname, *old_disk, *new_disk; 3550168404Spjd zpool_handle_t *zhp; 3551331395Smav zpool_boot_label_t boot_type; 3552331395Smav uint64_t boot_size; 3553168404Spjd int ret; 3554168404Spjd 3555168404Spjd /* check options */ 3556168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3557168404Spjd switch (c) { 3558168404Spjd case 'f': 3559168404Spjd force = B_TRUE; 3560168404Spjd break; 3561168404Spjd case '?': 3562168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3563168404Spjd optopt); 3564168404Spjd usage(B_FALSE); 3565168404Spjd } 3566168404Spjd } 3567168404Spjd 3568168404Spjd argc -= optind; 3569168404Spjd argv += optind; 3570168404Spjd 3571168404Spjd /* get pool name and check number of arguments */ 3572168404Spjd if (argc < 1) { 3573168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3574168404Spjd usage(B_FALSE); 3575168404Spjd } 3576168404Spjd 3577168404Spjd poolname = argv[0]; 3578168404Spjd 3579168404Spjd if (argc < 2) { 3580168404Spjd (void) fprintf(stderr, 3581168404Spjd gettext("missing <device> specification\n")); 3582168404Spjd usage(B_FALSE); 3583168404Spjd } 3584168404Spjd 3585168404Spjd old_disk = argv[1]; 3586168404Spjd 3587168404Spjd if (argc < 3) { 3588168404Spjd if (!replacing) { 3589168404Spjd (void) fprintf(stderr, 3590168404Spjd gettext("missing <new_device> specification\n")); 3591168404Spjd usage(B_FALSE); 3592168404Spjd } 3593168404Spjd new_disk = old_disk; 3594168404Spjd argc -= 1; 3595168404Spjd argv += 1; 3596168404Spjd } else { 3597168404Spjd new_disk = argv[2]; 3598168404Spjd argc -= 2; 3599168404Spjd argv += 2; 3600168404Spjd } 3601168404Spjd 3602168404Spjd if (argc > 1) { 3603168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3604168404Spjd usage(B_FALSE); 3605168404Spjd } 3606168404Spjd 3607168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3608168404Spjd return (1); 3609168404Spjd 3610185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3611168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3612168404Spjd poolname); 3613168404Spjd zpool_close(zhp); 3614168404Spjd return (1); 3615168404Spjd } 3616168404Spjd 3617331395Smav if (zpool_is_bootable(zhp)) 3618331395Smav boot_type = ZPOOL_COPY_BOOT_LABEL; 3619331395Smav else 3620331395Smav boot_type = ZPOOL_NO_BOOT_LABEL; 3621331395Smav 3622331395Smav boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL); 3623185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3624331395Smav boot_type, boot_size, argc, argv); 3625168404Spjd if (nvroot == NULL) { 3626168404Spjd zpool_close(zhp); 3627168404Spjd return (1); 3628168404Spjd } 3629168404Spjd 3630168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3631168404Spjd 3632168404Spjd nvlist_free(nvroot); 3633168404Spjd zpool_close(zhp); 3634168404Spjd 3635168404Spjd return (ret); 3636168404Spjd} 3637168404Spjd 3638168404Spjd/* 3639168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3640168404Spjd * 3641168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3642168404Spjd * 3643168404Spjd * Replace <device> with <new_device>. 3644168404Spjd */ 3645168404Spjd/* ARGSUSED */ 3646168404Spjdint 3647168404Spjdzpool_do_replace(int argc, char **argv) 3648168404Spjd{ 3649168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3650168404Spjd} 3651168404Spjd 3652168404Spjd/* 3653168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3654168404Spjd * 3655168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3656168404Spjd * 3657168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3658168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3659168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3660168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3661168404Spjd */ 3662168404Spjdint 3663168404Spjdzpool_do_attach(int argc, char **argv) 3664168404Spjd{ 3665168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3666168404Spjd} 3667168404Spjd 3668168404Spjd/* 3669168404Spjd * zpool detach [-f] <pool> <device> 3670168404Spjd * 3671168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3672168404Spjd * (not supported yet) 3673168404Spjd * 3674168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3675168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3676168404Spjd * has the only valid copy of some data. 3677168404Spjd */ 3678168404Spjd/* ARGSUSED */ 3679168404Spjdint 3680168404Spjdzpool_do_detach(int argc, char **argv) 3681168404Spjd{ 3682168404Spjd int c; 3683168404Spjd char *poolname, *path; 3684168404Spjd zpool_handle_t *zhp; 3685168404Spjd int ret; 3686168404Spjd 3687168404Spjd /* check options */ 3688168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3689168404Spjd switch (c) { 3690168404Spjd case 'f': 3691168404Spjd case '?': 3692168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3693168404Spjd optopt); 3694168404Spjd usage(B_FALSE); 3695168404Spjd } 3696168404Spjd } 3697168404Spjd 3698168404Spjd argc -= optind; 3699168404Spjd argv += optind; 3700168404Spjd 3701168404Spjd /* get pool name and check number of arguments */ 3702168404Spjd if (argc < 1) { 3703168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3704168404Spjd usage(B_FALSE); 3705168404Spjd } 3706168404Spjd 3707168404Spjd if (argc < 2) { 3708168404Spjd (void) fprintf(stderr, 3709168404Spjd gettext("missing <device> specification\n")); 3710168404Spjd usage(B_FALSE); 3711168404Spjd } 3712168404Spjd 3713168404Spjd poolname = argv[0]; 3714168404Spjd path = argv[1]; 3715168404Spjd 3716168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3717168404Spjd return (1); 3718168404Spjd 3719168404Spjd ret = zpool_vdev_detach(zhp, path); 3720168404Spjd 3721168404Spjd zpool_close(zhp); 3722168404Spjd 3723168404Spjd return (ret); 3724168404Spjd} 3725168404Spjd 3726168404Spjd/* 3727219089Spjd * zpool split [-n] [-o prop=val] ... 3728219089Spjd * [-o mntopt] ... 3729219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3730219089Spjd * 3731219089Spjd * -n Do not split the pool, but display the resulting layout if 3732219089Spjd * it were to be split. 3733219089Spjd * -o Set property=value, or set mount options. 3734219089Spjd * -R Mount the split-off pool under an alternate root. 3735219089Spjd * 3736219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3737219089Spjd * off may be listed, provided that no more than one device is specified 3738219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3739219089Spjd * state unless -R is specified. 3740219089Spjd * 3741219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3742219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3743219089Spjd * undergoing a resilvering operation. 3744219089Spjd */ 3745219089Spjdint 3746219089Spjdzpool_do_split(int argc, char **argv) 3747219089Spjd{ 3748219089Spjd char *srcpool, *newpool, *propval; 3749219089Spjd char *mntopts = NULL; 3750219089Spjd splitflags_t flags; 3751219089Spjd int c, ret = 0; 3752219089Spjd zpool_handle_t *zhp; 3753219089Spjd nvlist_t *config, *props = NULL; 3754219089Spjd 3755219089Spjd flags.dryrun = B_FALSE; 3756219089Spjd flags.import = B_FALSE; 3757219089Spjd 3758219089Spjd /* check options */ 3759219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3760219089Spjd switch (c) { 3761219089Spjd case 'R': 3762219089Spjd flags.import = B_TRUE; 3763219089Spjd if (add_prop_list( 3764219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3765219089Spjd &props, B_TRUE) != 0) { 3766296528Smav nvlist_free(props); 3767219089Spjd usage(B_FALSE); 3768219089Spjd } 3769219089Spjd break; 3770219089Spjd case 'n': 3771219089Spjd flags.dryrun = B_TRUE; 3772219089Spjd break; 3773219089Spjd case 'o': 3774219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3775219089Spjd *propval = '\0'; 3776219089Spjd propval++; 3777219089Spjd if (add_prop_list(optarg, propval, 3778219089Spjd &props, B_TRUE) != 0) { 3779296528Smav nvlist_free(props); 3780219089Spjd usage(B_FALSE); 3781219089Spjd } 3782219089Spjd } else { 3783219089Spjd mntopts = optarg; 3784219089Spjd } 3785219089Spjd break; 3786219089Spjd case ':': 3787219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3788219089Spjd "'%c' option\n"), optopt); 3789219089Spjd usage(B_FALSE); 3790219089Spjd break; 3791219089Spjd case '?': 3792219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3793219089Spjd optopt); 3794219089Spjd usage(B_FALSE); 3795219089Spjd break; 3796219089Spjd } 3797219089Spjd } 3798219089Spjd 3799219089Spjd if (!flags.import && mntopts != NULL) { 3800219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3801219089Spjd "valid when importing the pool\n")); 3802219089Spjd usage(B_FALSE); 3803219089Spjd } 3804219089Spjd 3805219089Spjd argc -= optind; 3806219089Spjd argv += optind; 3807219089Spjd 3808219089Spjd if (argc < 1) { 3809219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3810219089Spjd usage(B_FALSE); 3811219089Spjd } 3812219089Spjd if (argc < 2) { 3813219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3814219089Spjd usage(B_FALSE); 3815219089Spjd } 3816219089Spjd 3817219089Spjd srcpool = argv[0]; 3818219089Spjd newpool = argv[1]; 3819219089Spjd 3820219089Spjd argc -= 2; 3821219089Spjd argv += 2; 3822219089Spjd 3823219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3824219089Spjd return (1); 3825219089Spjd 3826219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3827219089Spjd if (config == NULL) { 3828219089Spjd ret = 1; 3829219089Spjd } else { 3830219089Spjd if (flags.dryrun) { 3831219089Spjd (void) printf(gettext("would create '%s' with the " 3832219089Spjd "following layout:\n\n"), newpool); 3833219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3834219089Spjd } 3835219089Spjd nvlist_free(config); 3836219089Spjd } 3837219089Spjd 3838219089Spjd zpool_close(zhp); 3839219089Spjd 3840219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3841219089Spjd return (ret); 3842219089Spjd 3843219089Spjd /* 3844219089Spjd * The split was successful. Now we need to open the new 3845219089Spjd * pool and import it. 3846219089Spjd */ 3847219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3848219089Spjd return (1); 3849219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3850219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3851219089Spjd ret = 1; 3852240415Smm (void) fprintf(stderr, gettext("Split was successful, but " 3853219089Spjd "the datasets could not all be mounted\n")); 3854219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3855219089Spjd "different altroot\n"), "zpool import"); 3856219089Spjd } 3857219089Spjd zpool_close(zhp); 3858219089Spjd 3859219089Spjd return (ret); 3860219089Spjd} 3861219089Spjd 3862219089Spjd 3863219089Spjd 3864219089Spjd/* 3865168404Spjd * zpool online <pool> <device> ... 3866168404Spjd */ 3867168404Spjdint 3868168404Spjdzpool_do_online(int argc, char **argv) 3869168404Spjd{ 3870168404Spjd int c, i; 3871168404Spjd char *poolname; 3872168404Spjd zpool_handle_t *zhp; 3873168404Spjd int ret = 0; 3874185029Spjd vdev_state_t newstate; 3875219089Spjd int flags = 0; 3876168404Spjd 3877168404Spjd /* check options */ 3878219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3879168404Spjd switch (c) { 3880219089Spjd case 'e': 3881219089Spjd flags |= ZFS_ONLINE_EXPAND; 3882219089Spjd break; 3883168404Spjd case 't': 3884168404Spjd case '?': 3885168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3886168404Spjd optopt); 3887168404Spjd usage(B_FALSE); 3888168404Spjd } 3889168404Spjd } 3890168404Spjd 3891168404Spjd argc -= optind; 3892168404Spjd argv += optind; 3893168404Spjd 3894168404Spjd /* get pool name and check number of arguments */ 3895168404Spjd if (argc < 1) { 3896168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3897168404Spjd usage(B_FALSE); 3898168404Spjd } 3899168404Spjd if (argc < 2) { 3900168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3901168404Spjd usage(B_FALSE); 3902168404Spjd } 3903168404Spjd 3904168404Spjd poolname = argv[0]; 3905168404Spjd 3906168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3907168404Spjd return (1); 3908168404Spjd 3909185029Spjd for (i = 1; i < argc; i++) { 3910219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3911185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3912185029Spjd (void) printf(gettext("warning: device '%s' " 3913185029Spjd "onlined, but remains in faulted state\n"), 3914185029Spjd argv[i]); 3915185029Spjd if (newstate == VDEV_STATE_FAULTED) 3916185029Spjd (void) printf(gettext("use 'zpool " 3917185029Spjd "clear' to restore a faulted " 3918185029Spjd "device\n")); 3919185029Spjd else 3920185029Spjd (void) printf(gettext("use 'zpool " 3921185029Spjd "replace' to replace devices " 3922185029Spjd "that are no longer present\n")); 3923185029Spjd } 3924185029Spjd } else { 3925168404Spjd ret = 1; 3926185029Spjd } 3927185029Spjd } 3928168404Spjd 3929168404Spjd zpool_close(zhp); 3930168404Spjd 3931168404Spjd return (ret); 3932168404Spjd} 3933168404Spjd 3934168404Spjd/* 3935168404Spjd * zpool offline [-ft] <pool> <device> ... 3936168404Spjd * 3937168404Spjd * -f Force the device into the offline state, even if doing 3938168404Spjd * so would appear to compromise pool availability. 3939168404Spjd * (not supported yet) 3940168404Spjd * 3941168404Spjd * -t Only take the device off-line temporarily. The offline 3942168404Spjd * state will not be persistent across reboots. 3943168404Spjd */ 3944168404Spjd/* ARGSUSED */ 3945168404Spjdint 3946168404Spjdzpool_do_offline(int argc, char **argv) 3947168404Spjd{ 3948168404Spjd int c, i; 3949168404Spjd char *poolname; 3950168404Spjd zpool_handle_t *zhp; 3951168404Spjd int ret = 0; 3952168404Spjd boolean_t istmp = B_FALSE; 3953168404Spjd 3954168404Spjd /* check options */ 3955168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3956168404Spjd switch (c) { 3957168404Spjd case 't': 3958168404Spjd istmp = B_TRUE; 3959168404Spjd break; 3960168404Spjd case 'f': 3961168404Spjd case '?': 3962168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3963168404Spjd optopt); 3964168404Spjd usage(B_FALSE); 3965168404Spjd } 3966168404Spjd } 3967168404Spjd 3968168404Spjd argc -= optind; 3969168404Spjd argv += optind; 3970168404Spjd 3971168404Spjd /* get pool name and check number of arguments */ 3972168404Spjd if (argc < 1) { 3973168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3974168404Spjd usage(B_FALSE); 3975168404Spjd } 3976168404Spjd if (argc < 2) { 3977168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3978168404Spjd usage(B_FALSE); 3979168404Spjd } 3980168404Spjd 3981168404Spjd poolname = argv[0]; 3982168404Spjd 3983168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3984168404Spjd return (1); 3985168404Spjd 3986185029Spjd for (i = 1; i < argc; i++) { 3987185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3988168404Spjd ret = 1; 3989185029Spjd } 3990168404Spjd 3991168404Spjd zpool_close(zhp); 3992168404Spjd 3993168404Spjd return (ret); 3994168404Spjd} 3995168404Spjd 3996168404Spjd/* 3997168404Spjd * zpool clear <pool> [device] 3998168404Spjd * 3999168404Spjd * Clear all errors associated with a pool or a particular device. 4000168404Spjd */ 4001168404Spjdint 4002168404Spjdzpool_do_clear(int argc, char **argv) 4003168404Spjd{ 4004219089Spjd int c; 4005168404Spjd int ret = 0; 4006219089Spjd boolean_t dryrun = B_FALSE; 4007219089Spjd boolean_t do_rewind = B_FALSE; 4008219089Spjd boolean_t xtreme_rewind = B_FALSE; 4009219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 4010219089Spjd nvlist_t *policy = NULL; 4011168404Spjd zpool_handle_t *zhp; 4012168404Spjd char *pool, *device; 4013168404Spjd 4014219089Spjd /* check options */ 4015219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 4016219089Spjd switch (c) { 4017219089Spjd case 'F': 4018219089Spjd do_rewind = B_TRUE; 4019219089Spjd break; 4020219089Spjd case 'n': 4021219089Spjd dryrun = B_TRUE; 4022219089Spjd break; 4023219089Spjd case 'X': 4024219089Spjd xtreme_rewind = B_TRUE; 4025219089Spjd break; 4026219089Spjd case '?': 4027219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4028219089Spjd optopt); 4029219089Spjd usage(B_FALSE); 4030219089Spjd } 4031219089Spjd } 4032219089Spjd 4033219089Spjd argc -= optind; 4034219089Spjd argv += optind; 4035219089Spjd 4036219089Spjd if (argc < 1) { 4037168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 4038168404Spjd usage(B_FALSE); 4039168404Spjd } 4040168404Spjd 4041219089Spjd if (argc > 2) { 4042168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 4043168404Spjd usage(B_FALSE); 4044168404Spjd } 4045168404Spjd 4046219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 4047219089Spjd (void) fprintf(stderr, 4048219089Spjd gettext("-n or -X only meaningful with -F\n")); 4049219089Spjd usage(B_FALSE); 4050219089Spjd } 4051219089Spjd if (dryrun) 4052219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 4053219089Spjd else if (do_rewind) 4054219089Spjd rewind_policy = ZPOOL_DO_REWIND; 4055219089Spjd if (xtreme_rewind) 4056219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 4057168404Spjd 4058219089Spjd /* In future, further rewind policy choices can be passed along here */ 4059219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 4060332550Smav nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, 4061332550Smav rewind_policy) != 0) { 4062168404Spjd return (1); 4063332550Smav } 4064168404Spjd 4065219089Spjd pool = argv[0]; 4066219089Spjd device = argc == 2 ? argv[1] : NULL; 4067219089Spjd 4068219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 4069219089Spjd nvlist_free(policy); 4070219089Spjd return (1); 4071219089Spjd } 4072219089Spjd 4073219089Spjd if (zpool_clear(zhp, device, policy) != 0) 4074168404Spjd ret = 1; 4075168404Spjd 4076168404Spjd zpool_close(zhp); 4077168404Spjd 4078219089Spjd nvlist_free(policy); 4079219089Spjd 4080168404Spjd return (ret); 4081168404Spjd} 4082168404Spjd 4083228103Smm/* 4084228103Smm * zpool reguid <pool> 4085228103Smm */ 4086228103Smmint 4087228103Smmzpool_do_reguid(int argc, char **argv) 4088228103Smm{ 4089228103Smm int c; 4090228103Smm char *poolname; 4091228103Smm zpool_handle_t *zhp; 4092228103Smm int ret = 0; 4093228103Smm 4094228103Smm /* check options */ 4095228103Smm while ((c = getopt(argc, argv, "")) != -1) { 4096228103Smm switch (c) { 4097228103Smm case '?': 4098228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4099228103Smm optopt); 4100228103Smm usage(B_FALSE); 4101228103Smm } 4102228103Smm } 4103228103Smm 4104228103Smm argc -= optind; 4105228103Smm argv += optind; 4106228103Smm 4107228103Smm /* get pool name and check number of arguments */ 4108228103Smm if (argc < 1) { 4109228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 4110228103Smm usage(B_FALSE); 4111228103Smm } 4112228103Smm 4113228103Smm if (argc > 1) { 4114228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 4115228103Smm usage(B_FALSE); 4116228103Smm } 4117228103Smm 4118228103Smm poolname = argv[0]; 4119228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 4120228103Smm return (1); 4121228103Smm 4122228103Smm ret = zpool_reguid(zhp); 4123228103Smm 4124228103Smm zpool_close(zhp); 4125228103Smm return (ret); 4126228103Smm} 4127228103Smm 4128228103Smm 4129236155Smm/* 4130236155Smm * zpool reopen <pool> 4131236155Smm * 4132236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 4133236155Smm */ 4134236155Smmint 4135236155Smmzpool_do_reopen(int argc, char **argv) 4136236155Smm{ 4137260138Sdelphij int c; 4138236155Smm int ret = 0; 4139236155Smm zpool_handle_t *zhp; 4140236155Smm char *pool; 4141236155Smm 4142260138Sdelphij /* check options */ 4143260138Sdelphij while ((c = getopt(argc, argv, "")) != -1) { 4144260138Sdelphij switch (c) { 4145260138Sdelphij case '?': 4146260138Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4147260138Sdelphij optopt); 4148260138Sdelphij usage(B_FALSE); 4149260138Sdelphij } 4150260138Sdelphij } 4151260138Sdelphij 4152236155Smm argc--; 4153236155Smm argv++; 4154236155Smm 4155260138Sdelphij if (argc < 1) { 4156260138Sdelphij (void) fprintf(stderr, gettext("missing pool name\n")); 4157260138Sdelphij usage(B_FALSE); 4158260138Sdelphij } 4159236155Smm 4160260138Sdelphij if (argc > 1) { 4161260138Sdelphij (void) fprintf(stderr, gettext("too many arguments\n")); 4162260138Sdelphij usage(B_FALSE); 4163260138Sdelphij } 4164260138Sdelphij 4165236155Smm pool = argv[0]; 4166236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 4167236155Smm return (1); 4168236155Smm 4169236155Smm ret = zpool_reopen(zhp); 4170236155Smm zpool_close(zhp); 4171236155Smm return (ret); 4172236155Smm} 4173236155Smm 4174168404Spjdtypedef struct scrub_cbdata { 4175168404Spjd int cb_type; 4176168404Spjd int cb_argc; 4177168404Spjd char **cb_argv; 4178324010Savg pool_scrub_cmd_t cb_scrub_cmd; 4179168404Spjd} scrub_cbdata_t; 4180168404Spjd 4181332547Smavstatic boolean_t 4182332547Smavzpool_has_checkpoint(zpool_handle_t *zhp) 4183332547Smav{ 4184332547Smav nvlist_t *config, *nvroot; 4185332547Smav 4186332547Smav config = zpool_get_config(zhp, NULL); 4187332547Smav 4188332547Smav if (config != NULL) { 4189332547Smav pool_checkpoint_stat_t *pcs = NULL; 4190332547Smav uint_t c; 4191332547Smav 4192332547Smav nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE); 4193332547Smav (void) nvlist_lookup_uint64_array(nvroot, 4194332547Smav ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c); 4195332547Smav 4196332547Smav if (pcs == NULL || pcs->pcs_state == CS_NONE) 4197332547Smav return (B_FALSE); 4198332547Smav 4199332547Smav assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS || 4200332547Smav pcs->pcs_state == CS_CHECKPOINT_DISCARDING); 4201332547Smav return (B_TRUE); 4202332547Smav } 4203332547Smav 4204332547Smav return (B_FALSE); 4205332547Smav} 4206332547Smav 4207168404Spjdint 4208168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 4209168404Spjd{ 4210168404Spjd scrub_cbdata_t *cb = data; 4211168404Spjd int err; 4212168404Spjd 4213168404Spjd /* 4214168404Spjd * Ignore faulted pools. 4215168404Spjd */ 4216168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4217168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 4218168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 4219168404Spjd return (1); 4220168404Spjd } 4221168404Spjd 4222324010Savg err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd); 4223168404Spjd 4224332547Smav if (err == 0 && zpool_has_checkpoint(zhp) && 4225332547Smav cb->cb_type == POOL_SCAN_SCRUB) { 4226332547Smav (void) printf(gettext("warning: will not scrub state that " 4227332547Smav "belongs to the checkpoint of pool '%s'\n"), 4228332547Smav zpool_get_name(zhp)); 4229332547Smav } 4230332547Smav 4231168404Spjd return (err != 0); 4232168404Spjd} 4233168404Spjd 4234168404Spjd/* 4235324010Savg * zpool scrub [-s | -p] <pool> ... 4236168404Spjd * 4237168404Spjd * -s Stop. Stops any in-progress scrub. 4238324010Savg * -p Pause. Pause in-progress scrub. 4239168404Spjd */ 4240168404Spjdint 4241168404Spjdzpool_do_scrub(int argc, char **argv) 4242168404Spjd{ 4243168404Spjd int c; 4244168404Spjd scrub_cbdata_t cb; 4245168404Spjd 4246219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 4247324010Savg cb.cb_scrub_cmd = POOL_SCRUB_NORMAL; 4248168404Spjd 4249168404Spjd /* check options */ 4250324010Savg while ((c = getopt(argc, argv, "sp")) != -1) { 4251168404Spjd switch (c) { 4252168404Spjd case 's': 4253219089Spjd cb.cb_type = POOL_SCAN_NONE; 4254168404Spjd break; 4255324010Savg case 'p': 4256324010Savg cb.cb_scrub_cmd = POOL_SCRUB_PAUSE; 4257324010Savg break; 4258168404Spjd case '?': 4259168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4260168404Spjd optopt); 4261168404Spjd usage(B_FALSE); 4262168404Spjd } 4263168404Spjd } 4264168404Spjd 4265324010Savg if (cb.cb_type == POOL_SCAN_NONE && 4266324010Savg cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) { 4267324010Savg (void) fprintf(stderr, gettext("invalid option combination: " 4268324010Savg "-s and -p are mutually exclusive\n")); 4269324010Savg usage(B_FALSE); 4270324010Savg } 4271324010Savg 4272168404Spjd cb.cb_argc = argc; 4273168404Spjd cb.cb_argv = argv; 4274168404Spjd argc -= optind; 4275168404Spjd argv += optind; 4276168404Spjd 4277168404Spjd if (argc < 1) { 4278168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 4279168404Spjd usage(B_FALSE); 4280168404Spjd } 4281168404Spjd 4282168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 4283168404Spjd} 4284168404Spjd 4285339111Smavstatic void 4286339111Smavzpool_collect_leaves(zpool_handle_t *zhp, nvlist_t *nvroot, nvlist_t *res) 4287339111Smav{ 4288339111Smav uint_t children = 0; 4289339111Smav nvlist_t **child; 4290339111Smav uint_t i; 4291339111Smav 4292339111Smav (void) nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 4293339111Smav &child, &children); 4294339111Smav 4295339111Smav if (children == 0) { 4296339111Smav char *path = zpool_vdev_name(g_zfs, zhp, nvroot, B_FALSE); 4297339111Smav fnvlist_add_boolean(res, path); 4298339111Smav free(path); 4299339111Smav return; 4300339111Smav } 4301339111Smav 4302339111Smav for (i = 0; i < children; i++) { 4303339111Smav zpool_collect_leaves(zhp, child[i], res); 4304339111Smav } 4305339111Smav} 4306339111Smav 4307339111Smav/* 4308339111Smav * zpool initialize [-cs] <pool> [<vdev> ...] 4309339111Smav * Initialize all unused blocks in the specified vdevs, or all vdevs in the pool 4310339111Smav * if none specified. 4311339111Smav * 4312339111Smav * -c Cancel. Ends active initializing. 4313339111Smav * -s Suspend. Initializing can then be restarted with no flags. 4314339111Smav */ 4315339111Smavint 4316339111Smavzpool_do_initialize(int argc, char **argv) 4317339111Smav{ 4318339111Smav int c; 4319339111Smav char *poolname; 4320339111Smav zpool_handle_t *zhp; 4321339111Smav nvlist_t *vdevs; 4322339111Smav int err = 0; 4323339111Smav 4324339111Smav struct option long_options[] = { 4325339111Smav {"cancel", no_argument, NULL, 'c'}, 4326339111Smav {"suspend", no_argument, NULL, 's'}, 4327339111Smav {0, 0, 0, 0} 4328339111Smav }; 4329339111Smav 4330339111Smav pool_initialize_func_t cmd_type = POOL_INITIALIZE_DO; 4331339111Smav while ((c = getopt_long(argc, argv, "cs", long_options, NULL)) != -1) { 4332339111Smav switch (c) { 4333339111Smav case 'c': 4334339111Smav if (cmd_type != POOL_INITIALIZE_DO) { 4335339111Smav (void) fprintf(stderr, gettext("-c cannot be " 4336339111Smav "combined with other options\n")); 4337339111Smav usage(B_FALSE); 4338339111Smav } 4339339111Smav cmd_type = POOL_INITIALIZE_CANCEL; 4340339111Smav break; 4341339111Smav case 's': 4342339111Smav if (cmd_type != POOL_INITIALIZE_DO) { 4343339111Smav (void) fprintf(stderr, gettext("-s cannot be " 4344339111Smav "combined with other options\n")); 4345339111Smav usage(B_FALSE); 4346339111Smav } 4347339111Smav cmd_type = POOL_INITIALIZE_SUSPEND; 4348339111Smav break; 4349339111Smav case '?': 4350339111Smav if (optopt != 0) { 4351339111Smav (void) fprintf(stderr, 4352339111Smav gettext("invalid option '%c'\n"), optopt); 4353339111Smav } else { 4354339111Smav (void) fprintf(stderr, 4355339111Smav gettext("invalid option '%s'\n"), 4356339111Smav argv[optind - 1]); 4357339111Smav } 4358339111Smav usage(B_FALSE); 4359339111Smav } 4360339111Smav } 4361339111Smav 4362339111Smav argc -= optind; 4363339111Smav argv += optind; 4364339111Smav 4365339111Smav if (argc < 1) { 4366339111Smav (void) fprintf(stderr, gettext("missing pool name argument\n")); 4367339111Smav usage(B_FALSE); 4368339111Smav return (-1); 4369339111Smav } 4370339111Smav 4371339111Smav poolname = argv[0]; 4372339111Smav zhp = zpool_open(g_zfs, poolname); 4373339111Smav if (zhp == NULL) 4374339111Smav return (-1); 4375339111Smav 4376339111Smav vdevs = fnvlist_alloc(); 4377339111Smav if (argc == 1) { 4378339111Smav /* no individual leaf vdevs specified, so add them all */ 4379339111Smav nvlist_t *config = zpool_get_config(zhp, NULL); 4380339111Smav nvlist_t *nvroot = fnvlist_lookup_nvlist(config, 4381339111Smav ZPOOL_CONFIG_VDEV_TREE); 4382339111Smav zpool_collect_leaves(zhp, nvroot, vdevs); 4383339111Smav } else { 4384339111Smav int i; 4385339111Smav for (i = 1; i < argc; i++) { 4386339111Smav fnvlist_add_boolean(vdevs, argv[i]); 4387339111Smav } 4388339111Smav } 4389339111Smav 4390339111Smav err = zpool_initialize(zhp, cmd_type, vdevs); 4391339111Smav 4392339111Smav fnvlist_free(vdevs); 4393339111Smav zpool_close(zhp); 4394339111Smav 4395339111Smav return (err); 4396339111Smav} 4397339111Smav 4398168404Spjdtypedef struct status_cbdata { 4399168404Spjd int cb_count; 4400168404Spjd boolean_t cb_allpools; 4401168404Spjd boolean_t cb_verbose; 4402168404Spjd boolean_t cb_explain; 4403168404Spjd boolean_t cb_first; 4404219089Spjd boolean_t cb_dedup_stats; 4405168404Spjd} status_cbdata_t; 4406168404Spjd 4407168404Spjd/* 4408168404Spjd * Print out detailed scrub status. 4409168404Spjd */ 4410332525Smavstatic void 4411219089Spjdprint_scan_status(pool_scan_stat_t *ps) 4412168404Spjd{ 4413324010Savg time_t start, end, pause; 4414339034Ssef uint64_t total_secs_left; 4415339034Ssef uint64_t elapsed, secs_left, mins_left, hours_left, days_left; 4416339034Ssef uint64_t pass_scanned, scanned, pass_issued, issued, total; 4417339034Ssef uint_t scan_rate, issue_rate; 4418168404Spjd double fraction_done; 4419339034Ssef char processed_buf[7], scanned_buf[7], issued_buf[7], total_buf[7]; 4420339034Ssef char srate_buf[7], irate_buf[7]; 4421168404Spjd 4422226583Spjd (void) printf(gettext(" scan: ")); 4423168404Spjd 4424219089Spjd /* If there's never been a scan, there's not much to say. */ 4425219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 4426219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 4427168404Spjd (void) printf(gettext("none requested\n")); 4428168404Spjd return; 4429168404Spjd } 4430168404Spjd 4431219089Spjd start = ps->pss_start_time; 4432219089Spjd end = ps->pss_end_time; 4433324010Savg pause = ps->pss_pass_scrub_pause; 4434339034Ssef 4435219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 4436168404Spjd 4437219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 4438219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 4439339034Ssef 4440339034Ssef /* Scan is finished or canceled. */ 4441219089Spjd if (ps->pss_state == DSS_FINISHED) { 4442339034Ssef total_secs_left = end - start; 4443339034Ssef days_left = total_secs_left / 60 / 60 / 24; 4444339034Ssef hours_left = (total_secs_left / 60 / 60) % 24; 4445339034Ssef mins_left = (total_secs_left / 60) % 60; 4446339034Ssef secs_left = (total_secs_left % 60); 4447339034Ssef 4448219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4449339034Ssef (void) printf(gettext("scrub repaired %s " 4450339034Ssef "in %llu days %02llu:%02llu:%02llu " 4451339034Ssef "with %llu errors on %s"), processed_buf, 4452339034Ssef (u_longlong_t)days_left, (u_longlong_t)hours_left, 4453339034Ssef (u_longlong_t)mins_left, (u_longlong_t)secs_left, 4454339034Ssef (u_longlong_t)ps->pss_errors, ctime(&end)); 4455219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4456339034Ssef (void) printf(gettext("resilvered %s " 4457339034Ssef "in %llu days %02llu:%02llu:%02llu " 4458339034Ssef "with %llu errors on %s"), processed_buf, 4459339034Ssef (u_longlong_t)days_left, (u_longlong_t)hours_left, 4460339034Ssef (u_longlong_t)mins_left, (u_longlong_t)secs_left, 4461339034Ssef (u_longlong_t)ps->pss_errors, ctime(&end)); 4462339034Ssef 4463219089Spjd } 4464339034Ssef 4465168404Spjd return; 4466219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 4467219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4468219089Spjd (void) printf(gettext("scrub canceled on %s"), 4469219089Spjd ctime(&end)); 4470219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4471219089Spjd (void) printf(gettext("resilver canceled on %s"), 4472219089Spjd ctime(&end)); 4473219089Spjd } 4474219089Spjd return; 4475168404Spjd } 4476168404Spjd 4477219089Spjd assert(ps->pss_state == DSS_SCANNING); 4478168404Spjd 4479339034Ssef /* Scan is in progress. Resilvers can't be paused. */ 4480219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4481324010Savg if (pause == 0) { 4482324010Savg (void) printf(gettext("scrub in progress since %s"), 4483324010Savg ctime(&start)); 4484324010Savg } else { 4485339034Ssef (void) printf(gettext("scrub paused since %s"), 4486339034Ssef ctime(&pause)); 4487339034Ssef (void) printf(gettext("\tscrub started on %s"), 4488324010Savg ctime(&start)); 4489324010Savg } 4490219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4491219089Spjd (void) printf(gettext("resilver in progress since %s"), 4492219089Spjd ctime(&start)); 4493219089Spjd } 4494219089Spjd 4495339034Ssef scanned = ps->pss_examined; 4496339034Ssef pass_scanned = ps->pss_pass_exam; 4497339034Ssef issued = ps->pss_issued; 4498339034Ssef pass_issued = ps->pss_pass_issued; 4499219089Spjd total = ps->pss_to_examine; 4500168404Spjd 4501339034Ssef /* we are only done with a block once we have issued the IO for it */ 4502339034Ssef fraction_done = (double)issued / total; 4503339034Ssef 4504339034Ssef /* elapsed time for this pass, rounding up to 1 if it's 0 */ 4505219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 4506324010Savg elapsed -= ps->pss_pass_scrub_spent_paused; 4507339034Ssef elapsed = (elapsed != 0) ? elapsed : 1; 4508219089Spjd 4509339034Ssef scan_rate = pass_scanned / elapsed; 4510339034Ssef issue_rate = pass_issued / elapsed; 4511339034Ssef total_secs_left = (issue_rate != 0) ? 4512339034Ssef ((total - issued) / issue_rate) : UINT64_MAX; 4513339034Ssef 4514339034Ssef days_left = total_secs_left / 60 / 60 / 24; 4515339034Ssef hours_left = (total_secs_left / 60 / 60) % 24; 4516339034Ssef mins_left = (total_secs_left / 60) % 60; 4517339034Ssef secs_left = (total_secs_left % 60); 4518339034Ssef 4519339034Ssef /* format all of the numbers we will be reporting */ 4520339034Ssef zfs_nicenum(scanned, scanned_buf, sizeof (scanned_buf)); 4521339034Ssef zfs_nicenum(issued, issued_buf, sizeof (issued_buf)); 4522219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 4523339034Ssef zfs_nicenum(scan_rate, srate_buf, sizeof (srate_buf)); 4524339034Ssef zfs_nicenum(issue_rate, irate_buf, sizeof (irate_buf)); 4525219089Spjd 4526339034Ssef /* doo not print estimated time if we have a paused scrub */ 4527324010Savg if (pause == 0) { 4528339034Ssef (void) printf(gettext("\t%s scanned at %s/s, " 4529339034Ssef "%s issued at %s/s, %s total\n"), 4530339034Ssef scanned_buf, srate_buf, issued_buf, irate_buf, total_buf); 4531219089Spjd } else { 4532339034Ssef (void) printf(gettext("\t%s scanned, %s issued, %s total\n"), 4533339034Ssef scanned_buf, issued_buf, total_buf); 4534219089Spjd } 4535219089Spjd 4536219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 4537339034Ssef (void) printf(gettext("\t%s resilvered, %.2f%% done"), 4538219089Spjd processed_buf, 100 * fraction_done); 4539219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 4540339034Ssef (void) printf(gettext("\t%s repaired, %.2f%% done"), 4541219089Spjd processed_buf, 100 * fraction_done); 4542219089Spjd } 4543339034Ssef 4544339034Ssef if (pause == 0) { 4545339034Ssef if (issue_rate >= 10 * 1024 * 1024) { 4546339034Ssef (void) printf(gettext(", %llu days " 4547339034Ssef "%02llu:%02llu:%02llu to go\n"), 4548339034Ssef (u_longlong_t)days_left, (u_longlong_t)hours_left, 4549339034Ssef (u_longlong_t)mins_left, (u_longlong_t)secs_left); 4550339034Ssef } else { 4551339034Ssef (void) printf(gettext(", no estimated " 4552339034Ssef "completion time\n")); 4553339034Ssef } 4554339034Ssef } else { 4555339034Ssef (void) printf(gettext("\n")); 4556339034Ssef } 4557168404Spjd} 4558168404Spjd 4559332525Smav/* 4560332547Smav * As we don't scrub checkpointed blocks, we want to warn the 4561332547Smav * user that we skipped scanning some blocks if a checkpoint exists 4562332547Smav * or existed at any time during the scan. 4563332547Smav */ 4564332547Smavstatic void 4565332547Smavprint_checkpoint_scan_warning(pool_scan_stat_t *ps, pool_checkpoint_stat_t *pcs) 4566332547Smav{ 4567332547Smav if (ps == NULL || pcs == NULL) 4568332547Smav return; 4569332547Smav 4570332547Smav if (pcs->pcs_state == CS_NONE || 4571332547Smav pcs->pcs_state == CS_CHECKPOINT_DISCARDING) 4572332547Smav return; 4573332547Smav 4574332547Smav assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS); 4575332547Smav 4576332547Smav if (ps->pss_state == DSS_NONE) 4577332547Smav return; 4578332547Smav 4579332547Smav if ((ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) && 4580332547Smav ps->pss_end_time < pcs->pcs_start_time) 4581332547Smav return; 4582332547Smav 4583332547Smav if (ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) { 4584332547Smav (void) printf(gettext(" scan warning: skipped blocks " 4585332547Smav "that are only referenced by the checkpoint.\n")); 4586332547Smav } else { 4587332547Smav assert(ps->pss_state == DSS_SCANNING); 4588332547Smav (void) printf(gettext(" scan warning: skipping blocks " 4589332547Smav "that are only referenced by the checkpoint.\n")); 4590332547Smav } 4591332547Smav} 4592332547Smav 4593332547Smav/* 4594332525Smav * Print out detailed removal status. 4595332525Smav */ 4596168404Spjdstatic void 4597332525Smavprint_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs) 4598332525Smav{ 4599332525Smav char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 4600332525Smav time_t start, end; 4601332525Smav nvlist_t *config, *nvroot; 4602332525Smav nvlist_t **child; 4603332525Smav uint_t children; 4604332525Smav char *vdev_name; 4605332525Smav 4606332525Smav if (prs == NULL || prs->prs_state == DSS_NONE) 4607332525Smav return; 4608332525Smav 4609332525Smav /* 4610332525Smav * Determine name of vdev. 4611332525Smav */ 4612332525Smav config = zpool_get_config(zhp, NULL); 4613332525Smav nvroot = fnvlist_lookup_nvlist(config, 4614332525Smav ZPOOL_CONFIG_VDEV_TREE); 4615332525Smav verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 4616332525Smav &child, &children) == 0); 4617332525Smav assert(prs->prs_removing_vdev < children); 4618332525Smav vdev_name = zpool_vdev_name(g_zfs, zhp, 4619332525Smav child[prs->prs_removing_vdev], B_TRUE); 4620332525Smav 4621332525Smav (void) printf(gettext("remove: ")); 4622332525Smav 4623332525Smav start = prs->prs_start_time; 4624332525Smav end = prs->prs_end_time; 4625332525Smav zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf)); 4626332525Smav 4627332525Smav /* 4628332525Smav * Removal is finished or canceled. 4629332525Smav */ 4630332525Smav if (prs->prs_state == DSS_FINISHED) { 4631332525Smav uint64_t minutes_taken = (end - start) / 60; 4632332525Smav 4633332525Smav (void) printf(gettext("Removal of vdev %llu copied %s " 4634332525Smav "in %lluh%um, completed on %s"), 4635332525Smav (longlong_t)prs->prs_removing_vdev, 4636332525Smav copied_buf, 4637332525Smav (u_longlong_t)(minutes_taken / 60), 4638332525Smav (uint_t)(minutes_taken % 60), 4639332525Smav ctime((time_t *)&end)); 4640332525Smav } else if (prs->prs_state == DSS_CANCELED) { 4641332525Smav (void) printf(gettext("Removal of %s canceled on %s"), 4642332525Smav vdev_name, ctime(&end)); 4643332525Smav } else { 4644332525Smav uint64_t copied, total, elapsed, mins_left, hours_left; 4645332525Smav double fraction_done; 4646332525Smav uint_t rate; 4647332525Smav 4648332525Smav assert(prs->prs_state == DSS_SCANNING); 4649332525Smav 4650332525Smav /* 4651332525Smav * Removal is in progress. 4652332525Smav */ 4653332525Smav (void) printf(gettext( 4654332525Smav "Evacuation of %s in progress since %s"), 4655332525Smav vdev_name, ctime(&start)); 4656332525Smav 4657332525Smav copied = prs->prs_copied > 0 ? prs->prs_copied : 1; 4658332525Smav total = prs->prs_to_copy; 4659332525Smav fraction_done = (double)copied / total; 4660332525Smav 4661332525Smav /* elapsed time for this pass */ 4662332525Smav elapsed = time(NULL) - prs->prs_start_time; 4663332525Smav elapsed = elapsed > 0 ? elapsed : 1; 4664332525Smav rate = copied / elapsed; 4665332525Smav rate = rate > 0 ? rate : 1; 4666332525Smav mins_left = ((total - copied) / rate) / 60; 4667332525Smav hours_left = mins_left / 60; 4668332525Smav 4669332525Smav zfs_nicenum(copied, examined_buf, sizeof (examined_buf)); 4670332525Smav zfs_nicenum(total, total_buf, sizeof (total_buf)); 4671332525Smav zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 4672332525Smav 4673332525Smav /* 4674332525Smav * do not print estimated time if hours_left is more than 4675332525Smav * 30 days 4676332525Smav */ 4677332525Smav (void) printf(gettext(" %s copied out of %s at %s/s, " 4678332525Smav "%.2f%% done"), 4679332525Smav examined_buf, total_buf, rate_buf, 100 * fraction_done); 4680332525Smav if (hours_left < (30 * 24)) { 4681332525Smav (void) printf(gettext(", %lluh%um to go\n"), 4682332525Smav (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 4683332525Smav } else { 4684332525Smav (void) printf(gettext( 4685332525Smav ", (copy is slow, no estimated time)\n")); 4686332525Smav } 4687332525Smav } 4688332525Smav 4689332525Smav if (prs->prs_mapping_memory > 0) { 4690332525Smav char mem_buf[7]; 4691332525Smav zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf)); 4692332525Smav (void) printf(gettext(" %s memory used for " 4693332525Smav "removed device mappings\n"), 4694332525Smav mem_buf); 4695332525Smav } 4696332525Smav} 4697332525Smav 4698332525Smavstatic void 4699332547Smavprint_checkpoint_status(pool_checkpoint_stat_t *pcs) 4700332547Smav{ 4701332547Smav time_t start; 4702332547Smav char space_buf[7]; 4703332547Smav 4704332547Smav if (pcs == NULL || pcs->pcs_state == CS_NONE) 4705332547Smav return; 4706332547Smav 4707332547Smav (void) printf(gettext("checkpoint: ")); 4708332547Smav 4709332547Smav start = pcs->pcs_start_time; 4710332547Smav zfs_nicenum(pcs->pcs_space, space_buf, sizeof (space_buf)); 4711332547Smav 4712332547Smav if (pcs->pcs_state == CS_CHECKPOINT_EXISTS) { 4713332547Smav char *date = ctime(&start); 4714332547Smav 4715332547Smav /* 4716332547Smav * ctime() adds a newline at the end of the generated 4717332547Smav * string, thus the weird format specifier and the 4718332547Smav * strlen() call used to chop it off from the output. 4719332547Smav */ 4720332547Smav (void) printf(gettext("created %.*s, consumes %s\n"), 4721332547Smav strlen(date) - 1, date, space_buf); 4722332547Smav return; 4723332547Smav } 4724332547Smav 4725332547Smav assert(pcs->pcs_state == CS_CHECKPOINT_DISCARDING); 4726332547Smav 4727332547Smav (void) printf(gettext("discarding, %s remaining.\n"), 4728332547Smav space_buf); 4729332547Smav} 4730332547Smav 4731332547Smavstatic void 4732168404Spjdprint_error_log(zpool_handle_t *zhp) 4733168404Spjd{ 4734185029Spjd nvlist_t *nverrlist = NULL; 4735168404Spjd nvpair_t *elem; 4736168404Spjd char *pathname; 4737168404Spjd size_t len = MAXPATHLEN * 2; 4738168404Spjd 4739168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 4740168404Spjd (void) printf("errors: List of errors unavailable " 4741168404Spjd "(insufficient privileges)\n"); 4742168404Spjd return; 4743168404Spjd } 4744168404Spjd 4745168404Spjd (void) printf("errors: Permanent errors have been " 4746168404Spjd "detected in the following files:\n\n"); 4747168404Spjd 4748168404Spjd pathname = safe_malloc(len); 4749168404Spjd elem = NULL; 4750168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 4751168404Spjd nvlist_t *nv; 4752168404Spjd uint64_t dsobj, obj; 4753168404Spjd 4754168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 4755168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 4756168404Spjd &dsobj) == 0); 4757168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 4758168404Spjd &obj) == 0); 4759168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 4760168404Spjd (void) printf("%7s %s\n", "", pathname); 4761168404Spjd } 4762168404Spjd free(pathname); 4763168404Spjd nvlist_free(nverrlist); 4764168404Spjd} 4765168404Spjd 4766168404Spjdstatic void 4767168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 4768168404Spjd int namewidth) 4769168404Spjd{ 4770168404Spjd uint_t i; 4771168404Spjd char *name; 4772168404Spjd 4773168404Spjd if (nspares == 0) 4774168404Spjd return; 4775168404Spjd 4776168404Spjd (void) printf(gettext("\tspares\n")); 4777168404Spjd 4778168404Spjd for (i = 0; i < nspares; i++) { 4779219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 4780168404Spjd print_status_config(zhp, name, spares[i], 4781209962Smm namewidth, 2, B_TRUE); 4782168404Spjd free(name); 4783168404Spjd } 4784168404Spjd} 4785168404Spjd 4786185029Spjdstatic void 4787185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 4788185029Spjd int namewidth) 4789185029Spjd{ 4790185029Spjd uint_t i; 4791185029Spjd char *name; 4792185029Spjd 4793185029Spjd if (nl2cache == 0) 4794185029Spjd return; 4795185029Spjd 4796185029Spjd (void) printf(gettext("\tcache\n")); 4797185029Spjd 4798185029Spjd for (i = 0; i < nl2cache; i++) { 4799219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 4800185029Spjd print_status_config(zhp, name, l2cache[i], 4801209962Smm namewidth, 2, B_FALSE); 4802185029Spjd free(name); 4803185029Spjd } 4804185029Spjd} 4805185029Spjd 4806219089Spjdstatic void 4807219089Spjdprint_dedup_stats(nvlist_t *config) 4808219089Spjd{ 4809219089Spjd ddt_histogram_t *ddh; 4810219089Spjd ddt_stat_t *dds; 4811219089Spjd ddt_object_t *ddo; 4812219089Spjd uint_t c; 4813219089Spjd 4814219089Spjd /* 4815219089Spjd * If the pool was faulted then we may not have been able to 4816253441Sdelphij * obtain the config. Otherwise, if we have anything in the dedup 4817219089Spjd * table continue processing the stats. 4818219089Spjd */ 4819219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 4820227497Smm (uint64_t **)&ddo, &c) != 0) 4821219089Spjd return; 4822219089Spjd 4823219089Spjd (void) printf("\n"); 4824227497Smm (void) printf(gettext(" dedup: ")); 4825227497Smm if (ddo->ddo_count == 0) { 4826227497Smm (void) printf(gettext("no DDT entries\n")); 4827227497Smm return; 4828227497Smm } 4829227497Smm 4830219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 4831219089Spjd (u_longlong_t)ddo->ddo_count, 4832219089Spjd (u_longlong_t)ddo->ddo_dspace, 4833219089Spjd (u_longlong_t)ddo->ddo_mspace); 4834219089Spjd 4835219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 4836219089Spjd (uint64_t **)&dds, &c) == 0); 4837219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 4838219089Spjd (uint64_t **)&ddh, &c) == 0); 4839219089Spjd zpool_dump_ddt(dds, ddh); 4840219089Spjd} 4841219089Spjd 4842168404Spjd/* 4843168404Spjd * Display a summary of pool status. Displays a summary such as: 4844168404Spjd * 4845168404Spjd * pool: tank 4846168404Spjd * status: DEGRADED 4847168404Spjd * reason: One or more devices ... 4848236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 4849168404Spjd * config: 4850168404Spjd * mirror DEGRADED 4851168404Spjd * c1t0d0 OK 4852168404Spjd * c2t0d0 UNAVAIL 4853168404Spjd * 4854168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 4855168404Spjd * option is specified, then we print out error rate information as well. 4856168404Spjd */ 4857168404Spjdint 4858168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 4859168404Spjd{ 4860168404Spjd status_cbdata_t *cbp = data; 4861168404Spjd nvlist_t *config, *nvroot; 4862168404Spjd char *msgid; 4863168404Spjd int reason; 4864168404Spjd const char *health; 4865168404Spjd uint_t c; 4866168404Spjd vdev_stat_t *vs; 4867168404Spjd 4868168404Spjd config = zpool_get_config(zhp, NULL); 4869168404Spjd reason = zpool_get_status(zhp, &msgid); 4870168404Spjd 4871168404Spjd cbp->cb_count++; 4872168404Spjd 4873168404Spjd /* 4874168404Spjd * If we were given 'zpool status -x', only report those pools with 4875168404Spjd * problems. 4876168404Spjd */ 4877248267Smm if (cbp->cb_explain && 4878248267Smm (reason == ZPOOL_STATUS_OK || 4879248267Smm reason == ZPOOL_STATUS_VERSION_OLDER || 4880268621Ssmh reason == ZPOOL_STATUS_NON_NATIVE_ASHIFT || 4881248267Smm reason == ZPOOL_STATUS_FEAT_DISABLED)) { 4882168404Spjd if (!cbp->cb_allpools) { 4883168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 4884168404Spjd zpool_get_name(zhp)); 4885168404Spjd if (cbp->cb_first) 4886168404Spjd cbp->cb_first = B_FALSE; 4887168404Spjd } 4888168404Spjd return (0); 4889168404Spjd } 4890168404Spjd 4891168404Spjd if (cbp->cb_first) 4892168404Spjd cbp->cb_first = B_FALSE; 4893168404Spjd else 4894168404Spjd (void) printf("\n"); 4895168404Spjd 4896332525Smav nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE); 4897219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 4898168404Spjd (uint64_t **)&vs, &c) == 0); 4899185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4900168404Spjd 4901168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4902168404Spjd (void) printf(gettext(" state: %s\n"), health); 4903168404Spjd 4904168404Spjd switch (reason) { 4905168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 4906168404Spjd (void) printf(gettext("status: One or more devices could not " 4907168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 4908168404Spjd "continue functioning in a degraded state.\n")); 4909168404Spjd (void) printf(gettext("action: Attach the missing device and " 4910168404Spjd "online it using 'zpool online'.\n")); 4911168404Spjd break; 4912168404Spjd 4913168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 4914168404Spjd (void) printf(gettext("status: One or more devices could not " 4915168404Spjd "be opened. There are insufficient\n\treplicas for the " 4916168404Spjd "pool to continue functioning.\n")); 4917168404Spjd (void) printf(gettext("action: Attach the missing device and " 4918168404Spjd "online it using 'zpool online'.\n")); 4919168404Spjd break; 4920168404Spjd 4921168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 4922168404Spjd (void) printf(gettext("status: One or more devices could not " 4923168404Spjd "be used because the label is missing or\n\tinvalid. " 4924168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 4925168404Spjd "functioning in a degraded state.\n")); 4926168404Spjd (void) printf(gettext("action: Replace the device using " 4927168404Spjd "'zpool replace'.\n")); 4928168404Spjd break; 4929168404Spjd 4930168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4931168404Spjd (void) printf(gettext("status: One or more devices could not " 4932168404Spjd "be used because the label is missing \n\tor invalid. " 4933168404Spjd "There are insufficient replicas for the pool to " 4934168404Spjd "continue\n\tfunctioning.\n")); 4935219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4936219089Spjd zpool_get_name(zhp), reason, config); 4937168404Spjd break; 4938168404Spjd 4939168404Spjd case ZPOOL_STATUS_FAILING_DEV: 4940168404Spjd (void) printf(gettext("status: One or more devices has " 4941168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 4942168404Spjd "made to correct the error. Applications are " 4943168404Spjd "unaffected.\n")); 4944168404Spjd (void) printf(gettext("action: Determine if the device needs " 4945168404Spjd "to be replaced, and clear the errors\n\tusing " 4946168404Spjd "'zpool clear' or replace the device with 'zpool " 4947168404Spjd "replace'.\n")); 4948168404Spjd break; 4949168404Spjd 4950168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 4951168404Spjd (void) printf(gettext("status: One or more devices has " 4952168404Spjd "been taken offline by the administrator.\n\tSufficient " 4953168404Spjd "replicas exist for the pool to continue functioning in " 4954168404Spjd "a\n\tdegraded state.\n")); 4955168404Spjd (void) printf(gettext("action: Online the device using " 4956168404Spjd "'zpool online' or replace the device with\n\t'zpool " 4957168404Spjd "replace'.\n")); 4958168404Spjd break; 4959168404Spjd 4960219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 4961219089Spjd (void) printf(gettext("status: One or more devices has " 4962219089Spjd "been removed by the administrator.\n\tSufficient " 4963219089Spjd "replicas exist for the pool to continue functioning in " 4964219089Spjd "a\n\tdegraded state.\n")); 4965219089Spjd (void) printf(gettext("action: Online the device using " 4966219089Spjd "'zpool online' or replace the device with\n\t'zpool " 4967219089Spjd "replace'.\n")); 4968219089Spjd break; 4969219089Spjd 4970168404Spjd case ZPOOL_STATUS_RESILVERING: 4971168404Spjd (void) printf(gettext("status: One or more devices is " 4972168404Spjd "currently being resilvered. The pool will\n\tcontinue " 4973168404Spjd "to function, possibly in a degraded state.\n")); 4974168404Spjd (void) printf(gettext("action: Wait for the resilver to " 4975168404Spjd "complete.\n")); 4976168404Spjd break; 4977168404Spjd 4978168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 4979168404Spjd (void) printf(gettext("status: One or more devices has " 4980168404Spjd "experienced an error resulting in data\n\tcorruption. " 4981168404Spjd "Applications may be affected.\n")); 4982168404Spjd (void) printf(gettext("action: Restore the file in question " 4983168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 4984168404Spjd "backup.\n")); 4985168404Spjd break; 4986168404Spjd 4987168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4988168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4989168404Spjd "and the pool cannot be opened.\n")); 4990219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4991219089Spjd zpool_get_name(zhp), reason, config); 4992168404Spjd break; 4993168404Spjd 4994168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4995238926Smm (void) printf(gettext("status: The pool is formatted using a " 4996238926Smm "legacy on-disk format. The pool can\n\tstill be used, " 4997238926Smm "but some features are unavailable.\n")); 4998168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4999168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 5000238926Smm "be accessible on software that does not support feature\n" 5001238926Smm "\tflags.\n")); 5002168404Spjd break; 5003168404Spjd 5004168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 5005168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 5006168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 5007168404Spjd "be accessed on this system.\n")); 5008168404Spjd (void) printf(gettext("action: Access the pool from a system " 5009168404Spjd "running more recent software, or\n\trestore the pool from " 5010168404Spjd "backup.\n")); 5011168404Spjd break; 5012168404Spjd 5013238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 5014238926Smm (void) printf(gettext("status: Some supported features are not " 5015238926Smm "enabled on the pool. The pool can\n\tstill be used, but " 5016238926Smm "some features are unavailable.\n")); 5017238926Smm (void) printf(gettext("action: Enable all features using " 5018238926Smm "'zpool upgrade'. Once this is done,\n\tthe pool may no " 5019238926Smm "longer be accessible by software that does not support\n\t" 5020243014Smm "the features. See zpool-features(7) for details.\n")); 5021238926Smm break; 5022238926Smm 5023236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 5024236884Smm (void) printf(gettext("status: The pool cannot be accessed on " 5025236884Smm "this system because it uses the\n\tfollowing feature(s) " 5026236884Smm "not supported on this system:\n")); 5027236884Smm zpool_print_unsup_feat(config); 5028236884Smm (void) printf("\n"); 5029236884Smm (void) printf(gettext("action: Access the pool from a system " 5030236884Smm "that supports the required feature(s),\n\tor restore the " 5031236884Smm "pool from backup.\n")); 5032236884Smm break; 5033236884Smm 5034236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 5035236884Smm (void) printf(gettext("status: The pool can only be accessed " 5036236884Smm "in read-only mode on this system. It\n\tcannot be " 5037236884Smm "accessed in read-write mode because it uses the " 5038236884Smm "following\n\tfeature(s) not supported on this system:\n")); 5039236884Smm zpool_print_unsup_feat(config); 5040236884Smm (void) printf("\n"); 5041236884Smm (void) printf(gettext("action: The pool cannot be accessed in " 5042236884Smm "read-write mode. Import the pool with\n" 5043236884Smm "\t\"-o readonly=on\", access the pool from a system that " 5044236884Smm "supports the\n\trequired feature(s), or restore the " 5045236884Smm "pool from backup.\n")); 5046236884Smm break; 5047236884Smm 5048185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 5049185029Spjd (void) printf(gettext("status: One or more devices are " 5050185029Spjd "faulted in response to persistent errors.\n\tSufficient " 5051185029Spjd "replicas exist for the pool to continue functioning " 5052185029Spjd "in a\n\tdegraded state.\n")); 5053185029Spjd (void) printf(gettext("action: Replace the faulted device, " 5054185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 5055185029Spjd break; 5056185029Spjd 5057185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 5058185029Spjd (void) printf(gettext("status: One or more devices are " 5059185029Spjd "faulted in response to persistent errors. There are " 5060185029Spjd "insufficient replicas for the pool to\n\tcontinue " 5061185029Spjd "functioning.\n")); 5062185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 5063185029Spjd "from a backup source. Manually marking the device\n" 5064185029Spjd "\trepaired using 'zpool clear' may allow some data " 5065185029Spjd "to be recovered.\n")); 5066185029Spjd break; 5067185029Spjd 5068185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 5069185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 5070185029Spjd (void) printf(gettext("status: One or more devices are " 5071185029Spjd "faulted in response to IO failures.\n")); 5072185029Spjd (void) printf(gettext("action: Make sure the affected devices " 5073185029Spjd "are connected, then run 'zpool clear'.\n")); 5074185029Spjd break; 5075185029Spjd 5076185029Spjd case ZPOOL_STATUS_BAD_LOG: 5077185029Spjd (void) printf(gettext("status: An intent log record " 5078185029Spjd "could not be read.\n" 5079185029Spjd "\tWaiting for adminstrator intervention to fix the " 5080185029Spjd "faulted pool.\n")); 5081185029Spjd (void) printf(gettext("action: Either restore the affected " 5082185029Spjd "device(s) and run 'zpool online',\n" 5083185029Spjd "\tor ignore the intent log records by running " 5084185029Spjd "'zpool clear'.\n")); 5085185029Spjd break; 5086185029Spjd 5087254591Sgibbs case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 5088254591Sgibbs (void) printf(gettext("status: One or more devices are " 5089254591Sgibbs "configured to use a non-native block size.\n" 5090254591Sgibbs "\tExpect reduced performance.\n")); 5091254591Sgibbs (void) printf(gettext("action: Replace affected devices with " 5092254591Sgibbs "devices that support the\n\tconfigured block size, or " 5093254591Sgibbs "migrate data to a properly configured\n\tpool.\n")); 5094254591Sgibbs break; 5095254591Sgibbs 5096168404Spjd default: 5097168404Spjd /* 5098168404Spjd * The remaining errors can't actually be generated, yet. 5099168404Spjd */ 5100168404Spjd assert(reason == ZPOOL_STATUS_OK); 5101168404Spjd } 5102168404Spjd 5103168404Spjd if (msgid != NULL) 5104236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 5105168404Spjd msgid); 5106168404Spjd 5107168404Spjd if (config != NULL) { 5108168404Spjd int namewidth; 5109168404Spjd uint64_t nerr; 5110185029Spjd nvlist_t **spares, **l2cache; 5111185029Spjd uint_t nspares, nl2cache; 5112332547Smav pool_checkpoint_stat_t *pcs = NULL; 5113219089Spjd pool_scan_stat_t *ps = NULL; 5114332525Smav pool_removal_stat_t *prs = NULL; 5115168404Spjd 5116219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 5117332547Smav ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c); 5118332547Smav (void) nvlist_lookup_uint64_array(nvroot, 5119219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 5120332525Smav (void) nvlist_lookup_uint64_array(nvroot, 5121332525Smav ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c); 5122332547Smav 5123332547Smav print_scan_status(ps); 5124332547Smav print_checkpoint_scan_warning(ps, pcs); 5125332525Smav print_removal_status(zhp, prs); 5126332547Smav print_checkpoint_status(pcs); 5127332525Smav 5128168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 5129168404Spjd if (namewidth < 10) 5130168404Spjd namewidth = 10; 5131168404Spjd 5132168404Spjd (void) printf(gettext("config:\n\n")); 5133168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 5134168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 5135168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 5136209962Smm namewidth, 0, B_FALSE); 5137209962Smm 5138185029Spjd if (num_logs(nvroot) > 0) 5139213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 5140185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 5141185029Spjd &l2cache, &nl2cache) == 0) 5142185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 5143185029Spjd 5144168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 5145168404Spjd &spares, &nspares) == 0) 5146168404Spjd print_spares(zhp, spares, nspares, namewidth); 5147168404Spjd 5148168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 5149168404Spjd &nerr) == 0) { 5150168404Spjd nvlist_t *nverrlist = NULL; 5151168404Spjd 5152168404Spjd /* 5153168404Spjd * If the approximate error count is small, get a 5154168404Spjd * precise count by fetching the entire log and 5155168404Spjd * uniquifying the results. 5156168404Spjd */ 5157185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 5158168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 5159168404Spjd nvpair_t *elem; 5160168404Spjd 5161168404Spjd elem = NULL; 5162168404Spjd nerr = 0; 5163168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 5164168404Spjd elem)) != NULL) { 5165168404Spjd nerr++; 5166168404Spjd } 5167168404Spjd } 5168168404Spjd nvlist_free(nverrlist); 5169168404Spjd 5170168404Spjd (void) printf("\n"); 5171168404Spjd 5172168404Spjd if (nerr == 0) 5173168404Spjd (void) printf(gettext("errors: No known data " 5174168404Spjd "errors\n")); 5175168404Spjd else if (!cbp->cb_verbose) 5176168404Spjd (void) printf(gettext("errors: %llu data " 5177168404Spjd "errors, use '-v' for a list\n"), 5178168404Spjd (u_longlong_t)nerr); 5179168404Spjd else 5180168404Spjd print_error_log(zhp); 5181168404Spjd } 5182219089Spjd 5183219089Spjd if (cbp->cb_dedup_stats) 5184219089Spjd print_dedup_stats(config); 5185168404Spjd } else { 5186168404Spjd (void) printf(gettext("config: The configuration cannot be " 5187168404Spjd "determined.\n")); 5188168404Spjd } 5189168404Spjd 5190168404Spjd return (0); 5191168404Spjd} 5192168404Spjd 5193168404Spjd/* 5194219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 5195168404Spjd * 5196168404Spjd * -v Display complete error logs 5197168404Spjd * -x Display only pools with potential problems 5198219089Spjd * -D Display dedup status (undocumented) 5199219089Spjd * -T Display a timestamp in date(1) or Unix format 5200168404Spjd * 5201168404Spjd * Describes the health status of all pools or some subset. 5202168404Spjd */ 5203168404Spjdint 5204168404Spjdzpool_do_status(int argc, char **argv) 5205168404Spjd{ 5206168404Spjd int c; 5207168404Spjd int ret; 5208219089Spjd unsigned long interval = 0, count = 0; 5209168404Spjd status_cbdata_t cb = { 0 }; 5210168404Spjd 5211168404Spjd /* check options */ 5212219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 5213168404Spjd switch (c) { 5214168404Spjd case 'v': 5215168404Spjd cb.cb_verbose = B_TRUE; 5216168404Spjd break; 5217168404Spjd case 'x': 5218168404Spjd cb.cb_explain = B_TRUE; 5219168404Spjd break; 5220219089Spjd case 'D': 5221219089Spjd cb.cb_dedup_stats = B_TRUE; 5222219089Spjd break; 5223219089Spjd case 'T': 5224219089Spjd get_timestamp_arg(*optarg); 5225219089Spjd break; 5226168404Spjd case '?': 5227168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5228168404Spjd optopt); 5229168404Spjd usage(B_FALSE); 5230168404Spjd } 5231168404Spjd } 5232168404Spjd 5233168404Spjd argc -= optind; 5234168404Spjd argv += optind; 5235168404Spjd 5236219089Spjd get_interval_count(&argc, argv, &interval, &count); 5237168404Spjd 5238168404Spjd if (argc == 0) 5239168404Spjd cb.cb_allpools = B_TRUE; 5240168404Spjd 5241219089Spjd cb.cb_first = B_TRUE; 5242168404Spjd 5243219089Spjd for (;;) { 5244219089Spjd if (timestamp_fmt != NODATE) 5245219089Spjd print_timestamp(timestamp_fmt); 5246168404Spjd 5247219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 5248219089Spjd status_callback, &cb); 5249219089Spjd 5250219089Spjd if (argc == 0 && cb.cb_count == 0) 5251219089Spjd (void) printf(gettext("no pools available\n")); 5252219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 5253219089Spjd (void) printf(gettext("all pools are healthy\n")); 5254219089Spjd 5255219089Spjd if (ret != 0) 5256219089Spjd return (ret); 5257219089Spjd 5258219089Spjd if (interval == 0) 5259219089Spjd break; 5260219089Spjd 5261219089Spjd if (count != 0 && --count == 0) 5262219089Spjd break; 5263219089Spjd 5264219089Spjd (void) sleep(interval); 5265219089Spjd } 5266219089Spjd 5267219089Spjd return (0); 5268168404Spjd} 5269168404Spjd 5270168404Spjdtypedef struct upgrade_cbdata { 5271276226Ssmh boolean_t cb_first; 5272276226Ssmh boolean_t cb_unavail; 5273307108Smav char cb_poolname[ZFS_MAX_DATASET_NAME_LEN]; 5274276226Ssmh int cb_argc; 5275276226Ssmh uint64_t cb_version; 5276276226Ssmh char **cb_argv; 5277168404Spjd} upgrade_cbdata_t; 5278168404Spjd 5279238950Smm#ifdef __FreeBSD__ 5280168404Spjdstatic int 5281212050Spjdis_root_pool(zpool_handle_t *zhp) 5282212050Spjd{ 5283212050Spjd static struct statfs sfs; 5284212050Spjd static char *poolname = NULL; 5285212050Spjd static boolean_t stated = B_FALSE; 5286212050Spjd char *slash; 5287212050Spjd 5288212067Spjd if (!stated) { 5289212050Spjd stated = B_TRUE; 5290212050Spjd if (statfs("/", &sfs) == -1) { 5291212050Spjd (void) fprintf(stderr, 5292212050Spjd "Unable to stat root file system: %s.\n", 5293212050Spjd strerror(errno)); 5294212067Spjd return (0); 5295212050Spjd } 5296212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 5297212067Spjd return (0); 5298212050Spjd poolname = sfs.f_mntfromname; 5299212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 5300212050Spjd *slash = '\0'; 5301212050Spjd } 5302212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 5303212050Spjd} 5304212050Spjd 5305238950Smmstatic void 5306271934Ssmhroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size) 5307271934Ssmh{ 5308238950Smm 5309238950Smm if (poolname[0] == '\0' && is_root_pool(zhp)) 5310238950Smm (void) strlcpy(poolname, zpool_get_name(zhp), size); 5311238950Smm} 5312238950Smm#endif /* FreeBSD */ 5313238950Smm 5314212050Spjdstatic int 5315238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version) 5316238926Smm{ 5317238926Smm int ret; 5318238926Smm nvlist_t *config; 5319238926Smm uint64_t oldversion; 5320238926Smm 5321238926Smm config = zpool_get_config(zhp, NULL); 5322238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5323238926Smm &oldversion) == 0); 5324238926Smm 5325238926Smm assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 5326238926Smm assert(oldversion < version); 5327238926Smm 5328238926Smm ret = zpool_upgrade(zhp, version); 5329238926Smm if (ret != 0) 5330238926Smm return (ret); 5331238926Smm 5332238926Smm if (version >= SPA_VERSION_FEATURES) { 5333238926Smm (void) printf(gettext("Successfully upgraded " 5334238926Smm "'%s' from version %llu to feature flags.\n"), 5335238926Smm zpool_get_name(zhp), oldversion); 5336238926Smm } else { 5337238926Smm (void) printf(gettext("Successfully upgraded " 5338238926Smm "'%s' from version %llu to version %llu.\n"), 5339238926Smm zpool_get_name(zhp), oldversion, version); 5340238926Smm } 5341238926Smm 5342238926Smm return (0); 5343238926Smm} 5344238926Smm 5345238926Smmstatic int 5346238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp) 5347238926Smm{ 5348238926Smm int i, ret, count; 5349238926Smm boolean_t firstff = B_TRUE; 5350238926Smm nvlist_t *enabled = zpool_get_features(zhp); 5351238926Smm 5352238926Smm count = 0; 5353238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5354238926Smm const char *fname = spa_feature_table[i].fi_uname; 5355238926Smm const char *fguid = spa_feature_table[i].fi_guid; 5356238926Smm if (!nvlist_exists(enabled, fguid)) { 5357238926Smm char *propname; 5358238926Smm verify(-1 != asprintf(&propname, "feature@%s", fname)); 5359238926Smm ret = zpool_set_prop(zhp, propname, 5360238926Smm ZFS_FEATURE_ENABLED); 5361238926Smm if (ret != 0) { 5362238926Smm free(propname); 5363238926Smm return (ret); 5364238926Smm } 5365238926Smm count++; 5366238926Smm 5367238926Smm if (firstff) { 5368238926Smm (void) printf(gettext("Enabled the " 5369238926Smm "following features on '%s':\n"), 5370238926Smm zpool_get_name(zhp)); 5371238926Smm firstff = B_FALSE; 5372238926Smm } 5373238926Smm (void) printf(gettext(" %s\n"), fname); 5374238926Smm free(propname); 5375238926Smm } 5376238926Smm } 5377238926Smm 5378238926Smm if (countp != NULL) 5379238926Smm *countp = count; 5380238926Smm return (0); 5381238926Smm} 5382238926Smm 5383238926Smmstatic int 5384168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 5385168404Spjd{ 5386168404Spjd upgrade_cbdata_t *cbp = arg; 5387168404Spjd nvlist_t *config; 5388168404Spjd uint64_t version; 5389238926Smm boolean_t printnl = B_FALSE; 5390238926Smm int ret; 5391168404Spjd 5392276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5393276194Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 5394276226Ssmh "currently unavailable.\n\n"), zpool_get_name(zhp)); 5395276226Ssmh cbp->cb_unavail = B_TRUE; 5396276194Ssmh /* Allow iteration to continue. */ 5397276194Ssmh return (0); 5398276194Ssmh } 5399276194Ssmh 5400168404Spjd config = zpool_get_config(zhp, NULL); 5401168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5402168404Spjd &version) == 0); 5403168404Spjd 5404238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 5405168404Spjd 5406238926Smm if (version < cbp->cb_version) { 5407238926Smm cbp->cb_first = B_FALSE; 5408238926Smm ret = upgrade_version(zhp, cbp->cb_version); 5409238926Smm if (ret != 0) 5410238926Smm return (ret); 5411238926Smm#ifdef __FreeBSD__ 5412238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 5413238950Smm sizeof(cbp->cb_poolname)); 5414271934Ssmh#endif /* __FreeBSD__ */ 5415238926Smm printnl = B_TRUE; 5416238926Smm 5417238926Smm#ifdef illumos 5418238926Smm /* 5419238926Smm * If they did "zpool upgrade -a", then we could 5420238926Smm * be doing ioctls to different pools. We need 5421238926Smm * to log this history once to each pool, and bypass 5422238926Smm * the normal history logging that happens in main(). 5423238926Smm */ 5424238926Smm (void) zpool_log_history(g_zfs, history_str); 5425238926Smm log_history = B_FALSE; 5426238926Smm#endif 5427238926Smm } 5428238926Smm 5429238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 5430238926Smm int count; 5431238926Smm ret = upgrade_enable_all(zhp, &count); 5432238926Smm if (ret != 0) 5433238926Smm return (ret); 5434238926Smm 5435238926Smm if (count > 0) { 5436168404Spjd cbp->cb_first = B_FALSE; 5437238926Smm printnl = B_TRUE; 5438271934Ssmh#ifdef __FreeBSD__ 5439271934Ssmh root_pool_upgrade_check(zhp, cbp->cb_poolname, 5440271934Ssmh sizeof(cbp->cb_poolname)); 5441271934Ssmh#endif /* __FreeBSD__ */ 5442248571Smm /* 5443248571Smm * If they did "zpool upgrade -a", then we could 5444248571Smm * be doing ioctls to different pools. We need 5445248571Smm * to log this history once to each pool, and bypass 5446248571Smm * the normal history logging that happens in main(). 5447248571Smm */ 5448248571Smm (void) zpool_log_history(g_zfs, history_str); 5449248571Smm log_history = B_FALSE; 5450168404Spjd } 5451238926Smm } 5452168404Spjd 5453238926Smm if (printnl) { 5454238926Smm (void) printf(gettext("\n")); 5455238926Smm } 5456238926Smm 5457238926Smm return (0); 5458238926Smm} 5459238926Smm 5460238926Smmstatic int 5461276226Ssmhupgrade_list_unavail(zpool_handle_t *zhp, void *arg) 5462276226Ssmh{ 5463276226Ssmh upgrade_cbdata_t *cbp = arg; 5464276226Ssmh 5465276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5466276226Ssmh if (cbp->cb_first) { 5467276226Ssmh (void) fprintf(stderr, gettext("The following pools " 5468276226Ssmh "are unavailable and cannot be upgraded as this " 5469276226Ssmh "time.\n\n")); 5470276226Ssmh (void) fprintf(stderr, gettext("POOL\n")); 5471276226Ssmh (void) fprintf(stderr, gettext("------------\n")); 5472276226Ssmh cbp->cb_first = B_FALSE; 5473276226Ssmh } 5474276226Ssmh (void) printf(gettext("%s\n"), zpool_get_name(zhp)); 5475276226Ssmh cbp->cb_unavail = B_TRUE; 5476276226Ssmh } 5477276226Ssmh return (0); 5478276226Ssmh} 5479276226Ssmh 5480276226Ssmhstatic int 5481238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 5482238926Smm{ 5483238926Smm upgrade_cbdata_t *cbp = arg; 5484238926Smm nvlist_t *config; 5485238926Smm uint64_t version; 5486238926Smm 5487276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5488276226Ssmh /* 5489276226Ssmh * This will have been reported by upgrade_list_unavail so 5490276226Ssmh * just allow iteration to continue. 5491276226Ssmh */ 5492276226Ssmh cbp->cb_unavail = B_TRUE; 5493276226Ssmh return (0); 5494276226Ssmh } 5495276226Ssmh 5496238926Smm config = zpool_get_config(zhp, NULL); 5497238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5498238926Smm &version) == 0); 5499238926Smm 5500238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 5501238926Smm 5502238926Smm if (version < SPA_VERSION_FEATURES) { 5503168404Spjd if (cbp->cb_first) { 5504168404Spjd (void) printf(gettext("The following pools are " 5505238926Smm "formatted with legacy version numbers and can\n" 5506238926Smm "be upgraded to use feature flags. After " 5507238926Smm "being upgraded, these pools\nwill no " 5508238926Smm "longer be accessible by software that does not " 5509238926Smm "support feature\nflags.\n\n")); 5510168404Spjd (void) printf(gettext("VER POOL\n")); 5511168404Spjd (void) printf(gettext("--- ------------\n")); 5512168404Spjd cbp->cb_first = B_FALSE; 5513168404Spjd } 5514168404Spjd 5515168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 5516168404Spjd zpool_get_name(zhp)); 5517168404Spjd } 5518168404Spjd 5519238926Smm return (0); 5520168404Spjd} 5521168404Spjd 5522238926Smmstatic int 5523238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 5524238926Smm{ 5525238926Smm upgrade_cbdata_t *cbp = arg; 5526238926Smm nvlist_t *config; 5527238926Smm uint64_t version; 5528238926Smm 5529276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5530276226Ssmh /* 5531276226Ssmh * This will have been reported by upgrade_list_unavail so 5532276226Ssmh * just allow iteration to continue. 5533276226Ssmh */ 5534276226Ssmh cbp->cb_unavail = B_TRUE; 5535276194Ssmh return (0); 5536276194Ssmh } 5537276194Ssmh 5538238926Smm config = zpool_get_config(zhp, NULL); 5539238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5540238926Smm &version) == 0); 5541238926Smm 5542238926Smm if (version >= SPA_VERSION_FEATURES) { 5543238926Smm int i; 5544238926Smm boolean_t poolfirst = B_TRUE; 5545238926Smm nvlist_t *enabled = zpool_get_features(zhp); 5546238926Smm 5547238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5548238926Smm const char *fguid = spa_feature_table[i].fi_guid; 5549238926Smm const char *fname = spa_feature_table[i].fi_uname; 5550238926Smm if (!nvlist_exists(enabled, fguid)) { 5551238926Smm if (cbp->cb_first) { 5552238926Smm (void) printf(gettext("\nSome " 5553238926Smm "supported features are not " 5554238926Smm "enabled on the following pools. " 5555238926Smm "Once a\nfeature is enabled the " 5556238926Smm "pool may become incompatible with " 5557238926Smm "software\nthat does not support " 5558238926Smm "the feature. See " 5559243014Smm "zpool-features(7) for " 5560238926Smm "details.\n\n")); 5561238926Smm (void) printf(gettext("POOL " 5562238926Smm "FEATURE\n")); 5563238926Smm (void) printf(gettext("------" 5564238926Smm "---------\n")); 5565238926Smm cbp->cb_first = B_FALSE; 5566238926Smm } 5567238926Smm 5568238926Smm if (poolfirst) { 5569238926Smm (void) printf(gettext("%s\n"), 5570238926Smm zpool_get_name(zhp)); 5571238926Smm poolfirst = B_FALSE; 5572238926Smm } 5573238926Smm 5574238926Smm (void) printf(gettext(" %s\n"), fname); 5575238926Smm } 5576238926Smm } 5577238926Smm } 5578238926Smm 5579238926Smm return (0); 5580238926Smm} 5581238926Smm 5582168404Spjd/* ARGSUSED */ 5583168404Spjdstatic int 5584168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 5585168404Spjd{ 5586238926Smm boolean_t printnl = B_FALSE; 5587185029Spjd upgrade_cbdata_t *cbp = data; 5588185029Spjd uint64_t cur_version; 5589168404Spjd int ret; 5590168404Spjd 5591276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5592276226Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 5593276226Ssmh "is currently unavailable.\n\n"), zpool_get_name(zhp)); 5594276226Ssmh cbp->cb_unavail = B_TRUE; 5595276226Ssmh return (1); 5596276226Ssmh } 5597276226Ssmh 5598185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 5599185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 5600185029Spjd "Pool 'log' must be renamed using export and import" 5601276226Ssmh " to upgrade.\n\n")); 5602185029Spjd return (1); 5603185029Spjd } 5604168404Spjd 5605185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5606185029Spjd if (cur_version > cbp->cb_version) { 5607168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 5608238926Smm "using more current version '%llu'.\n\n"), 5609185029Spjd zpool_get_name(zhp), cur_version); 5610185029Spjd return (0); 5611185029Spjd } 5612238926Smm 5613238926Smm if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 5614185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 5615238926Smm "using version %llu.\n\n"), zpool_get_name(zhp), 5616238926Smm cbp->cb_version); 5617168404Spjd return (0); 5618168404Spjd } 5619168404Spjd 5620238926Smm if (cur_version != cbp->cb_version) { 5621238926Smm printnl = B_TRUE; 5622238926Smm ret = upgrade_version(zhp, cbp->cb_version); 5623238950Smm if (ret != 0) 5624238950Smm return (ret); 5625238926Smm#ifdef __FreeBSD__ 5626238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 5627238950Smm sizeof(cbp->cb_poolname)); 5628271934Ssmh#endif /* __FreeBSD__ */ 5629238926Smm } 5630168404Spjd 5631238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 5632238926Smm int count = 0; 5633238926Smm ret = upgrade_enable_all(zhp, &count); 5634238926Smm if (ret != 0) 5635238926Smm return (ret); 5636238926Smm 5637238926Smm if (count != 0) { 5638238926Smm printnl = B_TRUE; 5639238950Smm#ifdef __FreeBSD__ 5640238951Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 5641238951Smm sizeof(cbp->cb_poolname)); 5642238950Smm#endif /* __FreeBSD __*/ 5643238926Smm } else if (cur_version == SPA_VERSION) { 5644238926Smm (void) printf(gettext("Pool '%s' already has all " 5645276226Ssmh "supported features enabled.\n\n"), 5646238926Smm zpool_get_name(zhp)); 5647238926Smm } 5648168404Spjd } 5649168404Spjd 5650238926Smm if (printnl) { 5651238926Smm (void) printf(gettext("\n")); 5652238926Smm } 5653238926Smm 5654238926Smm return (0); 5655168404Spjd} 5656168404Spjd 5657168404Spjd/* 5658168404Spjd * zpool upgrade 5659168404Spjd * zpool upgrade -v 5660185029Spjd * zpool upgrade [-V version] <-a | pool ...> 5661168404Spjd * 5662168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 5663168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 5664168404Spjd * upgrade all pools. 5665168404Spjd */ 5666168404Spjdint 5667168404Spjdzpool_do_upgrade(int argc, char **argv) 5668168404Spjd{ 5669168404Spjd int c; 5670168404Spjd upgrade_cbdata_t cb = { 0 }; 5671168404Spjd int ret = 0; 5672168404Spjd boolean_t showversions = B_FALSE; 5673238926Smm boolean_t upgradeall = B_FALSE; 5674185029Spjd char *end; 5675168404Spjd 5676185029Spjd 5677168404Spjd /* check options */ 5678219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 5679168404Spjd switch (c) { 5680168404Spjd case 'a': 5681238926Smm upgradeall = B_TRUE; 5682168404Spjd break; 5683168404Spjd case 'v': 5684168404Spjd showversions = B_TRUE; 5685168404Spjd break; 5686185029Spjd case 'V': 5687185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 5688236884Smm if (*end != '\0' || 5689236884Smm !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 5690185029Spjd (void) fprintf(stderr, 5691185029Spjd gettext("invalid version '%s'\n"), optarg); 5692185029Spjd usage(B_FALSE); 5693185029Spjd } 5694185029Spjd break; 5695219089Spjd case ':': 5696219089Spjd (void) fprintf(stderr, gettext("missing argument for " 5697219089Spjd "'%c' option\n"), optopt); 5698219089Spjd usage(B_FALSE); 5699219089Spjd break; 5700168404Spjd case '?': 5701168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5702168404Spjd optopt); 5703168404Spjd usage(B_FALSE); 5704168404Spjd } 5705168404Spjd } 5706168404Spjd 5707168404Spjd cb.cb_argc = argc; 5708168404Spjd cb.cb_argv = argv; 5709168404Spjd argc -= optind; 5710168404Spjd argv += optind; 5711168404Spjd 5712185029Spjd if (cb.cb_version == 0) { 5713185029Spjd cb.cb_version = SPA_VERSION; 5714238926Smm } else if (!upgradeall && argc == 0) { 5715185029Spjd (void) fprintf(stderr, gettext("-V option is " 5716185029Spjd "incompatible with other arguments\n")); 5717185029Spjd usage(B_FALSE); 5718185029Spjd } 5719185029Spjd 5720168404Spjd if (showversions) { 5721238926Smm if (upgradeall || argc != 0) { 5722168404Spjd (void) fprintf(stderr, gettext("-v option is " 5723168404Spjd "incompatible with other arguments\n")); 5724168404Spjd usage(B_FALSE); 5725168404Spjd } 5726238926Smm } else if (upgradeall) { 5727168404Spjd if (argc != 0) { 5728185029Spjd (void) fprintf(stderr, gettext("-a option should not " 5729185029Spjd "be used along with a pool name\n")); 5730168404Spjd usage(B_FALSE); 5731168404Spjd } 5732168404Spjd } 5733168404Spjd 5734236884Smm (void) printf(gettext("This system supports ZFS pool feature " 5735236884Smm "flags.\n\n")); 5736168404Spjd if (showversions) { 5737238926Smm int i; 5738238926Smm 5739238926Smm (void) printf(gettext("The following features are " 5740168404Spjd "supported:\n\n")); 5741238926Smm (void) printf(gettext("FEAT DESCRIPTION\n")); 5742238926Smm (void) printf("----------------------------------------------" 5743238926Smm "---------------\n"); 5744238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5745238926Smm zfeature_info_t *fi = &spa_feature_table[i]; 5746286708Smav const char *ro = 5747286708Smav (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ? 5748238926Smm " (read-only compatible)" : ""; 5749238926Smm 5750238926Smm (void) printf("%-37s%s\n", fi->fi_uname, ro); 5751238926Smm (void) printf(" %s\n", fi->fi_desc); 5752238926Smm } 5753238926Smm (void) printf("\n"); 5754238926Smm 5755238926Smm (void) printf(gettext("The following legacy versions are also " 5756238926Smm "supported:\n\n")); 5757168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 5758168404Spjd (void) printf("--- -----------------------------------------" 5759168404Spjd "---------------\n"); 5760168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 5761168404Spjd (void) printf(gettext(" 2 Ditto blocks " 5762168404Spjd "(replicated metadata)\n")); 5763168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 5764168404Spjd "RAID-Z\n")); 5765168404Spjd (void) printf(gettext(" 4 zpool history\n")); 5766168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 5767168404Spjd "algorithm\n")); 5768185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 5769185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 5770185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 5771185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 5772185029Spjd "properties\n")); 5773185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 5774185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 5775185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 5776185029Spjd (void) printf(gettext(" 13 snapused property\n")); 5777209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 5778209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 5779219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 5780219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 5781219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 5782219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 5783219089Spjd (void) printf(gettext(" 20 Compression using zle " 5784219089Spjd "(zero-length encoding)\n")); 5785219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 5786219089Spjd (void) printf(gettext(" 22 Received properties\n")); 5787219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 5788219089Spjd (void) printf(gettext(" 24 System attributes\n")); 5789219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 5790219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 5791219089Spjd "performance\n")); 5792219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 5793219089Spjd "performance\n")); 5794219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 5795219089Spjd (void) printf(gettext("\nFor more information on a particular " 5796219089Spjd "version, including supported releases,\n")); 5797219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 5798238926Smm } else if (argc == 0 && upgradeall) { 5799238926Smm cb.cb_first = B_TRUE; 5800168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 5801238926Smm if (ret == 0 && cb.cb_first) { 5802238926Smm if (cb.cb_version == SPA_VERSION) { 5803276226Ssmh (void) printf(gettext("All %spools are already " 5804276226Ssmh "formatted using feature flags.\n\n"), 5805276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5806276226Ssmh (void) printf(gettext("Every %sfeature flags " 5807238926Smm "pool already has all supported features " 5808276226Ssmh "enabled.\n"), 5809276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5810238926Smm } else { 5811238926Smm (void) printf(gettext("All pools are already " 5812238926Smm "formatted with version %llu or higher.\n"), 5813238926Smm cb.cb_version); 5814168404Spjd } 5815168404Spjd } 5816238926Smm } else if (argc == 0) { 5817238926Smm cb.cb_first = B_TRUE; 5818276226Ssmh ret = zpool_iter(g_zfs, upgrade_list_unavail, &cb); 5819276226Ssmh assert(ret == 0); 5820276226Ssmh 5821276226Ssmh if (!cb.cb_first) { 5822276226Ssmh (void) fprintf(stderr, "\n"); 5823276226Ssmh } 5824276226Ssmh 5825276226Ssmh cb.cb_first = B_TRUE; 5826238926Smm ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 5827238926Smm assert(ret == 0); 5828168404Spjd 5829238926Smm if (cb.cb_first) { 5830276226Ssmh (void) printf(gettext("All %spools are formatted using " 5831276226Ssmh "feature flags.\n\n"), cb.cb_unavail ? 5832276226Ssmh gettext("available ") : ""); 5833238926Smm } else { 5834238926Smm (void) printf(gettext("\nUse 'zpool upgrade -v' " 5835238926Smm "for a list of available legacy versions.\n")); 5836168404Spjd } 5837238926Smm 5838238926Smm cb.cb_first = B_TRUE; 5839238926Smm ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 5840238926Smm assert(ret == 0); 5841238926Smm 5842238926Smm if (cb.cb_first) { 5843276226Ssmh (void) printf(gettext("Every %sfeature flags pool has " 5844276226Ssmh "all supported features enabled.\n"), 5845276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5846238926Smm } else { 5847238926Smm (void) printf(gettext("\n")); 5848238926Smm } 5849168404Spjd } else { 5850276226Ssmh ret = for_each_pool(argc, argv, B_TRUE, NULL, 5851168404Spjd upgrade_one, &cb); 5852168404Spjd } 5853168404Spjd 5854212050Spjd if (cb.cb_poolname[0] != '\0') { 5855212050Spjd (void) printf( 5856212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 5857212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 5858212050Spjd "the following command will do it:\n" 5859212050Spjd "\n" 5860212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 5861212050Spjd cb.cb_poolname); 5862212050Spjd } 5863212050Spjd 5864168404Spjd return (ret); 5865168404Spjd} 5866168404Spjd 5867185029Spjdtypedef struct hist_cbdata { 5868185029Spjd boolean_t first; 5869248571Smm boolean_t longfmt; 5870248571Smm boolean_t internal; 5871185029Spjd} hist_cbdata_t; 5872185029Spjd 5873363954Smarkjstatic void 5874363954Smarkjprint_history_records(nvlist_t *nvhis, hist_cbdata_t *cb) 5875168404Spjd{ 5876168404Spjd nvlist_t **records; 5877168404Spjd uint_t numrecords; 5878363954Smarkj int i; 5879168404Spjd 5880168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 5881168404Spjd &records, &numrecords) == 0); 5882168404Spjd for (i = 0; i < numrecords; i++) { 5883248571Smm nvlist_t *rec = records[i]; 5884248571Smm char tbuf[30] = ""; 5885185029Spjd 5886248571Smm if (nvlist_exists(rec, ZPOOL_HIST_TIME)) { 5887248571Smm time_t tsec; 5888248571Smm struct tm t; 5889185029Spjd 5890248571Smm tsec = fnvlist_lookup_uint64(records[i], 5891248571Smm ZPOOL_HIST_TIME); 5892248571Smm (void) localtime_r(&tsec, &t); 5893248571Smm (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 5894248571Smm } 5895248571Smm 5896248571Smm if (nvlist_exists(rec, ZPOOL_HIST_CMD)) { 5897248571Smm (void) printf("%s %s", tbuf, 5898248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_CMD)); 5899248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) { 5900248571Smm int ievent = 5901248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT); 5902248571Smm if (!cb->internal) 5903185029Spjd continue; 5904248571Smm if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) { 5905248571Smm (void) printf("%s unrecognized record:\n", 5906248571Smm tbuf); 5907248571Smm dump_nvlist(rec, 4); 5908185029Spjd continue; 5909248571Smm } 5910248571Smm (void) printf("%s [internal %s txg:%lld] %s", tbuf, 5911248571Smm zfs_history_event_names[ievent], 5912248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5913248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR)); 5914248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) { 5915248571Smm if (!cb->internal) 5916248571Smm continue; 5917248571Smm (void) printf("%s [txg:%lld] %s", tbuf, 5918248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5919248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME)); 5920248571Smm if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) { 5921248571Smm (void) printf(" %s (%llu)", 5922248571Smm fnvlist_lookup_string(rec, 5923248571Smm ZPOOL_HIST_DSNAME), 5924248571Smm fnvlist_lookup_uint64(rec, 5925248571Smm ZPOOL_HIST_DSID)); 5926248571Smm } 5927248571Smm (void) printf(" %s", fnvlist_lookup_string(rec, 5928248571Smm ZPOOL_HIST_INT_STR)); 5929248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) { 5930248571Smm if (!cb->internal) 5931248571Smm continue; 5932248571Smm (void) printf("%s ioctl %s\n", tbuf, 5933248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL)); 5934248571Smm if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) { 5935248571Smm (void) printf(" input:\n"); 5936248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5937248571Smm ZPOOL_HIST_INPUT_NVL), 8); 5938248571Smm } 5939248571Smm if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) { 5940248571Smm (void) printf(" output:\n"); 5941248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5942248571Smm ZPOOL_HIST_OUTPUT_NVL), 8); 5943248571Smm } 5944325534Savg if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) { 5945325534Savg (void) printf(" errno: %lld\n", 5946325534Savg fnvlist_lookup_int64(rec, 5947325534Savg ZPOOL_HIST_ERRNO)); 5948325534Savg } 5949248571Smm } else { 5950248571Smm if (!cb->internal) 5951248571Smm continue; 5952248571Smm (void) printf("%s unrecognized record:\n", tbuf); 5953248571Smm dump_nvlist(rec, 4); 5954168404Spjd } 5955185029Spjd 5956185029Spjd if (!cb->longfmt) { 5957185029Spjd (void) printf("\n"); 5958185029Spjd continue; 5959185029Spjd } 5960185029Spjd (void) printf(" ["); 5961248571Smm if (nvlist_exists(rec, ZPOOL_HIST_WHO)) { 5962248571Smm uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO); 5963248571Smm struct passwd *pwd = getpwuid(who); 5964248571Smm (void) printf("user %d ", (int)who); 5965248571Smm if (pwd != NULL) 5966248571Smm (void) printf("(%s) ", pwd->pw_name); 5967185029Spjd } 5968248571Smm if (nvlist_exists(rec, ZPOOL_HIST_HOST)) { 5969248571Smm (void) printf("on %s", 5970248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_HOST)); 5971185029Spjd } 5972248571Smm if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) { 5973248571Smm (void) printf(":%s", 5974248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE)); 5975185029Spjd } 5976185029Spjd (void) printf("]"); 5977185029Spjd (void) printf("\n"); 5978168404Spjd } 5979363954Smarkj} 5980363954Smarkj 5981363954Smarkj/* 5982363954Smarkj * Print out the command history for a specific pool. 5983363954Smarkj */ 5984363954Smarkjstatic int 5985363954Smarkjget_history_one(zpool_handle_t *zhp, void *data) 5986363954Smarkj{ 5987363954Smarkj nvlist_t *nvhis; 5988363954Smarkj int ret; 5989363954Smarkj hist_cbdata_t *cb = (hist_cbdata_t *)data; 5990363954Smarkj uint64_t off = 0; 5991363954Smarkj boolean_t eof = B_FALSE; 5992363954Smarkj 5993363954Smarkj cb->first = B_FALSE; 5994363954Smarkj 5995363954Smarkj (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 5996363954Smarkj 5997363954Smarkj while (!eof) { 5998363954Smarkj if ((ret = zpool_get_history(zhp, &nvhis, &off, &eof)) != 0) 5999363954Smarkj return (ret); 6000363954Smarkj 6001363954Smarkj print_history_records(nvhis, cb); 6002363954Smarkj nvlist_free(nvhis); 6003363954Smarkj } 6004168404Spjd (void) printf("\n"); 6005168404Spjd 6006168404Spjd return (ret); 6007168404Spjd} 6008168404Spjd 6009168404Spjd/* 6010168404Spjd * zpool history <pool> 6011168404Spjd * 6012168404Spjd * Displays the history of commands that modified pools. 6013168404Spjd */ 6014168404Spjdint 6015168404Spjdzpool_do_history(int argc, char **argv) 6016168404Spjd{ 6017185029Spjd hist_cbdata_t cbdata = { 0 }; 6018168404Spjd int ret; 6019185029Spjd int c; 6020168404Spjd 6021185029Spjd cbdata.first = B_TRUE; 6022185029Spjd /* check options */ 6023185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 6024185029Spjd switch (c) { 6025185029Spjd case 'l': 6026248571Smm cbdata.longfmt = B_TRUE; 6027185029Spjd break; 6028185029Spjd case 'i': 6029248571Smm cbdata.internal = B_TRUE; 6030185029Spjd break; 6031185029Spjd case '?': 6032185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 6033185029Spjd optopt); 6034185029Spjd usage(B_FALSE); 6035185029Spjd } 6036185029Spjd } 6037168404Spjd argc -= optind; 6038168404Spjd argv += optind; 6039168404Spjd 6040168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 6041185029Spjd &cbdata); 6042168404Spjd 6043185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 6044168404Spjd (void) printf(gettext("no pools available\n")); 6045168404Spjd return (0); 6046168404Spjd } 6047168404Spjd 6048168404Spjd return (ret); 6049168404Spjd} 6050168404Spjd 6051168404Spjdstatic int 6052168404Spjdget_callback(zpool_handle_t *zhp, void *data) 6053168404Spjd{ 6054185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 6055168404Spjd char value[MAXNAMELEN]; 6056185029Spjd zprop_source_t srctype; 6057185029Spjd zprop_list_t *pl; 6058168404Spjd 6059168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 6060168404Spjd 6061168404Spjd /* 6062185029Spjd * Skip the special fake placeholder. This will also skip 6063185029Spjd * over the name property when 'all' is specified. 6064168404Spjd */ 6065185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 6066168404Spjd pl == cbp->cb_proplist) 6067168404Spjd continue; 6068168404Spjd 6069236884Smm if (pl->pl_prop == ZPROP_INVAL && 6070236884Smm (zpool_prop_feature(pl->pl_user_prop) || 6071236884Smm zpool_prop_unsupported(pl->pl_user_prop))) { 6072236884Smm srctype = ZPROP_SRC_LOCAL; 6073168404Spjd 6074236884Smm if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 6075236884Smm value, sizeof (value)) == 0) { 6076236884Smm zprop_print_one_property(zpool_get_name(zhp), 6077236884Smm cbp, pl->pl_user_prop, value, srctype, 6078236884Smm NULL, NULL); 6079236884Smm } 6080236884Smm } else { 6081236884Smm if (zpool_get_prop(zhp, pl->pl_prop, value, 6082263889Sdelphij sizeof (value), &srctype, cbp->cb_literal) != 0) 6083236884Smm continue; 6084236884Smm 6085236884Smm zprop_print_one_property(zpool_get_name(zhp), cbp, 6086236884Smm zpool_prop_to_name(pl->pl_prop), value, srctype, 6087236884Smm NULL, NULL); 6088236884Smm } 6089168404Spjd } 6090168404Spjd return (0); 6091168404Spjd} 6092168404Spjd 6093263889Sdelphij/* 6094263889Sdelphij * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ... 6095263889Sdelphij * 6096263889Sdelphij * -H Scripted mode. Don't display headers, and separate properties 6097263889Sdelphij * by a single tab. 6098263889Sdelphij * -o List of columns to display. Defaults to 6099263889Sdelphij * "name,property,value,source". 6100342941Savg * -p Diplay values in parsable (exact) format. 6101263889Sdelphij * 6102263889Sdelphij * Get properties of pools in the system. Output space statistics 6103263889Sdelphij * for each one as well as other attributes. 6104263889Sdelphij */ 6105168404Spjdint 6106168404Spjdzpool_do_get(int argc, char **argv) 6107168404Spjd{ 6108185029Spjd zprop_get_cbdata_t cb = { 0 }; 6109185029Spjd zprop_list_t fake_name = { 0 }; 6110168404Spjd int ret; 6111263889Sdelphij int c, i; 6112263889Sdelphij char *value; 6113168404Spjd 6114263889Sdelphij cb.cb_first = B_TRUE; 6115168404Spjd 6116263889Sdelphij /* 6117263889Sdelphij * Set up default columns and sources. 6118263889Sdelphij */ 6119185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 6120168404Spjd cb.cb_columns[0] = GET_COL_NAME; 6121168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 6122168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 6123168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 6124185029Spjd cb.cb_type = ZFS_TYPE_POOL; 6125168404Spjd 6126263889Sdelphij /* check options */ 6127263889Sdelphij while ((c = getopt(argc, argv, ":Hpo:")) != -1) { 6128263889Sdelphij switch (c) { 6129263889Sdelphij case 'p': 6130263889Sdelphij cb.cb_literal = B_TRUE; 6131263889Sdelphij break; 6132263889Sdelphij case 'H': 6133263889Sdelphij cb.cb_scripted = B_TRUE; 6134263889Sdelphij break; 6135263889Sdelphij case 'o': 6136263889Sdelphij bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 6137263889Sdelphij i = 0; 6138263889Sdelphij while (*optarg != '\0') { 6139263889Sdelphij static char *col_subopts[] = 6140263889Sdelphij { "name", "property", "value", "source", 6141263889Sdelphij "all", NULL }; 6142263889Sdelphij 6143263889Sdelphij if (i == ZFS_GET_NCOLS) { 6144263889Sdelphij (void) fprintf(stderr, gettext("too " 6145263889Sdelphij "many fields given to -o " 6146263889Sdelphij "option\n")); 6147263889Sdelphij usage(B_FALSE); 6148263889Sdelphij } 6149263889Sdelphij 6150263889Sdelphij switch (getsubopt(&optarg, col_subopts, 6151263889Sdelphij &value)) { 6152263889Sdelphij case 0: 6153263889Sdelphij cb.cb_columns[i++] = GET_COL_NAME; 6154263889Sdelphij break; 6155263889Sdelphij case 1: 6156263889Sdelphij cb.cb_columns[i++] = GET_COL_PROPERTY; 6157263889Sdelphij break; 6158263889Sdelphij case 2: 6159263889Sdelphij cb.cb_columns[i++] = GET_COL_VALUE; 6160263889Sdelphij break; 6161263889Sdelphij case 3: 6162263889Sdelphij cb.cb_columns[i++] = GET_COL_SOURCE; 6163263889Sdelphij break; 6164263889Sdelphij case 4: 6165263889Sdelphij if (i > 0) { 6166263889Sdelphij (void) fprintf(stderr, 6167263889Sdelphij gettext("\"all\" conflicts " 6168263889Sdelphij "with specific fields " 6169263889Sdelphij "given to -o option\n")); 6170263889Sdelphij usage(B_FALSE); 6171263889Sdelphij } 6172263889Sdelphij cb.cb_columns[0] = GET_COL_NAME; 6173263889Sdelphij cb.cb_columns[1] = GET_COL_PROPERTY; 6174263889Sdelphij cb.cb_columns[2] = GET_COL_VALUE; 6175263889Sdelphij cb.cb_columns[3] = GET_COL_SOURCE; 6176263889Sdelphij i = ZFS_GET_NCOLS; 6177263889Sdelphij break; 6178263889Sdelphij default: 6179263889Sdelphij (void) fprintf(stderr, 6180263889Sdelphij gettext("invalid column name " 6181295844Sdim "'%s'\n"), suboptarg); 6182263889Sdelphij usage(B_FALSE); 6183263889Sdelphij } 6184263889Sdelphij } 6185263889Sdelphij break; 6186263889Sdelphij case '?': 6187263889Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 6188263889Sdelphij optopt); 6189263889Sdelphij usage(B_FALSE); 6190263889Sdelphij } 6191263889Sdelphij } 6192263889Sdelphij 6193263889Sdelphij argc -= optind; 6194263889Sdelphij argv += optind; 6195263889Sdelphij 6196263889Sdelphij if (argc < 1) { 6197263889Sdelphij (void) fprintf(stderr, gettext("missing property " 6198263889Sdelphij "argument\n")); 6199263889Sdelphij usage(B_FALSE); 6200263889Sdelphij } 6201263889Sdelphij 6202263889Sdelphij if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, 6203185029Spjd ZFS_TYPE_POOL) != 0) 6204168404Spjd usage(B_FALSE); 6205168404Spjd 6206263889Sdelphij argc--; 6207263889Sdelphij argv++; 6208263889Sdelphij 6209168404Spjd if (cb.cb_proplist != NULL) { 6210185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 6211168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 6212168404Spjd fake_name.pl_next = cb.cb_proplist; 6213168404Spjd cb.cb_proplist = &fake_name; 6214168404Spjd } 6215168404Spjd 6216263889Sdelphij ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 6217168404Spjd get_callback, &cb); 6218168404Spjd 6219168404Spjd if (cb.cb_proplist == &fake_name) 6220185029Spjd zprop_free_list(fake_name.pl_next); 6221168404Spjd else 6222185029Spjd zprop_free_list(cb.cb_proplist); 6223168404Spjd 6224168404Spjd return (ret); 6225168404Spjd} 6226168404Spjd 6227168404Spjdtypedef struct set_cbdata { 6228168404Spjd char *cb_propname; 6229168404Spjd char *cb_value; 6230168404Spjd boolean_t cb_any_successful; 6231168404Spjd} set_cbdata_t; 6232168404Spjd 6233168404Spjdint 6234168404Spjdset_callback(zpool_handle_t *zhp, void *data) 6235168404Spjd{ 6236168404Spjd int error; 6237168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 6238168404Spjd 6239168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 6240168404Spjd 6241168404Spjd if (!error) 6242168404Spjd cb->cb_any_successful = B_TRUE; 6243168404Spjd 6244168404Spjd return (error); 6245168404Spjd} 6246168404Spjd 6247168404Spjdint 6248168404Spjdzpool_do_set(int argc, char **argv) 6249168404Spjd{ 6250168404Spjd set_cbdata_t cb = { 0 }; 6251168404Spjd int error; 6252168404Spjd 6253168404Spjd if (argc > 1 && argv[1][0] == '-') { 6254168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 6255168404Spjd argv[1][1]); 6256168404Spjd usage(B_FALSE); 6257168404Spjd } 6258168404Spjd 6259168404Spjd if (argc < 2) { 6260168404Spjd (void) fprintf(stderr, gettext("missing property=value " 6261168404Spjd "argument\n")); 6262168404Spjd usage(B_FALSE); 6263168404Spjd } 6264168404Spjd 6265168404Spjd if (argc < 3) { 6266168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 6267168404Spjd usage(B_FALSE); 6268168404Spjd } 6269168404Spjd 6270168404Spjd if (argc > 3) { 6271168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 6272168404Spjd usage(B_FALSE); 6273168404Spjd } 6274168404Spjd 6275168404Spjd cb.cb_propname = argv[1]; 6276168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 6277168404Spjd if (cb.cb_value == NULL) { 6278168404Spjd (void) fprintf(stderr, gettext("missing value in " 6279168404Spjd "property=value argument\n")); 6280168404Spjd usage(B_FALSE); 6281168404Spjd } 6282168404Spjd 6283168404Spjd *(cb.cb_value) = '\0'; 6284168404Spjd cb.cb_value++; 6285168404Spjd 6286168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 6287168404Spjd set_callback, &cb); 6288168404Spjd 6289168404Spjd return (error); 6290168404Spjd} 6291168404Spjd 6292168404Spjdstatic int 6293168404Spjdfind_command_idx(char *command, int *idx) 6294168404Spjd{ 6295168404Spjd int i; 6296168404Spjd 6297168404Spjd for (i = 0; i < NCOMMAND; i++) { 6298168404Spjd if (command_table[i].name == NULL) 6299168404Spjd continue; 6300168404Spjd 6301168404Spjd if (strcmp(command, command_table[i].name) == 0) { 6302168404Spjd *idx = i; 6303168404Spjd return (0); 6304168404Spjd } 6305168404Spjd } 6306168404Spjd return (1); 6307168404Spjd} 6308168404Spjd 6309168404Spjdint 6310168404Spjdmain(int argc, char **argv) 6311168404Spjd{ 6312296537Smav int ret = 0; 6313168404Spjd int i; 6314168404Spjd char *cmdname; 6315168404Spjd 6316168404Spjd (void) setlocale(LC_ALL, ""); 6317168404Spjd (void) textdomain(TEXT_DOMAIN); 6318168404Spjd 6319168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 6320168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 6321168404Spjd "initialize ZFS library\n")); 6322168404Spjd return (1); 6323168404Spjd } 6324168404Spjd 6325168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 6326168404Spjd 6327168404Spjd opterr = 0; 6328168404Spjd 6329168404Spjd /* 6330168404Spjd * Make sure the user has specified some command. 6331168404Spjd */ 6332168404Spjd if (argc < 2) { 6333168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 6334168404Spjd usage(B_FALSE); 6335168404Spjd } 6336168404Spjd 6337168404Spjd cmdname = argv[1]; 6338168404Spjd 6339168404Spjd /* 6340168404Spjd * Special case '-?' 6341168404Spjd */ 6342168404Spjd if (strcmp(cmdname, "-?") == 0) 6343168404Spjd usage(B_TRUE); 6344168404Spjd 6345248571Smm zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); 6346185029Spjd 6347168404Spjd /* 6348168404Spjd * Run the appropriate command. 6349168404Spjd */ 6350168404Spjd if (find_command_idx(cmdname, &i) == 0) { 6351168404Spjd current_command = &command_table[i]; 6352168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 6353185029Spjd } else if (strchr(cmdname, '=')) { 6354185029Spjd verify(find_command_idx("set", &i) == 0); 6355185029Spjd current_command = &command_table[i]; 6356185029Spjd ret = command_table[i].func(argc, argv); 6357185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 6358185029Spjd /* 6359185029Spjd * 'freeze' is a vile debugging abomination, so we treat 6360185029Spjd * it as such. 6361185029Spjd */ 6362252059Ssmh zfs_cmd_t zc = { 0 }; 6363252059Ssmh (void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name)); 6364252059Ssmh return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc)); 6365185029Spjd } else { 6366168404Spjd (void) fprintf(stderr, gettext("unrecognized " 6367168404Spjd "command '%s'\n"), cmdname); 6368168404Spjd usage(B_FALSE); 6369168404Spjd } 6370168404Spjd 6371248571Smm if (ret == 0 && log_history) 6372248571Smm (void) zpool_log_history(g_zfs, history_str); 6373248571Smm 6374168404Spjd libzfs_fini(g_zfs); 6375168404Spjd 6376168404Spjd /* 6377168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 6378168404Spjd * for the purposes of running ::findleaks. 6379168404Spjd */ 6380168404Spjd if (getenv("ZFS_ABORT") != NULL) { 6381168404Spjd (void) printf("dumping core by request\n"); 6382168404Spjd abort(); 6383168404Spjd } 6384168404Spjd 6385168404Spjd return (ret); 6386168404Spjd} 6387