zpool_main.c revision 332525
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> 39168404Spjd#include <libgen.h> 40168404Spjd#include <libintl.h> 41168404Spjd#include <libuutil.h> 42168404Spjd#include <locale.h> 43168404Spjd#include <stdio.h> 44168404Spjd#include <stdlib.h> 45168404Spjd#include <string.h> 46168404Spjd#include <strings.h> 47168404Spjd#include <unistd.h> 48168404Spjd#include <priv.h> 49185029Spjd#include <pwd.h> 50185029Spjd#include <zone.h> 51168404Spjd#include <sys/time.h> 52236155Smm#include <zfs_prop.h> 53168404Spjd#include <sys/fs/zfs.h> 54168404Spjd#include <sys/stat.h> 55168404Spjd 56168404Spjd#include <libzfs.h> 57168404Spjd 58168404Spjd#include "zpool_util.h" 59185029Spjd#include "zfs_comutil.h" 60236884Smm#include "zfeature_common.h" 61168404Spjd 62219089Spjd#include "statcommon.h" 63219089Spjd 64168404Spjdstatic int zpool_do_create(int, char **); 65168404Spjdstatic int zpool_do_destroy(int, char **); 66168404Spjd 67168404Spjdstatic int zpool_do_add(int, char **); 68168404Spjdstatic int zpool_do_remove(int, char **); 69224171Sgibbsstatic int zpool_do_labelclear(int, char **); 70168404Spjd 71168404Spjdstatic int zpool_do_list(int, char **); 72168404Spjdstatic int zpool_do_iostat(int, char **); 73168404Spjdstatic int zpool_do_status(int, char **); 74168404Spjd 75168404Spjdstatic int zpool_do_online(int, char **); 76168404Spjdstatic int zpool_do_offline(int, char **); 77168404Spjdstatic int zpool_do_clear(int, char **); 78236155Smmstatic int zpool_do_reopen(int, char **); 79168404Spjd 80228103Smmstatic int zpool_do_reguid(int, char **); 81228103Smm 82168404Spjdstatic int zpool_do_attach(int, char **); 83168404Spjdstatic int zpool_do_detach(int, char **); 84168404Spjdstatic int zpool_do_replace(int, char **); 85219089Spjdstatic int zpool_do_split(int, char **); 86168404Spjd 87168404Spjdstatic int zpool_do_scrub(int, char **); 88168404Spjd 89168404Spjdstatic int zpool_do_import(int, char **); 90168404Spjdstatic int zpool_do_export(int, char **); 91168404Spjd 92168404Spjdstatic int zpool_do_upgrade(int, char **); 93168404Spjd 94168404Spjdstatic int zpool_do_history(int, char **); 95168404Spjd 96168404Spjdstatic int zpool_do_get(int, char **); 97168404Spjdstatic int zpool_do_set(int, char **); 98168404Spjd 99168404Spjd/* 100168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 101168404Spjd * debugging facilities. 102168404Spjd */ 103185029Spjd 104185029Spjd#ifdef DEBUG 105168404Spjdconst char * 106168404Spjd_umem_debug_init(void) 107168404Spjd{ 108168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 109168404Spjd} 110168404Spjd 111168404Spjdconst char * 112168404Spjd_umem_logging_init(void) 113168404Spjd{ 114168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 115168404Spjd} 116185029Spjd#endif 117168404Spjd 118168404Spjdtypedef enum { 119168404Spjd HELP_ADD, 120168404Spjd HELP_ATTACH, 121168404Spjd HELP_CLEAR, 122168404Spjd HELP_CREATE, 123168404Spjd HELP_DESTROY, 124168404Spjd HELP_DETACH, 125168404Spjd HELP_EXPORT, 126168404Spjd HELP_HISTORY, 127168404Spjd HELP_IMPORT, 128168404Spjd HELP_IOSTAT, 129224171Sgibbs HELP_LABELCLEAR, 130168404Spjd HELP_LIST, 131168404Spjd HELP_OFFLINE, 132168404Spjd HELP_ONLINE, 133168404Spjd HELP_REPLACE, 134168404Spjd HELP_REMOVE, 135168404Spjd HELP_SCRUB, 136168404Spjd HELP_STATUS, 137168404Spjd HELP_UPGRADE, 138168404Spjd HELP_GET, 139219089Spjd HELP_SET, 140228103Smm HELP_SPLIT, 141236155Smm HELP_REGUID, 142236155Smm HELP_REOPEN 143168404Spjd} zpool_help_t; 144168404Spjd 145168404Spjd 146168404Spjdtypedef struct zpool_command { 147168404Spjd const char *name; 148168404Spjd int (*func)(int, char **); 149168404Spjd zpool_help_t usage; 150168404Spjd} zpool_command_t; 151168404Spjd 152168404Spjd/* 153168404Spjd * Master command table. Each ZFS command has a name, associated function, and 154168404Spjd * usage message. The usage messages need to be internationalized, so we have 155168404Spjd * to have a function to return the usage message based on a command index. 156168404Spjd * 157168404Spjd * These commands are organized according to how they are displayed in the usage 158168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 159168404Spjd * the generic usage message. 160168404Spjd */ 161168404Spjdstatic zpool_command_t command_table[] = { 162168404Spjd { "create", zpool_do_create, HELP_CREATE }, 163168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 164168404Spjd { NULL }, 165168404Spjd { "add", zpool_do_add, HELP_ADD }, 166168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 167168404Spjd { NULL }, 168224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 169224171Sgibbs { NULL }, 170168404Spjd { "list", zpool_do_list, HELP_LIST }, 171168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 172168404Spjd { "status", zpool_do_status, HELP_STATUS }, 173168404Spjd { NULL }, 174168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 175168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 176168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 177236155Smm { "reopen", zpool_do_reopen, HELP_REOPEN }, 178168404Spjd { NULL }, 179168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 180168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 181168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 182219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 183168404Spjd { NULL }, 184168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 185168404Spjd { NULL }, 186168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 187168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 188168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 189228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 190168404Spjd { NULL }, 191168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 192168404Spjd { "get", zpool_do_get, HELP_GET }, 193168404Spjd { "set", zpool_do_set, HELP_SET }, 194168404Spjd}; 195168404Spjd 196168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 197168404Spjd 198248571Smmstatic zpool_command_t *current_command; 199185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 200248571Smmstatic boolean_t log_history = B_TRUE; 201219089Spjdstatic uint_t timestamp_fmt = NODATE; 202219089Spjd 203168404Spjdstatic const char * 204289562Smavget_usage(zpool_help_t idx) 205289562Smav{ 206168404Spjd switch (idx) { 207168404Spjd case HELP_ADD: 208168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 209168404Spjd case HELP_ATTACH: 210168404Spjd return (gettext("\tattach [-f] <pool> <device> " 211185029Spjd "<new-device>\n")); 212168404Spjd case HELP_CLEAR: 213219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 214168404Spjd case HELP_CREATE: 215331395Smav return (gettext("\tcreate [-fnd] [-B] " 216331395Smav "[-o property=value] ... \n" 217185029Spjd "\t [-O file-system-property=value] ... \n" 218185029Spjd "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 219168404Spjd case HELP_DESTROY: 220168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 221168404Spjd case HELP_DETACH: 222168404Spjd return (gettext("\tdetach <pool> <device>\n")); 223168404Spjd case HELP_EXPORT: 224168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 225168404Spjd case HELP_HISTORY: 226185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 227168404Spjd case HELP_IMPORT: 228168404Spjd return (gettext("\timport [-d dir] [-D]\n" 229219089Spjd "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 230185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 231219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 232219089Spjd "[-R root] [-F [-n]] -a\n" 233185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 234219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 235219089Spjd "[-R root] [-F [-n]]\n" 236219089Spjd "\t <pool | id> [newpool]\n")); 237168404Spjd case HELP_IOSTAT: 238219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 239168404Spjd "[count]]\n")); 240224171Sgibbs case HELP_LABELCLEAR: 241224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 242168404Spjd case HELP_LIST: 243263889Sdelphij return (gettext("\tlist [-Hpv] [-o property[,...]] " 244219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 245168404Spjd case HELP_OFFLINE: 246168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 247168404Spjd case HELP_ONLINE: 248228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 249168404Spjd case HELP_REPLACE: 250168404Spjd return (gettext("\treplace [-f] <pool> <device> " 251185029Spjd "[new-device]\n")); 252168404Spjd case HELP_REMOVE: 253332525Smav return (gettext("\tremove [-nps] <pool> <device> ...\n")); 254236155Smm case HELP_REOPEN: 255260138Sdelphij return (gettext("\treopen <pool>\n")); 256168404Spjd case HELP_SCRUB: 257324010Savg return (gettext("\tscrub [-s | -p] <pool> ...\n")); 258168404Spjd case HELP_STATUS: 259219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 260219089Spjd "[count]]\n")); 261168404Spjd case HELP_UPGRADE: 262228020Smm return (gettext("\tupgrade [-v]\n" 263185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 264168404Spjd case HELP_GET: 265263889Sdelphij return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] " 266263889Sdelphij "<\"all\" | property[,...]> <pool> ...\n")); 267168404Spjd case HELP_SET: 268168404Spjd return (gettext("\tset <property=value> <pool> \n")); 269219089Spjd case HELP_SPLIT: 270219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 271219089Spjd "\t [-o property=value] <pool> <newpool> " 272219089Spjd "[<device> ...]\n")); 273228103Smm case HELP_REGUID: 274228103Smm return (gettext("\treguid <pool>\n")); 275168404Spjd } 276168404Spjd 277168404Spjd abort(); 278168404Spjd /* NOTREACHED */ 279168404Spjd} 280168404Spjd 281168404Spjd 282168404Spjd/* 283168404Spjd * Callback routine that will print out a pool property value. 284168404Spjd */ 285185029Spjdstatic int 286185029Spjdprint_prop_cb(int prop, void *cb) 287168404Spjd{ 288168404Spjd FILE *fp = cb; 289168404Spjd 290219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 291168404Spjd 292185029Spjd if (zpool_prop_readonly(prop)) 293185029Spjd (void) fprintf(fp, " NO "); 294185029Spjd else 295219089Spjd (void) fprintf(fp, " YES "); 296185029Spjd 297168404Spjd if (zpool_prop_values(prop) == NULL) 298168404Spjd (void) fprintf(fp, "-\n"); 299168404Spjd else 300168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 301168404Spjd 302185029Spjd return (ZPROP_CONT); 303168404Spjd} 304168404Spjd 305168404Spjd/* 306168404Spjd * Display usage message. If we're inside a command, display only the usage for 307168404Spjd * that command. Otherwise, iterate over the entire command table and display 308168404Spjd * a complete usage message. 309168404Spjd */ 310168404Spjdvoid 311168404Spjdusage(boolean_t requested) 312168404Spjd{ 313168404Spjd FILE *fp = requested ? stdout : stderr; 314168404Spjd 315168404Spjd if (current_command == NULL) { 316168404Spjd int i; 317168404Spjd 318168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 319168404Spjd (void) fprintf(fp, 320168404Spjd gettext("where 'command' is one of the following:\n\n")); 321168404Spjd 322168404Spjd for (i = 0; i < NCOMMAND; i++) { 323168404Spjd if (command_table[i].name == NULL) 324168404Spjd (void) fprintf(fp, "\n"); 325168404Spjd else 326168404Spjd (void) fprintf(fp, "%s", 327168404Spjd get_usage(command_table[i].usage)); 328168404Spjd } 329168404Spjd } else { 330168404Spjd (void) fprintf(fp, gettext("usage:\n")); 331168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 332168404Spjd } 333168404Spjd 334168404Spjd if (current_command != NULL && 335168404Spjd ((strcmp(current_command->name, "set") == 0) || 336185029Spjd (strcmp(current_command->name, "get") == 0) || 337185029Spjd (strcmp(current_command->name, "list") == 0))) { 338168404Spjd 339168404Spjd (void) fprintf(fp, 340168404Spjd gettext("\nthe following properties are supported:\n")); 341168404Spjd 342219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 343185029Spjd "PROPERTY", "EDIT", "VALUES"); 344168404Spjd 345168404Spjd /* Iterate over all properties */ 346185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 347185029Spjd ZFS_TYPE_POOL); 348236884Smm 349236884Smm (void) fprintf(fp, "\t%-15s ", "feature@..."); 350236884Smm (void) fprintf(fp, "YES disabled | enabled | active\n"); 351236884Smm 352236884Smm (void) fprintf(fp, gettext("\nThe feature@ properties must be " 353243014Smm "appended with a feature name.\nSee zpool-features(7).\n")); 354168404Spjd } 355168404Spjd 356168404Spjd /* 357168404Spjd * See comments at end of main(). 358168404Spjd */ 359168404Spjd if (getenv("ZFS_ABORT") != NULL) { 360168404Spjd (void) printf("dumping core by request\n"); 361168404Spjd abort(); 362168404Spjd } 363168404Spjd 364168404Spjd exit(requested ? 0 : 2); 365168404Spjd} 366168404Spjd 367168404Spjdvoid 368185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 369185029Spjd boolean_t print_logs) 370168404Spjd{ 371168404Spjd nvlist_t **child; 372168404Spjd uint_t c, children; 373168404Spjd char *vname; 374168404Spjd 375168404Spjd if (name != NULL) 376168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 377168404Spjd 378168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 379168404Spjd &child, &children) != 0) 380168404Spjd return; 381168404Spjd 382168404Spjd for (c = 0; c < children; c++) { 383185029Spjd uint64_t is_log = B_FALSE; 384185029Spjd 385185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 386185029Spjd &is_log); 387185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 388185029Spjd continue; 389185029Spjd 390219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 391185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 392185029Spjd B_FALSE); 393168404Spjd free(vname); 394168404Spjd } 395168404Spjd} 396168404Spjd 397238926Smmstatic boolean_t 398238926Smmprop_list_contains_feature(nvlist_t *proplist) 399238926Smm{ 400238926Smm nvpair_t *nvp; 401238926Smm for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; 402238926Smm nvp = nvlist_next_nvpair(proplist, nvp)) { 403238926Smm if (zpool_prop_feature(nvpair_name(nvp))) 404238926Smm return (B_TRUE); 405238926Smm } 406238926Smm return (B_FALSE); 407238926Smm} 408238926Smm 409168404Spjd/* 410185029Spjd * Add a property pair (name, string-value) into a property nvlist. 411185029Spjd */ 412185029Spjdstatic int 413185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 414185029Spjd boolean_t poolprop) 415185029Spjd{ 416185029Spjd zpool_prop_t prop = ZPROP_INVAL; 417185029Spjd zfs_prop_t fprop; 418185029Spjd nvlist_t *proplist; 419185029Spjd const char *normnm; 420185029Spjd char *strval; 421185029Spjd 422185029Spjd if (*props == NULL && 423185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 424185029Spjd (void) fprintf(stderr, 425185029Spjd gettext("internal error: out of memory\n")); 426185029Spjd return (1); 427185029Spjd } 428185029Spjd 429185029Spjd proplist = *props; 430185029Spjd 431185029Spjd if (poolprop) { 432238926Smm const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); 433238926Smm 434236884Smm if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 435236884Smm !zpool_prop_feature(propname)) { 436185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 437185029Spjd "not a valid pool property\n"), propname); 438185029Spjd return (2); 439185029Spjd } 440238926Smm 441238926Smm /* 442238926Smm * feature@ properties and version should not be specified 443238926Smm * at the same time. 444238926Smm */ 445329493Smav if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) && 446238926Smm nvlist_exists(proplist, vname)) || 447238926Smm (prop == ZPOOL_PROP_VERSION && 448238926Smm prop_list_contains_feature(proplist))) { 449238926Smm (void) fprintf(stderr, gettext("'feature@' and " 450238926Smm "'version' properties cannot be specified " 451238926Smm "together\n")); 452238926Smm return (2); 453238926Smm } 454238926Smm 455238926Smm 456236884Smm if (zpool_prop_feature(propname)) 457236884Smm normnm = propname; 458236884Smm else 459236884Smm normnm = zpool_prop_to_name(prop); 460185029Spjd } else { 461209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 462209962Smm normnm = zfs_prop_to_name(fprop); 463209962Smm } else { 464209962Smm normnm = propname; 465185029Spjd } 466185029Spjd } 467185029Spjd 468185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 469185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 470185029Spjd (void) fprintf(stderr, gettext("property '%s' " 471185029Spjd "specified multiple times\n"), propname); 472185029Spjd return (2); 473185029Spjd } 474185029Spjd 475185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 476185029Spjd (void) fprintf(stderr, gettext("internal " 477185029Spjd "error: out of memory\n")); 478185029Spjd return (1); 479185029Spjd } 480185029Spjd 481185029Spjd return (0); 482185029Spjd} 483185029Spjd 484185029Spjd/* 485168404Spjd * zpool add [-fn] <pool> <vdev> ... 486168404Spjd * 487168404Spjd * -f Force addition of devices, even if they appear in use 488168404Spjd * -n Do not add the devices, but display the resulting layout if 489168404Spjd * they were to be added. 490168404Spjd * 491168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 492168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 493168404Spjd * libzfs. 494168404Spjd */ 495168404Spjdint 496168404Spjdzpool_do_add(int argc, char **argv) 497168404Spjd{ 498168404Spjd boolean_t force = B_FALSE; 499168404Spjd boolean_t dryrun = B_FALSE; 500168404Spjd int c; 501168404Spjd nvlist_t *nvroot; 502168404Spjd char *poolname; 503331395Smav zpool_boot_label_t boot_type; 504331395Smav uint64_t boot_size; 505168404Spjd int ret; 506168404Spjd zpool_handle_t *zhp; 507168404Spjd nvlist_t *config; 508168404Spjd 509168404Spjd /* check options */ 510168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 511168404Spjd switch (c) { 512168404Spjd case 'f': 513168404Spjd force = B_TRUE; 514168404Spjd break; 515168404Spjd case 'n': 516168404Spjd dryrun = B_TRUE; 517168404Spjd break; 518168404Spjd case '?': 519168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 520168404Spjd optopt); 521168404Spjd usage(B_FALSE); 522168404Spjd } 523168404Spjd } 524168404Spjd 525168404Spjd argc -= optind; 526168404Spjd argv += optind; 527168404Spjd 528168404Spjd /* get pool name and check number of arguments */ 529168404Spjd if (argc < 1) { 530168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 531168404Spjd usage(B_FALSE); 532168404Spjd } 533168404Spjd if (argc < 2) { 534168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 535168404Spjd usage(B_FALSE); 536168404Spjd } 537168404Spjd 538168404Spjd poolname = argv[0]; 539168404Spjd 540168404Spjd argc--; 541168404Spjd argv++; 542168404Spjd 543168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 544168404Spjd return (1); 545168404Spjd 546168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 547168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 548168404Spjd poolname); 549168404Spjd zpool_close(zhp); 550168404Spjd return (1); 551168404Spjd } 552168404Spjd 553331395Smav if (zpool_is_bootable(zhp)) 554331395Smav boot_type = ZPOOL_COPY_BOOT_LABEL; 555331395Smav else 556331395Smav boot_type = ZPOOL_NO_BOOT_LABEL; 557331395Smav 558168404Spjd /* pass off to get_vdev_spec for processing */ 559331395Smav boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL); 560185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 561331395Smav boot_type, boot_size, argc, argv); 562168404Spjd if (nvroot == NULL) { 563168404Spjd zpool_close(zhp); 564168404Spjd return (1); 565168404Spjd } 566168404Spjd 567168404Spjd if (dryrun) { 568168404Spjd nvlist_t *poolnvroot; 569168404Spjd 570168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 571168404Spjd &poolnvroot) == 0); 572168404Spjd 573168404Spjd (void) printf(gettext("would update '%s' to the following " 574168404Spjd "configuration:\n"), zpool_get_name(zhp)); 575168404Spjd 576185029Spjd /* print original main pool and new tree */ 577185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 578185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 579168404Spjd 580185029Spjd /* Do the same for the logs */ 581185029Spjd if (num_logs(poolnvroot) > 0) { 582185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 583185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 584185029Spjd } else if (num_logs(nvroot) > 0) { 585185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 586185029Spjd } 587185029Spjd 588168404Spjd ret = 0; 589168404Spjd } else { 590168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 591168404Spjd } 592168404Spjd 593168404Spjd nvlist_free(nvroot); 594168404Spjd zpool_close(zhp); 595168404Spjd 596168404Spjd return (ret); 597168404Spjd} 598168404Spjd 599168404Spjd/* 600219089Spjd * zpool remove <pool> <vdev> ... 601168404Spjd * 602332525Smav * Removes the given vdev from the pool. 603168404Spjd */ 604168404Spjdint 605168404Spjdzpool_do_remove(int argc, char **argv) 606168404Spjd{ 607168404Spjd char *poolname; 608185029Spjd int i, ret = 0; 609168404Spjd zpool_handle_t *zhp; 610332525Smav boolean_t stop = B_FALSE; 611332525Smav boolean_t noop = B_FALSE; 612332525Smav boolean_t parsable = B_FALSE; 613332525Smav char c; 614168404Spjd 615332525Smav /* check options */ 616332525Smav while ((c = getopt(argc, argv, "nps")) != -1) { 617332525Smav switch (c) { 618332525Smav case 'n': 619332525Smav noop = B_TRUE; 620332525Smav break; 621332525Smav case 'p': 622332525Smav parsable = B_TRUE; 623332525Smav break; 624332525Smav case 's': 625332525Smav stop = B_TRUE; 626332525Smav break; 627332525Smav case '?': 628332525Smav (void) fprintf(stderr, gettext("invalid option '%c'\n"), 629332525Smav optopt); 630332525Smav usage(B_FALSE); 631332525Smav } 632332525Smav } 633168404Spjd 634332525Smav argc -= optind; 635332525Smav argv += optind; 636332525Smav 637168404Spjd /* get pool name and check number of arguments */ 638168404Spjd if (argc < 1) { 639168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 640168404Spjd usage(B_FALSE); 641168404Spjd } 642168404Spjd 643168404Spjd poolname = argv[0]; 644168404Spjd 645168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 646168404Spjd return (1); 647168404Spjd 648332525Smav if (stop && noop) { 649332525Smav (void) fprintf(stderr, gettext("stop request ignored\n")); 650332525Smav return (0); 651332525Smav } 652332525Smav 653332525Smav if (stop) { 654332525Smav if (argc > 1) { 655332525Smav (void) fprintf(stderr, gettext("too many arguments\n")); 656332525Smav usage(B_FALSE); 657332525Smav } 658332525Smav if (zpool_vdev_remove_cancel(zhp) != 0) 659185029Spjd ret = 1; 660332525Smav } else { 661332525Smav if (argc < 2) { 662332525Smav (void) fprintf(stderr, gettext("missing device\n")); 663332525Smav usage(B_FALSE); 664332525Smav } 665332525Smav 666332525Smav for (i = 1; i < argc; i++) { 667332525Smav if (noop) { 668332525Smav uint64_t size; 669332525Smav 670332525Smav if (zpool_vdev_indirect_size(zhp, argv[i], 671332525Smav &size) != 0) { 672332525Smav ret = 1; 673332525Smav break; 674332525Smav } 675332525Smav if (parsable) { 676332525Smav (void) printf("%s %llu\n", 677332525Smav argv[i], size); 678332525Smav } else { 679332525Smav char valstr[32]; 680332525Smav zfs_nicenum(size, valstr, 681332525Smav sizeof (valstr)); 682332525Smav (void) printf("Memory that will be " 683332525Smav "used after removing %s: %s\n", 684332525Smav argv[i], valstr); 685332525Smav } 686332525Smav } else { 687332525Smav if (zpool_vdev_remove(zhp, argv[i]) != 0) 688332525Smav ret = 1; 689332525Smav } 690332525Smav } 691168404Spjd } 692168404Spjd 693168404Spjd return (ret); 694168404Spjd} 695168404Spjd 696168404Spjd/* 697297763Smav * zpool labelclear [-f] <vdev> 698224171Sgibbs * 699297763Smav * -f Force clearing the label for the vdevs which are members of 700297763Smav * the exported or foreign pools. 701297763Smav * 702224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 703224171Sgibbs * on the device. 704224171Sgibbs */ 705224171Sgibbsint 706224171Sgibbszpool_do_labelclear(int argc, char **argv) 707224171Sgibbs{ 708297763Smav char vdev[MAXPATHLEN]; 709297763Smav char *name = NULL; 710297763Smav struct stat st; 711297763Smav int c, fd, ret = 0; 712297763Smav nvlist_t *config; 713224171Sgibbs pool_state_t state; 714224171Sgibbs boolean_t inuse = B_FALSE; 715224171Sgibbs boolean_t force = B_FALSE; 716224171Sgibbs 717224171Sgibbs /* check options */ 718224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 719224171Sgibbs switch (c) { 720224171Sgibbs case 'f': 721224171Sgibbs force = B_TRUE; 722224171Sgibbs break; 723224171Sgibbs default: 724224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 725224171Sgibbs optopt); 726224171Sgibbs usage(B_FALSE); 727224171Sgibbs } 728224171Sgibbs } 729224171Sgibbs 730224171Sgibbs argc -= optind; 731224171Sgibbs argv += optind; 732224171Sgibbs 733224171Sgibbs /* get vdev name */ 734224171Sgibbs if (argc < 1) { 735297763Smav (void) fprintf(stderr, gettext("missing vdev name\n")); 736224171Sgibbs usage(B_FALSE); 737224171Sgibbs } 738297763Smav if (argc > 1) { 739297763Smav (void) fprintf(stderr, gettext("too many arguments\n")); 740297763Smav usage(B_FALSE); 741297763Smav } 742224171Sgibbs 743297763Smav /* 744297763Smav * Check if we were given absolute path and use it as is. 745297763Smav * Otherwise if the provided vdev name doesn't point to a file, 746297763Smav * try prepending dsk path and appending s0. 747297763Smav */ 748297763Smav (void) strlcpy(vdev, argv[0], sizeof (vdev)); 749297763Smav if (vdev[0] != '/' && stat(vdev, &st) != 0) { 750297763Smav char *s; 751297763Smav 752297763Smav (void) snprintf(vdev, sizeof (vdev), "%s/%s", 753297763Smav#ifdef illumos 754297763Smav ZFS_DISK_ROOT, argv[0]); 755297763Smav if ((s = strrchr(argv[0], 's')) == NULL || 756297763Smav !isdigit(*(s + 1))) 757297763Smav (void) strlcat(vdev, "s0", sizeof (vdev)); 758297763Smav#else 759297763Smav "/dev", argv[0]); 760297763Smav#endif 761297763Smav if (stat(vdev, &st) != 0) { 762297763Smav (void) fprintf(stderr, gettext( 763297763Smav "failed to find device %s, try specifying absolute " 764297763Smav "path instead\n"), argv[0]); 765297763Smav return (1); 766297763Smav } 767297763Smav } 768297763Smav 769224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 770297763Smav (void) fprintf(stderr, gettext("failed to open %s: %s\n"), 771297763Smav vdev, strerror(errno)); 772297763Smav return (1); 773224171Sgibbs } 774224171Sgibbs 775324255Savg if (zpool_read_label(fd, &config) != 0) { 776224171Sgibbs (void) fprintf(stderr, 777297763Smav gettext("failed to read label from %s\n"), vdev); 778297763Smav return (1); 779297763Smav } 780297763Smav nvlist_free(config); 781224171Sgibbs 782297763Smav ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse); 783297763Smav if (ret != 0) { 784297763Smav (void) fprintf(stderr, 785297763Smav gettext("failed to check state for %s\n"), vdev); 786224171Sgibbs return (1); 787224171Sgibbs } 788224171Sgibbs 789297763Smav if (!inuse) 790297763Smav goto wipe_label; 791224171Sgibbs 792297763Smav switch (state) { 793297763Smav default: 794297763Smav case POOL_STATE_ACTIVE: 795297763Smav case POOL_STATE_SPARE: 796297763Smav case POOL_STATE_L2CACHE: 797297763Smav (void) fprintf(stderr, gettext( 798297763Smav "%s is a member (%s) of pool \"%s\"\n"), 799297763Smav vdev, zpool_pool_state_to_name(state), name); 800297763Smav ret = 1; 801297763Smav goto errout; 802224171Sgibbs 803297763Smav case POOL_STATE_EXPORTED: 804297763Smav if (force) 805297763Smav break; 806297763Smav (void) fprintf(stderr, gettext( 807297763Smav "use '-f' to override the following error:\n" 808297763Smav "%s is a member of exported pool \"%s\"\n"), 809297763Smav vdev, name); 810297763Smav ret = 1; 811297763Smav goto errout; 812224171Sgibbs 813297763Smav case POOL_STATE_POTENTIALLY_ACTIVE: 814297763Smav if (force) 815297763Smav break; 816297763Smav (void) fprintf(stderr, gettext( 817297763Smav "use '-f' to override the following error:\n" 818297763Smav "%s is a member of potentially active pool \"%s\"\n"), 819297763Smav vdev, name); 820297763Smav ret = 1; 821297763Smav goto errout; 822224171Sgibbs 823297763Smav case POOL_STATE_DESTROYED: 824297763Smav /* inuse should never be set for a destroyed pool */ 825297763Smav assert(0); 826297763Smav break; 827224171Sgibbs } 828224171Sgibbs 829224171Sgibbswipe_label: 830297763Smav ret = zpool_clear_label(fd); 831297763Smav if (ret != 0) { 832224171Sgibbs (void) fprintf(stderr, 833297763Smav gettext("failed to clear label for %s\n"), vdev); 834224171Sgibbs } 835224171Sgibbs 836224171Sgibbserrout: 837297763Smav free(name); 838297763Smav (void) close(fd); 839224171Sgibbs 840224171Sgibbs return (ret); 841224171Sgibbs} 842224171Sgibbs 843224171Sgibbs/* 844331395Smav * zpool create [-fnd] [-B] [-o property=value] ... 845185029Spjd * [-O file-system-property=value] ... 846185029Spjd * [-R root] [-m mountpoint] <pool> <dev> ... 847168404Spjd * 848331395Smav * -B Create boot partition. 849168404Spjd * -f Force creation, even if devices appear in use 850168404Spjd * -n Do not create the pool, but display the resulting layout if it 851168404Spjd * were to be created. 852168404Spjd * -R Create a pool under an alternate root 853168404Spjd * -m Set default mountpoint for the root dataset. By default it's 854236884Smm * '/<pool>' 855185029Spjd * -o Set property=value. 856236884Smm * -d Don't automatically enable all supported pool features 857236884Smm * (individual features can be enabled with -o). 858185029Spjd * -O Set fsproperty=value in the pool's root file system 859168404Spjd * 860168404Spjd * Creates the named pool according to the given vdev specification. The 861168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 862168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 863168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 864168404Spjd */ 865331395Smav 866331395Smav#define SYSTEM256 (256 * 1024 * 1024) 867168404Spjdint 868168404Spjdzpool_do_create(int argc, char **argv) 869168404Spjd{ 870168404Spjd boolean_t force = B_FALSE; 871168404Spjd boolean_t dryrun = B_FALSE; 872236884Smm boolean_t enable_all_pool_feat = B_TRUE; 873331395Smav zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL; 874331395Smav uint64_t boot_size = 0; 875168404Spjd int c; 876185029Spjd nvlist_t *nvroot = NULL; 877168404Spjd char *poolname; 878185029Spjd int ret = 1; 879168404Spjd char *altroot = NULL; 880168404Spjd char *mountpoint = NULL; 881185029Spjd nvlist_t *fsprops = NULL; 882185029Spjd nvlist_t *props = NULL; 883185029Spjd char *propval; 884168404Spjd 885168404Spjd /* check options */ 886331395Smav while ((c = getopt(argc, argv, ":fndBR:m:o:O:")) != -1) { 887168404Spjd switch (c) { 888168404Spjd case 'f': 889168404Spjd force = B_TRUE; 890168404Spjd break; 891168404Spjd case 'n': 892168404Spjd dryrun = B_TRUE; 893168404Spjd break; 894236884Smm case 'd': 895236884Smm enable_all_pool_feat = B_FALSE; 896236884Smm break; 897331395Smav case 'B': 898331395Smav#ifdef illumos 899331395Smav /* 900331395Smav * We should create the system partition. 901331395Smav * Also make sure the size is set. 902331395Smav */ 903331395Smav boot_type = ZPOOL_CREATE_BOOT_LABEL; 904331395Smav if (boot_size == 0) 905331395Smav boot_size = SYSTEM256; 906331395Smav break; 907331395Smav#else 908331395Smav (void) fprintf(stderr, 909331395Smav gettext("option '%c' is not supported\n"), 910331395Smav optopt); 911331395Smav goto badusage; 912331395Smav#endif 913168404Spjd case 'R': 914168404Spjd altroot = optarg; 915185029Spjd if (add_prop_list(zpool_prop_to_name( 916185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 917185029Spjd goto errout; 918185029Spjd if (nvlist_lookup_string(props, 919185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 920185029Spjd &propval) == 0) 921185029Spjd break; 922185029Spjd if (add_prop_list(zpool_prop_to_name( 923185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 924185029Spjd goto errout; 925168404Spjd break; 926168404Spjd case 'm': 927251634Sdelphij /* Equivalent to -O mountpoint=optarg */ 928168404Spjd mountpoint = optarg; 929168404Spjd break; 930185029Spjd case 'o': 931185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 932185029Spjd (void) fprintf(stderr, gettext("missing " 933185029Spjd "'=' for -o option\n")); 934185029Spjd goto errout; 935185029Spjd } 936185029Spjd *propval = '\0'; 937185029Spjd propval++; 938185029Spjd 939185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 940185029Spjd goto errout; 941236884Smm 942236884Smm /* 943331395Smav * Get bootsize value for make_root_vdev(). 944331395Smav */ 945331395Smav if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) { 946331395Smav if (zfs_nicestrtonum(g_zfs, propval, 947331395Smav &boot_size) < 0 || boot_size == 0) { 948331395Smav (void) fprintf(stderr, 949331395Smav gettext("bad boot partition size " 950331395Smav "'%s': %s\n"), propval, 951331395Smav libzfs_error_description(g_zfs)); 952331395Smav goto errout; 953331395Smav } 954331395Smav } 955331395Smav 956331395Smav /* 957236884Smm * If the user is creating a pool that doesn't support 958236884Smm * feature flags, don't enable any features. 959236884Smm */ 960236884Smm if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 961236884Smm char *end; 962236884Smm u_longlong_t ver; 963236884Smm 964236884Smm ver = strtoull(propval, &end, 10); 965236884Smm if (*end == '\0' && 966236884Smm ver < SPA_VERSION_FEATURES) { 967236884Smm enable_all_pool_feat = B_FALSE; 968236884Smm } 969236884Smm } 970279366Sdelphij if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) 971279366Sdelphij altroot = propval; 972185029Spjd break; 973185029Spjd case 'O': 974185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 975185029Spjd (void) fprintf(stderr, gettext("missing " 976185029Spjd "'=' for -O option\n")); 977185029Spjd goto errout; 978185029Spjd } 979185029Spjd *propval = '\0'; 980185029Spjd propval++; 981185029Spjd 982251634Sdelphij /* 983251634Sdelphij * Mountpoints are checked and then added later. 984251634Sdelphij * Uniquely among properties, they can be specified 985251634Sdelphij * more than once, to avoid conflict with -m. 986251634Sdelphij */ 987251634Sdelphij if (0 == strcmp(optarg, 988251634Sdelphij zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) { 989251634Sdelphij mountpoint = propval; 990251634Sdelphij } else if (add_prop_list(optarg, propval, &fsprops, 991251634Sdelphij B_FALSE)) { 992185029Spjd goto errout; 993251634Sdelphij } 994185029Spjd break; 995168404Spjd case ':': 996168404Spjd (void) fprintf(stderr, gettext("missing argument for " 997168404Spjd "'%c' option\n"), optopt); 998185029Spjd goto badusage; 999168404Spjd case '?': 1000168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1001168404Spjd optopt); 1002185029Spjd goto badusage; 1003168404Spjd } 1004168404Spjd } 1005168404Spjd 1006168404Spjd argc -= optind; 1007168404Spjd argv += optind; 1008168404Spjd 1009168404Spjd /* get pool name and check number of arguments */ 1010168404Spjd if (argc < 1) { 1011168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 1012185029Spjd goto badusage; 1013168404Spjd } 1014168404Spjd if (argc < 2) { 1015168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 1016185029Spjd goto badusage; 1017168404Spjd } 1018168404Spjd 1019168404Spjd poolname = argv[0]; 1020168404Spjd 1021168404Spjd /* 1022168404Spjd * As a special case, check for use of '/' in the name, and direct the 1023168404Spjd * user to use 'zfs create' instead. 1024168404Spjd */ 1025168404Spjd if (strchr(poolname, '/') != NULL) { 1026168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 1027168404Spjd "character '/' in pool name\n"), poolname); 1028168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 1029168404Spjd "create a dataset\n")); 1030185029Spjd goto errout; 1031168404Spjd } 1032168404Spjd 1033331395Smav /* 1034331395Smav * Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used, 1035331395Smav * and not set otherwise. 1036331395Smav */ 1037331395Smav if (boot_type == ZPOOL_CREATE_BOOT_LABEL) { 1038331395Smav const char *propname; 1039331395Smav char *strptr, *buf = NULL; 1040331395Smav int rv; 1041331395Smav 1042331395Smav propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE); 1043331395Smav if (nvlist_lookup_string(props, propname, &strptr) != 0) { 1044331395Smav (void) asprintf(&buf, "%" PRIu64, boot_size); 1045331395Smav if (buf == NULL) { 1046331395Smav (void) fprintf(stderr, 1047331395Smav gettext("internal error: out of memory\n")); 1048331395Smav goto errout; 1049331395Smav } 1050331395Smav rv = add_prop_list(propname, buf, &props, B_TRUE); 1051331395Smav free(buf); 1052331395Smav if (rv != 0) 1053331395Smav goto errout; 1054331395Smav } 1055331395Smav } else { 1056331395Smav const char *propname; 1057331395Smav char *strptr; 1058331395Smav 1059331395Smav propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE); 1060331395Smav if (nvlist_lookup_string(props, propname, &strptr) == 0) { 1061331395Smav (void) fprintf(stderr, gettext("error: setting boot " 1062331395Smav "partition size requires option '-B'\n")); 1063331395Smav goto errout; 1064331395Smav } 1065331395Smav } 1066331395Smav 1067168404Spjd /* pass off to get_vdev_spec for bulk processing */ 1068185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 1069331395Smav boot_type, boot_size, argc - 1, argv + 1); 1070168404Spjd if (nvroot == NULL) 1071185029Spjd goto errout; 1072168404Spjd 1073168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 1074185029Spjd if (!zfs_allocatable_devs(nvroot)) { 1075168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 1076168404Spjd "specification: at least one toplevel vdev must be " 1077168404Spjd "specified\n")); 1078185029Spjd goto errout; 1079168404Spjd } 1080168404Spjd 1081168404Spjd if (altroot != NULL && altroot[0] != '/') { 1082168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 1083168404Spjd "must be an absolute path\n"), altroot); 1084185029Spjd goto errout; 1085168404Spjd } 1086168404Spjd 1087168404Spjd /* 1088168404Spjd * Check the validity of the mountpoint and direct the user to use the 1089168404Spjd * '-m' mountpoint option if it looks like its in use. 1090244857Spjd * Ignore the checks if the '-f' option is given. 1091168404Spjd */ 1092244857Spjd if (!force && (mountpoint == NULL || 1093168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 1094244857Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) { 1095168404Spjd char buf[MAXPATHLEN]; 1096185029Spjd DIR *dirp; 1097168404Spjd 1098168404Spjd if (mountpoint && mountpoint[0] != '/') { 1099168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 1100168404Spjd "'%s': must be an absolute path, 'legacy', or " 1101168404Spjd "'none'\n"), mountpoint); 1102185029Spjd goto errout; 1103168404Spjd } 1104168404Spjd 1105168404Spjd if (mountpoint == NULL) { 1106168404Spjd if (altroot != NULL) 1107168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 1108168404Spjd altroot, poolname); 1109168404Spjd else 1110168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 1111168404Spjd poolname); 1112168404Spjd } else { 1113168404Spjd if (altroot != NULL) 1114168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 1115168404Spjd altroot, mountpoint); 1116168404Spjd else 1117168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 1118168404Spjd mountpoint); 1119168404Spjd } 1120168404Spjd 1121185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 1122185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 1123185029Spjd "%s\n"), buf, strerror(errno)); 1124185029Spjd (void) fprintf(stderr, gettext("use '-m' " 1125185029Spjd "option to provide a different default\n")); 1126185029Spjd goto errout; 1127185029Spjd } else if (dirp) { 1128185029Spjd int count = 0; 1129185029Spjd 1130185029Spjd while (count < 3 && readdir(dirp) != NULL) 1131185029Spjd count++; 1132185029Spjd (void) closedir(dirp); 1133185029Spjd 1134185029Spjd if (count > 2) { 1135168404Spjd (void) fprintf(stderr, gettext("mountpoint " 1136168404Spjd "'%s' exists and is not empty\n"), buf); 1137185029Spjd (void) fprintf(stderr, gettext("use '-m' " 1138185029Spjd "option to provide a " 1139185029Spjd "different default\n")); 1140185029Spjd goto errout; 1141185029Spjd } 1142168404Spjd } 1143168404Spjd } 1144168404Spjd 1145251634Sdelphij /* 1146251634Sdelphij * Now that the mountpoint's validity has been checked, ensure that 1147251634Sdelphij * the property is set appropriately prior to creating the pool. 1148251634Sdelphij */ 1149251634Sdelphij if (mountpoint != NULL) { 1150251634Sdelphij ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1151251634Sdelphij mountpoint, &fsprops, B_FALSE); 1152251634Sdelphij if (ret != 0) 1153251634Sdelphij goto errout; 1154251634Sdelphij } 1155251634Sdelphij 1156251634Sdelphij ret = 1; 1157168404Spjd if (dryrun) { 1158168404Spjd /* 1159168404Spjd * For a dry run invocation, print out a basic message and run 1160168404Spjd * through all the vdevs in the list and print out in an 1161168404Spjd * appropriate hierarchy. 1162168404Spjd */ 1163168404Spjd (void) printf(gettext("would create '%s' with the " 1164168404Spjd "following layout:\n\n"), poolname); 1165168404Spjd 1166185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 1167185029Spjd if (num_logs(nvroot) > 0) 1168185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 1169168404Spjd 1170168404Spjd ret = 0; 1171168404Spjd } else { 1172168404Spjd /* 1173168404Spjd * Hand off to libzfs. 1174168404Spjd */ 1175236884Smm if (enable_all_pool_feat) { 1176259813Sdelphij spa_feature_t i; 1177236884Smm for (i = 0; i < SPA_FEATURES; i++) { 1178236884Smm char propname[MAXPATHLEN]; 1179236884Smm zfeature_info_t *feat = &spa_feature_table[i]; 1180236884Smm 1181236884Smm (void) snprintf(propname, sizeof (propname), 1182236884Smm "feature@%s", feat->fi_uname); 1183236884Smm 1184236884Smm /* 1185236884Smm * Skip feature if user specified it manually 1186236884Smm * on the command line. 1187236884Smm */ 1188236884Smm if (nvlist_exists(props, propname)) 1189236884Smm continue; 1190236884Smm 1191251634Sdelphij ret = add_prop_list(propname, 1192251634Sdelphij ZFS_FEATURE_ENABLED, &props, B_TRUE); 1193251634Sdelphij if (ret != 0) 1194236884Smm goto errout; 1195236884Smm } 1196236884Smm } 1197251634Sdelphij 1198251634Sdelphij ret = 1; 1199185029Spjd if (zpool_create(g_zfs, poolname, 1200185029Spjd nvroot, props, fsprops) == 0) { 1201168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 1202168404Spjd ZFS_TYPE_FILESYSTEM); 1203168404Spjd if (pool != NULL) { 1204168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 1205185029Spjd ret = zfs_shareall(pool); 1206168404Spjd zfs_close(pool); 1207168404Spjd } 1208168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 1209168404Spjd (void) fprintf(stderr, gettext("pool name may have " 1210168404Spjd "been omitted\n")); 1211168404Spjd } 1212168404Spjd } 1213168404Spjd 1214185029Spjderrout: 1215168404Spjd nvlist_free(nvroot); 1216185029Spjd nvlist_free(fsprops); 1217185029Spjd nvlist_free(props); 1218168404Spjd return (ret); 1219185029Spjdbadusage: 1220185029Spjd nvlist_free(fsprops); 1221185029Spjd nvlist_free(props); 1222185029Spjd usage(B_FALSE); 1223185029Spjd return (2); 1224168404Spjd} 1225168404Spjd 1226168404Spjd/* 1227168404Spjd * zpool destroy <pool> 1228168404Spjd * 1229168404Spjd * -f Forcefully unmount any datasets 1230168404Spjd * 1231168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 1232168404Spjd */ 1233168404Spjdint 1234168404Spjdzpool_do_destroy(int argc, char **argv) 1235168404Spjd{ 1236168404Spjd boolean_t force = B_FALSE; 1237168404Spjd int c; 1238168404Spjd char *pool; 1239168404Spjd zpool_handle_t *zhp; 1240168404Spjd int ret; 1241168404Spjd 1242168404Spjd /* check options */ 1243168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 1244168404Spjd switch (c) { 1245168404Spjd case 'f': 1246168404Spjd force = B_TRUE; 1247168404Spjd break; 1248168404Spjd case '?': 1249168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1250168404Spjd optopt); 1251168404Spjd usage(B_FALSE); 1252168404Spjd } 1253168404Spjd } 1254168404Spjd 1255168404Spjd argc -= optind; 1256168404Spjd argv += optind; 1257168404Spjd 1258168404Spjd /* check arguments */ 1259168404Spjd if (argc < 1) { 1260168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1261168404Spjd usage(B_FALSE); 1262168404Spjd } 1263168404Spjd if (argc > 1) { 1264168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1265168404Spjd usage(B_FALSE); 1266168404Spjd } 1267168404Spjd 1268168404Spjd pool = argv[0]; 1269168404Spjd 1270168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1271168404Spjd /* 1272168404Spjd * As a special case, check for use of '/' in the name, and 1273168404Spjd * direct the user to use 'zfs destroy' instead. 1274168404Spjd */ 1275168404Spjd if (strchr(pool, '/') != NULL) 1276168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1277168404Spjd "destroy a dataset\n")); 1278168404Spjd return (1); 1279168404Spjd } 1280168404Spjd 1281168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1282168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1283168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1284168404Spjd return (1); 1285168404Spjd } 1286168404Spjd 1287248571Smm /* The history must be logged as part of the export */ 1288248571Smm log_history = B_FALSE; 1289168404Spjd 1290248571Smm ret = (zpool_destroy(zhp, history_str) != 0); 1291248571Smm 1292168404Spjd zpool_close(zhp); 1293168404Spjd 1294168404Spjd return (ret); 1295168404Spjd} 1296168404Spjd 1297168404Spjd/* 1298168404Spjd * zpool export [-f] <pool> ... 1299168404Spjd * 1300168404Spjd * -f Forcefully unmount datasets 1301168404Spjd * 1302168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1303168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1304168404Spjd * then the datasets will be forcefully unmounted. 1305168404Spjd */ 1306168404Spjdint 1307168404Spjdzpool_do_export(int argc, char **argv) 1308168404Spjd{ 1309168404Spjd boolean_t force = B_FALSE; 1310207670Smm boolean_t hardforce = B_FALSE; 1311168404Spjd int c; 1312168404Spjd zpool_handle_t *zhp; 1313168404Spjd int ret; 1314168404Spjd int i; 1315168404Spjd 1316168404Spjd /* check options */ 1317207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1318168404Spjd switch (c) { 1319168404Spjd case 'f': 1320168404Spjd force = B_TRUE; 1321168404Spjd break; 1322207670Smm case 'F': 1323207670Smm hardforce = B_TRUE; 1324207670Smm break; 1325168404Spjd case '?': 1326168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1327168404Spjd optopt); 1328168404Spjd usage(B_FALSE); 1329168404Spjd } 1330168404Spjd } 1331168404Spjd 1332168404Spjd argc -= optind; 1333168404Spjd argv += optind; 1334168404Spjd 1335168404Spjd /* check arguments */ 1336168404Spjd if (argc < 1) { 1337168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1338168404Spjd usage(B_FALSE); 1339168404Spjd } 1340168404Spjd 1341168404Spjd ret = 0; 1342168404Spjd for (i = 0; i < argc; i++) { 1343168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1344168404Spjd ret = 1; 1345168404Spjd continue; 1346168404Spjd } 1347168404Spjd 1348168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1349168404Spjd ret = 1; 1350168404Spjd zpool_close(zhp); 1351168404Spjd continue; 1352168404Spjd } 1353168404Spjd 1354248571Smm /* The history must be logged as part of the export */ 1355248571Smm log_history = B_FALSE; 1356248571Smm 1357207670Smm if (hardforce) { 1358248571Smm if (zpool_export_force(zhp, history_str) != 0) 1359207670Smm ret = 1; 1360248571Smm } else if (zpool_export(zhp, force, history_str) != 0) { 1361168404Spjd ret = 1; 1362207670Smm } 1363168404Spjd 1364168404Spjd zpool_close(zhp); 1365168404Spjd } 1366168404Spjd 1367168404Spjd return (ret); 1368168404Spjd} 1369168404Spjd 1370168404Spjd/* 1371168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1372168404Spjd * name column. 1373168404Spjd */ 1374168404Spjdstatic int 1375168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1376168404Spjd{ 1377219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1378168404Spjd nvlist_t **child; 1379168404Spjd uint_t c, children; 1380168404Spjd int ret; 1381168404Spjd 1382168404Spjd if (strlen(name) + depth > max) 1383168404Spjd max = strlen(name) + depth; 1384168404Spjd 1385168404Spjd free(name); 1386168404Spjd 1387168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1388168404Spjd &child, &children) == 0) { 1389168404Spjd for (c = 0; c < children; c++) 1390168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1391168404Spjd max)) > max) 1392168404Spjd max = ret; 1393168404Spjd } 1394168404Spjd 1395185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1396185029Spjd &child, &children) == 0) { 1397185029Spjd for (c = 0; c < children; c++) 1398185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1399185029Spjd max)) > max) 1400185029Spjd max = ret; 1401185029Spjd } 1402185029Spjd 1403168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1404168404Spjd &child, &children) == 0) { 1405168404Spjd for (c = 0; c < children; c++) 1406168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1407168404Spjd max)) > max) 1408168404Spjd max = ret; 1409168404Spjd } 1410168404Spjd 1411168404Spjd 1412168404Spjd return (max); 1413168404Spjd} 1414168404Spjd 1415213197Smmtypedef struct spare_cbdata { 1416213197Smm uint64_t cb_guid; 1417213197Smm zpool_handle_t *cb_zhp; 1418213197Smm} spare_cbdata_t; 1419168404Spjd 1420213197Smmstatic boolean_t 1421213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1422213197Smm{ 1423213197Smm uint64_t guid; 1424213197Smm nvlist_t **child; 1425213197Smm uint_t c, children; 1426213197Smm 1427213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1428213197Smm search == guid) 1429213197Smm return (B_TRUE); 1430213197Smm 1431213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1432213197Smm &child, &children) == 0) { 1433213197Smm for (c = 0; c < children; c++) 1434213197Smm if (find_vdev(child[c], search)) 1435213197Smm return (B_TRUE); 1436213197Smm } 1437213197Smm 1438213197Smm return (B_FALSE); 1439213197Smm} 1440213197Smm 1441213197Smmstatic int 1442213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1443213197Smm{ 1444213197Smm spare_cbdata_t *cbp = data; 1445213197Smm nvlist_t *config, *nvroot; 1446213197Smm 1447213197Smm config = zpool_get_config(zhp, NULL); 1448213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1449213197Smm &nvroot) == 0); 1450213197Smm 1451213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1452213197Smm cbp->cb_zhp = zhp; 1453213197Smm return (1); 1454213197Smm } 1455213197Smm 1456213197Smm zpool_close(zhp); 1457213197Smm return (0); 1458213197Smm} 1459213197Smm 1460168404Spjd/* 1461213197Smm * Print out configuration state as requested by status_callback. 1462213197Smm */ 1463213197Smmvoid 1464213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1465213197Smm int namewidth, int depth, boolean_t isspare) 1466213197Smm{ 1467213197Smm nvlist_t **child; 1468254591Sgibbs uint_t c, vsc, children; 1469219089Spjd pool_scan_stat_t *ps = NULL; 1470213197Smm vdev_stat_t *vs; 1471219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1472213197Smm char *vname; 1473213197Smm uint64_t notpresent; 1474254591Sgibbs uint64_t ashift; 1475213197Smm spare_cbdata_t cb; 1476224169Sgibbs const char *state; 1477332525Smav char *type; 1478213197Smm 1479213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1480213197Smm &child, &children) != 0) 1481213197Smm children = 0; 1482213197Smm 1483219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1484254591Sgibbs (uint64_t **)&vs, &vsc) == 0); 1485219089Spjd 1486332525Smav verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1487332525Smav 1488332525Smav if (strcmp(type, VDEV_TYPE_INDIRECT) == 0) 1489332525Smav return; 1490332525Smav 1491213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1492213197Smm if (isspare) { 1493213197Smm /* 1494213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1495213197Smm * online drives. 1496213197Smm */ 1497213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1498213197Smm state = "INUSE"; 1499213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1500213197Smm state = "AVAIL"; 1501213197Smm } 1502213197Smm 1503213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1504213197Smm name, state); 1505213197Smm 1506213197Smm if (!isspare) { 1507213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1508213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1509213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1510213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1511213197Smm } 1512213197Smm 1513213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1514224170Sgibbs ¬present) == 0 || 1515224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1516213197Smm char *path; 1517224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1518224170Sgibbs (void) printf(" was %s", path); 1519213197Smm } else if (vs->vs_aux != 0) { 1520213197Smm (void) printf(" "); 1521213197Smm 1522213197Smm switch (vs->vs_aux) { 1523213197Smm case VDEV_AUX_OPEN_FAILED: 1524213197Smm (void) printf(gettext("cannot open")); 1525213197Smm break; 1526213197Smm 1527213197Smm case VDEV_AUX_BAD_GUID_SUM: 1528213197Smm (void) printf(gettext("missing device")); 1529213197Smm break; 1530213197Smm 1531213197Smm case VDEV_AUX_NO_REPLICAS: 1532213197Smm (void) printf(gettext("insufficient replicas")); 1533213197Smm break; 1534213197Smm 1535213197Smm case VDEV_AUX_VERSION_NEWER: 1536213197Smm (void) printf(gettext("newer version")); 1537213197Smm break; 1538213197Smm 1539236884Smm case VDEV_AUX_UNSUP_FEAT: 1540236884Smm (void) printf(gettext("unsupported feature(s)")); 1541236884Smm break; 1542236884Smm 1543254591Sgibbs case VDEV_AUX_ASHIFT_TOO_BIG: 1544254591Sgibbs (void) printf(gettext("unsupported minimum blocksize")); 1545254591Sgibbs break; 1546254591Sgibbs 1547213197Smm case VDEV_AUX_SPARED: 1548213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1549213197Smm &cb.cb_guid) == 0); 1550213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1551213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1552213197Smm zpool_get_name(zhp)) == 0) 1553213197Smm (void) printf(gettext("currently in " 1554213197Smm "use")); 1555213197Smm else 1556213197Smm (void) printf(gettext("in use by " 1557213197Smm "pool '%s'"), 1558213197Smm zpool_get_name(cb.cb_zhp)); 1559213197Smm zpool_close(cb.cb_zhp); 1560213197Smm } else { 1561213197Smm (void) printf(gettext("currently in use")); 1562213197Smm } 1563213197Smm break; 1564213197Smm 1565213197Smm case VDEV_AUX_ERR_EXCEEDED: 1566213197Smm (void) printf(gettext("too many errors")); 1567213197Smm break; 1568213197Smm 1569213197Smm case VDEV_AUX_IO_FAILURE: 1570213197Smm (void) printf(gettext("experienced I/O failures")); 1571213197Smm break; 1572213197Smm 1573213197Smm case VDEV_AUX_BAD_LOG: 1574213197Smm (void) printf(gettext("bad intent log")); 1575213197Smm break; 1576213197Smm 1577219089Spjd case VDEV_AUX_EXTERNAL: 1578219089Spjd (void) printf(gettext("external device fault")); 1579219089Spjd break; 1580219089Spjd 1581219089Spjd case VDEV_AUX_SPLIT_POOL: 1582219089Spjd (void) printf(gettext("split into new pool")); 1583219089Spjd break; 1584219089Spjd 1585213197Smm default: 1586213197Smm (void) printf(gettext("corrupted data")); 1587213197Smm break; 1588213197Smm } 1589254591Sgibbs } else if (children == 0 && !isspare && 1590254591Sgibbs VDEV_STAT_VALID(vs_physical_ashift, vsc) && 1591254591Sgibbs vs->vs_configured_ashift < vs->vs_physical_ashift) { 1592254591Sgibbs (void) printf( 1593254591Sgibbs gettext(" block size: %dB configured, %dB native"), 1594254591Sgibbs 1 << vs->vs_configured_ashift, 1 << vs->vs_physical_ashift); 1595213197Smm } 1596213197Smm 1597219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1598219089Spjd (uint64_t **)&ps, &c); 1599219089Spjd 1600219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1601219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1602219089Spjd (void) printf(gettext(" (%s)"), 1603219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1604219089Spjd "resilvering" : "repairing"); 1605219089Spjd } 1606219089Spjd 1607213197Smm (void) printf("\n"); 1608213197Smm 1609213197Smm for (c = 0; c < children; c++) { 1610219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1611213197Smm 1612219089Spjd /* Don't print logs or holes here */ 1613213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1614219089Spjd &islog); 1615219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1616219089Spjd &ishole); 1617219089Spjd if (islog || ishole) 1618213197Smm continue; 1619219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1620213197Smm print_status_config(zhp, vname, child[c], 1621213197Smm namewidth, depth + 2, isspare); 1622213197Smm free(vname); 1623213197Smm } 1624213197Smm} 1625213197Smm 1626213197Smm 1627213197Smm/* 1628168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1629168404Spjd * pool, printing out the name and status for each one. 1630168404Spjd */ 1631168404Spjdvoid 1632213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1633168404Spjd{ 1634168404Spjd nvlist_t **child; 1635168404Spjd uint_t c, children; 1636168404Spjd vdev_stat_t *vs; 1637168404Spjd char *type, *vname; 1638168404Spjd 1639168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1640219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1641219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1642168404Spjd return; 1643168404Spjd 1644219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1645168404Spjd (uint64_t **)&vs, &c) == 0); 1646168404Spjd 1647168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1648185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1649168404Spjd 1650168404Spjd if (vs->vs_aux != 0) { 1651185029Spjd (void) printf(" "); 1652168404Spjd 1653168404Spjd switch (vs->vs_aux) { 1654168404Spjd case VDEV_AUX_OPEN_FAILED: 1655168404Spjd (void) printf(gettext("cannot open")); 1656168404Spjd break; 1657168404Spjd 1658168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1659168404Spjd (void) printf(gettext("missing device")); 1660168404Spjd break; 1661168404Spjd 1662168404Spjd case VDEV_AUX_NO_REPLICAS: 1663168404Spjd (void) printf(gettext("insufficient replicas")); 1664168404Spjd break; 1665168404Spjd 1666168404Spjd case VDEV_AUX_VERSION_NEWER: 1667168404Spjd (void) printf(gettext("newer version")); 1668168404Spjd break; 1669168404Spjd 1670236884Smm case VDEV_AUX_UNSUP_FEAT: 1671236884Smm (void) printf(gettext("unsupported feature(s)")); 1672236884Smm break; 1673236884Smm 1674185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1675185029Spjd (void) printf(gettext("too many errors")); 1676185029Spjd break; 1677185029Spjd 1678168404Spjd default: 1679168404Spjd (void) printf(gettext("corrupted data")); 1680168404Spjd break; 1681168404Spjd } 1682168404Spjd } 1683168404Spjd (void) printf("\n"); 1684168404Spjd 1685168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1686168404Spjd &child, &children) != 0) 1687168404Spjd return; 1688168404Spjd 1689168404Spjd for (c = 0; c < children; c++) { 1690185029Spjd uint64_t is_log = B_FALSE; 1691185029Spjd 1692185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1693185029Spjd &is_log); 1694213197Smm if (is_log) 1695185029Spjd continue; 1696185029Spjd 1697219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1698213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1699168404Spjd free(vname); 1700168404Spjd } 1701168404Spjd 1702185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1703185029Spjd &child, &children) == 0) { 1704185029Spjd (void) printf(gettext("\tcache\n")); 1705185029Spjd for (c = 0; c < children; c++) { 1706219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1707185029Spjd (void) printf("\t %s\n", vname); 1708185029Spjd free(vname); 1709185029Spjd } 1710185029Spjd } 1711185029Spjd 1712168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1713185029Spjd &child, &children) == 0) { 1714185029Spjd (void) printf(gettext("\tspares\n")); 1715185029Spjd for (c = 0; c < children; c++) { 1716219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1717185029Spjd (void) printf("\t %s\n", vname); 1718185029Spjd free(vname); 1719185029Spjd } 1720168404Spjd } 1721168404Spjd} 1722168404Spjd 1723168404Spjd/* 1724213197Smm * Print log vdevs. 1725213197Smm * Logs are recorded as top level vdevs in the main pool child array 1726213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1727213197Smm * print_import_config() to print the top level logs then any log 1728213197Smm * children (eg mirrored slogs) are printed recursively - which 1729213197Smm * works because only the top level vdev is marked "is_log" 1730213197Smm */ 1731213197Smmstatic void 1732213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1733213197Smm{ 1734213197Smm uint_t c, children; 1735213197Smm nvlist_t **child; 1736213197Smm 1737213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1738213197Smm &children) != 0) 1739213197Smm return; 1740213197Smm 1741213197Smm (void) printf(gettext("\tlogs\n")); 1742213197Smm 1743213197Smm for (c = 0; c < children; c++) { 1744213197Smm uint64_t is_log = B_FALSE; 1745213197Smm char *name; 1746213197Smm 1747213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1748213197Smm &is_log); 1749213197Smm if (!is_log) 1750213197Smm continue; 1751219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1752213197Smm if (verbose) 1753213197Smm print_status_config(zhp, name, child[c], namewidth, 1754213197Smm 2, B_FALSE); 1755213197Smm else 1756213197Smm print_import_config(name, child[c], namewidth, 2); 1757213197Smm free(name); 1758213197Smm } 1759213197Smm} 1760219089Spjd 1761213197Smm/* 1762168404Spjd * Display the status for the given pool. 1763168404Spjd */ 1764168404Spjdstatic void 1765168404Spjdshow_import(nvlist_t *config) 1766168404Spjd{ 1767168404Spjd uint64_t pool_state; 1768168404Spjd vdev_stat_t *vs; 1769168404Spjd char *name; 1770168404Spjd uint64_t guid; 1771168404Spjd char *msgid; 1772168404Spjd nvlist_t *nvroot; 1773168404Spjd int reason; 1774168404Spjd const char *health; 1775168404Spjd uint_t vsc; 1776168404Spjd int namewidth; 1777228103Smm char *comment; 1778168404Spjd 1779168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1780168404Spjd &name) == 0); 1781168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1782168404Spjd &guid) == 0); 1783168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1784168404Spjd &pool_state) == 0); 1785168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1786168404Spjd &nvroot) == 0); 1787168404Spjd 1788219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1789168404Spjd (uint64_t **)&vs, &vsc) == 0); 1790185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1791168404Spjd 1792168404Spjd reason = zpool_import_status(config, &msgid); 1793168404Spjd 1794228103Smm (void) printf(gettext(" pool: %s\n"), name); 1795228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1796228103Smm (void) printf(gettext(" state: %s"), health); 1797168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1798168404Spjd (void) printf(gettext(" (DESTROYED)")); 1799168404Spjd (void) printf("\n"); 1800168404Spjd 1801168404Spjd switch (reason) { 1802168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1803168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1804168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1805228103Smm (void) printf(gettext(" status: One or more devices are " 1806228103Smm "missing from the system.\n")); 1807168404Spjd break; 1808168404Spjd 1809168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1810168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1811228103Smm (void) printf(gettext(" status: One or more devices contains " 1812168404Spjd "corrupted data.\n")); 1813168404Spjd break; 1814168404Spjd 1815168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1816228103Smm (void) printf( 1817228103Smm gettext(" status: The pool data is corrupted.\n")); 1818168404Spjd break; 1819168404Spjd 1820168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1821228103Smm (void) printf(gettext(" status: One or more devices " 1822168404Spjd "are offlined.\n")); 1823168404Spjd break; 1824168404Spjd 1825168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1826228103Smm (void) printf(gettext(" status: The pool metadata is " 1827168404Spjd "corrupted.\n")); 1828168404Spjd break; 1829168404Spjd 1830168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1831238926Smm (void) printf(gettext(" status: The pool is formatted using a " 1832238926Smm "legacy on-disk version.\n")); 1833168404Spjd break; 1834168404Spjd 1835168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1836228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1837168404Spjd "incompatible version.\n")); 1838168404Spjd break; 1839168404Spjd 1840238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 1841238926Smm (void) printf(gettext(" status: Some supported features are " 1842238926Smm "not enabled on the pool.\n")); 1843238926Smm break; 1844238926Smm 1845236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1846236884Smm (void) printf(gettext("status: The pool uses the following " 1847236884Smm "feature(s) not supported on this sytem:\n")); 1848236884Smm zpool_print_unsup_feat(config); 1849236884Smm break; 1850236884Smm 1851236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1852236884Smm (void) printf(gettext("status: The pool can only be accessed " 1853236884Smm "in read-only mode on this system. It\n\tcannot be " 1854236884Smm "accessed in read-write mode because it uses the " 1855236884Smm "following\n\tfeature(s) not supported on this system:\n")); 1856236884Smm zpool_print_unsup_feat(config); 1857236884Smm break; 1858236884Smm 1859168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1860228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1861168498Spjd "another system.\n")); 1862168498Spjd break; 1863185029Spjd 1864185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1865185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1866228103Smm (void) printf(gettext(" status: One or more devices are " 1867185029Spjd "faulted.\n")); 1868185029Spjd break; 1869185029Spjd 1870185029Spjd case ZPOOL_STATUS_BAD_LOG: 1871228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1872185029Spjd "read.\n")); 1873185029Spjd break; 1874185029Spjd 1875219089Spjd case ZPOOL_STATUS_RESILVERING: 1876228103Smm (void) printf(gettext(" status: One or more devices were being " 1877219089Spjd "resilvered.\n")); 1878219089Spjd break; 1879219089Spjd 1880259131Sdelphij case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 1881259131Sdelphij (void) printf(gettext("status: One or more devices were " 1882259131Sdelphij "configured to use a non-native block size.\n" 1883259131Sdelphij "\tExpect reduced performance.\n")); 1884259131Sdelphij break; 1885259131Sdelphij 1886168404Spjd default: 1887168404Spjd /* 1888168404Spjd * No other status can be seen when importing pools. 1889168404Spjd */ 1890168404Spjd assert(reason == ZPOOL_STATUS_OK); 1891168404Spjd } 1892168404Spjd 1893168404Spjd /* 1894168404Spjd * Print out an action according to the overall state of the pool. 1895168404Spjd */ 1896168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1897238926Smm if (reason == ZPOOL_STATUS_VERSION_OLDER || 1898238926Smm reason == ZPOOL_STATUS_FEAT_DISABLED) { 1899228103Smm (void) printf(gettext(" action: The pool can be " 1900168404Spjd "imported using its name or numeric identifier, " 1901168404Spjd "though\n\tsome features will not be available " 1902168404Spjd "without an explicit 'zpool upgrade'.\n")); 1903238926Smm } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 1904228103Smm (void) printf(gettext(" action: The pool can be " 1905168498Spjd "imported using its name or numeric " 1906168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1907238926Smm } else { 1908228103Smm (void) printf(gettext(" action: The pool can be " 1909168404Spjd "imported using its name or numeric " 1910168404Spjd "identifier.\n")); 1911238926Smm } 1912168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1913228103Smm (void) printf(gettext(" action: The pool can be imported " 1914168404Spjd "despite missing or damaged devices. The\n\tfault " 1915168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1916168404Spjd } else { 1917168404Spjd switch (reason) { 1918168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1919228103Smm (void) printf(gettext(" action: The pool cannot be " 1920168404Spjd "imported. Access the pool on a system running " 1921168404Spjd "newer\n\tsoftware, or recreate the pool from " 1922168404Spjd "backup.\n")); 1923168404Spjd break; 1924236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1925236884Smm (void) printf(gettext("action: The pool cannot be " 1926236884Smm "imported. Access the pool on a system that " 1927236884Smm "supports\n\tthe required feature(s), or recreate " 1928236884Smm "the pool from backup.\n")); 1929236884Smm break; 1930236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1931236884Smm (void) printf(gettext("action: The pool cannot be " 1932236884Smm "imported in read-write mode. Import the pool " 1933236884Smm "with\n" 1934236884Smm "\t\"-o readonly=on\", access the pool on a system " 1935236884Smm "that supports the\n\trequired feature(s), or " 1936236884Smm "recreate the pool from backup.\n")); 1937236884Smm break; 1938168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1939168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1940168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1941228103Smm (void) printf(gettext(" action: The pool cannot be " 1942168404Spjd "imported. Attach the missing\n\tdevices and try " 1943168404Spjd "again.\n")); 1944168404Spjd break; 1945168404Spjd default: 1946228103Smm (void) printf(gettext(" action: The pool cannot be " 1947168404Spjd "imported due to damaged devices or data.\n")); 1948168404Spjd } 1949168404Spjd } 1950168404Spjd 1951228103Smm /* Print the comment attached to the pool. */ 1952228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 1953228103Smm (void) printf(gettext("comment: %s\n"), comment); 1954228103Smm 1955168404Spjd /* 1956168404Spjd * If the state is "closed" or "can't open", and the aux state 1957168404Spjd * is "corrupt data": 1958168404Spjd */ 1959168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1960168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1961168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1962168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1963168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1964168404Spjd "but can be imported using the '-Df' flags.\n")); 1965168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1966168404Spjd (void) printf(gettext("\tThe pool may be active on " 1967185029Spjd "another system, but can be imported using\n\t" 1968168404Spjd "the '-f' flag.\n")); 1969168404Spjd } 1970168404Spjd 1971168404Spjd if (msgid != NULL) 1972236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1973168404Spjd msgid); 1974168404Spjd 1975228103Smm (void) printf(gettext(" config:\n\n")); 1976168404Spjd 1977168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1978168404Spjd if (namewidth < 10) 1979168404Spjd namewidth = 10; 1980168404Spjd 1981213197Smm print_import_config(name, nvroot, namewidth, 0); 1982213197Smm if (num_logs(nvroot) > 0) 1983213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1984185029Spjd 1985168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1986168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1987168404Spjd "be part of this pool, though their\n\texact " 1988168404Spjd "configuration cannot be determined.\n")); 1989168404Spjd } 1990168404Spjd} 1991168404Spjd 1992168404Spjd/* 1993168404Spjd * Perform the import for the given configuration. This passes the heavy 1994185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1995185029Spjd * within the pool. 1996168404Spjd */ 1997168404Spjdstatic int 1998168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1999219089Spjd nvlist_t *props, int flags) 2000168404Spjd{ 2001168404Spjd zpool_handle_t *zhp; 2002168404Spjd char *name; 2003168404Spjd uint64_t state; 2004168404Spjd uint64_t version; 2005168404Spjd 2006168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 2007168404Spjd &name) == 0); 2008168404Spjd 2009168404Spjd verify(nvlist_lookup_uint64(config, 2010168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 2011168404Spjd verify(nvlist_lookup_uint64(config, 2012168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 2013236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 2014168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 2015236884Smm "is formatted using an unsupported ZFS version\n"), name); 2016168404Spjd return (1); 2017219089Spjd } else if (state != POOL_STATE_EXPORTED && 2018219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 2019168498Spjd uint64_t hostid; 2020168498Spjd 2021168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 2022168498Spjd &hostid) == 0) { 2023168498Spjd if ((unsigned long)hostid != gethostid()) { 2024168498Spjd char *hostname; 2025168498Spjd uint64_t timestamp; 2026168498Spjd time_t t; 2027168498Spjd 2028168498Spjd verify(nvlist_lookup_string(config, 2029168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 2030168498Spjd verify(nvlist_lookup_uint64(config, 2031168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 2032168498Spjd t = timestamp; 2033168498Spjd (void) fprintf(stderr, gettext("cannot import " 2034168498Spjd "'%s': pool may be in use from other " 2035168498Spjd "system, it was last accessed by %s " 2036168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 2037168498Spjd (unsigned long)hostid, 2038168498Spjd asctime(localtime(&t))); 2039168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 2040168498Spjd "import anyway\n")); 2041168498Spjd return (1); 2042168498Spjd } 2043168498Spjd } else { 2044168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2045168498Spjd "pool may be in use from other system\n"), name); 2046168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 2047168498Spjd "anyway\n")); 2048168498Spjd return (1); 2049168498Spjd } 2050168404Spjd } 2051168404Spjd 2052219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 2053168404Spjd return (1); 2054168404Spjd 2055168404Spjd if (newname != NULL) 2056168404Spjd name = (char *)newname; 2057168404Spjd 2058209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 2059209962Smm return (1); 2060168404Spjd 2061209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 2062219089Spjd !(flags & ZFS_IMPORT_ONLY) && 2063209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 2064168404Spjd zpool_close(zhp); 2065168404Spjd return (1); 2066168404Spjd } 2067168404Spjd 2068168404Spjd zpool_close(zhp); 2069219089Spjd return (0); 2070168404Spjd} 2071168404Spjd 2072168404Spjd/* 2073168404Spjd * zpool import [-d dir] [-D] 2074185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 2075185029Spjd * [-d dir | -c cachefile] [-f] -a 2076185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 2077219089Spjd * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 2078168404Spjd * 2079185029Spjd * -c Read pool information from a cachefile instead of searching 2080185029Spjd * devices. 2081185029Spjd * 2082168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 2083168404Spjd * one directory can be specified using multiple '-d' options. 2084168404Spjd * 2085168404Spjd * -D Scan for previously destroyed pools or import all or only 2086168404Spjd * specified destroyed pools. 2087168404Spjd * 2088168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 2089168404Spjd * the given root. The pool will remain exported when the machine 2090168404Spjd * is rebooted. 2091168404Spjd * 2092219089Spjd * -V Import even in the presence of faulted vdevs. This is an 2093185029Spjd * intentionally undocumented option for testing purposes, and 2094185029Spjd * treats the pool configuration as complete, leaving any bad 2095209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 2096209962Smm * import. 2097185029Spjd * 2098219089Spjd * -f Force import, even if it appears that the pool is active. 2099219089Spjd * 2100219089Spjd * -F Attempt rewind if necessary. 2101219089Spjd * 2102219089Spjd * -n See if rewind would work, but don't actually rewind. 2103219089Spjd * 2104219089Spjd * -N Import the pool but don't mount datasets. 2105219089Spjd * 2106219089Spjd * -T Specify a starting txg to use for import. This option is 2107219089Spjd * intentionally undocumented option for testing purposes. 2108219089Spjd * 2109168404Spjd * -a Import all pools found. 2110168404Spjd * 2111185029Spjd * -o Set property=value and/or temporary mount options (without '='). 2112185029Spjd * 2113168404Spjd * The import command scans for pools to import, and import pools based on pool 2114168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 2115168404Spjd */ 2116168404Spjdint 2117168404Spjdzpool_do_import(int argc, char **argv) 2118168404Spjd{ 2119168404Spjd char **searchdirs = NULL; 2120168404Spjd int nsearch = 0; 2121168404Spjd int c; 2122219089Spjd int err = 0; 2123185029Spjd nvlist_t *pools = NULL; 2124168404Spjd boolean_t do_all = B_FALSE; 2125168404Spjd boolean_t do_destroyed = B_FALSE; 2126168404Spjd char *mntopts = NULL; 2127168404Spjd nvpair_t *elem; 2128168404Spjd nvlist_t *config; 2129185029Spjd uint64_t searchguid = 0; 2130185029Spjd char *searchname = NULL; 2131185029Spjd char *propval; 2132168404Spjd nvlist_t *found_config; 2133219089Spjd nvlist_t *policy = NULL; 2134185029Spjd nvlist_t *props = NULL; 2135168404Spjd boolean_t first; 2136219089Spjd int flags = ZFS_IMPORT_NORMAL; 2137219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 2138219089Spjd boolean_t dryrun = B_FALSE; 2139219089Spjd boolean_t do_rewind = B_FALSE; 2140219089Spjd boolean_t xtreme_rewind = B_FALSE; 2141219089Spjd uint64_t pool_state, txg = -1ULL; 2142185029Spjd char *cachefile = NULL; 2143219089Spjd importargs_t idata = { 0 }; 2144219089Spjd char *endptr; 2145168404Spjd 2146168404Spjd /* check options */ 2147263385Sdelphij while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:R:T:VX")) != -1) { 2148168404Spjd switch (c) { 2149168404Spjd case 'a': 2150168404Spjd do_all = B_TRUE; 2151168404Spjd break; 2152185029Spjd case 'c': 2153185029Spjd cachefile = optarg; 2154185029Spjd break; 2155168404Spjd case 'd': 2156168404Spjd if (searchdirs == NULL) { 2157168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2158168404Spjd } else { 2159168404Spjd char **tmp = safe_malloc((nsearch + 1) * 2160168404Spjd sizeof (char *)); 2161168404Spjd bcopy(searchdirs, tmp, nsearch * 2162168404Spjd sizeof (char *)); 2163168404Spjd free(searchdirs); 2164168404Spjd searchdirs = tmp; 2165168404Spjd } 2166168404Spjd searchdirs[nsearch++] = optarg; 2167168404Spjd break; 2168168404Spjd case 'D': 2169168404Spjd do_destroyed = B_TRUE; 2170168404Spjd break; 2171168404Spjd case 'f': 2172219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 2173168404Spjd break; 2174185029Spjd case 'F': 2175219089Spjd do_rewind = B_TRUE; 2176185029Spjd break; 2177219089Spjd case 'm': 2178219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 2179219089Spjd break; 2180219089Spjd case 'n': 2181219089Spjd dryrun = B_TRUE; 2182219089Spjd break; 2183219089Spjd case 'N': 2184219089Spjd flags |= ZFS_IMPORT_ONLY; 2185219089Spjd break; 2186168404Spjd case 'o': 2187185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 2188185029Spjd *propval = '\0'; 2189185029Spjd propval++; 2190185029Spjd if (add_prop_list(optarg, propval, 2191185029Spjd &props, B_TRUE)) 2192185029Spjd goto error; 2193185029Spjd } else { 2194185029Spjd mntopts = optarg; 2195185029Spjd } 2196168404Spjd break; 2197168404Spjd case 'R': 2198185029Spjd if (add_prop_list(zpool_prop_to_name( 2199185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 2200185029Spjd goto error; 2201185029Spjd if (nvlist_lookup_string(props, 2202185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 2203185029Spjd &propval) == 0) 2204185029Spjd break; 2205185029Spjd if (add_prop_list(zpool_prop_to_name( 2206185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2207185029Spjd goto error; 2208168404Spjd break; 2209219089Spjd case 'T': 2210219089Spjd errno = 0; 2211268720Sdelphij txg = strtoull(optarg, &endptr, 0); 2212219089Spjd if (errno != 0 || *endptr != '\0') { 2213219089Spjd (void) fprintf(stderr, 2214219089Spjd gettext("invalid txg value\n")); 2215219089Spjd usage(B_FALSE); 2216219089Spjd } 2217219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 2218219089Spjd break; 2219219089Spjd case 'V': 2220219089Spjd flags |= ZFS_IMPORT_VERBATIM; 2221219089Spjd break; 2222219089Spjd case 'X': 2223219089Spjd xtreme_rewind = B_TRUE; 2224219089Spjd break; 2225168404Spjd case ':': 2226168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2227168404Spjd "'%c' option\n"), optopt); 2228168404Spjd usage(B_FALSE); 2229168404Spjd break; 2230168404Spjd case '?': 2231168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2232168404Spjd optopt); 2233168404Spjd usage(B_FALSE); 2234168404Spjd } 2235168404Spjd } 2236168404Spjd 2237168404Spjd argc -= optind; 2238168404Spjd argv += optind; 2239168404Spjd 2240185029Spjd if (cachefile && nsearch != 0) { 2241185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 2242185029Spjd usage(B_FALSE); 2243185029Spjd } 2244185029Spjd 2245219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 2246219089Spjd (void) fprintf(stderr, 2247219089Spjd gettext("-n or -X only meaningful with -F\n")); 2248219089Spjd usage(B_FALSE); 2249219089Spjd } 2250219089Spjd if (dryrun) 2251219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 2252219089Spjd else if (do_rewind) 2253219089Spjd rewind_policy = ZPOOL_DO_REWIND; 2254219089Spjd if (xtreme_rewind) 2255219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 2256219089Spjd 2257219089Spjd /* In the future, we can capture further policy and include it here */ 2258219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2259219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 2260219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 2261219089Spjd goto error; 2262219089Spjd 2263168404Spjd if (searchdirs == NULL) { 2264168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2265235478Savg searchdirs[0] = "/dev"; 2266168404Spjd nsearch = 1; 2267168404Spjd } 2268168404Spjd 2269168404Spjd /* check argument count */ 2270168404Spjd if (do_all) { 2271168404Spjd if (argc != 0) { 2272168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2273168404Spjd usage(B_FALSE); 2274168404Spjd } 2275168404Spjd } else { 2276168404Spjd if (argc > 2) { 2277168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2278168404Spjd usage(B_FALSE); 2279168404Spjd } 2280168404Spjd 2281168404Spjd /* 2282168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 2283168404Spjd * here because otherwise any attempt to discover pools will 2284168404Spjd * silently fail. 2285168404Spjd */ 2286168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2287168404Spjd (void) fprintf(stderr, gettext("cannot " 2288168404Spjd "discover pools: permission denied\n")); 2289168404Spjd free(searchdirs); 2290219089Spjd nvlist_free(policy); 2291168404Spjd return (1); 2292168404Spjd } 2293168404Spjd } 2294168404Spjd 2295168404Spjd /* 2296168404Spjd * Depending on the arguments given, we do one of the following: 2297168404Spjd * 2298168404Spjd * <none> Iterate through all pools and display information about 2299168404Spjd * each one. 2300168404Spjd * 2301168404Spjd * -a Iterate through all pools and try to import each one. 2302168404Spjd * 2303168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 2304168404Spjd * name and import that one. 2305168404Spjd * 2306168404Spjd * -D Above options applies only to destroyed pools. 2307168404Spjd */ 2308168404Spjd if (argc != 0) { 2309168404Spjd char *endptr; 2310168404Spjd 2311168404Spjd errno = 0; 2312168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 2313254758Sdelphij if (errno != 0 || *endptr != '\0') { 2314168404Spjd searchname = argv[0]; 2315254758Sdelphij searchguid = 0; 2316254758Sdelphij } 2317168404Spjd found_config = NULL; 2318168404Spjd 2319185029Spjd /* 2320219089Spjd * User specified a name or guid. Ensure it's unique. 2321185029Spjd */ 2322219089Spjd idata.unique = B_TRUE; 2323185029Spjd } 2324185029Spjd 2325219089Spjd 2326219089Spjd idata.path = searchdirs; 2327219089Spjd idata.paths = nsearch; 2328219089Spjd idata.poolname = searchname; 2329219089Spjd idata.guid = searchguid; 2330219089Spjd idata.cachefile = cachefile; 2331219089Spjd 2332219089Spjd pools = zpool_search_import(g_zfs, &idata); 2333219089Spjd 2334219089Spjd if (pools != NULL && idata.exists && 2335219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2336219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2337219089Spjd "a pool with that name already exists\n"), 2338219089Spjd argv[0]); 2339219089Spjd (void) fprintf(stderr, gettext("use the form '%s " 2340219089Spjd "<pool | id> <newpool>' to give it a new name\n"), 2341219089Spjd "zpool import"); 2342219089Spjd err = 1; 2343219089Spjd } else if (pools == NULL && idata.exists) { 2344219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2345219089Spjd "a pool with that name is already created/imported,\n"), 2346219089Spjd argv[0]); 2347219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2348219089Spjd "with that name were found\n")); 2349219089Spjd err = 1; 2350219089Spjd } else if (pools == NULL) { 2351185029Spjd if (argc != 0) { 2352185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2353185029Spjd "no such pool available\n"), argv[0]); 2354185029Spjd } 2355219089Spjd err = 1; 2356219089Spjd } 2357219089Spjd 2358219089Spjd if (err == 1) { 2359185029Spjd free(searchdirs); 2360219089Spjd nvlist_free(policy); 2361185029Spjd return (1); 2362185029Spjd } 2363185029Spjd 2364185029Spjd /* 2365185029Spjd * At this point we have a list of import candidate configs. Even if 2366185029Spjd * we were searching by pool name or guid, we still need to 2367185029Spjd * post-process the list to deal with pool state and possible 2368185029Spjd * duplicate names. 2369185029Spjd */ 2370168404Spjd err = 0; 2371168404Spjd elem = NULL; 2372168404Spjd first = B_TRUE; 2373168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2374168404Spjd 2375168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2376168404Spjd 2377168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2378168404Spjd &pool_state) == 0); 2379168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2380168404Spjd continue; 2381168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2382168404Spjd continue; 2383168404Spjd 2384219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2385219089Spjd policy) == 0); 2386219089Spjd 2387168404Spjd if (argc == 0) { 2388168404Spjd if (first) 2389168404Spjd first = B_FALSE; 2390168404Spjd else if (!do_all) 2391168404Spjd (void) printf("\n"); 2392168404Spjd 2393219089Spjd if (do_all) { 2394168404Spjd err |= do_import(config, NULL, mntopts, 2395219089Spjd props, flags); 2396219089Spjd } else { 2397168404Spjd show_import(config); 2398219089Spjd } 2399168404Spjd } else if (searchname != NULL) { 2400168404Spjd char *name; 2401168404Spjd 2402168404Spjd /* 2403168404Spjd * We are searching for a pool based on name. 2404168404Spjd */ 2405168404Spjd verify(nvlist_lookup_string(config, 2406168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2407168404Spjd 2408168404Spjd if (strcmp(name, searchname) == 0) { 2409168404Spjd if (found_config != NULL) { 2410168404Spjd (void) fprintf(stderr, gettext( 2411168404Spjd "cannot import '%s': more than " 2412168404Spjd "one matching pool\n"), searchname); 2413168404Spjd (void) fprintf(stderr, gettext( 2414168404Spjd "import by numeric ID instead\n")); 2415168404Spjd err = B_TRUE; 2416168404Spjd } 2417168404Spjd found_config = config; 2418168404Spjd } 2419168404Spjd } else { 2420168404Spjd uint64_t guid; 2421168404Spjd 2422168404Spjd /* 2423168404Spjd * Search for a pool by guid. 2424168404Spjd */ 2425168404Spjd verify(nvlist_lookup_uint64(config, 2426168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2427168404Spjd 2428168404Spjd if (guid == searchguid) 2429168404Spjd found_config = config; 2430168404Spjd } 2431168404Spjd } 2432168404Spjd 2433168404Spjd /* 2434168404Spjd * If we were searching for a specific pool, verify that we found a 2435168404Spjd * pool, and then do the import. 2436168404Spjd */ 2437168404Spjd if (argc != 0 && err == 0) { 2438168404Spjd if (found_config == NULL) { 2439168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2440168404Spjd "no such pool available\n"), argv[0]); 2441168404Spjd err = B_TRUE; 2442168404Spjd } else { 2443168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2444219089Spjd argv[1], mntopts, props, flags); 2445168404Spjd } 2446168404Spjd } 2447168404Spjd 2448168404Spjd /* 2449168404Spjd * If we were just looking for pools, report an error if none were 2450168404Spjd * found. 2451168404Spjd */ 2452168404Spjd if (argc == 0 && first) 2453168404Spjd (void) fprintf(stderr, 2454168404Spjd gettext("no pools available to import\n")); 2455168404Spjd 2456185029Spjderror: 2457185029Spjd nvlist_free(props); 2458168404Spjd nvlist_free(pools); 2459219089Spjd nvlist_free(policy); 2460168404Spjd free(searchdirs); 2461168404Spjd 2462168404Spjd return (err ? 1 : 0); 2463168404Spjd} 2464168404Spjd 2465168404Spjdtypedef struct iostat_cbdata { 2466236155Smm boolean_t cb_verbose; 2467236155Smm int cb_namewidth; 2468236155Smm int cb_iteration; 2469168404Spjd zpool_list_t *cb_list; 2470168404Spjd} iostat_cbdata_t; 2471168404Spjd 2472168404Spjdstatic void 2473168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2474168404Spjd{ 2475168404Spjd int i = 0; 2476168404Spjd 2477168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2478168404Spjd (void) printf("-"); 2479168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2480168404Spjd} 2481168404Spjd 2482168404Spjdstatic void 2483168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2484168404Spjd{ 2485168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2486168404Spjd cb->cb_namewidth, ""); 2487219089Spjd (void) printf("%-*s alloc free read write read write\n", 2488168404Spjd cb->cb_namewidth, "pool"); 2489168404Spjd print_iostat_separator(cb); 2490168404Spjd} 2491168404Spjd 2492168404Spjd/* 2493168404Spjd * Display a single statistic. 2494168404Spjd */ 2495185029Spjdstatic void 2496168404Spjdprint_one_stat(uint64_t value) 2497168404Spjd{ 2498168404Spjd char buf[64]; 2499168404Spjd 2500168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2501168404Spjd (void) printf(" %5s", buf); 2502168404Spjd} 2503168404Spjd 2504168404Spjd/* 2505168404Spjd * Print out all the statistics for the given vdev. This can either be the 2506168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2507168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2508168404Spjd */ 2509168404Spjdvoid 2510168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2511168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2512168404Spjd{ 2513168404Spjd nvlist_t **oldchild, **newchild; 2514168404Spjd uint_t c, children; 2515168404Spjd vdev_stat_t *oldvs, *newvs; 2516168404Spjd vdev_stat_t zerovs = { 0 }; 2517168404Spjd uint64_t tdelta; 2518168404Spjd double scale; 2519168404Spjd char *vname; 2520168404Spjd 2521332525Smav if (strcmp(name, VDEV_TYPE_INDIRECT) == 0) 2522332525Smav return; 2523332525Smav 2524168404Spjd if (oldnv != NULL) { 2525219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2526219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2527168404Spjd } else { 2528168404Spjd oldvs = &zerovs; 2529168404Spjd } 2530168404Spjd 2531219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2532168404Spjd (uint64_t **)&newvs, &c) == 0); 2533168404Spjd 2534168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2535168404Spjd (void) printf("%*s%s", depth, "", name); 2536168404Spjd else 2537168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2538168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2539168404Spjd 2540168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2541168404Spjd 2542168404Spjd if (tdelta == 0) 2543168404Spjd scale = 1.0; 2544168404Spjd else 2545168404Spjd scale = (double)NANOSEC / tdelta; 2546168404Spjd 2547168404Spjd /* only toplevel vdevs have capacity stats */ 2548168404Spjd if (newvs->vs_space == 0) { 2549168404Spjd (void) printf(" - -"); 2550168404Spjd } else { 2551168404Spjd print_one_stat(newvs->vs_alloc); 2552168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2553168404Spjd } 2554168404Spjd 2555168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2556168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2557168404Spjd 2558168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2559168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2560168404Spjd 2561168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2562168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2563168404Spjd 2564168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2565168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2566168404Spjd 2567168404Spjd (void) printf("\n"); 2568168404Spjd 2569168404Spjd if (!cb->cb_verbose) 2570168404Spjd return; 2571168404Spjd 2572168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2573168404Spjd &newchild, &children) != 0) 2574168404Spjd return; 2575168404Spjd 2576168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2577168404Spjd &oldchild, &c) != 0) 2578168404Spjd return; 2579168404Spjd 2580168404Spjd for (c = 0; c < children; c++) { 2581227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2582219089Spjd 2583227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2584227497Smm &ishole); 2585227497Smm 2586227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2587227497Smm &islog); 2588227497Smm 2589227497Smm if (ishole || islog) 2590219089Spjd continue; 2591219089Spjd 2592219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2593168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2594168404Spjd newchild[c], cb, depth + 2); 2595168404Spjd free(vname); 2596168404Spjd } 2597185029Spjd 2598185029Spjd /* 2599227497Smm * Log device section 2600227497Smm */ 2601227497Smm 2602227497Smm if (num_logs(newnv) > 0) { 2603227497Smm (void) printf("%-*s - - - - - " 2604227497Smm "-\n", cb->cb_namewidth, "logs"); 2605227497Smm 2606227497Smm for (c = 0; c < children; c++) { 2607227497Smm uint64_t islog = B_FALSE; 2608227497Smm (void) nvlist_lookup_uint64(newchild[c], 2609227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2610227497Smm 2611227497Smm if (islog) { 2612227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2613227497Smm B_FALSE); 2614227497Smm print_vdev_stats(zhp, vname, oldnv ? 2615227497Smm oldchild[c] : NULL, newchild[c], 2616227497Smm cb, depth + 2); 2617227497Smm free(vname); 2618227497Smm } 2619227497Smm } 2620227497Smm 2621227497Smm } 2622227497Smm 2623227497Smm /* 2624185029Spjd * Include level 2 ARC devices in iostat output 2625185029Spjd */ 2626185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2627185029Spjd &newchild, &children) != 0) 2628185029Spjd return; 2629185029Spjd 2630185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2631185029Spjd &oldchild, &c) != 0) 2632185029Spjd return; 2633185029Spjd 2634185029Spjd if (children > 0) { 2635185029Spjd (void) printf("%-*s - - - - - " 2636185029Spjd "-\n", cb->cb_namewidth, "cache"); 2637185029Spjd for (c = 0; c < children; c++) { 2638219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2639219089Spjd B_FALSE); 2640185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2641185029Spjd newchild[c], cb, depth + 2); 2642185029Spjd free(vname); 2643185029Spjd } 2644185029Spjd } 2645168404Spjd} 2646168404Spjd 2647168404Spjdstatic int 2648168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2649168404Spjd{ 2650168404Spjd iostat_cbdata_t *cb = data; 2651168404Spjd boolean_t missing; 2652168404Spjd 2653168404Spjd /* 2654168404Spjd * If the pool has disappeared, remove it from the list and continue. 2655168404Spjd */ 2656168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2657168404Spjd return (-1); 2658168404Spjd 2659168404Spjd if (missing) 2660168404Spjd pool_list_remove(cb->cb_list, zhp); 2661168404Spjd 2662168404Spjd return (0); 2663168404Spjd} 2664168404Spjd 2665168404Spjd/* 2666168404Spjd * Callback to print out the iostats for the given pool. 2667168404Spjd */ 2668168404Spjdint 2669168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2670168404Spjd{ 2671168404Spjd iostat_cbdata_t *cb = data; 2672168404Spjd nvlist_t *oldconfig, *newconfig; 2673168404Spjd nvlist_t *oldnvroot, *newnvroot; 2674168404Spjd 2675168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2676168404Spjd 2677168404Spjd if (cb->cb_iteration == 1) 2678168404Spjd oldconfig = NULL; 2679168404Spjd 2680168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2681168404Spjd &newnvroot) == 0); 2682168404Spjd 2683168404Spjd if (oldconfig == NULL) 2684168404Spjd oldnvroot = NULL; 2685168404Spjd else 2686168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2687168404Spjd &oldnvroot) == 0); 2688168404Spjd 2689168404Spjd /* 2690168404Spjd * Print out the statistics for the pool. 2691168404Spjd */ 2692168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2693168404Spjd 2694168404Spjd if (cb->cb_verbose) 2695168404Spjd print_iostat_separator(cb); 2696168404Spjd 2697168404Spjd return (0); 2698168404Spjd} 2699168404Spjd 2700168404Spjdint 2701168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2702168404Spjd{ 2703168404Spjd iostat_cbdata_t *cb = data; 2704168404Spjd nvlist_t *config, *nvroot; 2705168404Spjd 2706168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2707168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2708168404Spjd &nvroot) == 0); 2709168404Spjd if (!cb->cb_verbose) 2710168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2711168404Spjd else 2712236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2713236145Smm cb->cb_namewidth); 2714168404Spjd } 2715168404Spjd 2716168404Spjd /* 2717168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2718168404Spjd * maximum we can have and still fit in 80 columns. 2719168404Spjd */ 2720168404Spjd if (cb->cb_namewidth < 10) 2721168404Spjd cb->cb_namewidth = 10; 2722168404Spjd if (cb->cb_namewidth > 38) 2723168404Spjd cb->cb_namewidth = 38; 2724168404Spjd 2725168404Spjd return (0); 2726168404Spjd} 2727168404Spjd 2728168404Spjd/* 2729219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2730168404Spjd */ 2731219089Spjdstatic void 2732219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2733219089Spjd unsigned long *cnt) 2734168404Spjd{ 2735168404Spjd unsigned long interval = 0, count = 0; 2736219089Spjd int argc = *argcp, errno; 2737168404Spjd 2738168404Spjd /* 2739168404Spjd * Determine if the last argument is an integer or a pool name 2740168404Spjd */ 2741168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2742168404Spjd char *end; 2743168404Spjd 2744168404Spjd errno = 0; 2745168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2746168404Spjd 2747168404Spjd if (*end == '\0' && errno == 0) { 2748168404Spjd if (interval == 0) { 2749168404Spjd (void) fprintf(stderr, gettext("interval " 2750168404Spjd "cannot be zero\n")); 2751168404Spjd usage(B_FALSE); 2752168404Spjd } 2753168404Spjd /* 2754168404Spjd * Ignore the last parameter 2755168404Spjd */ 2756168404Spjd argc--; 2757168404Spjd } else { 2758168404Spjd /* 2759168404Spjd * If this is not a valid number, just plow on. The 2760168404Spjd * user will get a more informative error message later 2761168404Spjd * on. 2762168404Spjd */ 2763168404Spjd interval = 0; 2764168404Spjd } 2765168404Spjd } 2766168404Spjd 2767168404Spjd /* 2768168404Spjd * If the last argument is also an integer, then we have both a count 2769219089Spjd * and an interval. 2770168404Spjd */ 2771168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2772168404Spjd char *end; 2773168404Spjd 2774168404Spjd errno = 0; 2775168404Spjd count = interval; 2776168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2777168404Spjd 2778168404Spjd if (*end == '\0' && errno == 0) { 2779168404Spjd if (interval == 0) { 2780168404Spjd (void) fprintf(stderr, gettext("interval " 2781168404Spjd "cannot be zero\n")); 2782168404Spjd usage(B_FALSE); 2783168404Spjd } 2784168404Spjd 2785168404Spjd /* 2786168404Spjd * Ignore the last parameter 2787168404Spjd */ 2788168404Spjd argc--; 2789168404Spjd } else { 2790168404Spjd interval = 0; 2791168404Spjd } 2792168404Spjd } 2793168404Spjd 2794219089Spjd *iv = interval; 2795219089Spjd *cnt = count; 2796219089Spjd *argcp = argc; 2797219089Spjd} 2798219089Spjd 2799219089Spjdstatic void 2800219089Spjdget_timestamp_arg(char c) 2801219089Spjd{ 2802219089Spjd if (c == 'u') 2803219089Spjd timestamp_fmt = UDATE; 2804219089Spjd else if (c == 'd') 2805219089Spjd timestamp_fmt = DDATE; 2806219089Spjd else 2807219089Spjd usage(B_FALSE); 2808219089Spjd} 2809219089Spjd 2810219089Spjd/* 2811219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2812219089Spjd * 2813219089Spjd * -v Display statistics for individual vdevs 2814219089Spjd * -T Display a timestamp in date(1) or Unix format 2815219089Spjd * 2816219089Spjd * This command can be tricky because we want to be able to deal with pool 2817219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2818219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2819219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2820219089Spjd * changes are all handled within libzfs. 2821219089Spjd */ 2822219089Spjdint 2823219089Spjdzpool_do_iostat(int argc, char **argv) 2824219089Spjd{ 2825219089Spjd int c; 2826219089Spjd int ret; 2827219089Spjd int npools; 2828219089Spjd unsigned long interval = 0, count = 0; 2829219089Spjd zpool_list_t *list; 2830219089Spjd boolean_t verbose = B_FALSE; 2831219089Spjd iostat_cbdata_t cb; 2832219089Spjd 2833219089Spjd /* check options */ 2834219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2835219089Spjd switch (c) { 2836219089Spjd case 'T': 2837219089Spjd get_timestamp_arg(*optarg); 2838219089Spjd break; 2839219089Spjd case 'v': 2840219089Spjd verbose = B_TRUE; 2841219089Spjd break; 2842219089Spjd case '?': 2843219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2844219089Spjd optopt); 2845219089Spjd usage(B_FALSE); 2846219089Spjd } 2847219089Spjd } 2848219089Spjd 2849219089Spjd argc -= optind; 2850219089Spjd argv += optind; 2851219089Spjd 2852219089Spjd get_interval_count(&argc, argv, &interval, &count); 2853219089Spjd 2854168404Spjd /* 2855168404Spjd * Construct the list of all interesting pools. 2856168404Spjd */ 2857168404Spjd ret = 0; 2858168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2859168404Spjd return (1); 2860168404Spjd 2861168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2862168404Spjd pool_list_free(list); 2863168404Spjd return (1); 2864168404Spjd } 2865168404Spjd 2866168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2867168404Spjd pool_list_free(list); 2868168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2869168404Spjd return (1); 2870168404Spjd } 2871168404Spjd 2872168404Spjd /* 2873168404Spjd * Enter the main iostat loop. 2874168404Spjd */ 2875168404Spjd cb.cb_list = list; 2876168404Spjd cb.cb_verbose = verbose; 2877168404Spjd cb.cb_iteration = 0; 2878168404Spjd cb.cb_namewidth = 0; 2879168404Spjd 2880168404Spjd for (;;) { 2881168404Spjd pool_list_update(list); 2882168404Spjd 2883168404Spjd if ((npools = pool_list_count(list)) == 0) 2884168404Spjd break; 2885168404Spjd 2886168404Spjd /* 2887168404Spjd * Refresh all statistics. This is done as an explicit step 2888168404Spjd * before calculating the maximum name width, so that any 2889168404Spjd * configuration changes are properly accounted for. 2890168404Spjd */ 2891168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2892168404Spjd 2893168404Spjd /* 2894168404Spjd * Iterate over all pools to determine the maximum width 2895168404Spjd * for the pool / device name column across all pools. 2896168404Spjd */ 2897168404Spjd cb.cb_namewidth = 0; 2898168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2899168404Spjd 2900219089Spjd if (timestamp_fmt != NODATE) 2901219089Spjd print_timestamp(timestamp_fmt); 2902219089Spjd 2903168404Spjd /* 2904168404Spjd * If it's the first time, or verbose mode, print the header. 2905168404Spjd */ 2906168404Spjd if (++cb.cb_iteration == 1 || verbose) 2907168404Spjd print_iostat_header(&cb); 2908168404Spjd 2909168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2910168404Spjd 2911168404Spjd /* 2912168404Spjd * If there's more than one pool, and we're not in verbose mode 2913168404Spjd * (which prints a separator for us), then print a separator. 2914168404Spjd */ 2915168404Spjd if (npools > 1 && !verbose) 2916168404Spjd print_iostat_separator(&cb); 2917168404Spjd 2918168404Spjd if (verbose) 2919168404Spjd (void) printf("\n"); 2920168404Spjd 2921168404Spjd /* 2922168404Spjd * Flush the output so that redirection to a file isn't buffered 2923168404Spjd * indefinitely. 2924168404Spjd */ 2925168404Spjd (void) fflush(stdout); 2926168404Spjd 2927168404Spjd if (interval == 0) 2928168404Spjd break; 2929168404Spjd 2930168404Spjd if (count != 0 && --count == 0) 2931168404Spjd break; 2932168404Spjd 2933168404Spjd (void) sleep(interval); 2934168404Spjd } 2935168404Spjd 2936168404Spjd pool_list_free(list); 2937168404Spjd 2938168404Spjd return (ret); 2939168404Spjd} 2940168404Spjd 2941168404Spjdtypedef struct list_cbdata { 2942236155Smm boolean_t cb_verbose; 2943236155Smm int cb_namewidth; 2944168404Spjd boolean_t cb_scripted; 2945185029Spjd zprop_list_t *cb_proplist; 2946263889Sdelphij boolean_t cb_literal; 2947168404Spjd} list_cbdata_t; 2948168404Spjd 2949168404Spjd/* 2950168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2951168404Spjd */ 2952185029Spjdstatic void 2953236155Smmprint_header(list_cbdata_t *cb) 2954168404Spjd{ 2955236155Smm zprop_list_t *pl = cb->cb_proplist; 2956236884Smm char headerbuf[ZPOOL_MAXPROPLEN]; 2957185029Spjd const char *header; 2958185029Spjd boolean_t first = B_TRUE; 2959185029Spjd boolean_t right_justify; 2960236155Smm size_t width = 0; 2961168404Spjd 2962185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2963236155Smm width = pl->pl_width; 2964236155Smm if (first && cb->cb_verbose) { 2965236155Smm /* 2966236155Smm * Reset the width to accommodate the verbose listing 2967236155Smm * of devices. 2968236155Smm */ 2969236155Smm width = cb->cb_namewidth; 2970236155Smm } 2971236155Smm 2972185029Spjd if (!first) 2973168404Spjd (void) printf(" "); 2974168404Spjd else 2975185029Spjd first = B_FALSE; 2976168404Spjd 2977236884Smm right_justify = B_FALSE; 2978236884Smm if (pl->pl_prop != ZPROP_INVAL) { 2979236884Smm header = zpool_prop_column_name(pl->pl_prop); 2980236884Smm right_justify = zpool_prop_align_right(pl->pl_prop); 2981236884Smm } else { 2982236884Smm int i; 2983185029Spjd 2984236884Smm for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2985236884Smm headerbuf[i] = toupper(pl->pl_user_prop[i]); 2986236884Smm headerbuf[i] = '\0'; 2987236884Smm header = headerbuf; 2988236884Smm } 2989236884Smm 2990185029Spjd if (pl->pl_next == NULL && !right_justify) 2991185029Spjd (void) printf("%s", header); 2992185029Spjd else if (right_justify) 2993236155Smm (void) printf("%*s", width, header); 2994185029Spjd else 2995236155Smm (void) printf("%-*s", width, header); 2996236155Smm 2997168404Spjd } 2998168404Spjd 2999168404Spjd (void) printf("\n"); 3000168404Spjd} 3001168404Spjd 3002185029Spjd/* 3003185029Spjd * Given a pool and a list of properties, print out all the properties according 3004185029Spjd * to the described layout. 3005185029Spjd */ 3006185029Spjdstatic void 3007236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 3008168404Spjd{ 3009236155Smm zprop_list_t *pl = cb->cb_proplist; 3010185029Spjd boolean_t first = B_TRUE; 3011185029Spjd char property[ZPOOL_MAXPROPLEN]; 3012185029Spjd char *propstr; 3013185029Spjd boolean_t right_justify; 3014236155Smm size_t width; 3015168404Spjd 3016185029Spjd for (; pl != NULL; pl = pl->pl_next) { 3017236155Smm 3018236155Smm width = pl->pl_width; 3019236155Smm if (first && cb->cb_verbose) { 3020236155Smm /* 3021236155Smm * Reset the width to accommodate the verbose listing 3022236155Smm * of devices. 3023236155Smm */ 3024236155Smm width = cb->cb_namewidth; 3025236155Smm } 3026236155Smm 3027185029Spjd if (!first) { 3028236155Smm if (cb->cb_scripted) 3029168404Spjd (void) printf("\t"); 3030168404Spjd else 3031168404Spjd (void) printf(" "); 3032185029Spjd } else { 3033185029Spjd first = B_FALSE; 3034168404Spjd } 3035168404Spjd 3036185029Spjd right_justify = B_FALSE; 3037185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 3038272502Sdelphij if (zpool_get_prop(zhp, pl->pl_prop, property, 3039263889Sdelphij sizeof (property), NULL, cb->cb_literal) != 0) 3040185029Spjd propstr = "-"; 3041168404Spjd else 3042185029Spjd propstr = property; 3043168404Spjd 3044185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 3045236884Smm } else if ((zpool_prop_feature(pl->pl_user_prop) || 3046236884Smm zpool_prop_unsupported(pl->pl_user_prop)) && 3047236884Smm zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 3048236884Smm sizeof (property)) == 0) { 3049236884Smm propstr = property; 3050185029Spjd } else { 3051185029Spjd propstr = "-"; 3052185029Spjd } 3053168404Spjd 3054168404Spjd 3055185029Spjd /* 3056185029Spjd * If this is being called in scripted mode, or if this is the 3057185029Spjd * last column and it is left-justified, don't include a width 3058185029Spjd * format specifier. 3059185029Spjd */ 3060236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 3061185029Spjd (void) printf("%s", propstr); 3062185029Spjd else if (right_justify) 3063185029Spjd (void) printf("%*s", width, propstr); 3064185029Spjd else 3065185029Spjd (void) printf("%-*s", width, propstr); 3066185029Spjd } 3067168404Spjd 3068185029Spjd (void) printf("\n"); 3069185029Spjd} 3070168404Spjd 3071236155Smmstatic void 3072272502Sdelphijprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, 3073272502Sdelphij boolean_t valid) 3074236155Smm{ 3075236155Smm char propval[64]; 3076236155Smm boolean_t fixed; 3077236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 3078236155Smm 3079272502Sdelphij switch (prop) { 3080272502Sdelphij case ZPOOL_PROP_EXPANDSZ: 3081272502Sdelphij if (value == 0) 3082272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 3083272502Sdelphij else 3084272502Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 3085272502Sdelphij break; 3086272502Sdelphij case ZPOOL_PROP_FRAGMENTATION: 3087272502Sdelphij if (value == ZFS_FRAG_INVALID) { 3088272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 3089272502Sdelphij } else { 3090272502Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", 3091272502Sdelphij value); 3092272502Sdelphij } 3093272502Sdelphij break; 3094272502Sdelphij case ZPOOL_PROP_CAPACITY: 3095269118Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", value); 3096272502Sdelphij break; 3097272502Sdelphij default: 3098269118Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 3099272502Sdelphij } 3100236155Smm 3101272502Sdelphij if (!valid) 3102272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 3103272502Sdelphij 3104236155Smm if (scripted) 3105236155Smm (void) printf("\t%s", propval); 3106236155Smm else 3107236155Smm (void) printf(" %*s", width, propval); 3108236155Smm} 3109236155Smm 3110236155Smmvoid 3111236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 3112236155Smm list_cbdata_t *cb, int depth) 3113236155Smm{ 3114236155Smm nvlist_t **child; 3115236155Smm vdev_stat_t *vs; 3116236155Smm uint_t c, children; 3117236155Smm char *vname; 3118236155Smm boolean_t scripted = cb->cb_scripted; 3119289536Smav uint64_t islog = B_FALSE; 3120289536Smav boolean_t haslog = B_FALSE; 3121289536Smav char *dashes = "%-*s - - - - - -\n"; 3122236155Smm 3123236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 3124236155Smm (uint64_t **)&vs, &c) == 0); 3125236155Smm 3126236155Smm if (name != NULL) { 3127272502Sdelphij boolean_t toplevel = (vs->vs_space != 0); 3128272502Sdelphij uint64_t cap; 3129272502Sdelphij 3130332525Smav if (strcmp(name, VDEV_TYPE_INDIRECT) == 0) 3131332525Smav return; 3132332525Smav 3133236155Smm if (scripted) 3134236155Smm (void) printf("\t%s", name); 3135236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 3136236155Smm (void) printf("%*s%s", depth, "", name); 3137236155Smm else 3138236155Smm (void) printf("%*s%s%*s", depth, "", name, 3139236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 3140236155Smm 3141272502Sdelphij /* 3142272502Sdelphij * Print the properties for the individual vdevs. Some 3143272502Sdelphij * properties are only applicable to toplevel vdevs. The 3144272502Sdelphij * 'toplevel' boolean value is passed to the print_one_column() 3145272502Sdelphij * to indicate that the value is valid. 3146272502Sdelphij */ 3147272502Sdelphij print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted, 3148272502Sdelphij toplevel); 3149272502Sdelphij print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted, 3150272502Sdelphij toplevel); 3151272502Sdelphij print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, 3152272502Sdelphij scripted, toplevel); 3153272502Sdelphij print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted, 3154272502Sdelphij B_TRUE); 3155272502Sdelphij print_one_column(ZPOOL_PROP_FRAGMENTATION, 3156272502Sdelphij vs->vs_fragmentation, scripted, 3157272502Sdelphij (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel)); 3158272502Sdelphij cap = (vs->vs_space == 0) ? 0 : 3159272502Sdelphij (vs->vs_alloc * 100 / vs->vs_space); 3160272502Sdelphij print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel); 3161236155Smm (void) printf("\n"); 3162236155Smm } 3163236155Smm 3164236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 3165236155Smm &child, &children) != 0) 3166236155Smm return; 3167236155Smm 3168236155Smm for (c = 0; c < children; c++) { 3169236155Smm uint64_t ishole = B_FALSE; 3170236155Smm 3171236155Smm if (nvlist_lookup_uint64(child[c], 3172236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 3173236155Smm continue; 3174236155Smm 3175289536Smav if (nvlist_lookup_uint64(child[c], 3176289536Smav ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) { 3177289536Smav haslog = B_TRUE; 3178289536Smav continue; 3179289536Smav } 3180289536Smav 3181236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3182236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3183236155Smm free(vname); 3184236155Smm } 3185236155Smm 3186289536Smav if (haslog == B_TRUE) { 3187289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3188289536Smav (void) printf(dashes, cb->cb_namewidth, "log"); 3189289536Smav for (c = 0; c < children; c++) { 3190289536Smav if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3191289536Smav &islog) != 0 || !islog) 3192289536Smav continue; 3193289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3194289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3195289536Smav free(vname); 3196289536Smav } 3197289536Smav } 3198289536Smav 3199236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 3200289536Smav &child, &children) == 0 && children > 0) { 3201289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3202289536Smav (void) printf(dashes, cb->cb_namewidth, "cache"); 3203289536Smav for (c = 0; c < children; c++) { 3204289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3205289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3206289536Smav free(vname); 3207289536Smav } 3208289536Smav } 3209236155Smm 3210289536Smav if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child, 3211289536Smav &children) == 0 && children > 0) { 3212289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3213289536Smav (void) printf(dashes, cb->cb_namewidth, "spare"); 3214236155Smm for (c = 0; c < children; c++) { 3215289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3216236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3217236155Smm free(vname); 3218236155Smm } 3219236155Smm } 3220236155Smm} 3221236155Smm 3222236155Smm 3223185029Spjd/* 3224185029Spjd * Generic callback function to list a pool. 3225185029Spjd */ 3226185029Spjdint 3227185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 3228185029Spjd{ 3229185029Spjd list_cbdata_t *cbp = data; 3230236155Smm nvlist_t *config; 3231236155Smm nvlist_t *nvroot; 3232168404Spjd 3233236155Smm config = zpool_get_config(zhp, NULL); 3234168404Spjd 3235236155Smm print_pool(zhp, cbp); 3236236155Smm if (!cbp->cb_verbose) 3237236155Smm return (0); 3238168404Spjd 3239236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3240236155Smm &nvroot) == 0); 3241236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 3242236155Smm 3243168404Spjd return (0); 3244168404Spjd} 3245168404Spjd 3246168404Spjd/* 3247263889Sdelphij * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 3248168404Spjd * 3249185029Spjd * -H Scripted mode. Don't display headers, and separate properties 3250185029Spjd * by a single tab. 3251185029Spjd * -o List of properties to display. Defaults to 3252272502Sdelphij * "name,size,allocated,free,expandsize,fragmentation,capacity," 3253272502Sdelphij * "dedupratio,health,altroot" 3254263889Sdelphij * -p Diplay values in parsable (exact) format. 3255219089Spjd * -T Display a timestamp in date(1) or Unix format 3256168404Spjd * 3257168404Spjd * List all pools in the system, whether or not they're healthy. Output space 3258168404Spjd * statistics for each one, as well as health status summary. 3259168404Spjd */ 3260168404Spjdint 3261168404Spjdzpool_do_list(int argc, char **argv) 3262168404Spjd{ 3263168404Spjd int c; 3264168404Spjd int ret; 3265168404Spjd list_cbdata_t cb = { 0 }; 3266185029Spjd static char default_props[] = 3267272502Sdelphij "name,size,allocated,free,expandsize,fragmentation,capacity," 3268269118Sdelphij "dedupratio,health,altroot"; 3269185029Spjd char *props = default_props; 3270219089Spjd unsigned long interval = 0, count = 0; 3271236155Smm zpool_list_t *list; 3272236155Smm boolean_t first = B_TRUE; 3273168404Spjd 3274168404Spjd /* check options */ 3275263889Sdelphij while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) { 3276168404Spjd switch (c) { 3277168404Spjd case 'H': 3278168404Spjd cb.cb_scripted = B_TRUE; 3279168404Spjd break; 3280168404Spjd case 'o': 3281185029Spjd props = optarg; 3282168404Spjd break; 3283263889Sdelphij case 'p': 3284263889Sdelphij cb.cb_literal = B_TRUE; 3285263889Sdelphij break; 3286219089Spjd case 'T': 3287219089Spjd get_timestamp_arg(*optarg); 3288219089Spjd break; 3289236155Smm case 'v': 3290236155Smm cb.cb_verbose = B_TRUE; 3291236155Smm break; 3292168404Spjd case ':': 3293168404Spjd (void) fprintf(stderr, gettext("missing argument for " 3294168404Spjd "'%c' option\n"), optopt); 3295168404Spjd usage(B_FALSE); 3296168404Spjd break; 3297168404Spjd case '?': 3298168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3299168404Spjd optopt); 3300168404Spjd usage(B_FALSE); 3301168404Spjd } 3302168404Spjd } 3303168404Spjd 3304168404Spjd argc -= optind; 3305168404Spjd argv += optind; 3306168404Spjd 3307219089Spjd get_interval_count(&argc, argv, &interval, &count); 3308219089Spjd 3309185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3310185029Spjd usage(B_FALSE); 3311168404Spjd 3312219089Spjd for (;;) { 3313268470Sdelphij if ((list = pool_list_get(argc, argv, &cb.cb_proplist, 3314268470Sdelphij &ret)) == NULL) 3315268470Sdelphij return (1); 3316168404Spjd 3317236155Smm if (pool_list_count(list) == 0) 3318236155Smm break; 3319236155Smm 3320236155Smm cb.cb_namewidth = 0; 3321236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3322236155Smm 3323219089Spjd if (timestamp_fmt != NODATE) 3324219089Spjd print_timestamp(timestamp_fmt); 3325168404Spjd 3326236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 3327236155Smm print_header(&cb); 3328236155Smm first = B_FALSE; 3329219089Spjd } 3330236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 3331219089Spjd 3332219089Spjd if (interval == 0) 3333219089Spjd break; 3334219089Spjd 3335219089Spjd if (count != 0 && --count == 0) 3336219089Spjd break; 3337219089Spjd 3338268470Sdelphij pool_list_free(list); 3339219089Spjd (void) sleep(interval); 3340168404Spjd } 3341168404Spjd 3342268470Sdelphij if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3343268470Sdelphij (void) printf(gettext("no pools available\n")); 3344268470Sdelphij ret = 0; 3345268470Sdelphij } 3346268470Sdelphij 3347268470Sdelphij pool_list_free(list); 3348219089Spjd zprop_free_list(cb.cb_proplist); 3349168404Spjd return (ret); 3350168404Spjd} 3351168404Spjd 3352168404Spjdstatic int 3353168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 3354168404Spjd{ 3355168404Spjd boolean_t force = B_FALSE; 3356168404Spjd int c; 3357168404Spjd nvlist_t *nvroot; 3358168404Spjd char *poolname, *old_disk, *new_disk; 3359168404Spjd zpool_handle_t *zhp; 3360331395Smav zpool_boot_label_t boot_type; 3361331395Smav uint64_t boot_size; 3362168404Spjd int ret; 3363168404Spjd 3364168404Spjd /* check options */ 3365168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3366168404Spjd switch (c) { 3367168404Spjd case 'f': 3368168404Spjd force = B_TRUE; 3369168404Spjd break; 3370168404Spjd case '?': 3371168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3372168404Spjd optopt); 3373168404Spjd usage(B_FALSE); 3374168404Spjd } 3375168404Spjd } 3376168404Spjd 3377168404Spjd argc -= optind; 3378168404Spjd argv += optind; 3379168404Spjd 3380168404Spjd /* get pool name and check number of arguments */ 3381168404Spjd if (argc < 1) { 3382168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3383168404Spjd usage(B_FALSE); 3384168404Spjd } 3385168404Spjd 3386168404Spjd poolname = argv[0]; 3387168404Spjd 3388168404Spjd if (argc < 2) { 3389168404Spjd (void) fprintf(stderr, 3390168404Spjd gettext("missing <device> specification\n")); 3391168404Spjd usage(B_FALSE); 3392168404Spjd } 3393168404Spjd 3394168404Spjd old_disk = argv[1]; 3395168404Spjd 3396168404Spjd if (argc < 3) { 3397168404Spjd if (!replacing) { 3398168404Spjd (void) fprintf(stderr, 3399168404Spjd gettext("missing <new_device> specification\n")); 3400168404Spjd usage(B_FALSE); 3401168404Spjd } 3402168404Spjd new_disk = old_disk; 3403168404Spjd argc -= 1; 3404168404Spjd argv += 1; 3405168404Spjd } else { 3406168404Spjd new_disk = argv[2]; 3407168404Spjd argc -= 2; 3408168404Spjd argv += 2; 3409168404Spjd } 3410168404Spjd 3411168404Spjd if (argc > 1) { 3412168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3413168404Spjd usage(B_FALSE); 3414168404Spjd } 3415168404Spjd 3416168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3417168404Spjd return (1); 3418168404Spjd 3419185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3420168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3421168404Spjd poolname); 3422168404Spjd zpool_close(zhp); 3423168404Spjd return (1); 3424168404Spjd } 3425168404Spjd 3426331395Smav if (zpool_is_bootable(zhp)) 3427331395Smav boot_type = ZPOOL_COPY_BOOT_LABEL; 3428331395Smav else 3429331395Smav boot_type = ZPOOL_NO_BOOT_LABEL; 3430331395Smav 3431331395Smav boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL); 3432185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3433331395Smav boot_type, boot_size, argc, argv); 3434168404Spjd if (nvroot == NULL) { 3435168404Spjd zpool_close(zhp); 3436168404Spjd return (1); 3437168404Spjd } 3438168404Spjd 3439168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3440168404Spjd 3441168404Spjd nvlist_free(nvroot); 3442168404Spjd zpool_close(zhp); 3443168404Spjd 3444168404Spjd return (ret); 3445168404Spjd} 3446168404Spjd 3447168404Spjd/* 3448168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3449168404Spjd * 3450168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3451168404Spjd * 3452168404Spjd * Replace <device> with <new_device>. 3453168404Spjd */ 3454168404Spjd/* ARGSUSED */ 3455168404Spjdint 3456168404Spjdzpool_do_replace(int argc, char **argv) 3457168404Spjd{ 3458168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3459168404Spjd} 3460168404Spjd 3461168404Spjd/* 3462168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3463168404Spjd * 3464168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3465168404Spjd * 3466168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3467168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3468168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3469168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3470168404Spjd */ 3471168404Spjdint 3472168404Spjdzpool_do_attach(int argc, char **argv) 3473168404Spjd{ 3474168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3475168404Spjd} 3476168404Spjd 3477168404Spjd/* 3478168404Spjd * zpool detach [-f] <pool> <device> 3479168404Spjd * 3480168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3481168404Spjd * (not supported yet) 3482168404Spjd * 3483168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3484168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3485168404Spjd * has the only valid copy of some data. 3486168404Spjd */ 3487168404Spjd/* ARGSUSED */ 3488168404Spjdint 3489168404Spjdzpool_do_detach(int argc, char **argv) 3490168404Spjd{ 3491168404Spjd int c; 3492168404Spjd char *poolname, *path; 3493168404Spjd zpool_handle_t *zhp; 3494168404Spjd int ret; 3495168404Spjd 3496168404Spjd /* check options */ 3497168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3498168404Spjd switch (c) { 3499168404Spjd case 'f': 3500168404Spjd case '?': 3501168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3502168404Spjd optopt); 3503168404Spjd usage(B_FALSE); 3504168404Spjd } 3505168404Spjd } 3506168404Spjd 3507168404Spjd argc -= optind; 3508168404Spjd argv += optind; 3509168404Spjd 3510168404Spjd /* get pool name and check number of arguments */ 3511168404Spjd if (argc < 1) { 3512168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3513168404Spjd usage(B_FALSE); 3514168404Spjd } 3515168404Spjd 3516168404Spjd if (argc < 2) { 3517168404Spjd (void) fprintf(stderr, 3518168404Spjd gettext("missing <device> specification\n")); 3519168404Spjd usage(B_FALSE); 3520168404Spjd } 3521168404Spjd 3522168404Spjd poolname = argv[0]; 3523168404Spjd path = argv[1]; 3524168404Spjd 3525168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3526168404Spjd return (1); 3527168404Spjd 3528168404Spjd ret = zpool_vdev_detach(zhp, path); 3529168404Spjd 3530168404Spjd zpool_close(zhp); 3531168404Spjd 3532168404Spjd return (ret); 3533168404Spjd} 3534168404Spjd 3535168404Spjd/* 3536219089Spjd * zpool split [-n] [-o prop=val] ... 3537219089Spjd * [-o mntopt] ... 3538219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3539219089Spjd * 3540219089Spjd * -n Do not split the pool, but display the resulting layout if 3541219089Spjd * it were to be split. 3542219089Spjd * -o Set property=value, or set mount options. 3543219089Spjd * -R Mount the split-off pool under an alternate root. 3544219089Spjd * 3545219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3546219089Spjd * off may be listed, provided that no more than one device is specified 3547219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3548219089Spjd * state unless -R is specified. 3549219089Spjd * 3550219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3551219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3552219089Spjd * undergoing a resilvering operation. 3553219089Spjd */ 3554219089Spjdint 3555219089Spjdzpool_do_split(int argc, char **argv) 3556219089Spjd{ 3557219089Spjd char *srcpool, *newpool, *propval; 3558219089Spjd char *mntopts = NULL; 3559219089Spjd splitflags_t flags; 3560219089Spjd int c, ret = 0; 3561219089Spjd zpool_handle_t *zhp; 3562219089Spjd nvlist_t *config, *props = NULL; 3563219089Spjd 3564219089Spjd flags.dryrun = B_FALSE; 3565219089Spjd flags.import = B_FALSE; 3566219089Spjd 3567219089Spjd /* check options */ 3568219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3569219089Spjd switch (c) { 3570219089Spjd case 'R': 3571219089Spjd flags.import = B_TRUE; 3572219089Spjd if (add_prop_list( 3573219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3574219089Spjd &props, B_TRUE) != 0) { 3575296528Smav nvlist_free(props); 3576219089Spjd usage(B_FALSE); 3577219089Spjd } 3578219089Spjd break; 3579219089Spjd case 'n': 3580219089Spjd flags.dryrun = B_TRUE; 3581219089Spjd break; 3582219089Spjd case 'o': 3583219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3584219089Spjd *propval = '\0'; 3585219089Spjd propval++; 3586219089Spjd if (add_prop_list(optarg, propval, 3587219089Spjd &props, B_TRUE) != 0) { 3588296528Smav nvlist_free(props); 3589219089Spjd usage(B_FALSE); 3590219089Spjd } 3591219089Spjd } else { 3592219089Spjd mntopts = optarg; 3593219089Spjd } 3594219089Spjd break; 3595219089Spjd case ':': 3596219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3597219089Spjd "'%c' option\n"), optopt); 3598219089Spjd usage(B_FALSE); 3599219089Spjd break; 3600219089Spjd case '?': 3601219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3602219089Spjd optopt); 3603219089Spjd usage(B_FALSE); 3604219089Spjd break; 3605219089Spjd } 3606219089Spjd } 3607219089Spjd 3608219089Spjd if (!flags.import && mntopts != NULL) { 3609219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3610219089Spjd "valid when importing the pool\n")); 3611219089Spjd usage(B_FALSE); 3612219089Spjd } 3613219089Spjd 3614219089Spjd argc -= optind; 3615219089Spjd argv += optind; 3616219089Spjd 3617219089Spjd if (argc < 1) { 3618219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3619219089Spjd usage(B_FALSE); 3620219089Spjd } 3621219089Spjd if (argc < 2) { 3622219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3623219089Spjd usage(B_FALSE); 3624219089Spjd } 3625219089Spjd 3626219089Spjd srcpool = argv[0]; 3627219089Spjd newpool = argv[1]; 3628219089Spjd 3629219089Spjd argc -= 2; 3630219089Spjd argv += 2; 3631219089Spjd 3632219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3633219089Spjd return (1); 3634219089Spjd 3635219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3636219089Spjd if (config == NULL) { 3637219089Spjd ret = 1; 3638219089Spjd } else { 3639219089Spjd if (flags.dryrun) { 3640219089Spjd (void) printf(gettext("would create '%s' with the " 3641219089Spjd "following layout:\n\n"), newpool); 3642219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3643219089Spjd } 3644219089Spjd nvlist_free(config); 3645219089Spjd } 3646219089Spjd 3647219089Spjd zpool_close(zhp); 3648219089Spjd 3649219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3650219089Spjd return (ret); 3651219089Spjd 3652219089Spjd /* 3653219089Spjd * The split was successful. Now we need to open the new 3654219089Spjd * pool and import it. 3655219089Spjd */ 3656219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3657219089Spjd return (1); 3658219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3659219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3660219089Spjd ret = 1; 3661240415Smm (void) fprintf(stderr, gettext("Split was successful, but " 3662219089Spjd "the datasets could not all be mounted\n")); 3663219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3664219089Spjd "different altroot\n"), "zpool import"); 3665219089Spjd } 3666219089Spjd zpool_close(zhp); 3667219089Spjd 3668219089Spjd return (ret); 3669219089Spjd} 3670219089Spjd 3671219089Spjd 3672219089Spjd 3673219089Spjd/* 3674168404Spjd * zpool online <pool> <device> ... 3675168404Spjd */ 3676168404Spjdint 3677168404Spjdzpool_do_online(int argc, char **argv) 3678168404Spjd{ 3679168404Spjd int c, i; 3680168404Spjd char *poolname; 3681168404Spjd zpool_handle_t *zhp; 3682168404Spjd int ret = 0; 3683185029Spjd vdev_state_t newstate; 3684219089Spjd int flags = 0; 3685168404Spjd 3686168404Spjd /* check options */ 3687219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3688168404Spjd switch (c) { 3689219089Spjd case 'e': 3690219089Spjd flags |= ZFS_ONLINE_EXPAND; 3691219089Spjd break; 3692168404Spjd case 't': 3693168404Spjd case '?': 3694168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3695168404Spjd optopt); 3696168404Spjd usage(B_FALSE); 3697168404Spjd } 3698168404Spjd } 3699168404Spjd 3700168404Spjd argc -= optind; 3701168404Spjd argv += optind; 3702168404Spjd 3703168404Spjd /* get pool name and check number of arguments */ 3704168404Spjd if (argc < 1) { 3705168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3706168404Spjd usage(B_FALSE); 3707168404Spjd } 3708168404Spjd if (argc < 2) { 3709168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3710168404Spjd usage(B_FALSE); 3711168404Spjd } 3712168404Spjd 3713168404Spjd poolname = argv[0]; 3714168404Spjd 3715168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3716168404Spjd return (1); 3717168404Spjd 3718185029Spjd for (i = 1; i < argc; i++) { 3719219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3720185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3721185029Spjd (void) printf(gettext("warning: device '%s' " 3722185029Spjd "onlined, but remains in faulted state\n"), 3723185029Spjd argv[i]); 3724185029Spjd if (newstate == VDEV_STATE_FAULTED) 3725185029Spjd (void) printf(gettext("use 'zpool " 3726185029Spjd "clear' to restore a faulted " 3727185029Spjd "device\n")); 3728185029Spjd else 3729185029Spjd (void) printf(gettext("use 'zpool " 3730185029Spjd "replace' to replace devices " 3731185029Spjd "that are no longer present\n")); 3732185029Spjd } 3733185029Spjd } else { 3734168404Spjd ret = 1; 3735185029Spjd } 3736185029Spjd } 3737168404Spjd 3738168404Spjd zpool_close(zhp); 3739168404Spjd 3740168404Spjd return (ret); 3741168404Spjd} 3742168404Spjd 3743168404Spjd/* 3744168404Spjd * zpool offline [-ft] <pool> <device> ... 3745168404Spjd * 3746168404Spjd * -f Force the device into the offline state, even if doing 3747168404Spjd * so would appear to compromise pool availability. 3748168404Spjd * (not supported yet) 3749168404Spjd * 3750168404Spjd * -t Only take the device off-line temporarily. The offline 3751168404Spjd * state will not be persistent across reboots. 3752168404Spjd */ 3753168404Spjd/* ARGSUSED */ 3754168404Spjdint 3755168404Spjdzpool_do_offline(int argc, char **argv) 3756168404Spjd{ 3757168404Spjd int c, i; 3758168404Spjd char *poolname; 3759168404Spjd zpool_handle_t *zhp; 3760168404Spjd int ret = 0; 3761168404Spjd boolean_t istmp = B_FALSE; 3762168404Spjd 3763168404Spjd /* check options */ 3764168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3765168404Spjd switch (c) { 3766168404Spjd case 't': 3767168404Spjd istmp = B_TRUE; 3768168404Spjd break; 3769168404Spjd case 'f': 3770168404Spjd case '?': 3771168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3772168404Spjd optopt); 3773168404Spjd usage(B_FALSE); 3774168404Spjd } 3775168404Spjd } 3776168404Spjd 3777168404Spjd argc -= optind; 3778168404Spjd argv += optind; 3779168404Spjd 3780168404Spjd /* get pool name and check number of arguments */ 3781168404Spjd if (argc < 1) { 3782168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3783168404Spjd usage(B_FALSE); 3784168404Spjd } 3785168404Spjd if (argc < 2) { 3786168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3787168404Spjd usage(B_FALSE); 3788168404Spjd } 3789168404Spjd 3790168404Spjd poolname = argv[0]; 3791168404Spjd 3792168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3793168404Spjd return (1); 3794168404Spjd 3795185029Spjd for (i = 1; i < argc; i++) { 3796185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3797168404Spjd ret = 1; 3798185029Spjd } 3799168404Spjd 3800168404Spjd zpool_close(zhp); 3801168404Spjd 3802168404Spjd return (ret); 3803168404Spjd} 3804168404Spjd 3805168404Spjd/* 3806168404Spjd * zpool clear <pool> [device] 3807168404Spjd * 3808168404Spjd * Clear all errors associated with a pool or a particular device. 3809168404Spjd */ 3810168404Spjdint 3811168404Spjdzpool_do_clear(int argc, char **argv) 3812168404Spjd{ 3813219089Spjd int c; 3814168404Spjd int ret = 0; 3815219089Spjd boolean_t dryrun = B_FALSE; 3816219089Spjd boolean_t do_rewind = B_FALSE; 3817219089Spjd boolean_t xtreme_rewind = B_FALSE; 3818219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3819219089Spjd nvlist_t *policy = NULL; 3820168404Spjd zpool_handle_t *zhp; 3821168404Spjd char *pool, *device; 3822168404Spjd 3823219089Spjd /* check options */ 3824219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3825219089Spjd switch (c) { 3826219089Spjd case 'F': 3827219089Spjd do_rewind = B_TRUE; 3828219089Spjd break; 3829219089Spjd case 'n': 3830219089Spjd dryrun = B_TRUE; 3831219089Spjd break; 3832219089Spjd case 'X': 3833219089Spjd xtreme_rewind = B_TRUE; 3834219089Spjd break; 3835219089Spjd case '?': 3836219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3837219089Spjd optopt); 3838219089Spjd usage(B_FALSE); 3839219089Spjd } 3840219089Spjd } 3841219089Spjd 3842219089Spjd argc -= optind; 3843219089Spjd argv += optind; 3844219089Spjd 3845219089Spjd if (argc < 1) { 3846168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3847168404Spjd usage(B_FALSE); 3848168404Spjd } 3849168404Spjd 3850219089Spjd if (argc > 2) { 3851168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3852168404Spjd usage(B_FALSE); 3853168404Spjd } 3854168404Spjd 3855219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3856219089Spjd (void) fprintf(stderr, 3857219089Spjd gettext("-n or -X only meaningful with -F\n")); 3858219089Spjd usage(B_FALSE); 3859219089Spjd } 3860219089Spjd if (dryrun) 3861219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3862219089Spjd else if (do_rewind) 3863219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3864219089Spjd if (xtreme_rewind) 3865219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3866168404Spjd 3867219089Spjd /* In future, further rewind policy choices can be passed along here */ 3868219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3869219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3870168404Spjd return (1); 3871168404Spjd 3872219089Spjd pool = argv[0]; 3873219089Spjd device = argc == 2 ? argv[1] : NULL; 3874219089Spjd 3875219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3876219089Spjd nvlist_free(policy); 3877219089Spjd return (1); 3878219089Spjd } 3879219089Spjd 3880219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3881168404Spjd ret = 1; 3882168404Spjd 3883168404Spjd zpool_close(zhp); 3884168404Spjd 3885219089Spjd nvlist_free(policy); 3886219089Spjd 3887168404Spjd return (ret); 3888168404Spjd} 3889168404Spjd 3890228103Smm/* 3891228103Smm * zpool reguid <pool> 3892228103Smm */ 3893228103Smmint 3894228103Smmzpool_do_reguid(int argc, char **argv) 3895228103Smm{ 3896228103Smm int c; 3897228103Smm char *poolname; 3898228103Smm zpool_handle_t *zhp; 3899228103Smm int ret = 0; 3900228103Smm 3901228103Smm /* check options */ 3902228103Smm while ((c = getopt(argc, argv, "")) != -1) { 3903228103Smm switch (c) { 3904228103Smm case '?': 3905228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3906228103Smm optopt); 3907228103Smm usage(B_FALSE); 3908228103Smm } 3909228103Smm } 3910228103Smm 3911228103Smm argc -= optind; 3912228103Smm argv += optind; 3913228103Smm 3914228103Smm /* get pool name and check number of arguments */ 3915228103Smm if (argc < 1) { 3916228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 3917228103Smm usage(B_FALSE); 3918228103Smm } 3919228103Smm 3920228103Smm if (argc > 1) { 3921228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 3922228103Smm usage(B_FALSE); 3923228103Smm } 3924228103Smm 3925228103Smm poolname = argv[0]; 3926228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3927228103Smm return (1); 3928228103Smm 3929228103Smm ret = zpool_reguid(zhp); 3930228103Smm 3931228103Smm zpool_close(zhp); 3932228103Smm return (ret); 3933228103Smm} 3934228103Smm 3935228103Smm 3936236155Smm/* 3937236155Smm * zpool reopen <pool> 3938236155Smm * 3939236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 3940236155Smm */ 3941236155Smmint 3942236155Smmzpool_do_reopen(int argc, char **argv) 3943236155Smm{ 3944260138Sdelphij int c; 3945236155Smm int ret = 0; 3946236155Smm zpool_handle_t *zhp; 3947236155Smm char *pool; 3948236155Smm 3949260138Sdelphij /* check options */ 3950260138Sdelphij while ((c = getopt(argc, argv, "")) != -1) { 3951260138Sdelphij switch (c) { 3952260138Sdelphij case '?': 3953260138Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3954260138Sdelphij optopt); 3955260138Sdelphij usage(B_FALSE); 3956260138Sdelphij } 3957260138Sdelphij } 3958260138Sdelphij 3959236155Smm argc--; 3960236155Smm argv++; 3961236155Smm 3962260138Sdelphij if (argc < 1) { 3963260138Sdelphij (void) fprintf(stderr, gettext("missing pool name\n")); 3964260138Sdelphij usage(B_FALSE); 3965260138Sdelphij } 3966236155Smm 3967260138Sdelphij if (argc > 1) { 3968260138Sdelphij (void) fprintf(stderr, gettext("too many arguments\n")); 3969260138Sdelphij usage(B_FALSE); 3970260138Sdelphij } 3971260138Sdelphij 3972236155Smm pool = argv[0]; 3973236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 3974236155Smm return (1); 3975236155Smm 3976236155Smm ret = zpool_reopen(zhp); 3977236155Smm zpool_close(zhp); 3978236155Smm return (ret); 3979236155Smm} 3980236155Smm 3981168404Spjdtypedef struct scrub_cbdata { 3982168404Spjd int cb_type; 3983168404Spjd int cb_argc; 3984168404Spjd char **cb_argv; 3985324010Savg pool_scrub_cmd_t cb_scrub_cmd; 3986168404Spjd} scrub_cbdata_t; 3987168404Spjd 3988168404Spjdint 3989168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3990168404Spjd{ 3991168404Spjd scrub_cbdata_t *cb = data; 3992168404Spjd int err; 3993168404Spjd 3994168404Spjd /* 3995168404Spjd * Ignore faulted pools. 3996168404Spjd */ 3997168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3998168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3999168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 4000168404Spjd return (1); 4001168404Spjd } 4002168404Spjd 4003324010Savg err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd); 4004168404Spjd 4005168404Spjd return (err != 0); 4006168404Spjd} 4007168404Spjd 4008168404Spjd/* 4009324010Savg * zpool scrub [-s | -p] <pool> ... 4010168404Spjd * 4011168404Spjd * -s Stop. Stops any in-progress scrub. 4012324010Savg * -p Pause. Pause in-progress scrub. 4013168404Spjd */ 4014168404Spjdint 4015168404Spjdzpool_do_scrub(int argc, char **argv) 4016168404Spjd{ 4017168404Spjd int c; 4018168404Spjd scrub_cbdata_t cb; 4019168404Spjd 4020219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 4021324010Savg cb.cb_scrub_cmd = POOL_SCRUB_NORMAL; 4022168404Spjd 4023168404Spjd /* check options */ 4024324010Savg while ((c = getopt(argc, argv, "sp")) != -1) { 4025168404Spjd switch (c) { 4026168404Spjd case 's': 4027219089Spjd cb.cb_type = POOL_SCAN_NONE; 4028168404Spjd break; 4029324010Savg case 'p': 4030324010Savg cb.cb_scrub_cmd = POOL_SCRUB_PAUSE; 4031324010Savg break; 4032168404Spjd case '?': 4033168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4034168404Spjd optopt); 4035168404Spjd usage(B_FALSE); 4036168404Spjd } 4037168404Spjd } 4038168404Spjd 4039324010Savg if (cb.cb_type == POOL_SCAN_NONE && 4040324010Savg cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) { 4041324010Savg (void) fprintf(stderr, gettext("invalid option combination: " 4042324010Savg "-s and -p are mutually exclusive\n")); 4043324010Savg usage(B_FALSE); 4044324010Savg } 4045324010Savg 4046168404Spjd cb.cb_argc = argc; 4047168404Spjd cb.cb_argv = argv; 4048168404Spjd argc -= optind; 4049168404Spjd argv += optind; 4050168404Spjd 4051168404Spjd if (argc < 1) { 4052168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 4053168404Spjd usage(B_FALSE); 4054168404Spjd } 4055168404Spjd 4056168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 4057168404Spjd} 4058168404Spjd 4059168404Spjdtypedef struct status_cbdata { 4060168404Spjd int cb_count; 4061168404Spjd boolean_t cb_allpools; 4062168404Spjd boolean_t cb_verbose; 4063168404Spjd boolean_t cb_explain; 4064168404Spjd boolean_t cb_first; 4065219089Spjd boolean_t cb_dedup_stats; 4066168404Spjd} status_cbdata_t; 4067168404Spjd 4068168404Spjd/* 4069168404Spjd * Print out detailed scrub status. 4070168404Spjd */ 4071332525Smavstatic void 4072219089Spjdprint_scan_status(pool_scan_stat_t *ps) 4073168404Spjd{ 4074324010Savg time_t start, end, pause; 4075219089Spjd uint64_t elapsed, mins_left, hours_left; 4076219089Spjd uint64_t pass_exam, examined, total; 4077219089Spjd uint_t rate; 4078168404Spjd double fraction_done; 4079219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 4080168404Spjd 4081226583Spjd (void) printf(gettext(" scan: ")); 4082168404Spjd 4083219089Spjd /* If there's never been a scan, there's not much to say. */ 4084219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 4085219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 4086168404Spjd (void) printf(gettext("none requested\n")); 4087168404Spjd return; 4088168404Spjd } 4089168404Spjd 4090219089Spjd start = ps->pss_start_time; 4091219089Spjd end = ps->pss_end_time; 4092324010Savg pause = ps->pss_pass_scrub_pause; 4093219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 4094168404Spjd 4095219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 4096219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 4097219089Spjd /* 4098219089Spjd * Scan is finished or canceled. 4099219089Spjd */ 4100219089Spjd if (ps->pss_state == DSS_FINISHED) { 4101219089Spjd uint64_t minutes_taken = (end - start) / 60; 4102296537Smav char *fmt = NULL; 4103168404Spjd 4104219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4105219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 4106219089Spjd "%llu errors on %s"); 4107219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4108219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 4109219089Spjd "%llu errors on %s"); 4110219089Spjd } 4111219089Spjd /* LINTED */ 4112219089Spjd (void) printf(fmt, processed_buf, 4113185029Spjd (u_longlong_t)(minutes_taken / 60), 4114185029Spjd (uint_t)(minutes_taken % 60), 4115219089Spjd (u_longlong_t)ps->pss_errors, 4116219089Spjd ctime((time_t *)&end)); 4117168404Spjd return; 4118219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 4119219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4120219089Spjd (void) printf(gettext("scrub canceled on %s"), 4121219089Spjd ctime(&end)); 4122219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4123219089Spjd (void) printf(gettext("resilver canceled on %s"), 4124219089Spjd ctime(&end)); 4125219089Spjd } 4126219089Spjd return; 4127168404Spjd } 4128168404Spjd 4129219089Spjd assert(ps->pss_state == DSS_SCANNING); 4130168404Spjd 4131219089Spjd /* 4132219089Spjd * Scan is in progress. 4133219089Spjd */ 4134219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4135324010Savg if (pause == 0) { 4136324010Savg (void) printf(gettext("scrub in progress since %s"), 4137324010Savg ctime(&start)); 4138324010Savg } else { 4139324010Savg char buf[32]; 4140324010Savg struct tm *p = localtime(&pause); 4141324010Savg (void) strftime(buf, sizeof (buf), "%a %b %e %T %Y", p); 4142324010Savg (void) printf(gettext("scrub paused since %s\n"), buf); 4143324010Savg (void) printf(gettext("\tscrub started on %s"), 4144324010Savg ctime(&start)); 4145324010Savg } 4146219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4147219089Spjd (void) printf(gettext("resilver in progress since %s"), 4148219089Spjd ctime(&start)); 4149219089Spjd } 4150219089Spjd 4151219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 4152219089Spjd total = ps->pss_to_examine; 4153168404Spjd fraction_done = (double)examined / total; 4154168404Spjd 4155219089Spjd /* elapsed time for this pass */ 4156219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 4157324010Savg elapsed -= ps->pss_pass_scrub_spent_paused; 4158219089Spjd elapsed = elapsed ? elapsed : 1; 4159219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 4160219089Spjd rate = pass_exam / elapsed; 4161219089Spjd rate = rate ? rate : 1; 4162219089Spjd mins_left = ((total - examined) / rate) / 60; 4163219089Spjd hours_left = mins_left / 60; 4164219089Spjd 4165219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 4166219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 4167219089Spjd 4168219089Spjd /* 4169219089Spjd * do not print estimated time if hours_left is more than 30 days 4170324010Savg * or we have a paused scrub 4171219089Spjd */ 4172324010Savg if (pause == 0) { 4173324010Savg zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 4174324010Savg (void) printf(gettext("\t%s scanned out of %s at %s/s"), 4175324010Savg examined_buf, total_buf, rate_buf); 4176324010Savg if (hours_left < (30 * 24)) { 4177324010Savg (void) printf(gettext(", %lluh%um to go\n"), 4178324010Savg (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 4179324010Savg } else { 4180324010Savg (void) printf(gettext( 4181324010Savg ", (scan is slow, no estimated time)\n")); 4182324010Savg } 4183219089Spjd } else { 4184324010Savg (void) printf(gettext("\t%s scanned out of %s\n"), 4185324010Savg examined_buf, total_buf); 4186219089Spjd } 4187219089Spjd 4188219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 4189226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 4190219089Spjd processed_buf, 100 * fraction_done); 4191219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 4192226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 4193219089Spjd processed_buf, 100 * fraction_done); 4194219089Spjd } 4195168404Spjd} 4196168404Spjd 4197332525Smav/* 4198332525Smav * Print out detailed removal status. 4199332525Smav */ 4200168404Spjdstatic void 4201332525Smavprint_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs) 4202332525Smav{ 4203332525Smav char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 4204332525Smav time_t start, end; 4205332525Smav nvlist_t *config, *nvroot; 4206332525Smav nvlist_t **child; 4207332525Smav uint_t children; 4208332525Smav char *vdev_name; 4209332525Smav 4210332525Smav if (prs == NULL || prs->prs_state == DSS_NONE) 4211332525Smav return; 4212332525Smav 4213332525Smav /* 4214332525Smav * Determine name of vdev. 4215332525Smav */ 4216332525Smav config = zpool_get_config(zhp, NULL); 4217332525Smav nvroot = fnvlist_lookup_nvlist(config, 4218332525Smav ZPOOL_CONFIG_VDEV_TREE); 4219332525Smav verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 4220332525Smav &child, &children) == 0); 4221332525Smav assert(prs->prs_removing_vdev < children); 4222332525Smav vdev_name = zpool_vdev_name(g_zfs, zhp, 4223332525Smav child[prs->prs_removing_vdev], B_TRUE); 4224332525Smav 4225332525Smav (void) printf(gettext("remove: ")); 4226332525Smav 4227332525Smav start = prs->prs_start_time; 4228332525Smav end = prs->prs_end_time; 4229332525Smav zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf)); 4230332525Smav 4231332525Smav /* 4232332525Smav * Removal is finished or canceled. 4233332525Smav */ 4234332525Smav if (prs->prs_state == DSS_FINISHED) { 4235332525Smav uint64_t minutes_taken = (end - start) / 60; 4236332525Smav 4237332525Smav (void) printf(gettext("Removal of vdev %llu copied %s " 4238332525Smav "in %lluh%um, completed on %s"), 4239332525Smav (longlong_t)prs->prs_removing_vdev, 4240332525Smav copied_buf, 4241332525Smav (u_longlong_t)(minutes_taken / 60), 4242332525Smav (uint_t)(minutes_taken % 60), 4243332525Smav ctime((time_t *)&end)); 4244332525Smav } else if (prs->prs_state == DSS_CANCELED) { 4245332525Smav (void) printf(gettext("Removal of %s canceled on %s"), 4246332525Smav vdev_name, ctime(&end)); 4247332525Smav } else { 4248332525Smav uint64_t copied, total, elapsed, mins_left, hours_left; 4249332525Smav double fraction_done; 4250332525Smav uint_t rate; 4251332525Smav 4252332525Smav assert(prs->prs_state == DSS_SCANNING); 4253332525Smav 4254332525Smav /* 4255332525Smav * Removal is in progress. 4256332525Smav */ 4257332525Smav (void) printf(gettext( 4258332525Smav "Evacuation of %s in progress since %s"), 4259332525Smav vdev_name, ctime(&start)); 4260332525Smav 4261332525Smav copied = prs->prs_copied > 0 ? prs->prs_copied : 1; 4262332525Smav total = prs->prs_to_copy; 4263332525Smav fraction_done = (double)copied / total; 4264332525Smav 4265332525Smav /* elapsed time for this pass */ 4266332525Smav elapsed = time(NULL) - prs->prs_start_time; 4267332525Smav elapsed = elapsed > 0 ? elapsed : 1; 4268332525Smav rate = copied / elapsed; 4269332525Smav rate = rate > 0 ? rate : 1; 4270332525Smav mins_left = ((total - copied) / rate) / 60; 4271332525Smav hours_left = mins_left / 60; 4272332525Smav 4273332525Smav zfs_nicenum(copied, examined_buf, sizeof (examined_buf)); 4274332525Smav zfs_nicenum(total, total_buf, sizeof (total_buf)); 4275332525Smav zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 4276332525Smav 4277332525Smav /* 4278332525Smav * do not print estimated time if hours_left is more than 4279332525Smav * 30 days 4280332525Smav */ 4281332525Smav (void) printf(gettext(" %s copied out of %s at %s/s, " 4282332525Smav "%.2f%% done"), 4283332525Smav examined_buf, total_buf, rate_buf, 100 * fraction_done); 4284332525Smav if (hours_left < (30 * 24)) { 4285332525Smav (void) printf(gettext(", %lluh%um to go\n"), 4286332525Smav (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 4287332525Smav } else { 4288332525Smav (void) printf(gettext( 4289332525Smav ", (copy is slow, no estimated time)\n")); 4290332525Smav } 4291332525Smav } 4292332525Smav 4293332525Smav if (prs->prs_mapping_memory > 0) { 4294332525Smav char mem_buf[7]; 4295332525Smav zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf)); 4296332525Smav (void) printf(gettext(" %s memory used for " 4297332525Smav "removed device mappings\n"), 4298332525Smav mem_buf); 4299332525Smav } 4300332525Smav} 4301332525Smav 4302332525Smavstatic void 4303168404Spjdprint_error_log(zpool_handle_t *zhp) 4304168404Spjd{ 4305185029Spjd nvlist_t *nverrlist = NULL; 4306168404Spjd nvpair_t *elem; 4307168404Spjd char *pathname; 4308168404Spjd size_t len = MAXPATHLEN * 2; 4309168404Spjd 4310168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 4311168404Spjd (void) printf("errors: List of errors unavailable " 4312168404Spjd "(insufficient privileges)\n"); 4313168404Spjd return; 4314168404Spjd } 4315168404Spjd 4316168404Spjd (void) printf("errors: Permanent errors have been " 4317168404Spjd "detected in the following files:\n\n"); 4318168404Spjd 4319168404Spjd pathname = safe_malloc(len); 4320168404Spjd elem = NULL; 4321168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 4322168404Spjd nvlist_t *nv; 4323168404Spjd uint64_t dsobj, obj; 4324168404Spjd 4325168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 4326168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 4327168404Spjd &dsobj) == 0); 4328168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 4329168404Spjd &obj) == 0); 4330168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 4331168404Spjd (void) printf("%7s %s\n", "", pathname); 4332168404Spjd } 4333168404Spjd free(pathname); 4334168404Spjd nvlist_free(nverrlist); 4335168404Spjd} 4336168404Spjd 4337168404Spjdstatic void 4338168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 4339168404Spjd int namewidth) 4340168404Spjd{ 4341168404Spjd uint_t i; 4342168404Spjd char *name; 4343168404Spjd 4344168404Spjd if (nspares == 0) 4345168404Spjd return; 4346168404Spjd 4347168404Spjd (void) printf(gettext("\tspares\n")); 4348168404Spjd 4349168404Spjd for (i = 0; i < nspares; i++) { 4350219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 4351168404Spjd print_status_config(zhp, name, spares[i], 4352209962Smm namewidth, 2, B_TRUE); 4353168404Spjd free(name); 4354168404Spjd } 4355168404Spjd} 4356168404Spjd 4357185029Spjdstatic void 4358185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 4359185029Spjd int namewidth) 4360185029Spjd{ 4361185029Spjd uint_t i; 4362185029Spjd char *name; 4363185029Spjd 4364185029Spjd if (nl2cache == 0) 4365185029Spjd return; 4366185029Spjd 4367185029Spjd (void) printf(gettext("\tcache\n")); 4368185029Spjd 4369185029Spjd for (i = 0; i < nl2cache; i++) { 4370219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 4371185029Spjd print_status_config(zhp, name, l2cache[i], 4372209962Smm namewidth, 2, B_FALSE); 4373185029Spjd free(name); 4374185029Spjd } 4375185029Spjd} 4376185029Spjd 4377219089Spjdstatic void 4378219089Spjdprint_dedup_stats(nvlist_t *config) 4379219089Spjd{ 4380219089Spjd ddt_histogram_t *ddh; 4381219089Spjd ddt_stat_t *dds; 4382219089Spjd ddt_object_t *ddo; 4383219089Spjd uint_t c; 4384219089Spjd 4385219089Spjd /* 4386219089Spjd * If the pool was faulted then we may not have been able to 4387253441Sdelphij * obtain the config. Otherwise, if we have anything in the dedup 4388219089Spjd * table continue processing the stats. 4389219089Spjd */ 4390219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 4391227497Smm (uint64_t **)&ddo, &c) != 0) 4392219089Spjd return; 4393219089Spjd 4394219089Spjd (void) printf("\n"); 4395227497Smm (void) printf(gettext(" dedup: ")); 4396227497Smm if (ddo->ddo_count == 0) { 4397227497Smm (void) printf(gettext("no DDT entries\n")); 4398227497Smm return; 4399227497Smm } 4400227497Smm 4401219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 4402219089Spjd (u_longlong_t)ddo->ddo_count, 4403219089Spjd (u_longlong_t)ddo->ddo_dspace, 4404219089Spjd (u_longlong_t)ddo->ddo_mspace); 4405219089Spjd 4406219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 4407219089Spjd (uint64_t **)&dds, &c) == 0); 4408219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 4409219089Spjd (uint64_t **)&ddh, &c) == 0); 4410219089Spjd zpool_dump_ddt(dds, ddh); 4411219089Spjd} 4412219089Spjd 4413168404Spjd/* 4414168404Spjd * Display a summary of pool status. Displays a summary such as: 4415168404Spjd * 4416168404Spjd * pool: tank 4417168404Spjd * status: DEGRADED 4418168404Spjd * reason: One or more devices ... 4419236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 4420168404Spjd * config: 4421168404Spjd * mirror DEGRADED 4422168404Spjd * c1t0d0 OK 4423168404Spjd * c2t0d0 UNAVAIL 4424168404Spjd * 4425168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 4426168404Spjd * option is specified, then we print out error rate information as well. 4427168404Spjd */ 4428168404Spjdint 4429168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 4430168404Spjd{ 4431168404Spjd status_cbdata_t *cbp = data; 4432168404Spjd nvlist_t *config, *nvroot; 4433168404Spjd char *msgid; 4434168404Spjd int reason; 4435168404Spjd const char *health; 4436168404Spjd uint_t c; 4437168404Spjd vdev_stat_t *vs; 4438168404Spjd 4439168404Spjd config = zpool_get_config(zhp, NULL); 4440168404Spjd reason = zpool_get_status(zhp, &msgid); 4441168404Spjd 4442168404Spjd cbp->cb_count++; 4443168404Spjd 4444168404Spjd /* 4445168404Spjd * If we were given 'zpool status -x', only report those pools with 4446168404Spjd * problems. 4447168404Spjd */ 4448248267Smm if (cbp->cb_explain && 4449248267Smm (reason == ZPOOL_STATUS_OK || 4450248267Smm reason == ZPOOL_STATUS_VERSION_OLDER || 4451268621Ssmh reason == ZPOOL_STATUS_NON_NATIVE_ASHIFT || 4452248267Smm reason == ZPOOL_STATUS_FEAT_DISABLED)) { 4453168404Spjd if (!cbp->cb_allpools) { 4454168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 4455168404Spjd zpool_get_name(zhp)); 4456168404Spjd if (cbp->cb_first) 4457168404Spjd cbp->cb_first = B_FALSE; 4458168404Spjd } 4459168404Spjd return (0); 4460168404Spjd } 4461168404Spjd 4462168404Spjd if (cbp->cb_first) 4463168404Spjd cbp->cb_first = B_FALSE; 4464168404Spjd else 4465168404Spjd (void) printf("\n"); 4466168404Spjd 4467332525Smav nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE); 4468219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 4469168404Spjd (uint64_t **)&vs, &c) == 0); 4470185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4471168404Spjd 4472168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4473168404Spjd (void) printf(gettext(" state: %s\n"), health); 4474168404Spjd 4475168404Spjd switch (reason) { 4476168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 4477168404Spjd (void) printf(gettext("status: One or more devices could not " 4478168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 4479168404Spjd "continue functioning in a degraded state.\n")); 4480168404Spjd (void) printf(gettext("action: Attach the missing device and " 4481168404Spjd "online it using 'zpool online'.\n")); 4482168404Spjd break; 4483168404Spjd 4484168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 4485168404Spjd (void) printf(gettext("status: One or more devices could not " 4486168404Spjd "be opened. There are insufficient\n\treplicas for the " 4487168404Spjd "pool to continue functioning.\n")); 4488168404Spjd (void) printf(gettext("action: Attach the missing device and " 4489168404Spjd "online it using 'zpool online'.\n")); 4490168404Spjd break; 4491168404Spjd 4492168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 4493168404Spjd (void) printf(gettext("status: One or more devices could not " 4494168404Spjd "be used because the label is missing or\n\tinvalid. " 4495168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 4496168404Spjd "functioning in a degraded state.\n")); 4497168404Spjd (void) printf(gettext("action: Replace the device using " 4498168404Spjd "'zpool replace'.\n")); 4499168404Spjd break; 4500168404Spjd 4501168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4502168404Spjd (void) printf(gettext("status: One or more devices could not " 4503168404Spjd "be used because the label is missing \n\tor invalid. " 4504168404Spjd "There are insufficient replicas for the pool to " 4505168404Spjd "continue\n\tfunctioning.\n")); 4506219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4507219089Spjd zpool_get_name(zhp), reason, config); 4508168404Spjd break; 4509168404Spjd 4510168404Spjd case ZPOOL_STATUS_FAILING_DEV: 4511168404Spjd (void) printf(gettext("status: One or more devices has " 4512168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 4513168404Spjd "made to correct the error. Applications are " 4514168404Spjd "unaffected.\n")); 4515168404Spjd (void) printf(gettext("action: Determine if the device needs " 4516168404Spjd "to be replaced, and clear the errors\n\tusing " 4517168404Spjd "'zpool clear' or replace the device with 'zpool " 4518168404Spjd "replace'.\n")); 4519168404Spjd break; 4520168404Spjd 4521168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 4522168404Spjd (void) printf(gettext("status: One or more devices has " 4523168404Spjd "been taken offline by the administrator.\n\tSufficient " 4524168404Spjd "replicas exist for the pool to continue functioning in " 4525168404Spjd "a\n\tdegraded state.\n")); 4526168404Spjd (void) printf(gettext("action: Online the device using " 4527168404Spjd "'zpool online' or replace the device with\n\t'zpool " 4528168404Spjd "replace'.\n")); 4529168404Spjd break; 4530168404Spjd 4531219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 4532219089Spjd (void) printf(gettext("status: One or more devices has " 4533219089Spjd "been removed by the administrator.\n\tSufficient " 4534219089Spjd "replicas exist for the pool to continue functioning in " 4535219089Spjd "a\n\tdegraded state.\n")); 4536219089Spjd (void) printf(gettext("action: Online the device using " 4537219089Spjd "'zpool online' or replace the device with\n\t'zpool " 4538219089Spjd "replace'.\n")); 4539219089Spjd break; 4540219089Spjd 4541168404Spjd case ZPOOL_STATUS_RESILVERING: 4542168404Spjd (void) printf(gettext("status: One or more devices is " 4543168404Spjd "currently being resilvered. The pool will\n\tcontinue " 4544168404Spjd "to function, possibly in a degraded state.\n")); 4545168404Spjd (void) printf(gettext("action: Wait for the resilver to " 4546168404Spjd "complete.\n")); 4547168404Spjd break; 4548168404Spjd 4549168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 4550168404Spjd (void) printf(gettext("status: One or more devices has " 4551168404Spjd "experienced an error resulting in data\n\tcorruption. " 4552168404Spjd "Applications may be affected.\n")); 4553168404Spjd (void) printf(gettext("action: Restore the file in question " 4554168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 4555168404Spjd "backup.\n")); 4556168404Spjd break; 4557168404Spjd 4558168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4559168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4560168404Spjd "and the pool cannot be opened.\n")); 4561219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4562219089Spjd zpool_get_name(zhp), reason, config); 4563168404Spjd break; 4564168404Spjd 4565168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4566238926Smm (void) printf(gettext("status: The pool is formatted using a " 4567238926Smm "legacy on-disk format. The pool can\n\tstill be used, " 4568238926Smm "but some features are unavailable.\n")); 4569168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4570168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 4571238926Smm "be accessible on software that does not support feature\n" 4572238926Smm "\tflags.\n")); 4573168404Spjd break; 4574168404Spjd 4575168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 4576168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 4577168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 4578168404Spjd "be accessed on this system.\n")); 4579168404Spjd (void) printf(gettext("action: Access the pool from a system " 4580168404Spjd "running more recent software, or\n\trestore the pool from " 4581168404Spjd "backup.\n")); 4582168404Spjd break; 4583168404Spjd 4584238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 4585238926Smm (void) printf(gettext("status: Some supported features are not " 4586238926Smm "enabled on the pool. The pool can\n\tstill be used, but " 4587238926Smm "some features are unavailable.\n")); 4588238926Smm (void) printf(gettext("action: Enable all features using " 4589238926Smm "'zpool upgrade'. Once this is done,\n\tthe pool may no " 4590238926Smm "longer be accessible by software that does not support\n\t" 4591243014Smm "the features. See zpool-features(7) for details.\n")); 4592238926Smm break; 4593238926Smm 4594236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 4595236884Smm (void) printf(gettext("status: The pool cannot be accessed on " 4596236884Smm "this system because it uses the\n\tfollowing feature(s) " 4597236884Smm "not supported on this system:\n")); 4598236884Smm zpool_print_unsup_feat(config); 4599236884Smm (void) printf("\n"); 4600236884Smm (void) printf(gettext("action: Access the pool from a system " 4601236884Smm "that supports the required feature(s),\n\tor restore the " 4602236884Smm "pool from backup.\n")); 4603236884Smm break; 4604236884Smm 4605236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4606236884Smm (void) printf(gettext("status: The pool can only be accessed " 4607236884Smm "in read-only mode on this system. It\n\tcannot be " 4608236884Smm "accessed in read-write mode because it uses the " 4609236884Smm "following\n\tfeature(s) not supported on this system:\n")); 4610236884Smm zpool_print_unsup_feat(config); 4611236884Smm (void) printf("\n"); 4612236884Smm (void) printf(gettext("action: The pool cannot be accessed in " 4613236884Smm "read-write mode. Import the pool with\n" 4614236884Smm "\t\"-o readonly=on\", access the pool from a system that " 4615236884Smm "supports the\n\trequired feature(s), or restore the " 4616236884Smm "pool from backup.\n")); 4617236884Smm break; 4618236884Smm 4619185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 4620185029Spjd (void) printf(gettext("status: One or more devices are " 4621185029Spjd "faulted in response to persistent errors.\n\tSufficient " 4622185029Spjd "replicas exist for the pool to continue functioning " 4623185029Spjd "in a\n\tdegraded state.\n")); 4624185029Spjd (void) printf(gettext("action: Replace the faulted device, " 4625185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 4626185029Spjd break; 4627185029Spjd 4628185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 4629185029Spjd (void) printf(gettext("status: One or more devices are " 4630185029Spjd "faulted in response to persistent errors. There are " 4631185029Spjd "insufficient replicas for the pool to\n\tcontinue " 4632185029Spjd "functioning.\n")); 4633185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 4634185029Spjd "from a backup source. Manually marking the device\n" 4635185029Spjd "\trepaired using 'zpool clear' may allow some data " 4636185029Spjd "to be recovered.\n")); 4637185029Spjd break; 4638185029Spjd 4639185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 4640185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 4641185029Spjd (void) printf(gettext("status: One or more devices are " 4642185029Spjd "faulted in response to IO failures.\n")); 4643185029Spjd (void) printf(gettext("action: Make sure the affected devices " 4644185029Spjd "are connected, then run 'zpool clear'.\n")); 4645185029Spjd break; 4646185029Spjd 4647185029Spjd case ZPOOL_STATUS_BAD_LOG: 4648185029Spjd (void) printf(gettext("status: An intent log record " 4649185029Spjd "could not be read.\n" 4650185029Spjd "\tWaiting for adminstrator intervention to fix the " 4651185029Spjd "faulted pool.\n")); 4652185029Spjd (void) printf(gettext("action: Either restore the affected " 4653185029Spjd "device(s) and run 'zpool online',\n" 4654185029Spjd "\tor ignore the intent log records by running " 4655185029Spjd "'zpool clear'.\n")); 4656185029Spjd break; 4657185029Spjd 4658254591Sgibbs case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 4659254591Sgibbs (void) printf(gettext("status: One or more devices are " 4660254591Sgibbs "configured to use a non-native block size.\n" 4661254591Sgibbs "\tExpect reduced performance.\n")); 4662254591Sgibbs (void) printf(gettext("action: Replace affected devices with " 4663254591Sgibbs "devices that support the\n\tconfigured block size, or " 4664254591Sgibbs "migrate data to a properly configured\n\tpool.\n")); 4665254591Sgibbs break; 4666254591Sgibbs 4667168404Spjd default: 4668168404Spjd /* 4669168404Spjd * The remaining errors can't actually be generated, yet. 4670168404Spjd */ 4671168404Spjd assert(reason == ZPOOL_STATUS_OK); 4672168404Spjd } 4673168404Spjd 4674168404Spjd if (msgid != NULL) 4675236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4676168404Spjd msgid); 4677168404Spjd 4678168404Spjd if (config != NULL) { 4679168404Spjd int namewidth; 4680168404Spjd uint64_t nerr; 4681185029Spjd nvlist_t **spares, **l2cache; 4682185029Spjd uint_t nspares, nl2cache; 4683219089Spjd pool_scan_stat_t *ps = NULL; 4684332525Smav pool_removal_stat_t *prs = NULL; 4685168404Spjd 4686219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 4687219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 4688219089Spjd print_scan_status(ps); 4689168404Spjd 4690332525Smav (void) nvlist_lookup_uint64_array(nvroot, 4691332525Smav ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c); 4692332525Smav print_removal_status(zhp, prs); 4693332525Smav 4694168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 4695168404Spjd if (namewidth < 10) 4696168404Spjd namewidth = 10; 4697168404Spjd 4698168404Spjd (void) printf(gettext("config:\n\n")); 4699168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4700168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4701168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 4702209962Smm namewidth, 0, B_FALSE); 4703209962Smm 4704185029Spjd if (num_logs(nvroot) > 0) 4705213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 4706185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4707185029Spjd &l2cache, &nl2cache) == 0) 4708185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 4709185029Spjd 4710168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 4711168404Spjd &spares, &nspares) == 0) 4712168404Spjd print_spares(zhp, spares, nspares, namewidth); 4713168404Spjd 4714168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4715168404Spjd &nerr) == 0) { 4716168404Spjd nvlist_t *nverrlist = NULL; 4717168404Spjd 4718168404Spjd /* 4719168404Spjd * If the approximate error count is small, get a 4720168404Spjd * precise count by fetching the entire log and 4721168404Spjd * uniquifying the results. 4722168404Spjd */ 4723185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 4724168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 4725168404Spjd nvpair_t *elem; 4726168404Spjd 4727168404Spjd elem = NULL; 4728168404Spjd nerr = 0; 4729168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 4730168404Spjd elem)) != NULL) { 4731168404Spjd nerr++; 4732168404Spjd } 4733168404Spjd } 4734168404Spjd nvlist_free(nverrlist); 4735168404Spjd 4736168404Spjd (void) printf("\n"); 4737168404Spjd 4738168404Spjd if (nerr == 0) 4739168404Spjd (void) printf(gettext("errors: No known data " 4740168404Spjd "errors\n")); 4741168404Spjd else if (!cbp->cb_verbose) 4742168404Spjd (void) printf(gettext("errors: %llu data " 4743168404Spjd "errors, use '-v' for a list\n"), 4744168404Spjd (u_longlong_t)nerr); 4745168404Spjd else 4746168404Spjd print_error_log(zhp); 4747168404Spjd } 4748219089Spjd 4749219089Spjd if (cbp->cb_dedup_stats) 4750219089Spjd print_dedup_stats(config); 4751168404Spjd } else { 4752168404Spjd (void) printf(gettext("config: The configuration cannot be " 4753168404Spjd "determined.\n")); 4754168404Spjd } 4755168404Spjd 4756168404Spjd return (0); 4757168404Spjd} 4758168404Spjd 4759168404Spjd/* 4760219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4761168404Spjd * 4762168404Spjd * -v Display complete error logs 4763168404Spjd * -x Display only pools with potential problems 4764219089Spjd * -D Display dedup status (undocumented) 4765219089Spjd * -T Display a timestamp in date(1) or Unix format 4766168404Spjd * 4767168404Spjd * Describes the health status of all pools or some subset. 4768168404Spjd */ 4769168404Spjdint 4770168404Spjdzpool_do_status(int argc, char **argv) 4771168404Spjd{ 4772168404Spjd int c; 4773168404Spjd int ret; 4774219089Spjd unsigned long interval = 0, count = 0; 4775168404Spjd status_cbdata_t cb = { 0 }; 4776168404Spjd 4777168404Spjd /* check options */ 4778219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4779168404Spjd switch (c) { 4780168404Spjd case 'v': 4781168404Spjd cb.cb_verbose = B_TRUE; 4782168404Spjd break; 4783168404Spjd case 'x': 4784168404Spjd cb.cb_explain = B_TRUE; 4785168404Spjd break; 4786219089Spjd case 'D': 4787219089Spjd cb.cb_dedup_stats = B_TRUE; 4788219089Spjd break; 4789219089Spjd case 'T': 4790219089Spjd get_timestamp_arg(*optarg); 4791219089Spjd break; 4792168404Spjd case '?': 4793168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4794168404Spjd optopt); 4795168404Spjd usage(B_FALSE); 4796168404Spjd } 4797168404Spjd } 4798168404Spjd 4799168404Spjd argc -= optind; 4800168404Spjd argv += optind; 4801168404Spjd 4802219089Spjd get_interval_count(&argc, argv, &interval, &count); 4803168404Spjd 4804168404Spjd if (argc == 0) 4805168404Spjd cb.cb_allpools = B_TRUE; 4806168404Spjd 4807219089Spjd cb.cb_first = B_TRUE; 4808168404Spjd 4809219089Spjd for (;;) { 4810219089Spjd if (timestamp_fmt != NODATE) 4811219089Spjd print_timestamp(timestamp_fmt); 4812168404Spjd 4813219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 4814219089Spjd status_callback, &cb); 4815219089Spjd 4816219089Spjd if (argc == 0 && cb.cb_count == 0) 4817219089Spjd (void) printf(gettext("no pools available\n")); 4818219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 4819219089Spjd (void) printf(gettext("all pools are healthy\n")); 4820219089Spjd 4821219089Spjd if (ret != 0) 4822219089Spjd return (ret); 4823219089Spjd 4824219089Spjd if (interval == 0) 4825219089Spjd break; 4826219089Spjd 4827219089Spjd if (count != 0 && --count == 0) 4828219089Spjd break; 4829219089Spjd 4830219089Spjd (void) sleep(interval); 4831219089Spjd } 4832219089Spjd 4833219089Spjd return (0); 4834168404Spjd} 4835168404Spjd 4836168404Spjdtypedef struct upgrade_cbdata { 4837276226Ssmh boolean_t cb_first; 4838276226Ssmh boolean_t cb_unavail; 4839307108Smav char cb_poolname[ZFS_MAX_DATASET_NAME_LEN]; 4840276226Ssmh int cb_argc; 4841276226Ssmh uint64_t cb_version; 4842276226Ssmh char **cb_argv; 4843168404Spjd} upgrade_cbdata_t; 4844168404Spjd 4845238950Smm#ifdef __FreeBSD__ 4846168404Spjdstatic int 4847212050Spjdis_root_pool(zpool_handle_t *zhp) 4848212050Spjd{ 4849212050Spjd static struct statfs sfs; 4850212050Spjd static char *poolname = NULL; 4851212050Spjd static boolean_t stated = B_FALSE; 4852212050Spjd char *slash; 4853212050Spjd 4854212067Spjd if (!stated) { 4855212050Spjd stated = B_TRUE; 4856212050Spjd if (statfs("/", &sfs) == -1) { 4857212050Spjd (void) fprintf(stderr, 4858212050Spjd "Unable to stat root file system: %s.\n", 4859212050Spjd strerror(errno)); 4860212067Spjd return (0); 4861212050Spjd } 4862212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4863212067Spjd return (0); 4864212050Spjd poolname = sfs.f_mntfromname; 4865212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4866212050Spjd *slash = '\0'; 4867212050Spjd } 4868212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4869212050Spjd} 4870212050Spjd 4871238950Smmstatic void 4872271934Ssmhroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size) 4873271934Ssmh{ 4874238950Smm 4875238950Smm if (poolname[0] == '\0' && is_root_pool(zhp)) 4876238950Smm (void) strlcpy(poolname, zpool_get_name(zhp), size); 4877238950Smm} 4878238950Smm#endif /* FreeBSD */ 4879238950Smm 4880212050Spjdstatic int 4881238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version) 4882238926Smm{ 4883238926Smm int ret; 4884238926Smm nvlist_t *config; 4885238926Smm uint64_t oldversion; 4886238926Smm 4887238926Smm config = zpool_get_config(zhp, NULL); 4888238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4889238926Smm &oldversion) == 0); 4890238926Smm 4891238926Smm assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 4892238926Smm assert(oldversion < version); 4893238926Smm 4894238926Smm ret = zpool_upgrade(zhp, version); 4895238926Smm if (ret != 0) 4896238926Smm return (ret); 4897238926Smm 4898238926Smm if (version >= SPA_VERSION_FEATURES) { 4899238926Smm (void) printf(gettext("Successfully upgraded " 4900238926Smm "'%s' from version %llu to feature flags.\n"), 4901238926Smm zpool_get_name(zhp), oldversion); 4902238926Smm } else { 4903238926Smm (void) printf(gettext("Successfully upgraded " 4904238926Smm "'%s' from version %llu to version %llu.\n"), 4905238926Smm zpool_get_name(zhp), oldversion, version); 4906238926Smm } 4907238926Smm 4908238926Smm return (0); 4909238926Smm} 4910238926Smm 4911238926Smmstatic int 4912238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp) 4913238926Smm{ 4914238926Smm int i, ret, count; 4915238926Smm boolean_t firstff = B_TRUE; 4916238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4917238926Smm 4918238926Smm count = 0; 4919238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4920238926Smm const char *fname = spa_feature_table[i].fi_uname; 4921238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4922238926Smm if (!nvlist_exists(enabled, fguid)) { 4923238926Smm char *propname; 4924238926Smm verify(-1 != asprintf(&propname, "feature@%s", fname)); 4925238926Smm ret = zpool_set_prop(zhp, propname, 4926238926Smm ZFS_FEATURE_ENABLED); 4927238926Smm if (ret != 0) { 4928238926Smm free(propname); 4929238926Smm return (ret); 4930238926Smm } 4931238926Smm count++; 4932238926Smm 4933238926Smm if (firstff) { 4934238926Smm (void) printf(gettext("Enabled the " 4935238926Smm "following features on '%s':\n"), 4936238926Smm zpool_get_name(zhp)); 4937238926Smm firstff = B_FALSE; 4938238926Smm } 4939238926Smm (void) printf(gettext(" %s\n"), fname); 4940238926Smm free(propname); 4941238926Smm } 4942238926Smm } 4943238926Smm 4944238926Smm if (countp != NULL) 4945238926Smm *countp = count; 4946238926Smm return (0); 4947238926Smm} 4948238926Smm 4949238926Smmstatic int 4950168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4951168404Spjd{ 4952168404Spjd upgrade_cbdata_t *cbp = arg; 4953168404Spjd nvlist_t *config; 4954168404Spjd uint64_t version; 4955238926Smm boolean_t printnl = B_FALSE; 4956238926Smm int ret; 4957168404Spjd 4958276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4959276194Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 4960276226Ssmh "currently unavailable.\n\n"), zpool_get_name(zhp)); 4961276226Ssmh cbp->cb_unavail = B_TRUE; 4962276194Ssmh /* Allow iteration to continue. */ 4963276194Ssmh return (0); 4964276194Ssmh } 4965276194Ssmh 4966168404Spjd config = zpool_get_config(zhp, NULL); 4967168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4968168404Spjd &version) == 0); 4969168404Spjd 4970238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4971168404Spjd 4972238926Smm if (version < cbp->cb_version) { 4973238926Smm cbp->cb_first = B_FALSE; 4974238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4975238926Smm if (ret != 0) 4976238926Smm return (ret); 4977238926Smm#ifdef __FreeBSD__ 4978238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4979238950Smm sizeof(cbp->cb_poolname)); 4980271934Ssmh#endif /* __FreeBSD__ */ 4981238926Smm printnl = B_TRUE; 4982238926Smm 4983238926Smm#ifdef illumos 4984238926Smm /* 4985238926Smm * If they did "zpool upgrade -a", then we could 4986238926Smm * be doing ioctls to different pools. We need 4987238926Smm * to log this history once to each pool, and bypass 4988238926Smm * the normal history logging that happens in main(). 4989238926Smm */ 4990238926Smm (void) zpool_log_history(g_zfs, history_str); 4991238926Smm log_history = B_FALSE; 4992238926Smm#endif 4993238926Smm } 4994238926Smm 4995238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4996238926Smm int count; 4997238926Smm ret = upgrade_enable_all(zhp, &count); 4998238926Smm if (ret != 0) 4999238926Smm return (ret); 5000238926Smm 5001238926Smm if (count > 0) { 5002168404Spjd cbp->cb_first = B_FALSE; 5003238926Smm printnl = B_TRUE; 5004271934Ssmh#ifdef __FreeBSD__ 5005271934Ssmh root_pool_upgrade_check(zhp, cbp->cb_poolname, 5006271934Ssmh sizeof(cbp->cb_poolname)); 5007271934Ssmh#endif /* __FreeBSD__ */ 5008248571Smm /* 5009248571Smm * If they did "zpool upgrade -a", then we could 5010248571Smm * be doing ioctls to different pools. We need 5011248571Smm * to log this history once to each pool, and bypass 5012248571Smm * the normal history logging that happens in main(). 5013248571Smm */ 5014248571Smm (void) zpool_log_history(g_zfs, history_str); 5015248571Smm log_history = B_FALSE; 5016168404Spjd } 5017238926Smm } 5018168404Spjd 5019238926Smm if (printnl) { 5020238926Smm (void) printf(gettext("\n")); 5021238926Smm } 5022238926Smm 5023238926Smm return (0); 5024238926Smm} 5025238926Smm 5026238926Smmstatic int 5027276226Ssmhupgrade_list_unavail(zpool_handle_t *zhp, void *arg) 5028276226Ssmh{ 5029276226Ssmh upgrade_cbdata_t *cbp = arg; 5030276226Ssmh 5031276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5032276226Ssmh if (cbp->cb_first) { 5033276226Ssmh (void) fprintf(stderr, gettext("The following pools " 5034276226Ssmh "are unavailable and cannot be upgraded as this " 5035276226Ssmh "time.\n\n")); 5036276226Ssmh (void) fprintf(stderr, gettext("POOL\n")); 5037276226Ssmh (void) fprintf(stderr, gettext("------------\n")); 5038276226Ssmh cbp->cb_first = B_FALSE; 5039276226Ssmh } 5040276226Ssmh (void) printf(gettext("%s\n"), zpool_get_name(zhp)); 5041276226Ssmh cbp->cb_unavail = B_TRUE; 5042276226Ssmh } 5043276226Ssmh return (0); 5044276226Ssmh} 5045276226Ssmh 5046276226Ssmhstatic int 5047238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 5048238926Smm{ 5049238926Smm upgrade_cbdata_t *cbp = arg; 5050238926Smm nvlist_t *config; 5051238926Smm uint64_t version; 5052238926Smm 5053276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5054276226Ssmh /* 5055276226Ssmh * This will have been reported by upgrade_list_unavail so 5056276226Ssmh * just allow iteration to continue. 5057276226Ssmh */ 5058276226Ssmh cbp->cb_unavail = B_TRUE; 5059276226Ssmh return (0); 5060276226Ssmh } 5061276226Ssmh 5062238926Smm config = zpool_get_config(zhp, NULL); 5063238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5064238926Smm &version) == 0); 5065238926Smm 5066238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 5067238926Smm 5068238926Smm if (version < SPA_VERSION_FEATURES) { 5069168404Spjd if (cbp->cb_first) { 5070168404Spjd (void) printf(gettext("The following pools are " 5071238926Smm "formatted with legacy version numbers and can\n" 5072238926Smm "be upgraded to use feature flags. After " 5073238926Smm "being upgraded, these pools\nwill no " 5074238926Smm "longer be accessible by software that does not " 5075238926Smm "support feature\nflags.\n\n")); 5076168404Spjd (void) printf(gettext("VER POOL\n")); 5077168404Spjd (void) printf(gettext("--- ------------\n")); 5078168404Spjd cbp->cb_first = B_FALSE; 5079168404Spjd } 5080168404Spjd 5081168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 5082168404Spjd zpool_get_name(zhp)); 5083168404Spjd } 5084168404Spjd 5085238926Smm return (0); 5086168404Spjd} 5087168404Spjd 5088238926Smmstatic int 5089238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 5090238926Smm{ 5091238926Smm upgrade_cbdata_t *cbp = arg; 5092238926Smm nvlist_t *config; 5093238926Smm uint64_t version; 5094238926Smm 5095276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5096276226Ssmh /* 5097276226Ssmh * This will have been reported by upgrade_list_unavail so 5098276226Ssmh * just allow iteration to continue. 5099276226Ssmh */ 5100276226Ssmh cbp->cb_unavail = B_TRUE; 5101276194Ssmh return (0); 5102276194Ssmh } 5103276194Ssmh 5104238926Smm config = zpool_get_config(zhp, NULL); 5105238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5106238926Smm &version) == 0); 5107238926Smm 5108238926Smm if (version >= SPA_VERSION_FEATURES) { 5109238926Smm int i; 5110238926Smm boolean_t poolfirst = B_TRUE; 5111238926Smm nvlist_t *enabled = zpool_get_features(zhp); 5112238926Smm 5113238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5114238926Smm const char *fguid = spa_feature_table[i].fi_guid; 5115238926Smm const char *fname = spa_feature_table[i].fi_uname; 5116238926Smm if (!nvlist_exists(enabled, fguid)) { 5117238926Smm if (cbp->cb_first) { 5118238926Smm (void) printf(gettext("\nSome " 5119238926Smm "supported features are not " 5120238926Smm "enabled on the following pools. " 5121238926Smm "Once a\nfeature is enabled the " 5122238926Smm "pool may become incompatible with " 5123238926Smm "software\nthat does not support " 5124238926Smm "the feature. See " 5125243014Smm "zpool-features(7) for " 5126238926Smm "details.\n\n")); 5127238926Smm (void) printf(gettext("POOL " 5128238926Smm "FEATURE\n")); 5129238926Smm (void) printf(gettext("------" 5130238926Smm "---------\n")); 5131238926Smm cbp->cb_first = B_FALSE; 5132238926Smm } 5133238926Smm 5134238926Smm if (poolfirst) { 5135238926Smm (void) printf(gettext("%s\n"), 5136238926Smm zpool_get_name(zhp)); 5137238926Smm poolfirst = B_FALSE; 5138238926Smm } 5139238926Smm 5140238926Smm (void) printf(gettext(" %s\n"), fname); 5141238926Smm } 5142238926Smm } 5143238926Smm } 5144238926Smm 5145238926Smm return (0); 5146238926Smm} 5147238926Smm 5148168404Spjd/* ARGSUSED */ 5149168404Spjdstatic int 5150168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 5151168404Spjd{ 5152238926Smm boolean_t printnl = B_FALSE; 5153185029Spjd upgrade_cbdata_t *cbp = data; 5154185029Spjd uint64_t cur_version; 5155168404Spjd int ret; 5156168404Spjd 5157276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5158276226Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 5159276226Ssmh "is currently unavailable.\n\n"), zpool_get_name(zhp)); 5160276226Ssmh cbp->cb_unavail = B_TRUE; 5161276226Ssmh return (1); 5162276226Ssmh } 5163276226Ssmh 5164185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 5165185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 5166185029Spjd "Pool 'log' must be renamed using export and import" 5167276226Ssmh " to upgrade.\n\n")); 5168185029Spjd return (1); 5169185029Spjd } 5170168404Spjd 5171185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5172185029Spjd if (cur_version > cbp->cb_version) { 5173168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 5174238926Smm "using more current version '%llu'.\n\n"), 5175185029Spjd zpool_get_name(zhp), cur_version); 5176185029Spjd return (0); 5177185029Spjd } 5178238926Smm 5179238926Smm if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 5180185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 5181238926Smm "using version %llu.\n\n"), zpool_get_name(zhp), 5182238926Smm cbp->cb_version); 5183168404Spjd return (0); 5184168404Spjd } 5185168404Spjd 5186238926Smm if (cur_version != cbp->cb_version) { 5187238926Smm printnl = B_TRUE; 5188238926Smm ret = upgrade_version(zhp, cbp->cb_version); 5189238950Smm if (ret != 0) 5190238950Smm return (ret); 5191238926Smm#ifdef __FreeBSD__ 5192238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 5193238950Smm sizeof(cbp->cb_poolname)); 5194271934Ssmh#endif /* __FreeBSD__ */ 5195238926Smm } 5196168404Spjd 5197238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 5198238926Smm int count = 0; 5199238926Smm ret = upgrade_enable_all(zhp, &count); 5200238926Smm if (ret != 0) 5201238926Smm return (ret); 5202238926Smm 5203238926Smm if (count != 0) { 5204238926Smm printnl = B_TRUE; 5205238950Smm#ifdef __FreeBSD__ 5206238951Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 5207238951Smm sizeof(cbp->cb_poolname)); 5208238950Smm#endif /* __FreeBSD __*/ 5209238926Smm } else if (cur_version == SPA_VERSION) { 5210238926Smm (void) printf(gettext("Pool '%s' already has all " 5211276226Ssmh "supported features enabled.\n\n"), 5212238926Smm zpool_get_name(zhp)); 5213238926Smm } 5214168404Spjd } 5215168404Spjd 5216238926Smm if (printnl) { 5217238926Smm (void) printf(gettext("\n")); 5218238926Smm } 5219238926Smm 5220238926Smm return (0); 5221168404Spjd} 5222168404Spjd 5223168404Spjd/* 5224168404Spjd * zpool upgrade 5225168404Spjd * zpool upgrade -v 5226185029Spjd * zpool upgrade [-V version] <-a | pool ...> 5227168404Spjd * 5228168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 5229168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 5230168404Spjd * upgrade all pools. 5231168404Spjd */ 5232168404Spjdint 5233168404Spjdzpool_do_upgrade(int argc, char **argv) 5234168404Spjd{ 5235168404Spjd int c; 5236168404Spjd upgrade_cbdata_t cb = { 0 }; 5237168404Spjd int ret = 0; 5238168404Spjd boolean_t showversions = B_FALSE; 5239238926Smm boolean_t upgradeall = B_FALSE; 5240185029Spjd char *end; 5241168404Spjd 5242185029Spjd 5243168404Spjd /* check options */ 5244219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 5245168404Spjd switch (c) { 5246168404Spjd case 'a': 5247238926Smm upgradeall = B_TRUE; 5248168404Spjd break; 5249168404Spjd case 'v': 5250168404Spjd showversions = B_TRUE; 5251168404Spjd break; 5252185029Spjd case 'V': 5253185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 5254236884Smm if (*end != '\0' || 5255236884Smm !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 5256185029Spjd (void) fprintf(stderr, 5257185029Spjd gettext("invalid version '%s'\n"), optarg); 5258185029Spjd usage(B_FALSE); 5259185029Spjd } 5260185029Spjd break; 5261219089Spjd case ':': 5262219089Spjd (void) fprintf(stderr, gettext("missing argument for " 5263219089Spjd "'%c' option\n"), optopt); 5264219089Spjd usage(B_FALSE); 5265219089Spjd break; 5266168404Spjd case '?': 5267168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5268168404Spjd optopt); 5269168404Spjd usage(B_FALSE); 5270168404Spjd } 5271168404Spjd } 5272168404Spjd 5273168404Spjd cb.cb_argc = argc; 5274168404Spjd cb.cb_argv = argv; 5275168404Spjd argc -= optind; 5276168404Spjd argv += optind; 5277168404Spjd 5278185029Spjd if (cb.cb_version == 0) { 5279185029Spjd cb.cb_version = SPA_VERSION; 5280238926Smm } else if (!upgradeall && argc == 0) { 5281185029Spjd (void) fprintf(stderr, gettext("-V option is " 5282185029Spjd "incompatible with other arguments\n")); 5283185029Spjd usage(B_FALSE); 5284185029Spjd } 5285185029Spjd 5286168404Spjd if (showversions) { 5287238926Smm if (upgradeall || argc != 0) { 5288168404Spjd (void) fprintf(stderr, gettext("-v option is " 5289168404Spjd "incompatible with other arguments\n")); 5290168404Spjd usage(B_FALSE); 5291168404Spjd } 5292238926Smm } else if (upgradeall) { 5293168404Spjd if (argc != 0) { 5294185029Spjd (void) fprintf(stderr, gettext("-a option should not " 5295185029Spjd "be used along with a pool name\n")); 5296168404Spjd usage(B_FALSE); 5297168404Spjd } 5298168404Spjd } 5299168404Spjd 5300236884Smm (void) printf(gettext("This system supports ZFS pool feature " 5301236884Smm "flags.\n\n")); 5302168404Spjd if (showversions) { 5303238926Smm int i; 5304238926Smm 5305238926Smm (void) printf(gettext("The following features are " 5306168404Spjd "supported:\n\n")); 5307238926Smm (void) printf(gettext("FEAT DESCRIPTION\n")); 5308238926Smm (void) printf("----------------------------------------------" 5309238926Smm "---------------\n"); 5310238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5311238926Smm zfeature_info_t *fi = &spa_feature_table[i]; 5312286708Smav const char *ro = 5313286708Smav (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ? 5314238926Smm " (read-only compatible)" : ""; 5315238926Smm 5316238926Smm (void) printf("%-37s%s\n", fi->fi_uname, ro); 5317238926Smm (void) printf(" %s\n", fi->fi_desc); 5318238926Smm } 5319238926Smm (void) printf("\n"); 5320238926Smm 5321238926Smm (void) printf(gettext("The following legacy versions are also " 5322238926Smm "supported:\n\n")); 5323168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 5324168404Spjd (void) printf("--- -----------------------------------------" 5325168404Spjd "---------------\n"); 5326168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 5327168404Spjd (void) printf(gettext(" 2 Ditto blocks " 5328168404Spjd "(replicated metadata)\n")); 5329168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 5330168404Spjd "RAID-Z\n")); 5331168404Spjd (void) printf(gettext(" 4 zpool history\n")); 5332168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 5333168404Spjd "algorithm\n")); 5334185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 5335185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 5336185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 5337185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 5338185029Spjd "properties\n")); 5339185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 5340185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 5341185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 5342185029Spjd (void) printf(gettext(" 13 snapused property\n")); 5343209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 5344209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 5345219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 5346219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 5347219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 5348219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 5349219089Spjd (void) printf(gettext(" 20 Compression using zle " 5350219089Spjd "(zero-length encoding)\n")); 5351219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 5352219089Spjd (void) printf(gettext(" 22 Received properties\n")); 5353219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 5354219089Spjd (void) printf(gettext(" 24 System attributes\n")); 5355219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 5356219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 5357219089Spjd "performance\n")); 5358219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 5359219089Spjd "performance\n")); 5360219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 5361219089Spjd (void) printf(gettext("\nFor more information on a particular " 5362219089Spjd "version, including supported releases,\n")); 5363219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 5364238926Smm } else if (argc == 0 && upgradeall) { 5365238926Smm cb.cb_first = B_TRUE; 5366168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 5367238926Smm if (ret == 0 && cb.cb_first) { 5368238926Smm if (cb.cb_version == SPA_VERSION) { 5369276226Ssmh (void) printf(gettext("All %spools are already " 5370276226Ssmh "formatted using feature flags.\n\n"), 5371276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5372276226Ssmh (void) printf(gettext("Every %sfeature flags " 5373238926Smm "pool already has all supported features " 5374276226Ssmh "enabled.\n"), 5375276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5376238926Smm } else { 5377238926Smm (void) printf(gettext("All pools are already " 5378238926Smm "formatted with version %llu or higher.\n"), 5379238926Smm cb.cb_version); 5380168404Spjd } 5381168404Spjd } 5382238926Smm } else if (argc == 0) { 5383238926Smm cb.cb_first = B_TRUE; 5384276226Ssmh ret = zpool_iter(g_zfs, upgrade_list_unavail, &cb); 5385276226Ssmh assert(ret == 0); 5386276226Ssmh 5387276226Ssmh if (!cb.cb_first) { 5388276226Ssmh (void) fprintf(stderr, "\n"); 5389276226Ssmh } 5390276226Ssmh 5391276226Ssmh cb.cb_first = B_TRUE; 5392238926Smm ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 5393238926Smm assert(ret == 0); 5394168404Spjd 5395238926Smm if (cb.cb_first) { 5396276226Ssmh (void) printf(gettext("All %spools are formatted using " 5397276226Ssmh "feature flags.\n\n"), cb.cb_unavail ? 5398276226Ssmh gettext("available ") : ""); 5399238926Smm } else { 5400238926Smm (void) printf(gettext("\nUse 'zpool upgrade -v' " 5401238926Smm "for a list of available legacy versions.\n")); 5402168404Spjd } 5403238926Smm 5404238926Smm cb.cb_first = B_TRUE; 5405238926Smm ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 5406238926Smm assert(ret == 0); 5407238926Smm 5408238926Smm if (cb.cb_first) { 5409276226Ssmh (void) printf(gettext("Every %sfeature flags pool has " 5410276226Ssmh "all supported features enabled.\n"), 5411276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5412238926Smm } else { 5413238926Smm (void) printf(gettext("\n")); 5414238926Smm } 5415168404Spjd } else { 5416276226Ssmh ret = for_each_pool(argc, argv, B_TRUE, NULL, 5417168404Spjd upgrade_one, &cb); 5418168404Spjd } 5419168404Spjd 5420212050Spjd if (cb.cb_poolname[0] != '\0') { 5421212050Spjd (void) printf( 5422212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 5423212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 5424212050Spjd "the following command will do it:\n" 5425212050Spjd "\n" 5426212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 5427212050Spjd cb.cb_poolname); 5428212050Spjd } 5429212050Spjd 5430168404Spjd return (ret); 5431168404Spjd} 5432168404Spjd 5433185029Spjdtypedef struct hist_cbdata { 5434185029Spjd boolean_t first; 5435248571Smm boolean_t longfmt; 5436248571Smm boolean_t internal; 5437185029Spjd} hist_cbdata_t; 5438185029Spjd 5439168404Spjd/* 5440168404Spjd * Print out the command history for a specific pool. 5441168404Spjd */ 5442168404Spjdstatic int 5443168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 5444168404Spjd{ 5445168404Spjd nvlist_t *nvhis; 5446168404Spjd nvlist_t **records; 5447168404Spjd uint_t numrecords; 5448168404Spjd int ret, i; 5449185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 5450168404Spjd 5451185029Spjd cb->first = B_FALSE; 5452168404Spjd 5453168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 5454168404Spjd 5455168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 5456168404Spjd return (ret); 5457168404Spjd 5458168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 5459168404Spjd &records, &numrecords) == 0); 5460168404Spjd for (i = 0; i < numrecords; i++) { 5461248571Smm nvlist_t *rec = records[i]; 5462248571Smm char tbuf[30] = ""; 5463185029Spjd 5464248571Smm if (nvlist_exists(rec, ZPOOL_HIST_TIME)) { 5465248571Smm time_t tsec; 5466248571Smm struct tm t; 5467185029Spjd 5468248571Smm tsec = fnvlist_lookup_uint64(records[i], 5469248571Smm ZPOOL_HIST_TIME); 5470248571Smm (void) localtime_r(&tsec, &t); 5471248571Smm (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 5472248571Smm } 5473248571Smm 5474248571Smm if (nvlist_exists(rec, ZPOOL_HIST_CMD)) { 5475248571Smm (void) printf("%s %s", tbuf, 5476248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_CMD)); 5477248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) { 5478248571Smm int ievent = 5479248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT); 5480248571Smm if (!cb->internal) 5481185029Spjd continue; 5482248571Smm if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) { 5483248571Smm (void) printf("%s unrecognized record:\n", 5484248571Smm tbuf); 5485248571Smm dump_nvlist(rec, 4); 5486185029Spjd continue; 5487248571Smm } 5488248571Smm (void) printf("%s [internal %s txg:%lld] %s", tbuf, 5489248571Smm zfs_history_event_names[ievent], 5490248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5491248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR)); 5492248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) { 5493248571Smm if (!cb->internal) 5494248571Smm continue; 5495248571Smm (void) printf("%s [txg:%lld] %s", tbuf, 5496248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5497248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME)); 5498248571Smm if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) { 5499248571Smm (void) printf(" %s (%llu)", 5500248571Smm fnvlist_lookup_string(rec, 5501248571Smm ZPOOL_HIST_DSNAME), 5502248571Smm fnvlist_lookup_uint64(rec, 5503248571Smm ZPOOL_HIST_DSID)); 5504248571Smm } 5505248571Smm (void) printf(" %s", fnvlist_lookup_string(rec, 5506248571Smm ZPOOL_HIST_INT_STR)); 5507248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) { 5508248571Smm if (!cb->internal) 5509248571Smm continue; 5510248571Smm (void) printf("%s ioctl %s\n", tbuf, 5511248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL)); 5512248571Smm if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) { 5513248571Smm (void) printf(" input:\n"); 5514248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5515248571Smm ZPOOL_HIST_INPUT_NVL), 8); 5516248571Smm } 5517248571Smm if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) { 5518248571Smm (void) printf(" output:\n"); 5519248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5520248571Smm ZPOOL_HIST_OUTPUT_NVL), 8); 5521248571Smm } 5522325534Savg if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) { 5523325534Savg (void) printf(" errno: %lld\n", 5524325534Savg fnvlist_lookup_int64(rec, 5525325534Savg ZPOOL_HIST_ERRNO)); 5526325534Savg } 5527248571Smm } else { 5528248571Smm if (!cb->internal) 5529248571Smm continue; 5530248571Smm (void) printf("%s unrecognized record:\n", tbuf); 5531248571Smm dump_nvlist(rec, 4); 5532168404Spjd } 5533185029Spjd 5534185029Spjd if (!cb->longfmt) { 5535185029Spjd (void) printf("\n"); 5536185029Spjd continue; 5537185029Spjd } 5538185029Spjd (void) printf(" ["); 5539248571Smm if (nvlist_exists(rec, ZPOOL_HIST_WHO)) { 5540248571Smm uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO); 5541248571Smm struct passwd *pwd = getpwuid(who); 5542248571Smm (void) printf("user %d ", (int)who); 5543248571Smm if (pwd != NULL) 5544248571Smm (void) printf("(%s) ", pwd->pw_name); 5545185029Spjd } 5546248571Smm if (nvlist_exists(rec, ZPOOL_HIST_HOST)) { 5547248571Smm (void) printf("on %s", 5548248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_HOST)); 5549185029Spjd } 5550248571Smm if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) { 5551248571Smm (void) printf(":%s", 5552248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE)); 5553185029Spjd } 5554185029Spjd (void) printf("]"); 5555185029Spjd (void) printf("\n"); 5556168404Spjd } 5557168404Spjd (void) printf("\n"); 5558168404Spjd nvlist_free(nvhis); 5559168404Spjd 5560168404Spjd return (ret); 5561168404Spjd} 5562168404Spjd 5563168404Spjd/* 5564168404Spjd * zpool history <pool> 5565168404Spjd * 5566168404Spjd * Displays the history of commands that modified pools. 5567168404Spjd */ 5568168404Spjdint 5569168404Spjdzpool_do_history(int argc, char **argv) 5570168404Spjd{ 5571185029Spjd hist_cbdata_t cbdata = { 0 }; 5572168404Spjd int ret; 5573185029Spjd int c; 5574168404Spjd 5575185029Spjd cbdata.first = B_TRUE; 5576185029Spjd /* check options */ 5577185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 5578185029Spjd switch (c) { 5579185029Spjd case 'l': 5580248571Smm cbdata.longfmt = B_TRUE; 5581185029Spjd break; 5582185029Spjd case 'i': 5583248571Smm cbdata.internal = B_TRUE; 5584185029Spjd break; 5585185029Spjd case '?': 5586185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5587185029Spjd optopt); 5588185029Spjd usage(B_FALSE); 5589185029Spjd } 5590185029Spjd } 5591168404Spjd argc -= optind; 5592168404Spjd argv += optind; 5593168404Spjd 5594168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 5595185029Spjd &cbdata); 5596168404Spjd 5597185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 5598168404Spjd (void) printf(gettext("no pools available\n")); 5599168404Spjd return (0); 5600168404Spjd } 5601168404Spjd 5602168404Spjd return (ret); 5603168404Spjd} 5604168404Spjd 5605168404Spjdstatic int 5606168404Spjdget_callback(zpool_handle_t *zhp, void *data) 5607168404Spjd{ 5608185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 5609168404Spjd char value[MAXNAMELEN]; 5610185029Spjd zprop_source_t srctype; 5611185029Spjd zprop_list_t *pl; 5612168404Spjd 5613168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 5614168404Spjd 5615168404Spjd /* 5616185029Spjd * Skip the special fake placeholder. This will also skip 5617185029Spjd * over the name property when 'all' is specified. 5618168404Spjd */ 5619185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 5620168404Spjd pl == cbp->cb_proplist) 5621168404Spjd continue; 5622168404Spjd 5623236884Smm if (pl->pl_prop == ZPROP_INVAL && 5624236884Smm (zpool_prop_feature(pl->pl_user_prop) || 5625236884Smm zpool_prop_unsupported(pl->pl_user_prop))) { 5626236884Smm srctype = ZPROP_SRC_LOCAL; 5627168404Spjd 5628236884Smm if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 5629236884Smm value, sizeof (value)) == 0) { 5630236884Smm zprop_print_one_property(zpool_get_name(zhp), 5631236884Smm cbp, pl->pl_user_prop, value, srctype, 5632236884Smm NULL, NULL); 5633236884Smm } 5634236884Smm } else { 5635236884Smm if (zpool_get_prop(zhp, pl->pl_prop, value, 5636263889Sdelphij sizeof (value), &srctype, cbp->cb_literal) != 0) 5637236884Smm continue; 5638236884Smm 5639236884Smm zprop_print_one_property(zpool_get_name(zhp), cbp, 5640236884Smm zpool_prop_to_name(pl->pl_prop), value, srctype, 5641236884Smm NULL, NULL); 5642236884Smm } 5643168404Spjd } 5644168404Spjd return (0); 5645168404Spjd} 5646168404Spjd 5647263889Sdelphij/* 5648263889Sdelphij * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ... 5649263889Sdelphij * 5650263889Sdelphij * -H Scripted mode. Don't display headers, and separate properties 5651263889Sdelphij * by a single tab. 5652263889Sdelphij * -o List of columns to display. Defaults to 5653263889Sdelphij * "name,property,value,source". 5654263889Sdelphij * -p Diplay values in parsable (exact) format. 5655263889Sdelphij * 5656263889Sdelphij * Get properties of pools in the system. Output space statistics 5657263889Sdelphij * for each one as well as other attributes. 5658263889Sdelphij */ 5659168404Spjdint 5660168404Spjdzpool_do_get(int argc, char **argv) 5661168404Spjd{ 5662185029Spjd zprop_get_cbdata_t cb = { 0 }; 5663185029Spjd zprop_list_t fake_name = { 0 }; 5664168404Spjd int ret; 5665263889Sdelphij int c, i; 5666263889Sdelphij char *value; 5667168404Spjd 5668263889Sdelphij cb.cb_first = B_TRUE; 5669168404Spjd 5670263889Sdelphij /* 5671263889Sdelphij * Set up default columns and sources. 5672263889Sdelphij */ 5673185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 5674168404Spjd cb.cb_columns[0] = GET_COL_NAME; 5675168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 5676168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 5677168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 5678185029Spjd cb.cb_type = ZFS_TYPE_POOL; 5679168404Spjd 5680263889Sdelphij /* check options */ 5681263889Sdelphij while ((c = getopt(argc, argv, ":Hpo:")) != -1) { 5682263889Sdelphij switch (c) { 5683263889Sdelphij case 'p': 5684263889Sdelphij cb.cb_literal = B_TRUE; 5685263889Sdelphij break; 5686263889Sdelphij case 'H': 5687263889Sdelphij cb.cb_scripted = B_TRUE; 5688263889Sdelphij break; 5689263889Sdelphij case 'o': 5690263889Sdelphij bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 5691263889Sdelphij i = 0; 5692263889Sdelphij while (*optarg != '\0') { 5693263889Sdelphij static char *col_subopts[] = 5694263889Sdelphij { "name", "property", "value", "source", 5695263889Sdelphij "all", NULL }; 5696263889Sdelphij 5697263889Sdelphij if (i == ZFS_GET_NCOLS) { 5698263889Sdelphij (void) fprintf(stderr, gettext("too " 5699263889Sdelphij "many fields given to -o " 5700263889Sdelphij "option\n")); 5701263889Sdelphij usage(B_FALSE); 5702263889Sdelphij } 5703263889Sdelphij 5704263889Sdelphij switch (getsubopt(&optarg, col_subopts, 5705263889Sdelphij &value)) { 5706263889Sdelphij case 0: 5707263889Sdelphij cb.cb_columns[i++] = GET_COL_NAME; 5708263889Sdelphij break; 5709263889Sdelphij case 1: 5710263889Sdelphij cb.cb_columns[i++] = GET_COL_PROPERTY; 5711263889Sdelphij break; 5712263889Sdelphij case 2: 5713263889Sdelphij cb.cb_columns[i++] = GET_COL_VALUE; 5714263889Sdelphij break; 5715263889Sdelphij case 3: 5716263889Sdelphij cb.cb_columns[i++] = GET_COL_SOURCE; 5717263889Sdelphij break; 5718263889Sdelphij case 4: 5719263889Sdelphij if (i > 0) { 5720263889Sdelphij (void) fprintf(stderr, 5721263889Sdelphij gettext("\"all\" conflicts " 5722263889Sdelphij "with specific fields " 5723263889Sdelphij "given to -o option\n")); 5724263889Sdelphij usage(B_FALSE); 5725263889Sdelphij } 5726263889Sdelphij cb.cb_columns[0] = GET_COL_NAME; 5727263889Sdelphij cb.cb_columns[1] = GET_COL_PROPERTY; 5728263889Sdelphij cb.cb_columns[2] = GET_COL_VALUE; 5729263889Sdelphij cb.cb_columns[3] = GET_COL_SOURCE; 5730263889Sdelphij i = ZFS_GET_NCOLS; 5731263889Sdelphij break; 5732263889Sdelphij default: 5733263889Sdelphij (void) fprintf(stderr, 5734263889Sdelphij gettext("invalid column name " 5735295844Sdim "'%s'\n"), suboptarg); 5736263889Sdelphij usage(B_FALSE); 5737263889Sdelphij } 5738263889Sdelphij } 5739263889Sdelphij break; 5740263889Sdelphij case '?': 5741263889Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5742263889Sdelphij optopt); 5743263889Sdelphij usage(B_FALSE); 5744263889Sdelphij } 5745263889Sdelphij } 5746263889Sdelphij 5747263889Sdelphij argc -= optind; 5748263889Sdelphij argv += optind; 5749263889Sdelphij 5750263889Sdelphij if (argc < 1) { 5751263889Sdelphij (void) fprintf(stderr, gettext("missing property " 5752263889Sdelphij "argument\n")); 5753263889Sdelphij usage(B_FALSE); 5754263889Sdelphij } 5755263889Sdelphij 5756263889Sdelphij if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, 5757185029Spjd ZFS_TYPE_POOL) != 0) 5758168404Spjd usage(B_FALSE); 5759168404Spjd 5760263889Sdelphij argc--; 5761263889Sdelphij argv++; 5762263889Sdelphij 5763168404Spjd if (cb.cb_proplist != NULL) { 5764185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 5765168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 5766168404Spjd fake_name.pl_next = cb.cb_proplist; 5767168404Spjd cb.cb_proplist = &fake_name; 5768168404Spjd } 5769168404Spjd 5770263889Sdelphij ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 5771168404Spjd get_callback, &cb); 5772168404Spjd 5773168404Spjd if (cb.cb_proplist == &fake_name) 5774185029Spjd zprop_free_list(fake_name.pl_next); 5775168404Spjd else 5776185029Spjd zprop_free_list(cb.cb_proplist); 5777168404Spjd 5778168404Spjd return (ret); 5779168404Spjd} 5780168404Spjd 5781168404Spjdtypedef struct set_cbdata { 5782168404Spjd char *cb_propname; 5783168404Spjd char *cb_value; 5784168404Spjd boolean_t cb_any_successful; 5785168404Spjd} set_cbdata_t; 5786168404Spjd 5787168404Spjdint 5788168404Spjdset_callback(zpool_handle_t *zhp, void *data) 5789168404Spjd{ 5790168404Spjd int error; 5791168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 5792168404Spjd 5793168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 5794168404Spjd 5795168404Spjd if (!error) 5796168404Spjd cb->cb_any_successful = B_TRUE; 5797168404Spjd 5798168404Spjd return (error); 5799168404Spjd} 5800168404Spjd 5801168404Spjdint 5802168404Spjdzpool_do_set(int argc, char **argv) 5803168404Spjd{ 5804168404Spjd set_cbdata_t cb = { 0 }; 5805168404Spjd int error; 5806168404Spjd 5807168404Spjd if (argc > 1 && argv[1][0] == '-') { 5808168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5809168404Spjd argv[1][1]); 5810168404Spjd usage(B_FALSE); 5811168404Spjd } 5812168404Spjd 5813168404Spjd if (argc < 2) { 5814168404Spjd (void) fprintf(stderr, gettext("missing property=value " 5815168404Spjd "argument\n")); 5816168404Spjd usage(B_FALSE); 5817168404Spjd } 5818168404Spjd 5819168404Spjd if (argc < 3) { 5820168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 5821168404Spjd usage(B_FALSE); 5822168404Spjd } 5823168404Spjd 5824168404Spjd if (argc > 3) { 5825168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 5826168404Spjd usage(B_FALSE); 5827168404Spjd } 5828168404Spjd 5829168404Spjd cb.cb_propname = argv[1]; 5830168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 5831168404Spjd if (cb.cb_value == NULL) { 5832168404Spjd (void) fprintf(stderr, gettext("missing value in " 5833168404Spjd "property=value argument\n")); 5834168404Spjd usage(B_FALSE); 5835168404Spjd } 5836168404Spjd 5837168404Spjd *(cb.cb_value) = '\0'; 5838168404Spjd cb.cb_value++; 5839168404Spjd 5840168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 5841168404Spjd set_callback, &cb); 5842168404Spjd 5843168404Spjd return (error); 5844168404Spjd} 5845168404Spjd 5846168404Spjdstatic int 5847168404Spjdfind_command_idx(char *command, int *idx) 5848168404Spjd{ 5849168404Spjd int i; 5850168404Spjd 5851168404Spjd for (i = 0; i < NCOMMAND; i++) { 5852168404Spjd if (command_table[i].name == NULL) 5853168404Spjd continue; 5854168404Spjd 5855168404Spjd if (strcmp(command, command_table[i].name) == 0) { 5856168404Spjd *idx = i; 5857168404Spjd return (0); 5858168404Spjd } 5859168404Spjd } 5860168404Spjd return (1); 5861168404Spjd} 5862168404Spjd 5863168404Spjdint 5864168404Spjdmain(int argc, char **argv) 5865168404Spjd{ 5866296537Smav int ret = 0; 5867168404Spjd int i; 5868168404Spjd char *cmdname; 5869168404Spjd 5870168404Spjd (void) setlocale(LC_ALL, ""); 5871168404Spjd (void) textdomain(TEXT_DOMAIN); 5872168404Spjd 5873168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 5874168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 5875168404Spjd "initialize ZFS library\n")); 5876168404Spjd return (1); 5877168404Spjd } 5878168404Spjd 5879168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 5880168404Spjd 5881168404Spjd opterr = 0; 5882168404Spjd 5883168404Spjd /* 5884168404Spjd * Make sure the user has specified some command. 5885168404Spjd */ 5886168404Spjd if (argc < 2) { 5887168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 5888168404Spjd usage(B_FALSE); 5889168404Spjd } 5890168404Spjd 5891168404Spjd cmdname = argv[1]; 5892168404Spjd 5893168404Spjd /* 5894168404Spjd * Special case '-?' 5895168404Spjd */ 5896168404Spjd if (strcmp(cmdname, "-?") == 0) 5897168404Spjd usage(B_TRUE); 5898168404Spjd 5899248571Smm zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); 5900185029Spjd 5901168404Spjd /* 5902168404Spjd * Run the appropriate command. 5903168404Spjd */ 5904168404Spjd if (find_command_idx(cmdname, &i) == 0) { 5905168404Spjd current_command = &command_table[i]; 5906168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 5907185029Spjd } else if (strchr(cmdname, '=')) { 5908185029Spjd verify(find_command_idx("set", &i) == 0); 5909185029Spjd current_command = &command_table[i]; 5910185029Spjd ret = command_table[i].func(argc, argv); 5911185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 5912185029Spjd /* 5913185029Spjd * 'freeze' is a vile debugging abomination, so we treat 5914185029Spjd * it as such. 5915185029Spjd */ 5916252059Ssmh zfs_cmd_t zc = { 0 }; 5917252059Ssmh (void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name)); 5918252059Ssmh return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc)); 5919185029Spjd } else { 5920168404Spjd (void) fprintf(stderr, gettext("unrecognized " 5921168404Spjd "command '%s'\n"), cmdname); 5922168404Spjd usage(B_FALSE); 5923168404Spjd } 5924168404Spjd 5925248571Smm if (ret == 0 && log_history) 5926248571Smm (void) zpool_log_history(g_zfs, history_str); 5927248571Smm 5928168404Spjd libzfs_fini(g_zfs); 5929168404Spjd 5930168404Spjd /* 5931168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 5932168404Spjd * for the purposes of running ::findleaks. 5933168404Spjd */ 5934168404Spjd if (getenv("ZFS_ABORT") != NULL) { 5935168404Spjd (void) printf("dumping core by request\n"); 5936168404Spjd abort(); 5937168404Spjd } 5938168404Spjd 5939168404Spjd return (ret); 5940168404Spjd} 5941