zpool_main.c revision 236155
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24227497Smm * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 25236155Smm * Copyright (c) 2012 by Delphix. All rights reserved. 26236145Smm * Copyright (c) 2012 by Frederik Wessels. All rights reserved. 27236155Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 28168404Spjd */ 29168404Spjd 30168404Spjd#include <solaris.h> 31168404Spjd#include <assert.h> 32168404Spjd#include <ctype.h> 33168404Spjd#include <dirent.h> 34168404Spjd#include <errno.h> 35168404Spjd#include <fcntl.h> 36168404Spjd#include <libgen.h> 37168404Spjd#include <libintl.h> 38168404Spjd#include <libuutil.h> 39168404Spjd#include <locale.h> 40168404Spjd#include <stdio.h> 41168404Spjd#include <stdlib.h> 42168404Spjd#include <string.h> 43168404Spjd#include <strings.h> 44168404Spjd#include <unistd.h> 45168404Spjd#include <priv.h> 46185029Spjd#include <pwd.h> 47185029Spjd#include <zone.h> 48168404Spjd#include <sys/time.h> 49236155Smm#include <zfs_prop.h> 50168404Spjd#include <sys/fs/zfs.h> 51168404Spjd#include <sys/stat.h> 52168404Spjd 53168404Spjd#include <libzfs.h> 54168404Spjd 55168404Spjd#include "zpool_util.h" 56185029Spjd#include "zfs_comutil.h" 57168404Spjd 58219089Spjd#include "statcommon.h" 59219089Spjd 60168404Spjdstatic int zpool_do_create(int, char **); 61168404Spjdstatic int zpool_do_destroy(int, char **); 62168404Spjd 63168404Spjdstatic int zpool_do_add(int, char **); 64168404Spjdstatic int zpool_do_remove(int, char **); 65224171Sgibbsstatic int zpool_do_labelclear(int, char **); 66168404Spjd 67168404Spjdstatic int zpool_do_list(int, char **); 68168404Spjdstatic int zpool_do_iostat(int, char **); 69168404Spjdstatic int zpool_do_status(int, char **); 70168404Spjd 71168404Spjdstatic int zpool_do_online(int, char **); 72168404Spjdstatic int zpool_do_offline(int, char **); 73168404Spjdstatic int zpool_do_clear(int, char **); 74236155Smmstatic int zpool_do_reopen(int, char **); 75168404Spjd 76228103Smmstatic int zpool_do_reguid(int, char **); 77228103Smm 78168404Spjdstatic int zpool_do_attach(int, char **); 79168404Spjdstatic int zpool_do_detach(int, char **); 80168404Spjdstatic int zpool_do_replace(int, char **); 81219089Spjdstatic int zpool_do_split(int, char **); 82168404Spjd 83168404Spjdstatic int zpool_do_scrub(int, char **); 84168404Spjd 85168404Spjdstatic int zpool_do_import(int, char **); 86168404Spjdstatic int zpool_do_export(int, char **); 87168404Spjd 88168404Spjdstatic int zpool_do_upgrade(int, char **); 89168404Spjd 90168404Spjdstatic int zpool_do_history(int, char **); 91168404Spjd 92168404Spjdstatic int zpool_do_get(int, char **); 93168404Spjdstatic int zpool_do_set(int, char **); 94168404Spjd 95168404Spjd/* 96168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 97168404Spjd * debugging facilities. 98168404Spjd */ 99185029Spjd 100185029Spjd#ifdef DEBUG 101168404Spjdconst char * 102168404Spjd_umem_debug_init(void) 103168404Spjd{ 104168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 105168404Spjd} 106168404Spjd 107168404Spjdconst char * 108168404Spjd_umem_logging_init(void) 109168404Spjd{ 110168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 111168404Spjd} 112185029Spjd#endif 113168404Spjd 114168404Spjdtypedef enum { 115168404Spjd HELP_ADD, 116168404Spjd HELP_ATTACH, 117168404Spjd HELP_CLEAR, 118168404Spjd HELP_CREATE, 119168404Spjd HELP_DESTROY, 120168404Spjd HELP_DETACH, 121168404Spjd HELP_EXPORT, 122168404Spjd HELP_HISTORY, 123168404Spjd HELP_IMPORT, 124168404Spjd HELP_IOSTAT, 125224171Sgibbs HELP_LABELCLEAR, 126168404Spjd HELP_LIST, 127168404Spjd HELP_OFFLINE, 128168404Spjd HELP_ONLINE, 129168404Spjd HELP_REPLACE, 130168404Spjd HELP_REMOVE, 131168404Spjd HELP_SCRUB, 132168404Spjd HELP_STATUS, 133168404Spjd HELP_UPGRADE, 134168404Spjd HELP_GET, 135219089Spjd HELP_SET, 136228103Smm HELP_SPLIT, 137236155Smm HELP_REGUID, 138236155Smm HELP_REOPEN 139168404Spjd} zpool_help_t; 140168404Spjd 141168404Spjd 142168404Spjdtypedef struct zpool_command { 143168404Spjd const char *name; 144168404Spjd int (*func)(int, char **); 145168404Spjd zpool_help_t usage; 146168404Spjd} zpool_command_t; 147168404Spjd 148168404Spjd/* 149168404Spjd * Master command table. Each ZFS command has a name, associated function, and 150168404Spjd * usage message. The usage messages need to be internationalized, so we have 151168404Spjd * to have a function to return the usage message based on a command index. 152168404Spjd * 153168404Spjd * These commands are organized according to how they are displayed in the usage 154168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 155168404Spjd * the generic usage message. 156168404Spjd */ 157168404Spjdstatic zpool_command_t command_table[] = { 158168404Spjd { "create", zpool_do_create, HELP_CREATE }, 159168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 160168404Spjd { NULL }, 161168404Spjd { "add", zpool_do_add, HELP_ADD }, 162168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 163168404Spjd { NULL }, 164224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 165224171Sgibbs { NULL }, 166168404Spjd { "list", zpool_do_list, HELP_LIST }, 167168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 168168404Spjd { "status", zpool_do_status, HELP_STATUS }, 169168404Spjd { NULL }, 170168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 171168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 172168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 173236155Smm { "reopen", zpool_do_reopen, HELP_REOPEN }, 174168404Spjd { NULL }, 175168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 176168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 177168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 178219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 179168404Spjd { NULL }, 180168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 181168404Spjd { NULL }, 182168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 183168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 184168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 185228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 186168404Spjd { NULL }, 187168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 188168404Spjd { "get", zpool_do_get, HELP_GET }, 189168404Spjd { "set", zpool_do_set, HELP_SET }, 190168404Spjd}; 191168404Spjd 192168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 193168404Spjd 194168404Spjdzpool_command_t *current_command; 195185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 196168404Spjd 197219089Spjdstatic uint_t timestamp_fmt = NODATE; 198219089Spjd 199168404Spjdstatic const char * 200168404Spjdget_usage(zpool_help_t idx) { 201168404Spjd switch (idx) { 202168404Spjd case HELP_ADD: 203168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 204168404Spjd case HELP_ATTACH: 205168404Spjd return (gettext("\tattach [-f] <pool> <device> " 206185029Spjd "<new-device>\n")); 207168404Spjd case HELP_CLEAR: 208219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 209168404Spjd case HELP_CREATE: 210185029Spjd return (gettext("\tcreate [-fn] [-o property=value] ... \n" 211185029Spjd "\t [-O file-system-property=value] ... \n" 212185029Spjd "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 213168404Spjd case HELP_DESTROY: 214168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 215168404Spjd case HELP_DETACH: 216168404Spjd return (gettext("\tdetach <pool> <device>\n")); 217168404Spjd case HELP_EXPORT: 218168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 219168404Spjd case HELP_HISTORY: 220185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 221168404Spjd case HELP_IMPORT: 222168404Spjd return (gettext("\timport [-d dir] [-D]\n" 223219089Spjd "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 224185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 225219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 226219089Spjd "[-R root] [-F [-n]] -a\n" 227185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 228219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 229219089Spjd "[-R root] [-F [-n]]\n" 230219089Spjd "\t <pool | id> [newpool]\n")); 231168404Spjd case HELP_IOSTAT: 232219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 233168404Spjd "[count]]\n")); 234224171Sgibbs case HELP_LABELCLEAR: 235224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 236168404Spjd case HELP_LIST: 237185029Spjd return (gettext("\tlist [-H] [-o property[,...]] " 238219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 239168404Spjd case HELP_OFFLINE: 240168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 241168404Spjd case HELP_ONLINE: 242228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 243168404Spjd case HELP_REPLACE: 244168404Spjd return (gettext("\treplace [-f] <pool> <device> " 245185029Spjd "[new-device]\n")); 246168404Spjd case HELP_REMOVE: 247185029Spjd return (gettext("\tremove <pool> <device> ...\n")); 248236155Smm case HELP_REOPEN: 249236155Smm return (""); /* Undocumented command */ 250168404Spjd case HELP_SCRUB: 251168404Spjd return (gettext("\tscrub [-s] <pool> ...\n")); 252168404Spjd case HELP_STATUS: 253219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 254219089Spjd "[count]]\n")); 255168404Spjd case HELP_UPGRADE: 256228020Smm return (gettext("\tupgrade [-v]\n" 257185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 258168404Spjd case HELP_GET: 259185029Spjd return (gettext("\tget <\"all\" | property[,...]> " 260168404Spjd "<pool> ...\n")); 261168404Spjd case HELP_SET: 262168404Spjd return (gettext("\tset <property=value> <pool> \n")); 263219089Spjd case HELP_SPLIT: 264219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 265219089Spjd "\t [-o property=value] <pool> <newpool> " 266219089Spjd "[<device> ...]\n")); 267228103Smm case HELP_REGUID: 268228103Smm return (gettext("\treguid <pool>\n")); 269168404Spjd } 270168404Spjd 271168404Spjd abort(); 272168404Spjd /* NOTREACHED */ 273168404Spjd} 274168404Spjd 275168404Spjd 276168404Spjd/* 277168404Spjd * Callback routine that will print out a pool property value. 278168404Spjd */ 279185029Spjdstatic int 280185029Spjdprint_prop_cb(int prop, void *cb) 281168404Spjd{ 282168404Spjd FILE *fp = cb; 283168404Spjd 284219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 285168404Spjd 286185029Spjd if (zpool_prop_readonly(prop)) 287185029Spjd (void) fprintf(fp, " NO "); 288185029Spjd else 289219089Spjd (void) fprintf(fp, " YES "); 290185029Spjd 291168404Spjd if (zpool_prop_values(prop) == NULL) 292168404Spjd (void) fprintf(fp, "-\n"); 293168404Spjd else 294168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 295168404Spjd 296185029Spjd return (ZPROP_CONT); 297168404Spjd} 298168404Spjd 299168404Spjd/* 300168404Spjd * Display usage message. If we're inside a command, display only the usage for 301168404Spjd * that command. Otherwise, iterate over the entire command table and display 302168404Spjd * a complete usage message. 303168404Spjd */ 304168404Spjdvoid 305168404Spjdusage(boolean_t requested) 306168404Spjd{ 307168404Spjd FILE *fp = requested ? stdout : stderr; 308168404Spjd 309168404Spjd if (current_command == NULL) { 310168404Spjd int i; 311168404Spjd 312168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 313168404Spjd (void) fprintf(fp, 314168404Spjd gettext("where 'command' is one of the following:\n\n")); 315168404Spjd 316168404Spjd for (i = 0; i < NCOMMAND; i++) { 317168404Spjd if (command_table[i].name == NULL) 318168404Spjd (void) fprintf(fp, "\n"); 319168404Spjd else 320168404Spjd (void) fprintf(fp, "%s", 321168404Spjd get_usage(command_table[i].usage)); 322168404Spjd } 323168404Spjd } else { 324168404Spjd (void) fprintf(fp, gettext("usage:\n")); 325168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 326168404Spjd } 327168404Spjd 328168404Spjd if (current_command != NULL && 329168404Spjd ((strcmp(current_command->name, "set") == 0) || 330185029Spjd (strcmp(current_command->name, "get") == 0) || 331185029Spjd (strcmp(current_command->name, "list") == 0))) { 332168404Spjd 333168404Spjd (void) fprintf(fp, 334168404Spjd gettext("\nthe following properties are supported:\n")); 335168404Spjd 336219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 337185029Spjd "PROPERTY", "EDIT", "VALUES"); 338168404Spjd 339168404Spjd /* Iterate over all properties */ 340185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 341185029Spjd ZFS_TYPE_POOL); 342168404Spjd } 343168404Spjd 344168404Spjd /* 345168404Spjd * See comments at end of main(). 346168404Spjd */ 347168404Spjd if (getenv("ZFS_ABORT") != NULL) { 348168404Spjd (void) printf("dumping core by request\n"); 349168404Spjd abort(); 350168404Spjd } 351168404Spjd 352168404Spjd exit(requested ? 0 : 2); 353168404Spjd} 354168404Spjd 355168404Spjdvoid 356185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 357185029Spjd boolean_t print_logs) 358168404Spjd{ 359168404Spjd nvlist_t **child; 360168404Spjd uint_t c, children; 361168404Spjd char *vname; 362168404Spjd 363168404Spjd if (name != NULL) 364168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 365168404Spjd 366168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 367168404Spjd &child, &children) != 0) 368168404Spjd return; 369168404Spjd 370168404Spjd for (c = 0; c < children; c++) { 371185029Spjd uint64_t is_log = B_FALSE; 372185029Spjd 373185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 374185029Spjd &is_log); 375185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 376185029Spjd continue; 377185029Spjd 378219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 379185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 380185029Spjd B_FALSE); 381168404Spjd free(vname); 382168404Spjd } 383168404Spjd} 384168404Spjd 385168404Spjd/* 386185029Spjd * Add a property pair (name, string-value) into a property nvlist. 387185029Spjd */ 388185029Spjdstatic int 389185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 390185029Spjd boolean_t poolprop) 391185029Spjd{ 392185029Spjd zpool_prop_t prop = ZPROP_INVAL; 393185029Spjd zfs_prop_t fprop; 394185029Spjd nvlist_t *proplist; 395185029Spjd const char *normnm; 396185029Spjd char *strval; 397185029Spjd 398185029Spjd if (*props == NULL && 399185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 400185029Spjd (void) fprintf(stderr, 401185029Spjd gettext("internal error: out of memory\n")); 402185029Spjd return (1); 403185029Spjd } 404185029Spjd 405185029Spjd proplist = *props; 406185029Spjd 407185029Spjd if (poolprop) { 408185029Spjd if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 409185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 410185029Spjd "not a valid pool property\n"), propname); 411185029Spjd return (2); 412185029Spjd } 413185029Spjd normnm = zpool_prop_to_name(prop); 414185029Spjd } else { 415209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 416209962Smm normnm = zfs_prop_to_name(fprop); 417209962Smm } else { 418209962Smm normnm = propname; 419185029Spjd } 420185029Spjd } 421185029Spjd 422185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 423185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 424185029Spjd (void) fprintf(stderr, gettext("property '%s' " 425185029Spjd "specified multiple times\n"), propname); 426185029Spjd return (2); 427185029Spjd } 428185029Spjd 429185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 430185029Spjd (void) fprintf(stderr, gettext("internal " 431185029Spjd "error: out of memory\n")); 432185029Spjd return (1); 433185029Spjd } 434185029Spjd 435185029Spjd return (0); 436185029Spjd} 437185029Spjd 438185029Spjd/* 439168404Spjd * zpool add [-fn] <pool> <vdev> ... 440168404Spjd * 441168404Spjd * -f Force addition of devices, even if they appear in use 442168404Spjd * -n Do not add the devices, but display the resulting layout if 443168404Spjd * they were to be added. 444168404Spjd * 445168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 446168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 447168404Spjd * libzfs. 448168404Spjd */ 449168404Spjdint 450168404Spjdzpool_do_add(int argc, char **argv) 451168404Spjd{ 452168404Spjd boolean_t force = B_FALSE; 453168404Spjd boolean_t dryrun = B_FALSE; 454168404Spjd int c; 455168404Spjd nvlist_t *nvroot; 456168404Spjd char *poolname; 457168404Spjd int ret; 458168404Spjd zpool_handle_t *zhp; 459168404Spjd nvlist_t *config; 460168404Spjd 461168404Spjd /* check options */ 462168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 463168404Spjd switch (c) { 464168404Spjd case 'f': 465168404Spjd force = B_TRUE; 466168404Spjd break; 467168404Spjd case 'n': 468168404Spjd dryrun = B_TRUE; 469168404Spjd break; 470168404Spjd case '?': 471168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 472168404Spjd optopt); 473168404Spjd usage(B_FALSE); 474168404Spjd } 475168404Spjd } 476168404Spjd 477168404Spjd argc -= optind; 478168404Spjd argv += optind; 479168404Spjd 480168404Spjd /* get pool name and check number of arguments */ 481168404Spjd if (argc < 1) { 482168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 483168404Spjd usage(B_FALSE); 484168404Spjd } 485168404Spjd if (argc < 2) { 486168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 487168404Spjd usage(B_FALSE); 488168404Spjd } 489168404Spjd 490168404Spjd poolname = argv[0]; 491168404Spjd 492168404Spjd argc--; 493168404Spjd argv++; 494168404Spjd 495168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 496168404Spjd return (1); 497168404Spjd 498168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 499168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 500168404Spjd poolname); 501168404Spjd zpool_close(zhp); 502168404Spjd return (1); 503168404Spjd } 504168404Spjd 505168404Spjd /* pass off to get_vdev_spec for processing */ 506185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 507185029Spjd argc, argv); 508168404Spjd if (nvroot == NULL) { 509168404Spjd zpool_close(zhp); 510168404Spjd return (1); 511168404Spjd } 512168404Spjd 513168404Spjd if (dryrun) { 514168404Spjd nvlist_t *poolnvroot; 515168404Spjd 516168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 517168404Spjd &poolnvroot) == 0); 518168404Spjd 519168404Spjd (void) printf(gettext("would update '%s' to the following " 520168404Spjd "configuration:\n"), zpool_get_name(zhp)); 521168404Spjd 522185029Spjd /* print original main pool and new tree */ 523185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 524185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 525168404Spjd 526185029Spjd /* Do the same for the logs */ 527185029Spjd if (num_logs(poolnvroot) > 0) { 528185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 529185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 530185029Spjd } else if (num_logs(nvroot) > 0) { 531185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 532185029Spjd } 533185029Spjd 534168404Spjd ret = 0; 535168404Spjd } else { 536168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 537168404Spjd } 538168404Spjd 539168404Spjd nvlist_free(nvroot); 540168404Spjd zpool_close(zhp); 541168404Spjd 542168404Spjd return (ret); 543168404Spjd} 544168404Spjd 545168404Spjd/* 546219089Spjd * zpool remove <pool> <vdev> ... 547168404Spjd * 548219089Spjd * Removes the given vdev from the pool. Currently, this supports removing 549219089Spjd * spares, cache, and log devices from the pool. 550168404Spjd */ 551168404Spjdint 552168404Spjdzpool_do_remove(int argc, char **argv) 553168404Spjd{ 554168404Spjd char *poolname; 555185029Spjd int i, ret = 0; 556168404Spjd zpool_handle_t *zhp; 557168404Spjd 558168404Spjd argc--; 559168404Spjd argv++; 560168404Spjd 561168404Spjd /* get pool name and check number of arguments */ 562168404Spjd if (argc < 1) { 563168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 564168404Spjd usage(B_FALSE); 565168404Spjd } 566168404Spjd if (argc < 2) { 567168404Spjd (void) fprintf(stderr, gettext("missing device\n")); 568168404Spjd usage(B_FALSE); 569168404Spjd } 570168404Spjd 571168404Spjd poolname = argv[0]; 572168404Spjd 573168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 574168404Spjd return (1); 575168404Spjd 576185029Spjd for (i = 1; i < argc; i++) { 577185029Spjd if (zpool_vdev_remove(zhp, argv[i]) != 0) 578185029Spjd ret = 1; 579168404Spjd } 580168404Spjd 581168404Spjd return (ret); 582168404Spjd} 583168404Spjd 584168404Spjd/* 585224171Sgibbs * zpool labelclear <vdev> 586224171Sgibbs * 587224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 588224171Sgibbs * on the device. 589224171Sgibbs */ 590224171Sgibbsint 591224171Sgibbszpool_do_labelclear(int argc, char **argv) 592224171Sgibbs{ 593224171Sgibbs char *vdev, *name; 594224171Sgibbs int c, fd = -1, ret = 0; 595224171Sgibbs pool_state_t state; 596224171Sgibbs boolean_t inuse = B_FALSE; 597224171Sgibbs boolean_t force = B_FALSE; 598224171Sgibbs 599224171Sgibbs /* check options */ 600224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 601224171Sgibbs switch (c) { 602224171Sgibbs case 'f': 603224171Sgibbs force = B_TRUE; 604224171Sgibbs break; 605224171Sgibbs default: 606224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 607224171Sgibbs optopt); 608224171Sgibbs usage(B_FALSE); 609224171Sgibbs } 610224171Sgibbs } 611224171Sgibbs 612224171Sgibbs argc -= optind; 613224171Sgibbs argv += optind; 614224171Sgibbs 615224171Sgibbs /* get vdev name */ 616224171Sgibbs if (argc < 1) { 617224171Sgibbs (void) fprintf(stderr, gettext("missing vdev device name\n")); 618224171Sgibbs usage(B_FALSE); 619224171Sgibbs } 620224171Sgibbs 621224171Sgibbs vdev = argv[0]; 622224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 623224171Sgibbs (void) fprintf(stderr, gettext("Unable to open %s\n"), vdev); 624224171Sgibbs return (B_FALSE); 625224171Sgibbs } 626224171Sgibbs 627224171Sgibbs name = NULL; 628224171Sgibbs if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) { 629224171Sgibbs if (force) 630224171Sgibbs goto wipe_label; 631224171Sgibbs 632224171Sgibbs (void) fprintf(stderr, 633224171Sgibbs gettext("Unable to determine pool state for %s\n" 634224171Sgibbs "Use -f to force the clearing any label data\n"), vdev); 635224171Sgibbs 636224171Sgibbs return (1); 637224171Sgibbs } 638224171Sgibbs 639224171Sgibbs if (inuse) { 640224171Sgibbs switch (state) { 641224171Sgibbs default: 642224171Sgibbs case POOL_STATE_ACTIVE: 643224171Sgibbs case POOL_STATE_SPARE: 644224171Sgibbs case POOL_STATE_L2CACHE: 645224171Sgibbs (void) fprintf(stderr, 646224171Sgibbsgettext("labelclear operation failed.\n" 647224171Sgibbs "\tVdev %s is a member (%s), of pool \"%s\".\n" 648224171Sgibbs "\tTo remove label information from this device, export or destroy\n" 649224171Sgibbs "\tthe pool, or remove %s from the configuration of this pool\n" 650224171Sgibbs "\tand retry the labelclear operation\n"), 651224171Sgibbs vdev, zpool_pool_state_to_name(state), name, vdev); 652224171Sgibbs ret = 1; 653224171Sgibbs goto errout; 654224171Sgibbs 655224171Sgibbs case POOL_STATE_EXPORTED: 656224171Sgibbs if (force) 657224171Sgibbs break; 658224171Sgibbs 659224171Sgibbs (void) fprintf(stderr, 660224171Sgibbsgettext("labelclear operation failed.\n" 661224171Sgibbs "\tVdev %s is a member of the exported pool \"%s\".\n" 662224171Sgibbs "\tUse \"zpool labelclear -f %s\" to force the removal of label\n" 663224171Sgibbs "\tinformation.\n"), 664224171Sgibbs vdev, name, vdev); 665224171Sgibbs ret = 1; 666224171Sgibbs goto errout; 667224171Sgibbs 668224171Sgibbs case POOL_STATE_POTENTIALLY_ACTIVE: 669224171Sgibbs if (force) 670224171Sgibbs break; 671224171Sgibbs 672224171Sgibbs (void) fprintf(stderr, 673224171Sgibbsgettext("labelclear operation failed.\n" 674224171Sgibbs "\tVdev %s is a member of the pool \"%s\".\n" 675224171Sgibbs "\tThis pool is unknown to this system, but may be active on\n" 676224171Sgibbs "\tanother system. Use \'zpool labelclear -f %s\' to force the\n" 677224171Sgibbs "\tremoval of label information.\n"), 678224171Sgibbs vdev, name, vdev); 679224171Sgibbs ret = 1; 680224171Sgibbs goto errout; 681224171Sgibbs 682224171Sgibbs case POOL_STATE_DESTROYED: 683224171Sgibbs /* inuse should never be set for a destoryed pool... */ 684224171Sgibbs break; 685224171Sgibbs } 686224171Sgibbs } 687224171Sgibbs 688224171Sgibbswipe_label: 689224171Sgibbs if (zpool_clear_label(fd) != 0) { 690224171Sgibbs (void) fprintf(stderr, 691224171Sgibbs gettext("Label clear failed on vdev %s\n"), vdev); 692224171Sgibbs ret = 1; 693224171Sgibbs } 694224171Sgibbs 695224171Sgibbserrout: 696224171Sgibbs close(fd); 697224171Sgibbs if (name != NULL) 698224171Sgibbs free(name); 699224171Sgibbs 700224171Sgibbs return (ret); 701224171Sgibbs} 702224171Sgibbs 703224171Sgibbs/* 704185029Spjd * zpool create [-fn] [-o property=value] ... 705185029Spjd * [-O file-system-property=value] ... 706185029Spjd * [-R root] [-m mountpoint] <pool> <dev> ... 707168404Spjd * 708168404Spjd * -f Force creation, even if devices appear in use 709168404Spjd * -n Do not create the pool, but display the resulting layout if it 710168404Spjd * were to be created. 711168404Spjd * -R Create a pool under an alternate root 712168404Spjd * -m Set default mountpoint for the root dataset. By default it's 713168404Spjd * '/<pool>' 714185029Spjd * -o Set property=value. 715185029Spjd * -O Set fsproperty=value in the pool's root file system 716168404Spjd * 717168404Spjd * Creates the named pool according to the given vdev specification. The 718168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 719168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 720168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 721168404Spjd */ 722168404Spjdint 723168404Spjdzpool_do_create(int argc, char **argv) 724168404Spjd{ 725168404Spjd boolean_t force = B_FALSE; 726168404Spjd boolean_t dryrun = B_FALSE; 727168404Spjd int c; 728185029Spjd nvlist_t *nvroot = NULL; 729168404Spjd char *poolname; 730185029Spjd int ret = 1; 731168404Spjd char *altroot = NULL; 732168404Spjd char *mountpoint = NULL; 733185029Spjd nvlist_t *fsprops = NULL; 734185029Spjd nvlist_t *props = NULL; 735185029Spjd char *propval; 736168404Spjd 737168404Spjd /* check options */ 738185029Spjd while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) { 739168404Spjd switch (c) { 740168404Spjd case 'f': 741168404Spjd force = B_TRUE; 742168404Spjd break; 743168404Spjd case 'n': 744168404Spjd dryrun = B_TRUE; 745168404Spjd break; 746168404Spjd case 'R': 747168404Spjd altroot = optarg; 748185029Spjd if (add_prop_list(zpool_prop_to_name( 749185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 750185029Spjd goto errout; 751185029Spjd if (nvlist_lookup_string(props, 752185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 753185029Spjd &propval) == 0) 754185029Spjd break; 755185029Spjd if (add_prop_list(zpool_prop_to_name( 756185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 757185029Spjd goto errout; 758168404Spjd break; 759168404Spjd case 'm': 760168404Spjd mountpoint = optarg; 761168404Spjd break; 762185029Spjd case 'o': 763185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 764185029Spjd (void) fprintf(stderr, gettext("missing " 765185029Spjd "'=' for -o option\n")); 766185029Spjd goto errout; 767185029Spjd } 768185029Spjd *propval = '\0'; 769185029Spjd propval++; 770185029Spjd 771185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 772185029Spjd goto errout; 773185029Spjd break; 774185029Spjd case 'O': 775185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 776185029Spjd (void) fprintf(stderr, gettext("missing " 777185029Spjd "'=' for -O option\n")); 778185029Spjd goto errout; 779185029Spjd } 780185029Spjd *propval = '\0'; 781185029Spjd propval++; 782185029Spjd 783185029Spjd if (add_prop_list(optarg, propval, &fsprops, B_FALSE)) 784185029Spjd goto errout; 785185029Spjd break; 786168404Spjd case ':': 787168404Spjd (void) fprintf(stderr, gettext("missing argument for " 788168404Spjd "'%c' option\n"), optopt); 789185029Spjd goto badusage; 790168404Spjd case '?': 791168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 792168404Spjd optopt); 793185029Spjd goto badusage; 794168404Spjd } 795168404Spjd } 796168404Spjd 797168404Spjd argc -= optind; 798168404Spjd argv += optind; 799168404Spjd 800168404Spjd /* get pool name and check number of arguments */ 801168404Spjd if (argc < 1) { 802168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 803185029Spjd goto badusage; 804168404Spjd } 805168404Spjd if (argc < 2) { 806168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 807185029Spjd goto badusage; 808168404Spjd } 809168404Spjd 810168404Spjd poolname = argv[0]; 811168404Spjd 812168404Spjd /* 813168404Spjd * As a special case, check for use of '/' in the name, and direct the 814168404Spjd * user to use 'zfs create' instead. 815168404Spjd */ 816168404Spjd if (strchr(poolname, '/') != NULL) { 817168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 818168404Spjd "character '/' in pool name\n"), poolname); 819168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 820168404Spjd "create a dataset\n")); 821185029Spjd goto errout; 822168404Spjd } 823168404Spjd 824168404Spjd /* pass off to get_vdev_spec for bulk processing */ 825185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 826185029Spjd argc - 1, argv + 1); 827168404Spjd if (nvroot == NULL) 828185029Spjd goto errout; 829168404Spjd 830168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 831185029Spjd if (!zfs_allocatable_devs(nvroot)) { 832168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 833168404Spjd "specification: at least one toplevel vdev must be " 834168404Spjd "specified\n")); 835185029Spjd goto errout; 836168404Spjd } 837168404Spjd 838168404Spjd 839168404Spjd if (altroot != NULL && altroot[0] != '/') { 840168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 841168404Spjd "must be an absolute path\n"), altroot); 842185029Spjd goto errout; 843168404Spjd } 844168404Spjd 845168404Spjd /* 846168404Spjd * Check the validity of the mountpoint and direct the user to use the 847168404Spjd * '-m' mountpoint option if it looks like its in use. 848168404Spjd */ 849168404Spjd if (mountpoint == NULL || 850168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 851168404Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 852168404Spjd char buf[MAXPATHLEN]; 853185029Spjd DIR *dirp; 854168404Spjd 855168404Spjd if (mountpoint && mountpoint[0] != '/') { 856168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 857168404Spjd "'%s': must be an absolute path, 'legacy', or " 858168404Spjd "'none'\n"), mountpoint); 859185029Spjd goto errout; 860168404Spjd } 861168404Spjd 862168404Spjd if (mountpoint == NULL) { 863168404Spjd if (altroot != NULL) 864168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 865168404Spjd altroot, poolname); 866168404Spjd else 867168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 868168404Spjd poolname); 869168404Spjd } else { 870168404Spjd if (altroot != NULL) 871168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 872168404Spjd altroot, mountpoint); 873168404Spjd else 874168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 875168404Spjd mountpoint); 876168404Spjd } 877168404Spjd 878185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 879185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 880185029Spjd "%s\n"), buf, strerror(errno)); 881185029Spjd (void) fprintf(stderr, gettext("use '-m' " 882185029Spjd "option to provide a different default\n")); 883185029Spjd goto errout; 884185029Spjd } else if (dirp) { 885185029Spjd int count = 0; 886185029Spjd 887185029Spjd while (count < 3 && readdir(dirp) != NULL) 888185029Spjd count++; 889185029Spjd (void) closedir(dirp); 890185029Spjd 891185029Spjd if (count > 2) { 892168404Spjd (void) fprintf(stderr, gettext("mountpoint " 893168404Spjd "'%s' exists and is not empty\n"), buf); 894185029Spjd (void) fprintf(stderr, gettext("use '-m' " 895185029Spjd "option to provide a " 896185029Spjd "different default\n")); 897185029Spjd goto errout; 898185029Spjd } 899168404Spjd } 900168404Spjd } 901168404Spjd 902168404Spjd if (dryrun) { 903168404Spjd /* 904168404Spjd * For a dry run invocation, print out a basic message and run 905168404Spjd * through all the vdevs in the list and print out in an 906168404Spjd * appropriate hierarchy. 907168404Spjd */ 908168404Spjd (void) printf(gettext("would create '%s' with the " 909168404Spjd "following layout:\n\n"), poolname); 910168404Spjd 911185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 912185029Spjd if (num_logs(nvroot) > 0) 913185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 914168404Spjd 915168404Spjd ret = 0; 916168404Spjd } else { 917168404Spjd /* 918168404Spjd * Hand off to libzfs. 919168404Spjd */ 920185029Spjd if (zpool_create(g_zfs, poolname, 921185029Spjd nvroot, props, fsprops) == 0) { 922168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 923168404Spjd ZFS_TYPE_FILESYSTEM); 924168404Spjd if (pool != NULL) { 925168404Spjd if (mountpoint != NULL) 926168404Spjd verify(zfs_prop_set(pool, 927168404Spjd zfs_prop_to_name( 928168404Spjd ZFS_PROP_MOUNTPOINT), 929168404Spjd mountpoint) == 0); 930168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 931185029Spjd ret = zfs_shareall(pool); 932168404Spjd zfs_close(pool); 933168404Spjd } 934168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 935168404Spjd (void) fprintf(stderr, gettext("pool name may have " 936168404Spjd "been omitted\n")); 937168404Spjd } 938168404Spjd } 939168404Spjd 940185029Spjderrout: 941168404Spjd nvlist_free(nvroot); 942185029Spjd nvlist_free(fsprops); 943185029Spjd nvlist_free(props); 944168404Spjd return (ret); 945185029Spjdbadusage: 946185029Spjd nvlist_free(fsprops); 947185029Spjd nvlist_free(props); 948185029Spjd usage(B_FALSE); 949185029Spjd return (2); 950168404Spjd} 951168404Spjd 952168404Spjd/* 953168404Spjd * zpool destroy <pool> 954168404Spjd * 955168404Spjd * -f Forcefully unmount any datasets 956168404Spjd * 957168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 958168404Spjd */ 959168404Spjdint 960168404Spjdzpool_do_destroy(int argc, char **argv) 961168404Spjd{ 962168404Spjd boolean_t force = B_FALSE; 963168404Spjd int c; 964168404Spjd char *pool; 965168404Spjd zpool_handle_t *zhp; 966168404Spjd int ret; 967168404Spjd 968168404Spjd /* check options */ 969168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 970168404Spjd switch (c) { 971168404Spjd case 'f': 972168404Spjd force = B_TRUE; 973168404Spjd break; 974168404Spjd case '?': 975168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 976168404Spjd optopt); 977168404Spjd usage(B_FALSE); 978168404Spjd } 979168404Spjd } 980168404Spjd 981168404Spjd argc -= optind; 982168404Spjd argv += optind; 983168404Spjd 984168404Spjd /* check arguments */ 985168404Spjd if (argc < 1) { 986168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 987168404Spjd usage(B_FALSE); 988168404Spjd } 989168404Spjd if (argc > 1) { 990168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 991168404Spjd usage(B_FALSE); 992168404Spjd } 993168404Spjd 994168404Spjd pool = argv[0]; 995168404Spjd 996168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 997168404Spjd /* 998168404Spjd * As a special case, check for use of '/' in the name, and 999168404Spjd * direct the user to use 'zfs destroy' instead. 1000168404Spjd */ 1001168404Spjd if (strchr(pool, '/') != NULL) 1002168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1003168404Spjd "destroy a dataset\n")); 1004168404Spjd return (1); 1005168404Spjd } 1006168404Spjd 1007168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1008168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1009168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1010168404Spjd return (1); 1011168404Spjd } 1012168404Spjd 1013168404Spjd ret = (zpool_destroy(zhp) != 0); 1014168404Spjd 1015168404Spjd zpool_close(zhp); 1016168404Spjd 1017168404Spjd return (ret); 1018168404Spjd} 1019168404Spjd 1020168404Spjd/* 1021168404Spjd * zpool export [-f] <pool> ... 1022168404Spjd * 1023168404Spjd * -f Forcefully unmount datasets 1024168404Spjd * 1025168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1026168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1027168404Spjd * then the datasets will be forcefully unmounted. 1028168404Spjd */ 1029168404Spjdint 1030168404Spjdzpool_do_export(int argc, char **argv) 1031168404Spjd{ 1032168404Spjd boolean_t force = B_FALSE; 1033207670Smm boolean_t hardforce = B_FALSE; 1034168404Spjd int c; 1035168404Spjd zpool_handle_t *zhp; 1036168404Spjd int ret; 1037168404Spjd int i; 1038168404Spjd 1039168404Spjd /* check options */ 1040207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1041168404Spjd switch (c) { 1042168404Spjd case 'f': 1043168404Spjd force = B_TRUE; 1044168404Spjd break; 1045207670Smm case 'F': 1046207670Smm hardforce = B_TRUE; 1047207670Smm break; 1048168404Spjd case '?': 1049168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1050168404Spjd optopt); 1051168404Spjd usage(B_FALSE); 1052168404Spjd } 1053168404Spjd } 1054168404Spjd 1055168404Spjd argc -= optind; 1056168404Spjd argv += optind; 1057168404Spjd 1058168404Spjd /* check arguments */ 1059168404Spjd if (argc < 1) { 1060168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1061168404Spjd usage(B_FALSE); 1062168404Spjd } 1063168404Spjd 1064168404Spjd ret = 0; 1065168404Spjd for (i = 0; i < argc; i++) { 1066168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1067168404Spjd ret = 1; 1068168404Spjd continue; 1069168404Spjd } 1070168404Spjd 1071168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1072168404Spjd ret = 1; 1073168404Spjd zpool_close(zhp); 1074168404Spjd continue; 1075168404Spjd } 1076168404Spjd 1077207670Smm if (hardforce) { 1078207670Smm if (zpool_export_force(zhp) != 0) 1079207670Smm ret = 1; 1080207670Smm } else if (zpool_export(zhp, force) != 0) { 1081168404Spjd ret = 1; 1082207670Smm } 1083168404Spjd 1084168404Spjd zpool_close(zhp); 1085168404Spjd } 1086168404Spjd 1087168404Spjd return (ret); 1088168404Spjd} 1089168404Spjd 1090168404Spjd/* 1091168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1092168404Spjd * name column. 1093168404Spjd */ 1094168404Spjdstatic int 1095168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1096168404Spjd{ 1097219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1098168404Spjd nvlist_t **child; 1099168404Spjd uint_t c, children; 1100168404Spjd int ret; 1101168404Spjd 1102168404Spjd if (strlen(name) + depth > max) 1103168404Spjd max = strlen(name) + depth; 1104168404Spjd 1105168404Spjd free(name); 1106168404Spjd 1107168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1108168404Spjd &child, &children) == 0) { 1109168404Spjd for (c = 0; c < children; c++) 1110168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1111168404Spjd max)) > max) 1112168404Spjd max = ret; 1113168404Spjd } 1114168404Spjd 1115185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1116185029Spjd &child, &children) == 0) { 1117185029Spjd for (c = 0; c < children; c++) 1118185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1119185029Spjd max)) > max) 1120185029Spjd max = ret; 1121185029Spjd } 1122185029Spjd 1123168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1124168404Spjd &child, &children) == 0) { 1125168404Spjd for (c = 0; c < children; c++) 1126168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1127168404Spjd max)) > max) 1128168404Spjd max = ret; 1129168404Spjd } 1130168404Spjd 1131168404Spjd 1132168404Spjd return (max); 1133168404Spjd} 1134168404Spjd 1135213197Smmtypedef struct spare_cbdata { 1136213197Smm uint64_t cb_guid; 1137213197Smm zpool_handle_t *cb_zhp; 1138213197Smm} spare_cbdata_t; 1139168404Spjd 1140213197Smmstatic boolean_t 1141213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1142213197Smm{ 1143213197Smm uint64_t guid; 1144213197Smm nvlist_t **child; 1145213197Smm uint_t c, children; 1146213197Smm 1147213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1148213197Smm search == guid) 1149213197Smm return (B_TRUE); 1150213197Smm 1151213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1152213197Smm &child, &children) == 0) { 1153213197Smm for (c = 0; c < children; c++) 1154213197Smm if (find_vdev(child[c], search)) 1155213197Smm return (B_TRUE); 1156213197Smm } 1157213197Smm 1158213197Smm return (B_FALSE); 1159213197Smm} 1160213197Smm 1161213197Smmstatic int 1162213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1163213197Smm{ 1164213197Smm spare_cbdata_t *cbp = data; 1165213197Smm nvlist_t *config, *nvroot; 1166213197Smm 1167213197Smm config = zpool_get_config(zhp, NULL); 1168213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1169213197Smm &nvroot) == 0); 1170213197Smm 1171213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1172213197Smm cbp->cb_zhp = zhp; 1173213197Smm return (1); 1174213197Smm } 1175213197Smm 1176213197Smm zpool_close(zhp); 1177213197Smm return (0); 1178213197Smm} 1179213197Smm 1180168404Spjd/* 1181213197Smm * Print out configuration state as requested by status_callback. 1182213197Smm */ 1183213197Smmvoid 1184213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1185213197Smm int namewidth, int depth, boolean_t isspare) 1186213197Smm{ 1187213197Smm nvlist_t **child; 1188213197Smm uint_t c, children; 1189219089Spjd pool_scan_stat_t *ps = NULL; 1190213197Smm vdev_stat_t *vs; 1191219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1192213197Smm char *vname; 1193213197Smm uint64_t notpresent; 1194213197Smm spare_cbdata_t cb; 1195224169Sgibbs const char *state; 1196213197Smm 1197213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1198213197Smm &child, &children) != 0) 1199213197Smm children = 0; 1200213197Smm 1201219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1202219089Spjd (uint64_t **)&vs, &c) == 0); 1203219089Spjd 1204213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1205213197Smm if (isspare) { 1206213197Smm /* 1207213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1208213197Smm * online drives. 1209213197Smm */ 1210213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1211213197Smm state = "INUSE"; 1212213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1213213197Smm state = "AVAIL"; 1214213197Smm } 1215213197Smm 1216213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1217213197Smm name, state); 1218213197Smm 1219213197Smm if (!isspare) { 1220213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1221213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1222213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1223213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1224213197Smm } 1225213197Smm 1226213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1227224170Sgibbs ¬present) == 0 || 1228224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1229213197Smm char *path; 1230224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1231224170Sgibbs (void) printf(" was %s", path); 1232213197Smm } else if (vs->vs_aux != 0) { 1233213197Smm (void) printf(" "); 1234213197Smm 1235213197Smm switch (vs->vs_aux) { 1236213197Smm case VDEV_AUX_OPEN_FAILED: 1237213197Smm (void) printf(gettext("cannot open")); 1238213197Smm break; 1239213197Smm 1240213197Smm case VDEV_AUX_BAD_GUID_SUM: 1241213197Smm (void) printf(gettext("missing device")); 1242213197Smm break; 1243213197Smm 1244213197Smm case VDEV_AUX_NO_REPLICAS: 1245213197Smm (void) printf(gettext("insufficient replicas")); 1246213197Smm break; 1247213197Smm 1248213197Smm case VDEV_AUX_VERSION_NEWER: 1249213197Smm (void) printf(gettext("newer version")); 1250213197Smm break; 1251213197Smm 1252213197Smm case VDEV_AUX_SPARED: 1253213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1254213197Smm &cb.cb_guid) == 0); 1255213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1256213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1257213197Smm zpool_get_name(zhp)) == 0) 1258213197Smm (void) printf(gettext("currently in " 1259213197Smm "use")); 1260213197Smm else 1261213197Smm (void) printf(gettext("in use by " 1262213197Smm "pool '%s'"), 1263213197Smm zpool_get_name(cb.cb_zhp)); 1264213197Smm zpool_close(cb.cb_zhp); 1265213197Smm } else { 1266213197Smm (void) printf(gettext("currently in use")); 1267213197Smm } 1268213197Smm break; 1269213197Smm 1270213197Smm case VDEV_AUX_ERR_EXCEEDED: 1271213197Smm (void) printf(gettext("too many errors")); 1272213197Smm break; 1273213197Smm 1274213197Smm case VDEV_AUX_IO_FAILURE: 1275213197Smm (void) printf(gettext("experienced I/O failures")); 1276213197Smm break; 1277213197Smm 1278213197Smm case VDEV_AUX_BAD_LOG: 1279213197Smm (void) printf(gettext("bad intent log")); 1280213197Smm break; 1281213197Smm 1282219089Spjd case VDEV_AUX_EXTERNAL: 1283219089Spjd (void) printf(gettext("external device fault")); 1284219089Spjd break; 1285219089Spjd 1286219089Spjd case VDEV_AUX_SPLIT_POOL: 1287219089Spjd (void) printf(gettext("split into new pool")); 1288219089Spjd break; 1289219089Spjd 1290213197Smm default: 1291213197Smm (void) printf(gettext("corrupted data")); 1292213197Smm break; 1293213197Smm } 1294213197Smm } 1295213197Smm 1296219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1297219089Spjd (uint64_t **)&ps, &c); 1298219089Spjd 1299219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1300219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1301219089Spjd (void) printf(gettext(" (%s)"), 1302219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1303219089Spjd "resilvering" : "repairing"); 1304219089Spjd } 1305219089Spjd 1306213197Smm (void) printf("\n"); 1307213197Smm 1308213197Smm for (c = 0; c < children; c++) { 1309219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1310213197Smm 1311219089Spjd /* Don't print logs or holes here */ 1312213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1313219089Spjd &islog); 1314219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1315219089Spjd &ishole); 1316219089Spjd if (islog || ishole) 1317213197Smm continue; 1318219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1319213197Smm print_status_config(zhp, vname, child[c], 1320213197Smm namewidth, depth + 2, isspare); 1321213197Smm free(vname); 1322213197Smm } 1323213197Smm} 1324213197Smm 1325213197Smm 1326213197Smm/* 1327168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1328168404Spjd * pool, printing out the name and status for each one. 1329168404Spjd */ 1330168404Spjdvoid 1331213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1332168404Spjd{ 1333168404Spjd nvlist_t **child; 1334168404Spjd uint_t c, children; 1335168404Spjd vdev_stat_t *vs; 1336168404Spjd char *type, *vname; 1337168404Spjd 1338168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1339219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1340219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1341168404Spjd return; 1342168404Spjd 1343219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1344168404Spjd (uint64_t **)&vs, &c) == 0); 1345168404Spjd 1346168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1347185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1348168404Spjd 1349168404Spjd if (vs->vs_aux != 0) { 1350185029Spjd (void) printf(" "); 1351168404Spjd 1352168404Spjd switch (vs->vs_aux) { 1353168404Spjd case VDEV_AUX_OPEN_FAILED: 1354168404Spjd (void) printf(gettext("cannot open")); 1355168404Spjd break; 1356168404Spjd 1357168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1358168404Spjd (void) printf(gettext("missing device")); 1359168404Spjd break; 1360168404Spjd 1361168404Spjd case VDEV_AUX_NO_REPLICAS: 1362168404Spjd (void) printf(gettext("insufficient replicas")); 1363168404Spjd break; 1364168404Spjd 1365168404Spjd case VDEV_AUX_VERSION_NEWER: 1366168404Spjd (void) printf(gettext("newer version")); 1367168404Spjd break; 1368168404Spjd 1369185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1370185029Spjd (void) printf(gettext("too many errors")); 1371185029Spjd break; 1372185029Spjd 1373168404Spjd default: 1374168404Spjd (void) printf(gettext("corrupted data")); 1375168404Spjd break; 1376168404Spjd } 1377168404Spjd } 1378168404Spjd (void) printf("\n"); 1379168404Spjd 1380168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1381168404Spjd &child, &children) != 0) 1382168404Spjd return; 1383168404Spjd 1384168404Spjd for (c = 0; c < children; c++) { 1385185029Spjd uint64_t is_log = B_FALSE; 1386185029Spjd 1387185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1388185029Spjd &is_log); 1389213197Smm if (is_log) 1390185029Spjd continue; 1391185029Spjd 1392219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1393213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1394168404Spjd free(vname); 1395168404Spjd } 1396168404Spjd 1397185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1398185029Spjd &child, &children) == 0) { 1399185029Spjd (void) printf(gettext("\tcache\n")); 1400185029Spjd for (c = 0; c < children; c++) { 1401219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1402185029Spjd (void) printf("\t %s\n", vname); 1403185029Spjd free(vname); 1404185029Spjd } 1405185029Spjd } 1406185029Spjd 1407168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1408185029Spjd &child, &children) == 0) { 1409185029Spjd (void) printf(gettext("\tspares\n")); 1410185029Spjd for (c = 0; c < children; c++) { 1411219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1412185029Spjd (void) printf("\t %s\n", vname); 1413185029Spjd free(vname); 1414185029Spjd } 1415168404Spjd } 1416168404Spjd} 1417168404Spjd 1418168404Spjd/* 1419213197Smm * Print log vdevs. 1420213197Smm * Logs are recorded as top level vdevs in the main pool child array 1421213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1422213197Smm * print_import_config() to print the top level logs then any log 1423213197Smm * children (eg mirrored slogs) are printed recursively - which 1424213197Smm * works because only the top level vdev is marked "is_log" 1425213197Smm */ 1426213197Smmstatic void 1427213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1428213197Smm{ 1429213197Smm uint_t c, children; 1430213197Smm nvlist_t **child; 1431213197Smm 1432213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1433213197Smm &children) != 0) 1434213197Smm return; 1435213197Smm 1436213197Smm (void) printf(gettext("\tlogs\n")); 1437213197Smm 1438213197Smm for (c = 0; c < children; c++) { 1439213197Smm uint64_t is_log = B_FALSE; 1440213197Smm char *name; 1441213197Smm 1442213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1443213197Smm &is_log); 1444213197Smm if (!is_log) 1445213197Smm continue; 1446219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1447213197Smm if (verbose) 1448213197Smm print_status_config(zhp, name, child[c], namewidth, 1449213197Smm 2, B_FALSE); 1450213197Smm else 1451213197Smm print_import_config(name, child[c], namewidth, 2); 1452213197Smm free(name); 1453213197Smm } 1454213197Smm} 1455219089Spjd 1456213197Smm/* 1457168404Spjd * Display the status for the given pool. 1458168404Spjd */ 1459168404Spjdstatic void 1460168404Spjdshow_import(nvlist_t *config) 1461168404Spjd{ 1462168404Spjd uint64_t pool_state; 1463168404Spjd vdev_stat_t *vs; 1464168404Spjd char *name; 1465168404Spjd uint64_t guid; 1466168404Spjd char *msgid; 1467168404Spjd nvlist_t *nvroot; 1468168404Spjd int reason; 1469168404Spjd const char *health; 1470168404Spjd uint_t vsc; 1471168404Spjd int namewidth; 1472228103Smm char *comment; 1473168404Spjd 1474168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1475168404Spjd &name) == 0); 1476168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1477168404Spjd &guid) == 0); 1478168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1479168404Spjd &pool_state) == 0); 1480168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1481168404Spjd &nvroot) == 0); 1482168404Spjd 1483219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1484168404Spjd (uint64_t **)&vs, &vsc) == 0); 1485185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1486168404Spjd 1487168404Spjd reason = zpool_import_status(config, &msgid); 1488168404Spjd 1489228103Smm (void) printf(gettext(" pool: %s\n"), name); 1490228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1491228103Smm (void) printf(gettext(" state: %s"), health); 1492168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1493168404Spjd (void) printf(gettext(" (DESTROYED)")); 1494168404Spjd (void) printf("\n"); 1495168404Spjd 1496168404Spjd switch (reason) { 1497168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1498168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1499168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1500228103Smm (void) printf(gettext(" status: One or more devices are " 1501228103Smm "missing from the system.\n")); 1502168404Spjd break; 1503168404Spjd 1504168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1505168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1506228103Smm (void) printf(gettext(" status: One or more devices contains " 1507168404Spjd "corrupted data.\n")); 1508168404Spjd break; 1509168404Spjd 1510168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1511228103Smm (void) printf( 1512228103Smm gettext(" status: The pool data is corrupted.\n")); 1513168404Spjd break; 1514168404Spjd 1515168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1516228103Smm (void) printf(gettext(" status: One or more devices " 1517168404Spjd "are offlined.\n")); 1518168404Spjd break; 1519168404Spjd 1520168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1521228103Smm (void) printf(gettext(" status: The pool metadata is " 1522168404Spjd "corrupted.\n")); 1523168404Spjd break; 1524168404Spjd 1525168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1526228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1527168404Spjd "older on-disk version.\n")); 1528168404Spjd break; 1529168404Spjd 1530168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1531228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1532168404Spjd "incompatible version.\n")); 1533168404Spjd break; 1534168404Spjd 1535168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1536228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1537168498Spjd "another system.\n")); 1538168498Spjd break; 1539185029Spjd 1540185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1541185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1542228103Smm (void) printf(gettext(" status: One or more devices are " 1543185029Spjd "faulted.\n")); 1544185029Spjd break; 1545185029Spjd 1546185029Spjd case ZPOOL_STATUS_BAD_LOG: 1547228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1548185029Spjd "read.\n")); 1549185029Spjd break; 1550185029Spjd 1551219089Spjd case ZPOOL_STATUS_RESILVERING: 1552228103Smm (void) printf(gettext(" status: One or more devices were being " 1553219089Spjd "resilvered.\n")); 1554219089Spjd break; 1555219089Spjd 1556168404Spjd default: 1557168404Spjd /* 1558168404Spjd * No other status can be seen when importing pools. 1559168404Spjd */ 1560168404Spjd assert(reason == ZPOOL_STATUS_OK); 1561168404Spjd } 1562168404Spjd 1563168404Spjd /* 1564168404Spjd * Print out an action according to the overall state of the pool. 1565168404Spjd */ 1566168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1567168404Spjd if (reason == ZPOOL_STATUS_VERSION_OLDER) 1568228103Smm (void) printf(gettext(" action: The pool can be " 1569168404Spjd "imported using its name or numeric identifier, " 1570168404Spjd "though\n\tsome features will not be available " 1571168404Spjd "without an explicit 'zpool upgrade'.\n")); 1572168498Spjd else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 1573228103Smm (void) printf(gettext(" action: The pool can be " 1574168498Spjd "imported using its name or numeric " 1575168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1576168404Spjd else 1577228103Smm (void) printf(gettext(" action: The pool can be " 1578168404Spjd "imported using its name or numeric " 1579168404Spjd "identifier.\n")); 1580168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1581228103Smm (void) printf(gettext(" action: The pool can be imported " 1582168404Spjd "despite missing or damaged devices. The\n\tfault " 1583168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1584168404Spjd } else { 1585168404Spjd switch (reason) { 1586168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1587228103Smm (void) printf(gettext(" action: The pool cannot be " 1588168404Spjd "imported. Access the pool on a system running " 1589168404Spjd "newer\n\tsoftware, or recreate the pool from " 1590168404Spjd "backup.\n")); 1591168404Spjd break; 1592168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1593168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1594168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1595228103Smm (void) printf(gettext(" action: The pool cannot be " 1596168404Spjd "imported. Attach the missing\n\tdevices and try " 1597168404Spjd "again.\n")); 1598168404Spjd break; 1599168404Spjd default: 1600228103Smm (void) printf(gettext(" action: The pool cannot be " 1601168404Spjd "imported due to damaged devices or data.\n")); 1602168404Spjd } 1603168404Spjd } 1604168404Spjd 1605228103Smm /* Print the comment attached to the pool. */ 1606228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 1607228103Smm (void) printf(gettext("comment: %s\n"), comment); 1608228103Smm 1609168404Spjd /* 1610168404Spjd * If the state is "closed" or "can't open", and the aux state 1611168404Spjd * is "corrupt data": 1612168404Spjd */ 1613168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1614168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1615168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1616168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1617168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1618168404Spjd "but can be imported using the '-Df' flags.\n")); 1619168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1620168404Spjd (void) printf(gettext("\tThe pool may be active on " 1621185029Spjd "another system, but can be imported using\n\t" 1622168404Spjd "the '-f' flag.\n")); 1623168404Spjd } 1624168404Spjd 1625168404Spjd if (msgid != NULL) 1626236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1627168404Spjd msgid); 1628168404Spjd 1629228103Smm (void) printf(gettext(" config:\n\n")); 1630168404Spjd 1631168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1632168404Spjd if (namewidth < 10) 1633168404Spjd namewidth = 10; 1634168404Spjd 1635213197Smm print_import_config(name, nvroot, namewidth, 0); 1636213197Smm if (num_logs(nvroot) > 0) 1637213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1638185029Spjd 1639168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1640168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1641168404Spjd "be part of this pool, though their\n\texact " 1642168404Spjd "configuration cannot be determined.\n")); 1643168404Spjd } 1644168404Spjd} 1645168404Spjd 1646168404Spjd/* 1647168404Spjd * Perform the import for the given configuration. This passes the heavy 1648185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1649185029Spjd * within the pool. 1650168404Spjd */ 1651168404Spjdstatic int 1652168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1653219089Spjd nvlist_t *props, int flags) 1654168404Spjd{ 1655168404Spjd zpool_handle_t *zhp; 1656168404Spjd char *name; 1657168404Spjd uint64_t state; 1658168404Spjd uint64_t version; 1659168404Spjd 1660168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1661168404Spjd &name) == 0); 1662168404Spjd 1663168404Spjd verify(nvlist_lookup_uint64(config, 1664168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1665168404Spjd verify(nvlist_lookup_uint64(config, 1666168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1667185029Spjd if (version > SPA_VERSION) { 1668168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1669168404Spjd "is formatted using a newer ZFS version\n"), name); 1670168404Spjd return (1); 1671219089Spjd } else if (state != POOL_STATE_EXPORTED && 1672219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 1673168498Spjd uint64_t hostid; 1674168498Spjd 1675168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1676168498Spjd &hostid) == 0) { 1677168498Spjd if ((unsigned long)hostid != gethostid()) { 1678168498Spjd char *hostname; 1679168498Spjd uint64_t timestamp; 1680168498Spjd time_t t; 1681168498Spjd 1682168498Spjd verify(nvlist_lookup_string(config, 1683168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1684168498Spjd verify(nvlist_lookup_uint64(config, 1685168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1686168498Spjd t = timestamp; 1687168498Spjd (void) fprintf(stderr, gettext("cannot import " 1688168498Spjd "'%s': pool may be in use from other " 1689168498Spjd "system, it was last accessed by %s " 1690168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1691168498Spjd (unsigned long)hostid, 1692168498Spjd asctime(localtime(&t))); 1693168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1694168498Spjd "import anyway\n")); 1695168498Spjd return (1); 1696168498Spjd } 1697168498Spjd } else { 1698168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1699168498Spjd "pool may be in use from other system\n"), name); 1700168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1701168498Spjd "anyway\n")); 1702168498Spjd return (1); 1703168498Spjd } 1704168404Spjd } 1705168404Spjd 1706219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1707168404Spjd return (1); 1708168404Spjd 1709168404Spjd if (newname != NULL) 1710168404Spjd name = (char *)newname; 1711168404Spjd 1712209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 1713209962Smm return (1); 1714168404Spjd 1715209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1716219089Spjd !(flags & ZFS_IMPORT_ONLY) && 1717209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1718168404Spjd zpool_close(zhp); 1719168404Spjd return (1); 1720168404Spjd } 1721168404Spjd 1722168404Spjd zpool_close(zhp); 1723219089Spjd return (0); 1724168404Spjd} 1725168404Spjd 1726168404Spjd/* 1727168404Spjd * zpool import [-d dir] [-D] 1728185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1729185029Spjd * [-d dir | -c cachefile] [-f] -a 1730185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1731219089Spjd * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 1732168404Spjd * 1733185029Spjd * -c Read pool information from a cachefile instead of searching 1734185029Spjd * devices. 1735185029Spjd * 1736168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1737168404Spjd * one directory can be specified using multiple '-d' options. 1738168404Spjd * 1739168404Spjd * -D Scan for previously destroyed pools or import all or only 1740168404Spjd * specified destroyed pools. 1741168404Spjd * 1742168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1743168404Spjd * the given root. The pool will remain exported when the machine 1744168404Spjd * is rebooted. 1745168404Spjd * 1746219089Spjd * -V Import even in the presence of faulted vdevs. This is an 1747185029Spjd * intentionally undocumented option for testing purposes, and 1748185029Spjd * treats the pool configuration as complete, leaving any bad 1749209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 1750209962Smm * import. 1751185029Spjd * 1752219089Spjd * -f Force import, even if it appears that the pool is active. 1753219089Spjd * 1754219089Spjd * -F Attempt rewind if necessary. 1755219089Spjd * 1756219089Spjd * -n See if rewind would work, but don't actually rewind. 1757219089Spjd * 1758219089Spjd * -N Import the pool but don't mount datasets. 1759219089Spjd * 1760219089Spjd * -T Specify a starting txg to use for import. This option is 1761219089Spjd * intentionally undocumented option for testing purposes. 1762219089Spjd * 1763168404Spjd * -a Import all pools found. 1764168404Spjd * 1765185029Spjd * -o Set property=value and/or temporary mount options (without '='). 1766185029Spjd * 1767168404Spjd * The import command scans for pools to import, and import pools based on pool 1768168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 1769168404Spjd */ 1770168404Spjdint 1771168404Spjdzpool_do_import(int argc, char **argv) 1772168404Spjd{ 1773168404Spjd char **searchdirs = NULL; 1774168404Spjd int nsearch = 0; 1775168404Spjd int c; 1776219089Spjd int err = 0; 1777185029Spjd nvlist_t *pools = NULL; 1778168404Spjd boolean_t do_all = B_FALSE; 1779168404Spjd boolean_t do_destroyed = B_FALSE; 1780168404Spjd char *mntopts = NULL; 1781168404Spjd nvpair_t *elem; 1782168404Spjd nvlist_t *config; 1783185029Spjd uint64_t searchguid = 0; 1784185029Spjd char *searchname = NULL; 1785185029Spjd char *propval; 1786168404Spjd nvlist_t *found_config; 1787219089Spjd nvlist_t *policy = NULL; 1788185029Spjd nvlist_t *props = NULL; 1789168404Spjd boolean_t first; 1790219089Spjd int flags = ZFS_IMPORT_NORMAL; 1791219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 1792219089Spjd boolean_t dryrun = B_FALSE; 1793219089Spjd boolean_t do_rewind = B_FALSE; 1794219089Spjd boolean_t xtreme_rewind = B_FALSE; 1795219089Spjd uint64_t pool_state, txg = -1ULL; 1796185029Spjd char *cachefile = NULL; 1797219089Spjd importargs_t idata = { 0 }; 1798219089Spjd char *endptr; 1799168404Spjd 1800168404Spjd /* check options */ 1801219089Spjd while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) { 1802168404Spjd switch (c) { 1803168404Spjd case 'a': 1804168404Spjd do_all = B_TRUE; 1805168404Spjd break; 1806185029Spjd case 'c': 1807185029Spjd cachefile = optarg; 1808185029Spjd break; 1809168404Spjd case 'd': 1810168404Spjd if (searchdirs == NULL) { 1811168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1812168404Spjd } else { 1813168404Spjd char **tmp = safe_malloc((nsearch + 1) * 1814168404Spjd sizeof (char *)); 1815168404Spjd bcopy(searchdirs, tmp, nsearch * 1816168404Spjd sizeof (char *)); 1817168404Spjd free(searchdirs); 1818168404Spjd searchdirs = tmp; 1819168404Spjd } 1820168404Spjd searchdirs[nsearch++] = optarg; 1821168404Spjd break; 1822168404Spjd case 'D': 1823168404Spjd do_destroyed = B_TRUE; 1824168404Spjd break; 1825168404Spjd case 'f': 1826219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 1827168404Spjd break; 1828185029Spjd case 'F': 1829219089Spjd do_rewind = B_TRUE; 1830185029Spjd break; 1831219089Spjd case 'm': 1832219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 1833219089Spjd break; 1834219089Spjd case 'n': 1835219089Spjd dryrun = B_TRUE; 1836219089Spjd break; 1837219089Spjd case 'N': 1838219089Spjd flags |= ZFS_IMPORT_ONLY; 1839219089Spjd break; 1840168404Spjd case 'o': 1841185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 1842185029Spjd *propval = '\0'; 1843185029Spjd propval++; 1844185029Spjd if (add_prop_list(optarg, propval, 1845185029Spjd &props, B_TRUE)) 1846185029Spjd goto error; 1847185029Spjd } else { 1848185029Spjd mntopts = optarg; 1849185029Spjd } 1850168404Spjd break; 1851168404Spjd case 'R': 1852185029Spjd if (add_prop_list(zpool_prop_to_name( 1853185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 1854185029Spjd goto error; 1855185029Spjd if (nvlist_lookup_string(props, 1856185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 1857185029Spjd &propval) == 0) 1858185029Spjd break; 1859185029Spjd if (add_prop_list(zpool_prop_to_name( 1860185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1861185029Spjd goto error; 1862168404Spjd break; 1863219089Spjd case 'T': 1864219089Spjd errno = 0; 1865219089Spjd txg = strtoull(optarg, &endptr, 10); 1866219089Spjd if (errno != 0 || *endptr != '\0') { 1867219089Spjd (void) fprintf(stderr, 1868219089Spjd gettext("invalid txg value\n")); 1869219089Spjd usage(B_FALSE); 1870219089Spjd } 1871219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 1872219089Spjd break; 1873219089Spjd case 'V': 1874219089Spjd flags |= ZFS_IMPORT_VERBATIM; 1875219089Spjd break; 1876219089Spjd case 'X': 1877219089Spjd xtreme_rewind = B_TRUE; 1878219089Spjd break; 1879168404Spjd case ':': 1880168404Spjd (void) fprintf(stderr, gettext("missing argument for " 1881168404Spjd "'%c' option\n"), optopt); 1882168404Spjd usage(B_FALSE); 1883168404Spjd break; 1884168404Spjd case '?': 1885168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1886168404Spjd optopt); 1887168404Spjd usage(B_FALSE); 1888168404Spjd } 1889168404Spjd } 1890168404Spjd 1891168404Spjd argc -= optind; 1892168404Spjd argv += optind; 1893168404Spjd 1894185029Spjd if (cachefile && nsearch != 0) { 1895185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 1896185029Spjd usage(B_FALSE); 1897185029Spjd } 1898185029Spjd 1899219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 1900219089Spjd (void) fprintf(stderr, 1901219089Spjd gettext("-n or -X only meaningful with -F\n")); 1902219089Spjd usage(B_FALSE); 1903219089Spjd } 1904219089Spjd if (dryrun) 1905219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 1906219089Spjd else if (do_rewind) 1907219089Spjd rewind_policy = ZPOOL_DO_REWIND; 1908219089Spjd if (xtreme_rewind) 1909219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 1910219089Spjd 1911219089Spjd /* In the future, we can capture further policy and include it here */ 1912219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 1913219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 1914219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 1915219089Spjd goto error; 1916219089Spjd 1917168404Spjd if (searchdirs == NULL) { 1918168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1919235478Savg searchdirs[0] = "/dev"; 1920168404Spjd nsearch = 1; 1921168404Spjd } 1922168404Spjd 1923168404Spjd /* check argument count */ 1924168404Spjd if (do_all) { 1925168404Spjd if (argc != 0) { 1926168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1927168404Spjd usage(B_FALSE); 1928168404Spjd } 1929168404Spjd } else { 1930168404Spjd if (argc > 2) { 1931168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1932168404Spjd usage(B_FALSE); 1933168404Spjd } 1934168404Spjd 1935168404Spjd /* 1936168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 1937168404Spjd * here because otherwise any attempt to discover pools will 1938168404Spjd * silently fail. 1939168404Spjd */ 1940168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1941168404Spjd (void) fprintf(stderr, gettext("cannot " 1942168404Spjd "discover pools: permission denied\n")); 1943168404Spjd free(searchdirs); 1944219089Spjd nvlist_free(policy); 1945168404Spjd return (1); 1946168404Spjd } 1947168404Spjd } 1948168404Spjd 1949168404Spjd /* 1950168404Spjd * Depending on the arguments given, we do one of the following: 1951168404Spjd * 1952168404Spjd * <none> Iterate through all pools and display information about 1953168404Spjd * each one. 1954168404Spjd * 1955168404Spjd * -a Iterate through all pools and try to import each one. 1956168404Spjd * 1957168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 1958168404Spjd * name and import that one. 1959168404Spjd * 1960168404Spjd * -D Above options applies only to destroyed pools. 1961168404Spjd */ 1962168404Spjd if (argc != 0) { 1963168404Spjd char *endptr; 1964168404Spjd 1965168404Spjd errno = 0; 1966168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 1967168404Spjd if (errno != 0 || *endptr != '\0') 1968168404Spjd searchname = argv[0]; 1969168404Spjd found_config = NULL; 1970168404Spjd 1971185029Spjd /* 1972219089Spjd * User specified a name or guid. Ensure it's unique. 1973185029Spjd */ 1974219089Spjd idata.unique = B_TRUE; 1975185029Spjd } 1976185029Spjd 1977219089Spjd 1978219089Spjd idata.path = searchdirs; 1979219089Spjd idata.paths = nsearch; 1980219089Spjd idata.poolname = searchname; 1981219089Spjd idata.guid = searchguid; 1982219089Spjd idata.cachefile = cachefile; 1983219089Spjd 1984219089Spjd pools = zpool_search_import(g_zfs, &idata); 1985219089Spjd 1986219089Spjd if (pools != NULL && idata.exists && 1987219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 1988219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1989219089Spjd "a pool with that name already exists\n"), 1990219089Spjd argv[0]); 1991219089Spjd (void) fprintf(stderr, gettext("use the form '%s " 1992219089Spjd "<pool | id> <newpool>' to give it a new name\n"), 1993219089Spjd "zpool import"); 1994219089Spjd err = 1; 1995219089Spjd } else if (pools == NULL && idata.exists) { 1996219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1997219089Spjd "a pool with that name is already created/imported,\n"), 1998219089Spjd argv[0]); 1999219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2000219089Spjd "with that name were found\n")); 2001219089Spjd err = 1; 2002219089Spjd } else if (pools == NULL) { 2003185029Spjd if (argc != 0) { 2004185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2005185029Spjd "no such pool available\n"), argv[0]); 2006185029Spjd } 2007219089Spjd err = 1; 2008219089Spjd } 2009219089Spjd 2010219089Spjd if (err == 1) { 2011185029Spjd free(searchdirs); 2012219089Spjd nvlist_free(policy); 2013185029Spjd return (1); 2014185029Spjd } 2015185029Spjd 2016185029Spjd /* 2017185029Spjd * At this point we have a list of import candidate configs. Even if 2018185029Spjd * we were searching by pool name or guid, we still need to 2019185029Spjd * post-process the list to deal with pool state and possible 2020185029Spjd * duplicate names. 2021185029Spjd */ 2022168404Spjd err = 0; 2023168404Spjd elem = NULL; 2024168404Spjd first = B_TRUE; 2025168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2026168404Spjd 2027168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2028168404Spjd 2029168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2030168404Spjd &pool_state) == 0); 2031168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2032168404Spjd continue; 2033168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2034168404Spjd continue; 2035168404Spjd 2036219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2037219089Spjd policy) == 0); 2038219089Spjd 2039168404Spjd if (argc == 0) { 2040168404Spjd if (first) 2041168404Spjd first = B_FALSE; 2042168404Spjd else if (!do_all) 2043168404Spjd (void) printf("\n"); 2044168404Spjd 2045219089Spjd if (do_all) { 2046168404Spjd err |= do_import(config, NULL, mntopts, 2047219089Spjd props, flags); 2048219089Spjd } else { 2049168404Spjd show_import(config); 2050219089Spjd } 2051168404Spjd } else if (searchname != NULL) { 2052168404Spjd char *name; 2053168404Spjd 2054168404Spjd /* 2055168404Spjd * We are searching for a pool based on name. 2056168404Spjd */ 2057168404Spjd verify(nvlist_lookup_string(config, 2058168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2059168404Spjd 2060168404Spjd if (strcmp(name, searchname) == 0) { 2061168404Spjd if (found_config != NULL) { 2062168404Spjd (void) fprintf(stderr, gettext( 2063168404Spjd "cannot import '%s': more than " 2064168404Spjd "one matching pool\n"), searchname); 2065168404Spjd (void) fprintf(stderr, gettext( 2066168404Spjd "import by numeric ID instead\n")); 2067168404Spjd err = B_TRUE; 2068168404Spjd } 2069168404Spjd found_config = config; 2070168404Spjd } 2071168404Spjd } else { 2072168404Spjd uint64_t guid; 2073168404Spjd 2074168404Spjd /* 2075168404Spjd * Search for a pool by guid. 2076168404Spjd */ 2077168404Spjd verify(nvlist_lookup_uint64(config, 2078168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2079168404Spjd 2080168404Spjd if (guid == searchguid) 2081168404Spjd found_config = config; 2082168404Spjd } 2083168404Spjd } 2084168404Spjd 2085168404Spjd /* 2086168404Spjd * If we were searching for a specific pool, verify that we found a 2087168404Spjd * pool, and then do the import. 2088168404Spjd */ 2089168404Spjd if (argc != 0 && err == 0) { 2090168404Spjd if (found_config == NULL) { 2091168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2092168404Spjd "no such pool available\n"), argv[0]); 2093168404Spjd err = B_TRUE; 2094168404Spjd } else { 2095168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2096219089Spjd argv[1], mntopts, props, flags); 2097168404Spjd } 2098168404Spjd } 2099168404Spjd 2100168404Spjd /* 2101168404Spjd * If we were just looking for pools, report an error if none were 2102168404Spjd * found. 2103168404Spjd */ 2104168404Spjd if (argc == 0 && first) 2105168404Spjd (void) fprintf(stderr, 2106168404Spjd gettext("no pools available to import\n")); 2107168404Spjd 2108185029Spjderror: 2109185029Spjd nvlist_free(props); 2110168404Spjd nvlist_free(pools); 2111219089Spjd nvlist_free(policy); 2112168404Spjd free(searchdirs); 2113168404Spjd 2114168404Spjd return (err ? 1 : 0); 2115168404Spjd} 2116168404Spjd 2117168404Spjdtypedef struct iostat_cbdata { 2118236155Smm boolean_t cb_verbose; 2119236155Smm int cb_namewidth; 2120236155Smm int cb_iteration; 2121168404Spjd zpool_list_t *cb_list; 2122168404Spjd} iostat_cbdata_t; 2123168404Spjd 2124168404Spjdstatic void 2125168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2126168404Spjd{ 2127168404Spjd int i = 0; 2128168404Spjd 2129168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2130168404Spjd (void) printf("-"); 2131168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2132168404Spjd} 2133168404Spjd 2134168404Spjdstatic void 2135168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2136168404Spjd{ 2137168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2138168404Spjd cb->cb_namewidth, ""); 2139219089Spjd (void) printf("%-*s alloc free read write read write\n", 2140168404Spjd cb->cb_namewidth, "pool"); 2141168404Spjd print_iostat_separator(cb); 2142168404Spjd} 2143168404Spjd 2144168404Spjd/* 2145168404Spjd * Display a single statistic. 2146168404Spjd */ 2147185029Spjdstatic void 2148168404Spjdprint_one_stat(uint64_t value) 2149168404Spjd{ 2150168404Spjd char buf[64]; 2151168404Spjd 2152168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2153168404Spjd (void) printf(" %5s", buf); 2154168404Spjd} 2155168404Spjd 2156168404Spjd/* 2157168404Spjd * Print out all the statistics for the given vdev. This can either be the 2158168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2159168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2160168404Spjd */ 2161168404Spjdvoid 2162168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2163168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2164168404Spjd{ 2165168404Spjd nvlist_t **oldchild, **newchild; 2166168404Spjd uint_t c, children; 2167168404Spjd vdev_stat_t *oldvs, *newvs; 2168168404Spjd vdev_stat_t zerovs = { 0 }; 2169168404Spjd uint64_t tdelta; 2170168404Spjd double scale; 2171168404Spjd char *vname; 2172168404Spjd 2173168404Spjd if (oldnv != NULL) { 2174219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2175219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2176168404Spjd } else { 2177168404Spjd oldvs = &zerovs; 2178168404Spjd } 2179168404Spjd 2180219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2181168404Spjd (uint64_t **)&newvs, &c) == 0); 2182168404Spjd 2183168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2184168404Spjd (void) printf("%*s%s", depth, "", name); 2185168404Spjd else 2186168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2187168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2188168404Spjd 2189168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2190168404Spjd 2191168404Spjd if (tdelta == 0) 2192168404Spjd scale = 1.0; 2193168404Spjd else 2194168404Spjd scale = (double)NANOSEC / tdelta; 2195168404Spjd 2196168404Spjd /* only toplevel vdevs have capacity stats */ 2197168404Spjd if (newvs->vs_space == 0) { 2198168404Spjd (void) printf(" - -"); 2199168404Spjd } else { 2200168404Spjd print_one_stat(newvs->vs_alloc); 2201168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2202168404Spjd } 2203168404Spjd 2204168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2205168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2206168404Spjd 2207168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2208168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2209168404Spjd 2210168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2211168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2212168404Spjd 2213168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2214168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2215168404Spjd 2216168404Spjd (void) printf("\n"); 2217168404Spjd 2218168404Spjd if (!cb->cb_verbose) 2219168404Spjd return; 2220168404Spjd 2221168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2222168404Spjd &newchild, &children) != 0) 2223168404Spjd return; 2224168404Spjd 2225168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2226168404Spjd &oldchild, &c) != 0) 2227168404Spjd return; 2228168404Spjd 2229168404Spjd for (c = 0; c < children; c++) { 2230227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2231219089Spjd 2232227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2233227497Smm &ishole); 2234227497Smm 2235227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2236227497Smm &islog); 2237227497Smm 2238227497Smm if (ishole || islog) 2239219089Spjd continue; 2240219089Spjd 2241219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2242168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2243168404Spjd newchild[c], cb, depth + 2); 2244168404Spjd free(vname); 2245168404Spjd } 2246185029Spjd 2247185029Spjd /* 2248227497Smm * Log device section 2249227497Smm */ 2250227497Smm 2251227497Smm if (num_logs(newnv) > 0) { 2252227497Smm (void) printf("%-*s - - - - - " 2253227497Smm "-\n", cb->cb_namewidth, "logs"); 2254227497Smm 2255227497Smm for (c = 0; c < children; c++) { 2256227497Smm uint64_t islog = B_FALSE; 2257227497Smm (void) nvlist_lookup_uint64(newchild[c], 2258227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2259227497Smm 2260227497Smm if (islog) { 2261227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2262227497Smm B_FALSE); 2263227497Smm print_vdev_stats(zhp, vname, oldnv ? 2264227497Smm oldchild[c] : NULL, newchild[c], 2265227497Smm cb, depth + 2); 2266227497Smm free(vname); 2267227497Smm } 2268227497Smm } 2269227497Smm 2270227497Smm } 2271227497Smm 2272227497Smm /* 2273185029Spjd * Include level 2 ARC devices in iostat output 2274185029Spjd */ 2275185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2276185029Spjd &newchild, &children) != 0) 2277185029Spjd return; 2278185029Spjd 2279185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2280185029Spjd &oldchild, &c) != 0) 2281185029Spjd return; 2282185029Spjd 2283185029Spjd if (children > 0) { 2284185029Spjd (void) printf("%-*s - - - - - " 2285185029Spjd "-\n", cb->cb_namewidth, "cache"); 2286185029Spjd for (c = 0; c < children; c++) { 2287219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2288219089Spjd B_FALSE); 2289185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2290185029Spjd newchild[c], cb, depth + 2); 2291185029Spjd free(vname); 2292185029Spjd } 2293185029Spjd } 2294168404Spjd} 2295168404Spjd 2296168404Spjdstatic int 2297168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2298168404Spjd{ 2299168404Spjd iostat_cbdata_t *cb = data; 2300168404Spjd boolean_t missing; 2301168404Spjd 2302168404Spjd /* 2303168404Spjd * If the pool has disappeared, remove it from the list and continue. 2304168404Spjd */ 2305168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2306168404Spjd return (-1); 2307168404Spjd 2308168404Spjd if (missing) 2309168404Spjd pool_list_remove(cb->cb_list, zhp); 2310168404Spjd 2311168404Spjd return (0); 2312168404Spjd} 2313168404Spjd 2314168404Spjd/* 2315168404Spjd * Callback to print out the iostats for the given pool. 2316168404Spjd */ 2317168404Spjdint 2318168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2319168404Spjd{ 2320168404Spjd iostat_cbdata_t *cb = data; 2321168404Spjd nvlist_t *oldconfig, *newconfig; 2322168404Spjd nvlist_t *oldnvroot, *newnvroot; 2323168404Spjd 2324168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2325168404Spjd 2326168404Spjd if (cb->cb_iteration == 1) 2327168404Spjd oldconfig = NULL; 2328168404Spjd 2329168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2330168404Spjd &newnvroot) == 0); 2331168404Spjd 2332168404Spjd if (oldconfig == NULL) 2333168404Spjd oldnvroot = NULL; 2334168404Spjd else 2335168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2336168404Spjd &oldnvroot) == 0); 2337168404Spjd 2338168404Spjd /* 2339168404Spjd * Print out the statistics for the pool. 2340168404Spjd */ 2341168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2342168404Spjd 2343168404Spjd if (cb->cb_verbose) 2344168404Spjd print_iostat_separator(cb); 2345168404Spjd 2346168404Spjd return (0); 2347168404Spjd} 2348168404Spjd 2349168404Spjdint 2350168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2351168404Spjd{ 2352168404Spjd iostat_cbdata_t *cb = data; 2353168404Spjd nvlist_t *config, *nvroot; 2354168404Spjd 2355168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2356168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2357168404Spjd &nvroot) == 0); 2358168404Spjd if (!cb->cb_verbose) 2359168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2360168404Spjd else 2361236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2362236145Smm cb->cb_namewidth); 2363168404Spjd } 2364168404Spjd 2365168404Spjd /* 2366168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2367168404Spjd * maximum we can have and still fit in 80 columns. 2368168404Spjd */ 2369168404Spjd if (cb->cb_namewidth < 10) 2370168404Spjd cb->cb_namewidth = 10; 2371168404Spjd if (cb->cb_namewidth > 38) 2372168404Spjd cb->cb_namewidth = 38; 2373168404Spjd 2374168404Spjd return (0); 2375168404Spjd} 2376168404Spjd 2377168404Spjd/* 2378219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2379168404Spjd */ 2380219089Spjdstatic void 2381219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2382219089Spjd unsigned long *cnt) 2383168404Spjd{ 2384168404Spjd unsigned long interval = 0, count = 0; 2385219089Spjd int argc = *argcp, errno; 2386168404Spjd 2387168404Spjd /* 2388168404Spjd * Determine if the last argument is an integer or a pool name 2389168404Spjd */ 2390168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2391168404Spjd char *end; 2392168404Spjd 2393168404Spjd errno = 0; 2394168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2395168404Spjd 2396168404Spjd if (*end == '\0' && errno == 0) { 2397168404Spjd if (interval == 0) { 2398168404Spjd (void) fprintf(stderr, gettext("interval " 2399168404Spjd "cannot be zero\n")); 2400168404Spjd usage(B_FALSE); 2401168404Spjd } 2402168404Spjd /* 2403168404Spjd * Ignore the last parameter 2404168404Spjd */ 2405168404Spjd argc--; 2406168404Spjd } else { 2407168404Spjd /* 2408168404Spjd * If this is not a valid number, just plow on. The 2409168404Spjd * user will get a more informative error message later 2410168404Spjd * on. 2411168404Spjd */ 2412168404Spjd interval = 0; 2413168404Spjd } 2414168404Spjd } 2415168404Spjd 2416168404Spjd /* 2417168404Spjd * If the last argument is also an integer, then we have both a count 2418219089Spjd * and an interval. 2419168404Spjd */ 2420168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2421168404Spjd char *end; 2422168404Spjd 2423168404Spjd errno = 0; 2424168404Spjd count = interval; 2425168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2426168404Spjd 2427168404Spjd if (*end == '\0' && errno == 0) { 2428168404Spjd if (interval == 0) { 2429168404Spjd (void) fprintf(stderr, gettext("interval " 2430168404Spjd "cannot be zero\n")); 2431168404Spjd usage(B_FALSE); 2432168404Spjd } 2433168404Spjd 2434168404Spjd /* 2435168404Spjd * Ignore the last parameter 2436168404Spjd */ 2437168404Spjd argc--; 2438168404Spjd } else { 2439168404Spjd interval = 0; 2440168404Spjd } 2441168404Spjd } 2442168404Spjd 2443219089Spjd *iv = interval; 2444219089Spjd *cnt = count; 2445219089Spjd *argcp = argc; 2446219089Spjd} 2447219089Spjd 2448219089Spjdstatic void 2449219089Spjdget_timestamp_arg(char c) 2450219089Spjd{ 2451219089Spjd if (c == 'u') 2452219089Spjd timestamp_fmt = UDATE; 2453219089Spjd else if (c == 'd') 2454219089Spjd timestamp_fmt = DDATE; 2455219089Spjd else 2456219089Spjd usage(B_FALSE); 2457219089Spjd} 2458219089Spjd 2459219089Spjd/* 2460219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2461219089Spjd * 2462219089Spjd * -v Display statistics for individual vdevs 2463219089Spjd * -T Display a timestamp in date(1) or Unix format 2464219089Spjd * 2465219089Spjd * This command can be tricky because we want to be able to deal with pool 2466219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2467219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2468219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2469219089Spjd * changes are all handled within libzfs. 2470219089Spjd */ 2471219089Spjdint 2472219089Spjdzpool_do_iostat(int argc, char **argv) 2473219089Spjd{ 2474219089Spjd int c; 2475219089Spjd int ret; 2476219089Spjd int npools; 2477219089Spjd unsigned long interval = 0, count = 0; 2478219089Spjd zpool_list_t *list; 2479219089Spjd boolean_t verbose = B_FALSE; 2480219089Spjd iostat_cbdata_t cb; 2481219089Spjd 2482219089Spjd /* check options */ 2483219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2484219089Spjd switch (c) { 2485219089Spjd case 'T': 2486219089Spjd get_timestamp_arg(*optarg); 2487219089Spjd break; 2488219089Spjd case 'v': 2489219089Spjd verbose = B_TRUE; 2490219089Spjd break; 2491219089Spjd case '?': 2492219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2493219089Spjd optopt); 2494219089Spjd usage(B_FALSE); 2495219089Spjd } 2496219089Spjd } 2497219089Spjd 2498219089Spjd argc -= optind; 2499219089Spjd argv += optind; 2500219089Spjd 2501219089Spjd get_interval_count(&argc, argv, &interval, &count); 2502219089Spjd 2503168404Spjd /* 2504168404Spjd * Construct the list of all interesting pools. 2505168404Spjd */ 2506168404Spjd ret = 0; 2507168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2508168404Spjd return (1); 2509168404Spjd 2510168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2511168404Spjd pool_list_free(list); 2512168404Spjd return (1); 2513168404Spjd } 2514168404Spjd 2515168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2516168404Spjd pool_list_free(list); 2517168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2518168404Spjd return (1); 2519168404Spjd } 2520168404Spjd 2521168404Spjd /* 2522168404Spjd * Enter the main iostat loop. 2523168404Spjd */ 2524168404Spjd cb.cb_list = list; 2525168404Spjd cb.cb_verbose = verbose; 2526168404Spjd cb.cb_iteration = 0; 2527168404Spjd cb.cb_namewidth = 0; 2528168404Spjd 2529168404Spjd for (;;) { 2530168404Spjd pool_list_update(list); 2531168404Spjd 2532168404Spjd if ((npools = pool_list_count(list)) == 0) 2533168404Spjd break; 2534168404Spjd 2535168404Spjd /* 2536168404Spjd * Refresh all statistics. This is done as an explicit step 2537168404Spjd * before calculating the maximum name width, so that any 2538168404Spjd * configuration changes are properly accounted for. 2539168404Spjd */ 2540168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2541168404Spjd 2542168404Spjd /* 2543168404Spjd * Iterate over all pools to determine the maximum width 2544168404Spjd * for the pool / device name column across all pools. 2545168404Spjd */ 2546168404Spjd cb.cb_namewidth = 0; 2547168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2548168404Spjd 2549219089Spjd if (timestamp_fmt != NODATE) 2550219089Spjd print_timestamp(timestamp_fmt); 2551219089Spjd 2552168404Spjd /* 2553168404Spjd * If it's the first time, or verbose mode, print the header. 2554168404Spjd */ 2555168404Spjd if (++cb.cb_iteration == 1 || verbose) 2556168404Spjd print_iostat_header(&cb); 2557168404Spjd 2558168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2559168404Spjd 2560168404Spjd /* 2561168404Spjd * If there's more than one pool, and we're not in verbose mode 2562168404Spjd * (which prints a separator for us), then print a separator. 2563168404Spjd */ 2564168404Spjd if (npools > 1 && !verbose) 2565168404Spjd print_iostat_separator(&cb); 2566168404Spjd 2567168404Spjd if (verbose) 2568168404Spjd (void) printf("\n"); 2569168404Spjd 2570168404Spjd /* 2571168404Spjd * Flush the output so that redirection to a file isn't buffered 2572168404Spjd * indefinitely. 2573168404Spjd */ 2574168404Spjd (void) fflush(stdout); 2575168404Spjd 2576168404Spjd if (interval == 0) 2577168404Spjd break; 2578168404Spjd 2579168404Spjd if (count != 0 && --count == 0) 2580168404Spjd break; 2581168404Spjd 2582168404Spjd (void) sleep(interval); 2583168404Spjd } 2584168404Spjd 2585168404Spjd pool_list_free(list); 2586168404Spjd 2587168404Spjd return (ret); 2588168404Spjd} 2589168404Spjd 2590168404Spjdtypedef struct list_cbdata { 2591236155Smm boolean_t cb_verbose; 2592236155Smm int cb_namewidth; 2593168404Spjd boolean_t cb_scripted; 2594185029Spjd zprop_list_t *cb_proplist; 2595168404Spjd} list_cbdata_t; 2596168404Spjd 2597168404Spjd/* 2598168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2599168404Spjd */ 2600185029Spjdstatic void 2601236155Smmprint_header(list_cbdata_t *cb) 2602168404Spjd{ 2603236155Smm zprop_list_t *pl = cb->cb_proplist; 2604185029Spjd const char *header; 2605185029Spjd boolean_t first = B_TRUE; 2606185029Spjd boolean_t right_justify; 2607236155Smm size_t width = 0; 2608168404Spjd 2609185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2610185029Spjd if (pl->pl_prop == ZPROP_INVAL) 2611185029Spjd continue; 2612185029Spjd 2613236155Smm width = pl->pl_width; 2614236155Smm if (first && cb->cb_verbose) { 2615236155Smm /* 2616236155Smm * Reset the width to accommodate the verbose listing 2617236155Smm * of devices. 2618236155Smm */ 2619236155Smm width = cb->cb_namewidth; 2620236155Smm } 2621236155Smm 2622185029Spjd if (!first) 2623168404Spjd (void) printf(" "); 2624168404Spjd else 2625185029Spjd first = B_FALSE; 2626168404Spjd 2627185029Spjd header = zpool_prop_column_name(pl->pl_prop); 2628185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2629185029Spjd 2630185029Spjd if (pl->pl_next == NULL && !right_justify) 2631185029Spjd (void) printf("%s", header); 2632185029Spjd else if (right_justify) 2633236155Smm (void) printf("%*s", width, header); 2634185029Spjd else 2635236155Smm (void) printf("%-*s", width, header); 2636236155Smm 2637168404Spjd } 2638168404Spjd 2639168404Spjd (void) printf("\n"); 2640168404Spjd} 2641168404Spjd 2642185029Spjd/* 2643185029Spjd * Given a pool and a list of properties, print out all the properties according 2644185029Spjd * to the described layout. 2645185029Spjd */ 2646185029Spjdstatic void 2647236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 2648168404Spjd{ 2649236155Smm zprop_list_t *pl = cb->cb_proplist; 2650185029Spjd boolean_t first = B_TRUE; 2651185029Spjd char property[ZPOOL_MAXPROPLEN]; 2652185029Spjd char *propstr; 2653185029Spjd boolean_t right_justify; 2654236155Smm size_t width; 2655168404Spjd 2656185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2657236155Smm 2658236155Smm width = pl->pl_width; 2659236155Smm if (first && cb->cb_verbose) { 2660236155Smm /* 2661236155Smm * Reset the width to accommodate the verbose listing 2662236155Smm * of devices. 2663236155Smm */ 2664236155Smm width = cb->cb_namewidth; 2665236155Smm } 2666236155Smm 2667185029Spjd if (!first) { 2668236155Smm if (cb->cb_scripted) 2669168404Spjd (void) printf("\t"); 2670168404Spjd else 2671168404Spjd (void) printf(" "); 2672185029Spjd } else { 2673185029Spjd first = B_FALSE; 2674168404Spjd } 2675168404Spjd 2676185029Spjd right_justify = B_FALSE; 2677185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2678236155Smm if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ && 2679236155Smm zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0) 2680236155Smm propstr = "-"; 2681236155Smm else if (zpool_get_prop(zhp, pl->pl_prop, property, 2682185029Spjd sizeof (property), NULL) != 0) 2683185029Spjd propstr = "-"; 2684168404Spjd else 2685185029Spjd propstr = property; 2686168404Spjd 2687185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2688185029Spjd } else { 2689185029Spjd propstr = "-"; 2690185029Spjd } 2691168404Spjd 2692168404Spjd 2693185029Spjd /* 2694185029Spjd * If this is being called in scripted mode, or if this is the 2695185029Spjd * last column and it is left-justified, don't include a width 2696185029Spjd * format specifier. 2697185029Spjd */ 2698236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 2699185029Spjd (void) printf("%s", propstr); 2700185029Spjd else if (right_justify) 2701185029Spjd (void) printf("%*s", width, propstr); 2702185029Spjd else 2703185029Spjd (void) printf("%-*s", width, propstr); 2704185029Spjd } 2705168404Spjd 2706185029Spjd (void) printf("\n"); 2707185029Spjd} 2708168404Spjd 2709236155Smmstatic void 2710236155Smmprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted) 2711236155Smm{ 2712236155Smm char propval[64]; 2713236155Smm boolean_t fixed; 2714236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 2715236155Smm 2716236155Smm zfs_nicenum(value, propval, sizeof (propval)); 2717236155Smm 2718236155Smm if (prop == ZPOOL_PROP_EXPANDSZ && value == 0) 2719236155Smm (void) strlcpy(propval, "-", sizeof (propval)); 2720236155Smm 2721236155Smm if (scripted) 2722236155Smm (void) printf("\t%s", propval); 2723236155Smm else 2724236155Smm (void) printf(" %*s", width, propval); 2725236155Smm} 2726236155Smm 2727236155Smmvoid 2728236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 2729236155Smm list_cbdata_t *cb, int depth) 2730236155Smm{ 2731236155Smm nvlist_t **child; 2732236155Smm vdev_stat_t *vs; 2733236155Smm uint_t c, children; 2734236155Smm char *vname; 2735236155Smm boolean_t scripted = cb->cb_scripted; 2736236155Smm 2737236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 2738236155Smm (uint64_t **)&vs, &c) == 0); 2739236155Smm 2740236155Smm if (name != NULL) { 2741236155Smm if (scripted) 2742236155Smm (void) printf("\t%s", name); 2743236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 2744236155Smm (void) printf("%*s%s", depth, "", name); 2745236155Smm else 2746236155Smm (void) printf("%*s%s%*s", depth, "", name, 2747236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2748236155Smm 2749236155Smm /* only toplevel vdevs have capacity stats */ 2750236155Smm if (vs->vs_space == 0) { 2751236155Smm if (scripted) 2752236155Smm (void) printf("\t-\t-\t-"); 2753236155Smm else 2754236155Smm (void) printf(" - - -"); 2755236155Smm } else { 2756236155Smm print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, 2757236155Smm scripted); 2758236155Smm print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc, 2759236155Smm scripted); 2760236155Smm print_one_column(ZPOOL_PROP_FREE, 2761236155Smm vs->vs_space - vs->vs_alloc, scripted); 2762236155Smm } 2763236155Smm print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, 2764236155Smm scripted); 2765236155Smm (void) printf("\n"); 2766236155Smm } 2767236155Smm 2768236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2769236155Smm &child, &children) != 0) 2770236155Smm return; 2771236155Smm 2772236155Smm for (c = 0; c < children; c++) { 2773236155Smm uint64_t ishole = B_FALSE; 2774236155Smm 2775236155Smm if (nvlist_lookup_uint64(child[c], 2776236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 2777236155Smm continue; 2778236155Smm 2779236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 2780236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 2781236155Smm free(vname); 2782236155Smm } 2783236155Smm 2784236155Smm /* 2785236155Smm * Include level 2 ARC devices in iostat output 2786236155Smm */ 2787236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 2788236155Smm &child, &children) != 0) 2789236155Smm return; 2790236155Smm 2791236155Smm if (children > 0) { 2792236155Smm (void) printf("%-*s - - - - - " 2793236155Smm "-\n", cb->cb_namewidth, "cache"); 2794236155Smm for (c = 0; c < children; c++) { 2795236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], 2796236155Smm B_FALSE); 2797236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 2798236155Smm free(vname); 2799236155Smm } 2800236155Smm } 2801236155Smm} 2802236155Smm 2803236155Smm 2804185029Spjd/* 2805185029Spjd * Generic callback function to list a pool. 2806185029Spjd */ 2807185029Spjdint 2808185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 2809185029Spjd{ 2810185029Spjd list_cbdata_t *cbp = data; 2811236155Smm nvlist_t *config; 2812236155Smm nvlist_t *nvroot; 2813168404Spjd 2814236155Smm config = zpool_get_config(zhp, NULL); 2815168404Spjd 2816236155Smm print_pool(zhp, cbp); 2817236155Smm if (!cbp->cb_verbose) 2818236155Smm return (0); 2819168404Spjd 2820236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2821236155Smm &nvroot) == 0); 2822236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 2823236155Smm 2824168404Spjd return (0); 2825168404Spjd} 2826168404Spjd 2827168404Spjd/* 2828219089Spjd * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 2829168404Spjd * 2830185029Spjd * -H Scripted mode. Don't display headers, and separate properties 2831185029Spjd * by a single tab. 2832185029Spjd * -o List of properties to display. Defaults to 2833219089Spjd * "name,size,allocated,free,capacity,health,altroot" 2834219089Spjd * -T Display a timestamp in date(1) or Unix format 2835168404Spjd * 2836168404Spjd * List all pools in the system, whether or not they're healthy. Output space 2837168404Spjd * statistics for each one, as well as health status summary. 2838168404Spjd */ 2839168404Spjdint 2840168404Spjdzpool_do_list(int argc, char **argv) 2841168404Spjd{ 2842168404Spjd int c; 2843168404Spjd int ret; 2844168404Spjd list_cbdata_t cb = { 0 }; 2845185029Spjd static char default_props[] = 2846236155Smm "name,size,allocated,free,capacity,dedupratio," 2847236155Smm "health,altroot"; 2848185029Spjd char *props = default_props; 2849219089Spjd unsigned long interval = 0, count = 0; 2850236155Smm zpool_list_t *list; 2851236155Smm boolean_t first = B_TRUE; 2852168404Spjd 2853168404Spjd /* check options */ 2854236155Smm while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) { 2855168404Spjd switch (c) { 2856168404Spjd case 'H': 2857168404Spjd cb.cb_scripted = B_TRUE; 2858168404Spjd break; 2859168404Spjd case 'o': 2860185029Spjd props = optarg; 2861168404Spjd break; 2862219089Spjd case 'T': 2863219089Spjd get_timestamp_arg(*optarg); 2864219089Spjd break; 2865236155Smm case 'v': 2866236155Smm cb.cb_verbose = B_TRUE; 2867236155Smm break; 2868168404Spjd case ':': 2869168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2870168404Spjd "'%c' option\n"), optopt); 2871168404Spjd usage(B_FALSE); 2872168404Spjd break; 2873168404Spjd case '?': 2874168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2875168404Spjd optopt); 2876168404Spjd usage(B_FALSE); 2877168404Spjd } 2878168404Spjd } 2879168404Spjd 2880168404Spjd argc -= optind; 2881168404Spjd argv += optind; 2882168404Spjd 2883219089Spjd get_interval_count(&argc, argv, &interval, &count); 2884219089Spjd 2885185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 2886185029Spjd usage(B_FALSE); 2887168404Spjd 2888236155Smm if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL) 2889236155Smm return (1); 2890168404Spjd 2891236155Smm if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 2892236155Smm (void) printf(gettext("no pools available\n")); 2893236155Smm zprop_free_list(cb.cb_proplist); 2894236155Smm return (0); 2895236155Smm } 2896236155Smm 2897219089Spjd for (;;) { 2898236155Smm pool_list_update(list); 2899168404Spjd 2900236155Smm if (pool_list_count(list) == 0) 2901236155Smm break; 2902236155Smm 2903236155Smm cb.cb_namewidth = 0; 2904236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2905236155Smm 2906219089Spjd if (timestamp_fmt != NODATE) 2907219089Spjd print_timestamp(timestamp_fmt); 2908168404Spjd 2909236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 2910236155Smm print_header(&cb); 2911236155Smm first = B_FALSE; 2912219089Spjd } 2913236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 2914219089Spjd 2915219089Spjd if (interval == 0) 2916219089Spjd break; 2917219089Spjd 2918219089Spjd if (count != 0 && --count == 0) 2919219089Spjd break; 2920219089Spjd 2921219089Spjd (void) sleep(interval); 2922168404Spjd } 2923168404Spjd 2924219089Spjd zprop_free_list(cb.cb_proplist); 2925168404Spjd return (ret); 2926168404Spjd} 2927168404Spjd 2928168404Spjdstatic nvlist_t * 2929168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name) 2930168404Spjd{ 2931168404Spjd nvlist_t **child; 2932168404Spjd uint_t c, children; 2933168404Spjd nvlist_t *match; 2934168404Spjd char *path; 2935168404Spjd 2936168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2937168404Spjd &child, &children) != 0) { 2938168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2939219089Spjd if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 2940219089Spjd name += sizeof(_PATH_DEV) - 1; 2941219089Spjd if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 2942219089Spjd path += sizeof(_PATH_DEV) - 1; 2943168404Spjd if (strcmp(name, path) == 0) 2944168404Spjd return (nv); 2945168404Spjd return (NULL); 2946168404Spjd } 2947168404Spjd 2948168404Spjd for (c = 0; c < children; c++) 2949168404Spjd if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2950168404Spjd return (match); 2951168404Spjd 2952168404Spjd return (NULL); 2953168404Spjd} 2954168404Spjd 2955168404Spjdstatic int 2956168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 2957168404Spjd{ 2958168404Spjd boolean_t force = B_FALSE; 2959168404Spjd int c; 2960168404Spjd nvlist_t *nvroot; 2961168404Spjd char *poolname, *old_disk, *new_disk; 2962168404Spjd zpool_handle_t *zhp; 2963168404Spjd int ret; 2964168404Spjd 2965168404Spjd /* check options */ 2966168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 2967168404Spjd switch (c) { 2968168404Spjd case 'f': 2969168404Spjd force = B_TRUE; 2970168404Spjd break; 2971168404Spjd case '?': 2972168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2973168404Spjd optopt); 2974168404Spjd usage(B_FALSE); 2975168404Spjd } 2976168404Spjd } 2977168404Spjd 2978168404Spjd argc -= optind; 2979168404Spjd argv += optind; 2980168404Spjd 2981168404Spjd /* get pool name and check number of arguments */ 2982168404Spjd if (argc < 1) { 2983168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 2984168404Spjd usage(B_FALSE); 2985168404Spjd } 2986168404Spjd 2987168404Spjd poolname = argv[0]; 2988168404Spjd 2989168404Spjd if (argc < 2) { 2990168404Spjd (void) fprintf(stderr, 2991168404Spjd gettext("missing <device> specification\n")); 2992168404Spjd usage(B_FALSE); 2993168404Spjd } 2994168404Spjd 2995168404Spjd old_disk = argv[1]; 2996168404Spjd 2997168404Spjd if (argc < 3) { 2998168404Spjd if (!replacing) { 2999168404Spjd (void) fprintf(stderr, 3000168404Spjd gettext("missing <new_device> specification\n")); 3001168404Spjd usage(B_FALSE); 3002168404Spjd } 3003168404Spjd new_disk = old_disk; 3004168404Spjd argc -= 1; 3005168404Spjd argv += 1; 3006168404Spjd } else { 3007168404Spjd new_disk = argv[2]; 3008168404Spjd argc -= 2; 3009168404Spjd argv += 2; 3010168404Spjd } 3011168404Spjd 3012168404Spjd if (argc > 1) { 3013168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3014168404Spjd usage(B_FALSE); 3015168404Spjd } 3016168404Spjd 3017168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3018168404Spjd return (1); 3019168404Spjd 3020185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3021168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3022168404Spjd poolname); 3023168404Spjd zpool_close(zhp); 3024168404Spjd return (1); 3025168404Spjd } 3026168404Spjd 3027185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3028185029Spjd argc, argv); 3029168404Spjd if (nvroot == NULL) { 3030168404Spjd zpool_close(zhp); 3031168404Spjd return (1); 3032168404Spjd } 3033168404Spjd 3034168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3035168404Spjd 3036168404Spjd nvlist_free(nvroot); 3037168404Spjd zpool_close(zhp); 3038168404Spjd 3039168404Spjd return (ret); 3040168404Spjd} 3041168404Spjd 3042168404Spjd/* 3043168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3044168404Spjd * 3045168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3046168404Spjd * 3047168404Spjd * Replace <device> with <new_device>. 3048168404Spjd */ 3049168404Spjd/* ARGSUSED */ 3050168404Spjdint 3051168404Spjdzpool_do_replace(int argc, char **argv) 3052168404Spjd{ 3053168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3054168404Spjd} 3055168404Spjd 3056168404Spjd/* 3057168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3058168404Spjd * 3059168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3060168404Spjd * 3061168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3062168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3063168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3064168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3065168404Spjd */ 3066168404Spjdint 3067168404Spjdzpool_do_attach(int argc, char **argv) 3068168404Spjd{ 3069168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3070168404Spjd} 3071168404Spjd 3072168404Spjd/* 3073168404Spjd * zpool detach [-f] <pool> <device> 3074168404Spjd * 3075168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3076168404Spjd * (not supported yet) 3077168404Spjd * 3078168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3079168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3080168404Spjd * has the only valid copy of some data. 3081168404Spjd */ 3082168404Spjd/* ARGSUSED */ 3083168404Spjdint 3084168404Spjdzpool_do_detach(int argc, char **argv) 3085168404Spjd{ 3086168404Spjd int c; 3087168404Spjd char *poolname, *path; 3088168404Spjd zpool_handle_t *zhp; 3089168404Spjd int ret; 3090168404Spjd 3091168404Spjd /* check options */ 3092168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3093168404Spjd switch (c) { 3094168404Spjd case 'f': 3095168404Spjd case '?': 3096168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3097168404Spjd optopt); 3098168404Spjd usage(B_FALSE); 3099168404Spjd } 3100168404Spjd } 3101168404Spjd 3102168404Spjd argc -= optind; 3103168404Spjd argv += optind; 3104168404Spjd 3105168404Spjd /* get pool name and check number of arguments */ 3106168404Spjd if (argc < 1) { 3107168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3108168404Spjd usage(B_FALSE); 3109168404Spjd } 3110168404Spjd 3111168404Spjd if (argc < 2) { 3112168404Spjd (void) fprintf(stderr, 3113168404Spjd gettext("missing <device> specification\n")); 3114168404Spjd usage(B_FALSE); 3115168404Spjd } 3116168404Spjd 3117168404Spjd poolname = argv[0]; 3118168404Spjd path = argv[1]; 3119168404Spjd 3120168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3121168404Spjd return (1); 3122168404Spjd 3123168404Spjd ret = zpool_vdev_detach(zhp, path); 3124168404Spjd 3125168404Spjd zpool_close(zhp); 3126168404Spjd 3127168404Spjd return (ret); 3128168404Spjd} 3129168404Spjd 3130168404Spjd/* 3131219089Spjd * zpool split [-n] [-o prop=val] ... 3132219089Spjd * [-o mntopt] ... 3133219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3134219089Spjd * 3135219089Spjd * -n Do not split the pool, but display the resulting layout if 3136219089Spjd * it were to be split. 3137219089Spjd * -o Set property=value, or set mount options. 3138219089Spjd * -R Mount the split-off pool under an alternate root. 3139219089Spjd * 3140219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3141219089Spjd * off may be listed, provided that no more than one device is specified 3142219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3143219089Spjd * state unless -R is specified. 3144219089Spjd * 3145219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3146219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3147219089Spjd * undergoing a resilvering operation. 3148219089Spjd */ 3149219089Spjdint 3150219089Spjdzpool_do_split(int argc, char **argv) 3151219089Spjd{ 3152219089Spjd char *srcpool, *newpool, *propval; 3153219089Spjd char *mntopts = NULL; 3154219089Spjd splitflags_t flags; 3155219089Spjd int c, ret = 0; 3156219089Spjd zpool_handle_t *zhp; 3157219089Spjd nvlist_t *config, *props = NULL; 3158219089Spjd 3159219089Spjd flags.dryrun = B_FALSE; 3160219089Spjd flags.import = B_FALSE; 3161219089Spjd 3162219089Spjd /* check options */ 3163219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3164219089Spjd switch (c) { 3165219089Spjd case 'R': 3166219089Spjd flags.import = B_TRUE; 3167219089Spjd if (add_prop_list( 3168219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3169219089Spjd &props, B_TRUE) != 0) { 3170219089Spjd if (props) 3171219089Spjd nvlist_free(props); 3172219089Spjd usage(B_FALSE); 3173219089Spjd } 3174219089Spjd break; 3175219089Spjd case 'n': 3176219089Spjd flags.dryrun = B_TRUE; 3177219089Spjd break; 3178219089Spjd case 'o': 3179219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3180219089Spjd *propval = '\0'; 3181219089Spjd propval++; 3182219089Spjd if (add_prop_list(optarg, propval, 3183219089Spjd &props, B_TRUE) != 0) { 3184219089Spjd if (props) 3185219089Spjd nvlist_free(props); 3186219089Spjd usage(B_FALSE); 3187219089Spjd } 3188219089Spjd } else { 3189219089Spjd mntopts = optarg; 3190219089Spjd } 3191219089Spjd break; 3192219089Spjd case ':': 3193219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3194219089Spjd "'%c' option\n"), optopt); 3195219089Spjd usage(B_FALSE); 3196219089Spjd break; 3197219089Spjd case '?': 3198219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3199219089Spjd optopt); 3200219089Spjd usage(B_FALSE); 3201219089Spjd break; 3202219089Spjd } 3203219089Spjd } 3204219089Spjd 3205219089Spjd if (!flags.import && mntopts != NULL) { 3206219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3207219089Spjd "valid when importing the pool\n")); 3208219089Spjd usage(B_FALSE); 3209219089Spjd } 3210219089Spjd 3211219089Spjd argc -= optind; 3212219089Spjd argv += optind; 3213219089Spjd 3214219089Spjd if (argc < 1) { 3215219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3216219089Spjd usage(B_FALSE); 3217219089Spjd } 3218219089Spjd if (argc < 2) { 3219219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3220219089Spjd usage(B_FALSE); 3221219089Spjd } 3222219089Spjd 3223219089Spjd srcpool = argv[0]; 3224219089Spjd newpool = argv[1]; 3225219089Spjd 3226219089Spjd argc -= 2; 3227219089Spjd argv += 2; 3228219089Spjd 3229219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3230219089Spjd return (1); 3231219089Spjd 3232219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3233219089Spjd if (config == NULL) { 3234219089Spjd ret = 1; 3235219089Spjd } else { 3236219089Spjd if (flags.dryrun) { 3237219089Spjd (void) printf(gettext("would create '%s' with the " 3238219089Spjd "following layout:\n\n"), newpool); 3239219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3240219089Spjd } 3241219089Spjd nvlist_free(config); 3242219089Spjd } 3243219089Spjd 3244219089Spjd zpool_close(zhp); 3245219089Spjd 3246219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3247219089Spjd return (ret); 3248219089Spjd 3249219089Spjd /* 3250219089Spjd * The split was successful. Now we need to open the new 3251219089Spjd * pool and import it. 3252219089Spjd */ 3253219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3254219089Spjd return (1); 3255219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3256219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3257219089Spjd ret = 1; 3258219089Spjd (void) fprintf(stderr, gettext("Split was succssful, but " 3259219089Spjd "the datasets could not all be mounted\n")); 3260219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3261219089Spjd "different altroot\n"), "zpool import"); 3262219089Spjd } 3263219089Spjd zpool_close(zhp); 3264219089Spjd 3265219089Spjd return (ret); 3266219089Spjd} 3267219089Spjd 3268219089Spjd 3269219089Spjd 3270219089Spjd/* 3271168404Spjd * zpool online <pool> <device> ... 3272168404Spjd */ 3273168404Spjdint 3274168404Spjdzpool_do_online(int argc, char **argv) 3275168404Spjd{ 3276168404Spjd int c, i; 3277168404Spjd char *poolname; 3278168404Spjd zpool_handle_t *zhp; 3279168404Spjd int ret = 0; 3280185029Spjd vdev_state_t newstate; 3281219089Spjd int flags = 0; 3282168404Spjd 3283168404Spjd /* check options */ 3284219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3285168404Spjd switch (c) { 3286219089Spjd case 'e': 3287219089Spjd flags |= ZFS_ONLINE_EXPAND; 3288219089Spjd break; 3289168404Spjd case 't': 3290168404Spjd case '?': 3291168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3292168404Spjd optopt); 3293168404Spjd usage(B_FALSE); 3294168404Spjd } 3295168404Spjd } 3296168404Spjd 3297168404Spjd argc -= optind; 3298168404Spjd argv += optind; 3299168404Spjd 3300168404Spjd /* get pool name and check number of arguments */ 3301168404Spjd if (argc < 1) { 3302168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3303168404Spjd usage(B_FALSE); 3304168404Spjd } 3305168404Spjd if (argc < 2) { 3306168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3307168404Spjd usage(B_FALSE); 3308168404Spjd } 3309168404Spjd 3310168404Spjd poolname = argv[0]; 3311168404Spjd 3312168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3313168404Spjd return (1); 3314168404Spjd 3315185029Spjd for (i = 1; i < argc; i++) { 3316219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3317185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3318185029Spjd (void) printf(gettext("warning: device '%s' " 3319185029Spjd "onlined, but remains in faulted state\n"), 3320185029Spjd argv[i]); 3321185029Spjd if (newstate == VDEV_STATE_FAULTED) 3322185029Spjd (void) printf(gettext("use 'zpool " 3323185029Spjd "clear' to restore a faulted " 3324185029Spjd "device\n")); 3325185029Spjd else 3326185029Spjd (void) printf(gettext("use 'zpool " 3327185029Spjd "replace' to replace devices " 3328185029Spjd "that are no longer present\n")); 3329185029Spjd } 3330185029Spjd } else { 3331168404Spjd ret = 1; 3332185029Spjd } 3333185029Spjd } 3334168404Spjd 3335168404Spjd zpool_close(zhp); 3336168404Spjd 3337168404Spjd return (ret); 3338168404Spjd} 3339168404Spjd 3340168404Spjd/* 3341168404Spjd * zpool offline [-ft] <pool> <device> ... 3342168404Spjd * 3343168404Spjd * -f Force the device into the offline state, even if doing 3344168404Spjd * so would appear to compromise pool availability. 3345168404Spjd * (not supported yet) 3346168404Spjd * 3347168404Spjd * -t Only take the device off-line temporarily. The offline 3348168404Spjd * state will not be persistent across reboots. 3349168404Spjd */ 3350168404Spjd/* ARGSUSED */ 3351168404Spjdint 3352168404Spjdzpool_do_offline(int argc, char **argv) 3353168404Spjd{ 3354168404Spjd int c, i; 3355168404Spjd char *poolname; 3356168404Spjd zpool_handle_t *zhp; 3357168404Spjd int ret = 0; 3358168404Spjd boolean_t istmp = B_FALSE; 3359168404Spjd 3360168404Spjd /* check options */ 3361168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3362168404Spjd switch (c) { 3363168404Spjd case 't': 3364168404Spjd istmp = B_TRUE; 3365168404Spjd break; 3366168404Spjd case 'f': 3367168404Spjd case '?': 3368168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3369168404Spjd optopt); 3370168404Spjd usage(B_FALSE); 3371168404Spjd } 3372168404Spjd } 3373168404Spjd 3374168404Spjd argc -= optind; 3375168404Spjd argv += optind; 3376168404Spjd 3377168404Spjd /* get pool name and check number of arguments */ 3378168404Spjd if (argc < 1) { 3379168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3380168404Spjd usage(B_FALSE); 3381168404Spjd } 3382168404Spjd if (argc < 2) { 3383168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3384168404Spjd usage(B_FALSE); 3385168404Spjd } 3386168404Spjd 3387168404Spjd poolname = argv[0]; 3388168404Spjd 3389168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3390168404Spjd return (1); 3391168404Spjd 3392185029Spjd for (i = 1; i < argc; i++) { 3393185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3394168404Spjd ret = 1; 3395185029Spjd } 3396168404Spjd 3397168404Spjd zpool_close(zhp); 3398168404Spjd 3399168404Spjd return (ret); 3400168404Spjd} 3401168404Spjd 3402168404Spjd/* 3403168404Spjd * zpool clear <pool> [device] 3404168404Spjd * 3405168404Spjd * Clear all errors associated with a pool or a particular device. 3406168404Spjd */ 3407168404Spjdint 3408168404Spjdzpool_do_clear(int argc, char **argv) 3409168404Spjd{ 3410219089Spjd int c; 3411168404Spjd int ret = 0; 3412219089Spjd boolean_t dryrun = B_FALSE; 3413219089Spjd boolean_t do_rewind = B_FALSE; 3414219089Spjd boolean_t xtreme_rewind = B_FALSE; 3415219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3416219089Spjd nvlist_t *policy = NULL; 3417168404Spjd zpool_handle_t *zhp; 3418168404Spjd char *pool, *device; 3419168404Spjd 3420219089Spjd /* check options */ 3421219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3422219089Spjd switch (c) { 3423219089Spjd case 'F': 3424219089Spjd do_rewind = B_TRUE; 3425219089Spjd break; 3426219089Spjd case 'n': 3427219089Spjd dryrun = B_TRUE; 3428219089Spjd break; 3429219089Spjd case 'X': 3430219089Spjd xtreme_rewind = B_TRUE; 3431219089Spjd break; 3432219089Spjd case '?': 3433219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3434219089Spjd optopt); 3435219089Spjd usage(B_FALSE); 3436219089Spjd } 3437219089Spjd } 3438219089Spjd 3439219089Spjd argc -= optind; 3440219089Spjd argv += optind; 3441219089Spjd 3442219089Spjd if (argc < 1) { 3443168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3444168404Spjd usage(B_FALSE); 3445168404Spjd } 3446168404Spjd 3447219089Spjd if (argc > 2) { 3448168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3449168404Spjd usage(B_FALSE); 3450168404Spjd } 3451168404Spjd 3452219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3453219089Spjd (void) fprintf(stderr, 3454219089Spjd gettext("-n or -X only meaningful with -F\n")); 3455219089Spjd usage(B_FALSE); 3456219089Spjd } 3457219089Spjd if (dryrun) 3458219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3459219089Spjd else if (do_rewind) 3460219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3461219089Spjd if (xtreme_rewind) 3462219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3463168404Spjd 3464219089Spjd /* In future, further rewind policy choices can be passed along here */ 3465219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3466219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3467168404Spjd return (1); 3468168404Spjd 3469219089Spjd pool = argv[0]; 3470219089Spjd device = argc == 2 ? argv[1] : NULL; 3471219089Spjd 3472219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3473219089Spjd nvlist_free(policy); 3474219089Spjd return (1); 3475219089Spjd } 3476219089Spjd 3477219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3478168404Spjd ret = 1; 3479168404Spjd 3480168404Spjd zpool_close(zhp); 3481168404Spjd 3482219089Spjd nvlist_free(policy); 3483219089Spjd 3484168404Spjd return (ret); 3485168404Spjd} 3486168404Spjd 3487228103Smm/* 3488228103Smm * zpool reguid <pool> 3489228103Smm */ 3490228103Smmint 3491228103Smmzpool_do_reguid(int argc, char **argv) 3492228103Smm{ 3493228103Smm int c; 3494228103Smm char *poolname; 3495228103Smm zpool_handle_t *zhp; 3496228103Smm int ret = 0; 3497228103Smm 3498228103Smm /* check options */ 3499228103Smm while ((c = getopt(argc, argv, "")) != -1) { 3500228103Smm switch (c) { 3501228103Smm case '?': 3502228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3503228103Smm optopt); 3504228103Smm usage(B_FALSE); 3505228103Smm } 3506228103Smm } 3507228103Smm 3508228103Smm argc -= optind; 3509228103Smm argv += optind; 3510228103Smm 3511228103Smm /* get pool name and check number of arguments */ 3512228103Smm if (argc < 1) { 3513228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 3514228103Smm usage(B_FALSE); 3515228103Smm } 3516228103Smm 3517228103Smm if (argc > 1) { 3518228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 3519228103Smm usage(B_FALSE); 3520228103Smm } 3521228103Smm 3522228103Smm poolname = argv[0]; 3523228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3524228103Smm return (1); 3525228103Smm 3526228103Smm ret = zpool_reguid(zhp); 3527228103Smm 3528228103Smm zpool_close(zhp); 3529228103Smm return (ret); 3530228103Smm} 3531228103Smm 3532228103Smm 3533236155Smm/* 3534236155Smm * zpool reopen <pool> 3535236155Smm * 3536236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 3537236155Smm * 3538236155Smm * NOTE: This command is currently undocumented. If the command is ever 3539236155Smm * exposed then the appropriate usage() messages will need to be made. 3540236155Smm */ 3541236155Smmint 3542236155Smmzpool_do_reopen(int argc, char **argv) 3543236155Smm{ 3544236155Smm int ret = 0; 3545236155Smm zpool_handle_t *zhp; 3546236155Smm char *pool; 3547236155Smm 3548236155Smm argc--; 3549236155Smm argv++; 3550236155Smm 3551236155Smm if (argc != 1) 3552236155Smm return (2); 3553236155Smm 3554236155Smm pool = argv[0]; 3555236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 3556236155Smm return (1); 3557236155Smm 3558236155Smm ret = zpool_reopen(zhp); 3559236155Smm zpool_close(zhp); 3560236155Smm return (ret); 3561236155Smm} 3562236155Smm 3563168404Spjdtypedef struct scrub_cbdata { 3564168404Spjd int cb_type; 3565168404Spjd int cb_argc; 3566168404Spjd char **cb_argv; 3567168404Spjd} scrub_cbdata_t; 3568168404Spjd 3569168404Spjdint 3570168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3571168404Spjd{ 3572168404Spjd scrub_cbdata_t *cb = data; 3573168404Spjd int err; 3574168404Spjd 3575168404Spjd /* 3576168404Spjd * Ignore faulted pools. 3577168404Spjd */ 3578168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3579168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3580168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 3581168404Spjd return (1); 3582168404Spjd } 3583168404Spjd 3584219089Spjd err = zpool_scan(zhp, cb->cb_type); 3585168404Spjd 3586168404Spjd return (err != 0); 3587168404Spjd} 3588168404Spjd 3589168404Spjd/* 3590168404Spjd * zpool scrub [-s] <pool> ... 3591168404Spjd * 3592168404Spjd * -s Stop. Stops any in-progress scrub. 3593168404Spjd */ 3594168404Spjdint 3595168404Spjdzpool_do_scrub(int argc, char **argv) 3596168404Spjd{ 3597168404Spjd int c; 3598168404Spjd scrub_cbdata_t cb; 3599168404Spjd 3600219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 3601168404Spjd 3602168404Spjd /* check options */ 3603168404Spjd while ((c = getopt(argc, argv, "s")) != -1) { 3604168404Spjd switch (c) { 3605168404Spjd case 's': 3606219089Spjd cb.cb_type = POOL_SCAN_NONE; 3607168404Spjd break; 3608168404Spjd case '?': 3609168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3610168404Spjd optopt); 3611168404Spjd usage(B_FALSE); 3612168404Spjd } 3613168404Spjd } 3614168404Spjd 3615168404Spjd cb.cb_argc = argc; 3616168404Spjd cb.cb_argv = argv; 3617168404Spjd argc -= optind; 3618168404Spjd argv += optind; 3619168404Spjd 3620168404Spjd if (argc < 1) { 3621168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3622168404Spjd usage(B_FALSE); 3623168404Spjd } 3624168404Spjd 3625168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3626168404Spjd} 3627168404Spjd 3628168404Spjdtypedef struct status_cbdata { 3629168404Spjd int cb_count; 3630168404Spjd boolean_t cb_allpools; 3631168404Spjd boolean_t cb_verbose; 3632168404Spjd boolean_t cb_explain; 3633168404Spjd boolean_t cb_first; 3634219089Spjd boolean_t cb_dedup_stats; 3635168404Spjd} status_cbdata_t; 3636168404Spjd 3637168404Spjd/* 3638168404Spjd * Print out detailed scrub status. 3639168404Spjd */ 3640168404Spjdvoid 3641219089Spjdprint_scan_status(pool_scan_stat_t *ps) 3642168404Spjd{ 3643219089Spjd time_t start, end; 3644219089Spjd uint64_t elapsed, mins_left, hours_left; 3645219089Spjd uint64_t pass_exam, examined, total; 3646219089Spjd uint_t rate; 3647168404Spjd double fraction_done; 3648219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3649168404Spjd 3650226583Spjd (void) printf(gettext(" scan: ")); 3651168404Spjd 3652219089Spjd /* If there's never been a scan, there's not much to say. */ 3653219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 3654219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 3655168404Spjd (void) printf(gettext("none requested\n")); 3656168404Spjd return; 3657168404Spjd } 3658168404Spjd 3659219089Spjd start = ps->pss_start_time; 3660219089Spjd end = ps->pss_end_time; 3661219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3662168404Spjd 3663219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 3664219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 3665219089Spjd /* 3666219089Spjd * Scan is finished or canceled. 3667219089Spjd */ 3668219089Spjd if (ps->pss_state == DSS_FINISHED) { 3669219089Spjd uint64_t minutes_taken = (end - start) / 60; 3670219089Spjd char *fmt; 3671168404Spjd 3672219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3673219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 3674219089Spjd "%llu errors on %s"); 3675219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3676219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 3677219089Spjd "%llu errors on %s"); 3678219089Spjd } 3679219089Spjd /* LINTED */ 3680219089Spjd (void) printf(fmt, processed_buf, 3681185029Spjd (u_longlong_t)(minutes_taken / 60), 3682185029Spjd (uint_t)(minutes_taken % 60), 3683219089Spjd (u_longlong_t)ps->pss_errors, 3684219089Spjd ctime((time_t *)&end)); 3685168404Spjd return; 3686219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 3687219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3688219089Spjd (void) printf(gettext("scrub canceled on %s"), 3689219089Spjd ctime(&end)); 3690219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3691219089Spjd (void) printf(gettext("resilver canceled on %s"), 3692219089Spjd ctime(&end)); 3693219089Spjd } 3694219089Spjd return; 3695168404Spjd } 3696168404Spjd 3697219089Spjd assert(ps->pss_state == DSS_SCANNING); 3698168404Spjd 3699219089Spjd /* 3700219089Spjd * Scan is in progress. 3701219089Spjd */ 3702219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3703219089Spjd (void) printf(gettext("scrub in progress since %s"), 3704219089Spjd ctime(&start)); 3705219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3706219089Spjd (void) printf(gettext("resilver in progress since %s"), 3707219089Spjd ctime(&start)); 3708219089Spjd } 3709219089Spjd 3710219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 3711219089Spjd total = ps->pss_to_examine; 3712168404Spjd fraction_done = (double)examined / total; 3713168404Spjd 3714219089Spjd /* elapsed time for this pass */ 3715219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 3716219089Spjd elapsed = elapsed ? elapsed : 1; 3717219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 3718219089Spjd rate = pass_exam / elapsed; 3719219089Spjd rate = rate ? rate : 1; 3720219089Spjd mins_left = ((total - examined) / rate) / 60; 3721219089Spjd hours_left = mins_left / 60; 3722219089Spjd 3723219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 3724219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 3725219089Spjd zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 3726219089Spjd 3727219089Spjd /* 3728219089Spjd * do not print estimated time if hours_left is more than 30 days 3729219089Spjd */ 3730226583Spjd (void) printf(gettext(" %s scanned out of %s at %s/s"), 3731219089Spjd examined_buf, total_buf, rate_buf); 3732219089Spjd if (hours_left < (30 * 24)) { 3733219089Spjd (void) printf(gettext(", %lluh%um to go\n"), 3734219089Spjd (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 3735219089Spjd } else { 3736219089Spjd (void) printf(gettext( 3737219089Spjd ", (scan is slow, no estimated time)\n")); 3738219089Spjd } 3739219089Spjd 3740219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 3741226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 3742219089Spjd processed_buf, 100 * fraction_done); 3743219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 3744226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 3745219089Spjd processed_buf, 100 * fraction_done); 3746219089Spjd } 3747168404Spjd} 3748168404Spjd 3749168404Spjdstatic void 3750168404Spjdprint_error_log(zpool_handle_t *zhp) 3751168404Spjd{ 3752185029Spjd nvlist_t *nverrlist = NULL; 3753168404Spjd nvpair_t *elem; 3754168404Spjd char *pathname; 3755168404Spjd size_t len = MAXPATHLEN * 2; 3756168404Spjd 3757168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 3758168404Spjd (void) printf("errors: List of errors unavailable " 3759168404Spjd "(insufficient privileges)\n"); 3760168404Spjd return; 3761168404Spjd } 3762168404Spjd 3763168404Spjd (void) printf("errors: Permanent errors have been " 3764168404Spjd "detected in the following files:\n\n"); 3765168404Spjd 3766168404Spjd pathname = safe_malloc(len); 3767168404Spjd elem = NULL; 3768168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 3769168404Spjd nvlist_t *nv; 3770168404Spjd uint64_t dsobj, obj; 3771168404Spjd 3772168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 3773168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 3774168404Spjd &dsobj) == 0); 3775168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 3776168404Spjd &obj) == 0); 3777168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 3778168404Spjd (void) printf("%7s %s\n", "", pathname); 3779168404Spjd } 3780168404Spjd free(pathname); 3781168404Spjd nvlist_free(nverrlist); 3782168404Spjd} 3783168404Spjd 3784168404Spjdstatic void 3785168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 3786168404Spjd int namewidth) 3787168404Spjd{ 3788168404Spjd uint_t i; 3789168404Spjd char *name; 3790168404Spjd 3791168404Spjd if (nspares == 0) 3792168404Spjd return; 3793168404Spjd 3794168404Spjd (void) printf(gettext("\tspares\n")); 3795168404Spjd 3796168404Spjd for (i = 0; i < nspares; i++) { 3797219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 3798168404Spjd print_status_config(zhp, name, spares[i], 3799209962Smm namewidth, 2, B_TRUE); 3800168404Spjd free(name); 3801168404Spjd } 3802168404Spjd} 3803168404Spjd 3804185029Spjdstatic void 3805185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 3806185029Spjd int namewidth) 3807185029Spjd{ 3808185029Spjd uint_t i; 3809185029Spjd char *name; 3810185029Spjd 3811185029Spjd if (nl2cache == 0) 3812185029Spjd return; 3813185029Spjd 3814185029Spjd (void) printf(gettext("\tcache\n")); 3815185029Spjd 3816185029Spjd for (i = 0; i < nl2cache; i++) { 3817219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 3818185029Spjd print_status_config(zhp, name, l2cache[i], 3819209962Smm namewidth, 2, B_FALSE); 3820185029Spjd free(name); 3821185029Spjd } 3822185029Spjd} 3823185029Spjd 3824219089Spjdstatic void 3825219089Spjdprint_dedup_stats(nvlist_t *config) 3826219089Spjd{ 3827219089Spjd ddt_histogram_t *ddh; 3828219089Spjd ddt_stat_t *dds; 3829219089Spjd ddt_object_t *ddo; 3830219089Spjd uint_t c; 3831219089Spjd 3832219089Spjd /* 3833219089Spjd * If the pool was faulted then we may not have been able to 3834219089Spjd * obtain the config. Otherwise, if have anything in the dedup 3835219089Spjd * table continue processing the stats. 3836219089Spjd */ 3837219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 3838227497Smm (uint64_t **)&ddo, &c) != 0) 3839219089Spjd return; 3840219089Spjd 3841219089Spjd (void) printf("\n"); 3842227497Smm (void) printf(gettext(" dedup: ")); 3843227497Smm if (ddo->ddo_count == 0) { 3844227497Smm (void) printf(gettext("no DDT entries\n")); 3845227497Smm return; 3846227497Smm } 3847227497Smm 3848219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 3849219089Spjd (u_longlong_t)ddo->ddo_count, 3850219089Spjd (u_longlong_t)ddo->ddo_dspace, 3851219089Spjd (u_longlong_t)ddo->ddo_mspace); 3852219089Spjd 3853219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 3854219089Spjd (uint64_t **)&dds, &c) == 0); 3855219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 3856219089Spjd (uint64_t **)&ddh, &c) == 0); 3857219089Spjd zpool_dump_ddt(dds, ddh); 3858219089Spjd} 3859219089Spjd 3860168404Spjd/* 3861168404Spjd * Display a summary of pool status. Displays a summary such as: 3862168404Spjd * 3863168404Spjd * pool: tank 3864168404Spjd * status: DEGRADED 3865168404Spjd * reason: One or more devices ... 3866236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 3867168404Spjd * config: 3868168404Spjd * mirror DEGRADED 3869168404Spjd * c1t0d0 OK 3870168404Spjd * c2t0d0 UNAVAIL 3871168404Spjd * 3872168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 3873168404Spjd * option is specified, then we print out error rate information as well. 3874168404Spjd */ 3875168404Spjdint 3876168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 3877168404Spjd{ 3878168404Spjd status_cbdata_t *cbp = data; 3879168404Spjd nvlist_t *config, *nvroot; 3880168404Spjd char *msgid; 3881168404Spjd int reason; 3882168404Spjd const char *health; 3883168404Spjd uint_t c; 3884168404Spjd vdev_stat_t *vs; 3885168404Spjd 3886168404Spjd config = zpool_get_config(zhp, NULL); 3887168404Spjd reason = zpool_get_status(zhp, &msgid); 3888168404Spjd 3889168404Spjd cbp->cb_count++; 3890168404Spjd 3891168404Spjd /* 3892168404Spjd * If we were given 'zpool status -x', only report those pools with 3893168404Spjd * problems. 3894168404Spjd */ 3895168404Spjd if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 3896168404Spjd if (!cbp->cb_allpools) { 3897168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 3898168404Spjd zpool_get_name(zhp)); 3899168404Spjd if (cbp->cb_first) 3900168404Spjd cbp->cb_first = B_FALSE; 3901168404Spjd } 3902168404Spjd return (0); 3903168404Spjd } 3904168404Spjd 3905168404Spjd if (cbp->cb_first) 3906168404Spjd cbp->cb_first = B_FALSE; 3907168404Spjd else 3908168404Spjd (void) printf("\n"); 3909168404Spjd 3910168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3911168404Spjd &nvroot) == 0); 3912219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 3913168404Spjd (uint64_t **)&vs, &c) == 0); 3914185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 3915168404Spjd 3916168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 3917168404Spjd (void) printf(gettext(" state: %s\n"), health); 3918168404Spjd 3919168404Spjd switch (reason) { 3920168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 3921168404Spjd (void) printf(gettext("status: One or more devices could not " 3922168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 3923168404Spjd "continue functioning in a degraded state.\n")); 3924168404Spjd (void) printf(gettext("action: Attach the missing device and " 3925168404Spjd "online it using 'zpool online'.\n")); 3926168404Spjd break; 3927168404Spjd 3928168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 3929168404Spjd (void) printf(gettext("status: One or more devices could not " 3930168404Spjd "be opened. There are insufficient\n\treplicas for the " 3931168404Spjd "pool to continue functioning.\n")); 3932168404Spjd (void) printf(gettext("action: Attach the missing device and " 3933168404Spjd "online it using 'zpool online'.\n")); 3934168404Spjd break; 3935168404Spjd 3936168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 3937168404Spjd (void) printf(gettext("status: One or more devices could not " 3938168404Spjd "be used because the label is missing or\n\tinvalid. " 3939168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 3940168404Spjd "functioning in a degraded state.\n")); 3941168404Spjd (void) printf(gettext("action: Replace the device using " 3942168404Spjd "'zpool replace'.\n")); 3943168404Spjd break; 3944168404Spjd 3945168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 3946168404Spjd (void) printf(gettext("status: One or more devices could not " 3947168404Spjd "be used because the label is missing \n\tor invalid. " 3948168404Spjd "There are insufficient replicas for the pool to " 3949168404Spjd "continue\n\tfunctioning.\n")); 3950219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 3951219089Spjd zpool_get_name(zhp), reason, config); 3952168404Spjd break; 3953168404Spjd 3954168404Spjd case ZPOOL_STATUS_FAILING_DEV: 3955168404Spjd (void) printf(gettext("status: One or more devices has " 3956168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 3957168404Spjd "made to correct the error. Applications are " 3958168404Spjd "unaffected.\n")); 3959168404Spjd (void) printf(gettext("action: Determine if the device needs " 3960168404Spjd "to be replaced, and clear the errors\n\tusing " 3961168404Spjd "'zpool clear' or replace the device with 'zpool " 3962168404Spjd "replace'.\n")); 3963168404Spjd break; 3964168404Spjd 3965168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 3966168404Spjd (void) printf(gettext("status: One or more devices has " 3967168404Spjd "been taken offline by the administrator.\n\tSufficient " 3968168404Spjd "replicas exist for the pool to continue functioning in " 3969168404Spjd "a\n\tdegraded state.\n")); 3970168404Spjd (void) printf(gettext("action: Online the device using " 3971168404Spjd "'zpool online' or replace the device with\n\t'zpool " 3972168404Spjd "replace'.\n")); 3973168404Spjd break; 3974168404Spjd 3975219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 3976219089Spjd (void) printf(gettext("status: One or more devices has " 3977219089Spjd "been removed by the administrator.\n\tSufficient " 3978219089Spjd "replicas exist for the pool to continue functioning in " 3979219089Spjd "a\n\tdegraded state.\n")); 3980219089Spjd (void) printf(gettext("action: Online the device using " 3981219089Spjd "'zpool online' or replace the device with\n\t'zpool " 3982219089Spjd "replace'.\n")); 3983219089Spjd break; 3984219089Spjd 3985168404Spjd case ZPOOL_STATUS_RESILVERING: 3986168404Spjd (void) printf(gettext("status: One or more devices is " 3987168404Spjd "currently being resilvered. The pool will\n\tcontinue " 3988168404Spjd "to function, possibly in a degraded state.\n")); 3989168404Spjd (void) printf(gettext("action: Wait for the resilver to " 3990168404Spjd "complete.\n")); 3991168404Spjd break; 3992168404Spjd 3993168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 3994168404Spjd (void) printf(gettext("status: One or more devices has " 3995168404Spjd "experienced an error resulting in data\n\tcorruption. " 3996168404Spjd "Applications may be affected.\n")); 3997168404Spjd (void) printf(gettext("action: Restore the file in question " 3998168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 3999168404Spjd "backup.\n")); 4000168404Spjd break; 4001168404Spjd 4002168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4003168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4004168404Spjd "and the pool cannot be opened.\n")); 4005219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4006219089Spjd zpool_get_name(zhp), reason, config); 4007168404Spjd break; 4008168404Spjd 4009168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4010168404Spjd (void) printf(gettext("status: The pool is formatted using an " 4011168404Spjd "older on-disk format. The pool can\n\tstill be used, but " 4012168404Spjd "some features are unavailable.\n")); 4013168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4014168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 4015168404Spjd "be accessible on older software versions.\n")); 4016168404Spjd break; 4017168404Spjd 4018168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 4019168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 4020168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 4021168404Spjd "be accessed on this system.\n")); 4022168404Spjd (void) printf(gettext("action: Access the pool from a system " 4023168404Spjd "running more recent software, or\n\trestore the pool from " 4024168404Spjd "backup.\n")); 4025168404Spjd break; 4026168404Spjd 4027185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 4028185029Spjd (void) printf(gettext("status: One or more devices are " 4029185029Spjd "faulted in response to persistent errors.\n\tSufficient " 4030185029Spjd "replicas exist for the pool to continue functioning " 4031185029Spjd "in a\n\tdegraded state.\n")); 4032185029Spjd (void) printf(gettext("action: Replace the faulted device, " 4033185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 4034185029Spjd break; 4035185029Spjd 4036185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 4037185029Spjd (void) printf(gettext("status: One or more devices are " 4038185029Spjd "faulted in response to persistent errors. There are " 4039185029Spjd "insufficient replicas for the pool to\n\tcontinue " 4040185029Spjd "functioning.\n")); 4041185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 4042185029Spjd "from a backup source. Manually marking the device\n" 4043185029Spjd "\trepaired using 'zpool clear' may allow some data " 4044185029Spjd "to be recovered.\n")); 4045185029Spjd break; 4046185029Spjd 4047185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 4048185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 4049185029Spjd (void) printf(gettext("status: One or more devices are " 4050185029Spjd "faulted in response to IO failures.\n")); 4051185029Spjd (void) printf(gettext("action: Make sure the affected devices " 4052185029Spjd "are connected, then run 'zpool clear'.\n")); 4053185029Spjd break; 4054185029Spjd 4055185029Spjd case ZPOOL_STATUS_BAD_LOG: 4056185029Spjd (void) printf(gettext("status: An intent log record " 4057185029Spjd "could not be read.\n" 4058185029Spjd "\tWaiting for adminstrator intervention to fix the " 4059185029Spjd "faulted pool.\n")); 4060185029Spjd (void) printf(gettext("action: Either restore the affected " 4061185029Spjd "device(s) and run 'zpool online',\n" 4062185029Spjd "\tor ignore the intent log records by running " 4063185029Spjd "'zpool clear'.\n")); 4064185029Spjd break; 4065185029Spjd 4066168404Spjd default: 4067168404Spjd /* 4068168404Spjd * The remaining errors can't actually be generated, yet. 4069168404Spjd */ 4070168404Spjd assert(reason == ZPOOL_STATUS_OK); 4071168404Spjd } 4072168404Spjd 4073168404Spjd if (msgid != NULL) 4074236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4075168404Spjd msgid); 4076168404Spjd 4077168404Spjd if (config != NULL) { 4078168404Spjd int namewidth; 4079168404Spjd uint64_t nerr; 4080185029Spjd nvlist_t **spares, **l2cache; 4081185029Spjd uint_t nspares, nl2cache; 4082219089Spjd pool_scan_stat_t *ps = NULL; 4083168404Spjd 4084219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 4085219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 4086219089Spjd print_scan_status(ps); 4087168404Spjd 4088168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 4089168404Spjd if (namewidth < 10) 4090168404Spjd namewidth = 10; 4091168404Spjd 4092168404Spjd (void) printf(gettext("config:\n\n")); 4093168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4094168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4095168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 4096209962Smm namewidth, 0, B_FALSE); 4097209962Smm 4098185029Spjd if (num_logs(nvroot) > 0) 4099213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 4100185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4101185029Spjd &l2cache, &nl2cache) == 0) 4102185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 4103185029Spjd 4104168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 4105168404Spjd &spares, &nspares) == 0) 4106168404Spjd print_spares(zhp, spares, nspares, namewidth); 4107168404Spjd 4108168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4109168404Spjd &nerr) == 0) { 4110168404Spjd nvlist_t *nverrlist = NULL; 4111168404Spjd 4112168404Spjd /* 4113168404Spjd * If the approximate error count is small, get a 4114168404Spjd * precise count by fetching the entire log and 4115168404Spjd * uniquifying the results. 4116168404Spjd */ 4117185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 4118168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 4119168404Spjd nvpair_t *elem; 4120168404Spjd 4121168404Spjd elem = NULL; 4122168404Spjd nerr = 0; 4123168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 4124168404Spjd elem)) != NULL) { 4125168404Spjd nerr++; 4126168404Spjd } 4127168404Spjd } 4128168404Spjd nvlist_free(nverrlist); 4129168404Spjd 4130168404Spjd (void) printf("\n"); 4131168404Spjd 4132168404Spjd if (nerr == 0) 4133168404Spjd (void) printf(gettext("errors: No known data " 4134168404Spjd "errors\n")); 4135168404Spjd else if (!cbp->cb_verbose) 4136168404Spjd (void) printf(gettext("errors: %llu data " 4137168404Spjd "errors, use '-v' for a list\n"), 4138168404Spjd (u_longlong_t)nerr); 4139168404Spjd else 4140168404Spjd print_error_log(zhp); 4141168404Spjd } 4142219089Spjd 4143219089Spjd if (cbp->cb_dedup_stats) 4144219089Spjd print_dedup_stats(config); 4145168404Spjd } else { 4146168404Spjd (void) printf(gettext("config: The configuration cannot be " 4147168404Spjd "determined.\n")); 4148168404Spjd } 4149168404Spjd 4150168404Spjd return (0); 4151168404Spjd} 4152168404Spjd 4153168404Spjd/* 4154219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4155168404Spjd * 4156168404Spjd * -v Display complete error logs 4157168404Spjd * -x Display only pools with potential problems 4158219089Spjd * -D Display dedup status (undocumented) 4159219089Spjd * -T Display a timestamp in date(1) or Unix format 4160168404Spjd * 4161168404Spjd * Describes the health status of all pools or some subset. 4162168404Spjd */ 4163168404Spjdint 4164168404Spjdzpool_do_status(int argc, char **argv) 4165168404Spjd{ 4166168404Spjd int c; 4167168404Spjd int ret; 4168219089Spjd unsigned long interval = 0, count = 0; 4169168404Spjd status_cbdata_t cb = { 0 }; 4170168404Spjd 4171168404Spjd /* check options */ 4172219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4173168404Spjd switch (c) { 4174168404Spjd case 'v': 4175168404Spjd cb.cb_verbose = B_TRUE; 4176168404Spjd break; 4177168404Spjd case 'x': 4178168404Spjd cb.cb_explain = B_TRUE; 4179168404Spjd break; 4180219089Spjd case 'D': 4181219089Spjd cb.cb_dedup_stats = B_TRUE; 4182219089Spjd break; 4183219089Spjd case 'T': 4184219089Spjd get_timestamp_arg(*optarg); 4185219089Spjd break; 4186168404Spjd case '?': 4187168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4188168404Spjd optopt); 4189168404Spjd usage(B_FALSE); 4190168404Spjd } 4191168404Spjd } 4192168404Spjd 4193168404Spjd argc -= optind; 4194168404Spjd argv += optind; 4195168404Spjd 4196219089Spjd get_interval_count(&argc, argv, &interval, &count); 4197168404Spjd 4198168404Spjd if (argc == 0) 4199168404Spjd cb.cb_allpools = B_TRUE; 4200168404Spjd 4201219089Spjd cb.cb_first = B_TRUE; 4202168404Spjd 4203219089Spjd for (;;) { 4204219089Spjd if (timestamp_fmt != NODATE) 4205219089Spjd print_timestamp(timestamp_fmt); 4206168404Spjd 4207219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 4208219089Spjd status_callback, &cb); 4209219089Spjd 4210219089Spjd if (argc == 0 && cb.cb_count == 0) 4211219089Spjd (void) printf(gettext("no pools available\n")); 4212219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 4213219089Spjd (void) printf(gettext("all pools are healthy\n")); 4214219089Spjd 4215219089Spjd if (ret != 0) 4216219089Spjd return (ret); 4217219089Spjd 4218219089Spjd if (interval == 0) 4219219089Spjd break; 4220219089Spjd 4221219089Spjd if (count != 0 && --count == 0) 4222219089Spjd break; 4223219089Spjd 4224219089Spjd (void) sleep(interval); 4225219089Spjd } 4226219089Spjd 4227219089Spjd return (0); 4228168404Spjd} 4229168404Spjd 4230168404Spjdtypedef struct upgrade_cbdata { 4231168404Spjd int cb_all; 4232168404Spjd int cb_first; 4233168404Spjd int cb_newer; 4234212050Spjd char cb_poolname[ZPOOL_MAXNAMELEN]; 4235168404Spjd int cb_argc; 4236185029Spjd uint64_t cb_version; 4237168404Spjd char **cb_argv; 4238168404Spjd} upgrade_cbdata_t; 4239168404Spjd 4240168404Spjdstatic int 4241212050Spjdis_root_pool(zpool_handle_t *zhp) 4242212050Spjd{ 4243212050Spjd static struct statfs sfs; 4244212050Spjd static char *poolname = NULL; 4245212050Spjd static boolean_t stated = B_FALSE; 4246212050Spjd char *slash; 4247212050Spjd 4248212067Spjd if (!stated) { 4249212050Spjd stated = B_TRUE; 4250212050Spjd if (statfs("/", &sfs) == -1) { 4251212050Spjd (void) fprintf(stderr, 4252212050Spjd "Unable to stat root file system: %s.\n", 4253212050Spjd strerror(errno)); 4254212067Spjd return (0); 4255212050Spjd } 4256212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4257212067Spjd return (0); 4258212050Spjd poolname = sfs.f_mntfromname; 4259212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4260212050Spjd *slash = '\0'; 4261212050Spjd } 4262212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4263212050Spjd} 4264212050Spjd 4265212050Spjdstatic int 4266168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4267168404Spjd{ 4268168404Spjd upgrade_cbdata_t *cbp = arg; 4269168404Spjd nvlist_t *config; 4270168404Spjd uint64_t version; 4271168404Spjd int ret = 0; 4272168404Spjd 4273168404Spjd config = zpool_get_config(zhp, NULL); 4274168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4275168404Spjd &version) == 0); 4276168404Spjd 4277185029Spjd if (!cbp->cb_newer && version < SPA_VERSION) { 4278168404Spjd if (!cbp->cb_all) { 4279168404Spjd if (cbp->cb_first) { 4280168404Spjd (void) printf(gettext("The following pools are " 4281168404Spjd "out of date, and can be upgraded. After " 4282168404Spjd "being\nupgraded, these pools will no " 4283168404Spjd "longer be accessible by older software " 4284168404Spjd "versions.\n\n")); 4285168404Spjd (void) printf(gettext("VER POOL\n")); 4286168404Spjd (void) printf(gettext("--- ------------\n")); 4287168404Spjd cbp->cb_first = B_FALSE; 4288168404Spjd } 4289168404Spjd 4290168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4291168404Spjd zpool_get_name(zhp)); 4292168404Spjd } else { 4293168404Spjd cbp->cb_first = B_FALSE; 4294185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 4295168404Spjd if (!ret) { 4296168404Spjd (void) printf(gettext("Successfully upgraded " 4297185029Spjd "'%s'\n\n"), zpool_get_name(zhp)); 4298212050Spjd if (cbp->cb_poolname[0] == '\0' && 4299212050Spjd is_root_pool(zhp)) { 4300212050Spjd (void) strlcpy(cbp->cb_poolname, 4301212050Spjd zpool_get_name(zhp), 4302212050Spjd sizeof(cbp->cb_poolname)); 4303212050Spjd } 4304168404Spjd } 4305168404Spjd } 4306185029Spjd } else if (cbp->cb_newer && version > SPA_VERSION) { 4307168404Spjd assert(!cbp->cb_all); 4308168404Spjd 4309168404Spjd if (cbp->cb_first) { 4310168404Spjd (void) printf(gettext("The following pools are " 4311168404Spjd "formatted using a newer software version and\n" 4312168404Spjd "cannot be accessed on the current system.\n\n")); 4313168404Spjd (void) printf(gettext("VER POOL\n")); 4314168404Spjd (void) printf(gettext("--- ------------\n")); 4315168404Spjd cbp->cb_first = B_FALSE; 4316168404Spjd } 4317168404Spjd 4318168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4319168404Spjd zpool_get_name(zhp)); 4320168404Spjd } 4321168404Spjd 4322168404Spjd zpool_close(zhp); 4323168404Spjd return (ret); 4324168404Spjd} 4325168404Spjd 4326168404Spjd/* ARGSUSED */ 4327168404Spjdstatic int 4328168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 4329168404Spjd{ 4330185029Spjd upgrade_cbdata_t *cbp = data; 4331185029Spjd uint64_t cur_version; 4332168404Spjd int ret; 4333168404Spjd 4334185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 4335185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 4336185029Spjd "Pool 'log' must be renamed using export and import" 4337185029Spjd " to upgrade.\n")); 4338185029Spjd return (1); 4339185029Spjd } 4340168404Spjd 4341185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4342185029Spjd if (cur_version > cbp->cb_version) { 4343168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 4344185029Spjd "using more current version '%llu'.\n"), 4345185029Spjd zpool_get_name(zhp), cur_version); 4346185029Spjd return (0); 4347185029Spjd } 4348185029Spjd if (cur_version == cbp->cb_version) { 4349185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 4350168404Spjd "using the current version.\n"), zpool_get_name(zhp)); 4351168404Spjd return (0); 4352168404Spjd } 4353168404Spjd 4354185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 4355168404Spjd 4356168404Spjd if (!ret) { 4357168404Spjd (void) printf(gettext("Successfully upgraded '%s' " 4358185029Spjd "from version %llu to version %llu\n\n"), 4359185029Spjd zpool_get_name(zhp), (u_longlong_t)cur_version, 4360185029Spjd (u_longlong_t)cbp->cb_version); 4361212050Spjd if (cbp->cb_poolname[0] == '\0' && is_root_pool(zhp)) { 4362212050Spjd (void) strlcpy(cbp->cb_poolname, zpool_get_name(zhp), 4363212050Spjd sizeof(cbp->cb_poolname)); 4364212050Spjd } 4365168404Spjd } 4366168404Spjd 4367168404Spjd return (ret != 0); 4368168404Spjd} 4369168404Spjd 4370168404Spjd/* 4371168404Spjd * zpool upgrade 4372168404Spjd * zpool upgrade -v 4373185029Spjd * zpool upgrade [-V version] <-a | pool ...> 4374168404Spjd * 4375168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 4376168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 4377168404Spjd * upgrade all pools. 4378168404Spjd */ 4379168404Spjdint 4380168404Spjdzpool_do_upgrade(int argc, char **argv) 4381168404Spjd{ 4382168404Spjd int c; 4383168404Spjd upgrade_cbdata_t cb = { 0 }; 4384168404Spjd int ret = 0; 4385168404Spjd boolean_t showversions = B_FALSE; 4386185029Spjd char *end; 4387168404Spjd 4388185029Spjd 4389168404Spjd /* check options */ 4390219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 4391168404Spjd switch (c) { 4392168404Spjd case 'a': 4393168404Spjd cb.cb_all = B_TRUE; 4394168404Spjd break; 4395168404Spjd case 'v': 4396168404Spjd showversions = B_TRUE; 4397168404Spjd break; 4398185029Spjd case 'V': 4399185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 4400185029Spjd if (*end != '\0' || cb.cb_version > SPA_VERSION || 4401185029Spjd cb.cb_version < SPA_VERSION_1) { 4402185029Spjd (void) fprintf(stderr, 4403185029Spjd gettext("invalid version '%s'\n"), optarg); 4404185029Spjd usage(B_FALSE); 4405185029Spjd } 4406185029Spjd break; 4407219089Spjd case ':': 4408219089Spjd (void) fprintf(stderr, gettext("missing argument for " 4409219089Spjd "'%c' option\n"), optopt); 4410219089Spjd usage(B_FALSE); 4411219089Spjd break; 4412168404Spjd case '?': 4413168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4414168404Spjd optopt); 4415168404Spjd usage(B_FALSE); 4416168404Spjd } 4417168404Spjd } 4418168404Spjd 4419168404Spjd cb.cb_argc = argc; 4420168404Spjd cb.cb_argv = argv; 4421168404Spjd argc -= optind; 4422168404Spjd argv += optind; 4423168404Spjd 4424185029Spjd if (cb.cb_version == 0) { 4425185029Spjd cb.cb_version = SPA_VERSION; 4426185029Spjd } else if (!cb.cb_all && argc == 0) { 4427185029Spjd (void) fprintf(stderr, gettext("-V option is " 4428185029Spjd "incompatible with other arguments\n")); 4429185029Spjd usage(B_FALSE); 4430185029Spjd } 4431185029Spjd 4432168404Spjd if (showversions) { 4433168404Spjd if (cb.cb_all || argc != 0) { 4434168404Spjd (void) fprintf(stderr, gettext("-v option is " 4435168404Spjd "incompatible with other arguments\n")); 4436168404Spjd usage(B_FALSE); 4437168404Spjd } 4438168404Spjd } else if (cb.cb_all) { 4439168404Spjd if (argc != 0) { 4440185029Spjd (void) fprintf(stderr, gettext("-a option should not " 4441185029Spjd "be used along with a pool name\n")); 4442168404Spjd usage(B_FALSE); 4443168404Spjd } 4444168404Spjd } 4445168404Spjd 4446185029Spjd (void) printf(gettext("This system is currently running " 4447185029Spjd "ZFS pool version %llu.\n\n"), SPA_VERSION); 4448168404Spjd cb.cb_first = B_TRUE; 4449168404Spjd if (showversions) { 4450168404Spjd (void) printf(gettext("The following versions are " 4451168404Spjd "supported:\n\n")); 4452168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 4453168404Spjd (void) printf("--- -----------------------------------------" 4454168404Spjd "---------------\n"); 4455168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 4456168404Spjd (void) printf(gettext(" 2 Ditto blocks " 4457168404Spjd "(replicated metadata)\n")); 4458168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 4459168404Spjd "RAID-Z\n")); 4460168404Spjd (void) printf(gettext(" 4 zpool history\n")); 4461168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 4462168404Spjd "algorithm\n")); 4463185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 4464185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 4465185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 4466185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 4467185029Spjd "properties\n")); 4468185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 4469185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 4470185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 4471185029Spjd (void) printf(gettext(" 13 snapused property\n")); 4472209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 4473209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 4474219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 4475219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 4476219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 4477219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 4478219089Spjd (void) printf(gettext(" 20 Compression using zle " 4479219089Spjd "(zero-length encoding)\n")); 4480219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 4481219089Spjd (void) printf(gettext(" 22 Received properties\n")); 4482219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 4483219089Spjd (void) printf(gettext(" 24 System attributes\n")); 4484219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 4485219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 4486219089Spjd "performance\n")); 4487219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 4488219089Spjd "performance\n")); 4489219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 4490219089Spjd (void) printf(gettext("\nFor more information on a particular " 4491219089Spjd "version, including supported releases,\n")); 4492219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 4493168404Spjd } else if (argc == 0) { 4494168404Spjd int notfound; 4495168404Spjd 4496168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4497168404Spjd notfound = cb.cb_first; 4498168404Spjd 4499168404Spjd if (!cb.cb_all && ret == 0) { 4500168404Spjd if (!cb.cb_first) 4501168404Spjd (void) printf("\n"); 4502168404Spjd cb.cb_first = B_TRUE; 4503168404Spjd cb.cb_newer = B_TRUE; 4504168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4505168404Spjd if (!cb.cb_first) { 4506168404Spjd notfound = B_FALSE; 4507168404Spjd (void) printf("\n"); 4508168404Spjd } 4509168404Spjd } 4510168404Spjd 4511168404Spjd if (ret == 0) { 4512168404Spjd if (notfound) 4513168404Spjd (void) printf(gettext("All pools are formatted " 4514168404Spjd "using this version.\n")); 4515168404Spjd else if (!cb.cb_all) 4516168404Spjd (void) printf(gettext("Use 'zpool upgrade -v' " 4517168404Spjd "for a list of available versions and " 4518168404Spjd "their associated\nfeatures.\n")); 4519168404Spjd } 4520168404Spjd } else { 4521168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, 4522168404Spjd upgrade_one, &cb); 4523168404Spjd } 4524168404Spjd 4525212050Spjd if (cb.cb_poolname[0] != '\0') { 4526212050Spjd (void) printf( 4527212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 4528212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 4529212050Spjd "the following command will do it:\n" 4530212050Spjd "\n" 4531212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 4532212050Spjd cb.cb_poolname); 4533212050Spjd } 4534212050Spjd 4535168404Spjd return (ret); 4536168404Spjd} 4537168404Spjd 4538185029Spjdtypedef struct hist_cbdata { 4539185029Spjd boolean_t first; 4540185029Spjd int longfmt; 4541185029Spjd int internal; 4542185029Spjd} hist_cbdata_t; 4543185029Spjd 4544168404Spjd/* 4545168404Spjd * Print out the command history for a specific pool. 4546168404Spjd */ 4547168404Spjdstatic int 4548168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 4549168404Spjd{ 4550168404Spjd nvlist_t *nvhis; 4551168404Spjd nvlist_t **records; 4552168404Spjd uint_t numrecords; 4553168404Spjd char *cmdstr; 4554185029Spjd char *pathstr; 4555168404Spjd uint64_t dst_time; 4556168404Spjd time_t tsec; 4557168404Spjd struct tm t; 4558168404Spjd char tbuf[30]; 4559168404Spjd int ret, i; 4560185029Spjd uint64_t who; 4561185029Spjd struct passwd *pwd; 4562185029Spjd char *hostname; 4563185029Spjd char *zonename; 4564185029Spjd char internalstr[MAXPATHLEN]; 4565185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 4566185029Spjd uint64_t txg; 4567185029Spjd uint64_t ievent; 4568168404Spjd 4569185029Spjd cb->first = B_FALSE; 4570168404Spjd 4571168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 4572168404Spjd 4573168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 4574168404Spjd return (ret); 4575168404Spjd 4576168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 4577168404Spjd &records, &numrecords) == 0); 4578168404Spjd for (i = 0; i < numrecords; i++) { 4579168404Spjd if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 4580185029Spjd &dst_time) != 0) 4581185029Spjd continue; 4582185029Spjd 4583185029Spjd /* is it an internal event or a standard event? */ 4584185029Spjd if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 4585185029Spjd &cmdstr) != 0) { 4586185029Spjd if (cb->internal == 0) 4587185029Spjd continue; 4588185029Spjd 4589185029Spjd if (nvlist_lookup_uint64(records[i], 4590185029Spjd ZPOOL_HIST_INT_EVENT, &ievent) != 0) 4591185029Spjd continue; 4592185029Spjd verify(nvlist_lookup_uint64(records[i], 4593185029Spjd ZPOOL_HIST_TXG, &txg) == 0); 4594185029Spjd verify(nvlist_lookup_string(records[i], 4595185029Spjd ZPOOL_HIST_INT_STR, &pathstr) == 0); 4596185029Spjd if (ievent >= LOG_END) 4597185029Spjd continue; 4598185029Spjd (void) snprintf(internalstr, 4599185029Spjd sizeof (internalstr), 4600185029Spjd "[internal %s txg:%lld] %s", 4601219089Spjd zfs_history_event_names[ievent], txg, 4602185029Spjd pathstr); 4603185029Spjd cmdstr = internalstr; 4604168404Spjd } 4605185029Spjd tsec = dst_time; 4606185029Spjd (void) localtime_r(&tsec, &t); 4607185029Spjd (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 4608185029Spjd (void) printf("%s %s", tbuf, cmdstr); 4609185029Spjd 4610185029Spjd if (!cb->longfmt) { 4611185029Spjd (void) printf("\n"); 4612185029Spjd continue; 4613185029Spjd } 4614185029Spjd (void) printf(" ["); 4615185029Spjd if (nvlist_lookup_uint64(records[i], 4616185029Spjd ZPOOL_HIST_WHO, &who) == 0) { 4617185029Spjd pwd = getpwuid((uid_t)who); 4618185029Spjd if (pwd) 4619185029Spjd (void) printf("user %s on", 4620185029Spjd pwd->pw_name); 4621185029Spjd else 4622185029Spjd (void) printf("user %d on", 4623185029Spjd (int)who); 4624185029Spjd } else { 4625185029Spjd (void) printf(gettext("no info]\n")); 4626185029Spjd continue; 4627185029Spjd } 4628185029Spjd if (nvlist_lookup_string(records[i], 4629185029Spjd ZPOOL_HIST_HOST, &hostname) == 0) { 4630185029Spjd (void) printf(" %s", hostname); 4631185029Spjd } 4632185029Spjd if (nvlist_lookup_string(records[i], 4633185029Spjd ZPOOL_HIST_ZONE, &zonename) == 0) { 4634185029Spjd (void) printf(":%s", zonename); 4635185029Spjd } 4636185029Spjd 4637185029Spjd (void) printf("]"); 4638185029Spjd (void) printf("\n"); 4639168404Spjd } 4640168404Spjd (void) printf("\n"); 4641168404Spjd nvlist_free(nvhis); 4642168404Spjd 4643168404Spjd return (ret); 4644168404Spjd} 4645168404Spjd 4646168404Spjd/* 4647168404Spjd * zpool history <pool> 4648168404Spjd * 4649168404Spjd * Displays the history of commands that modified pools. 4650168404Spjd */ 4651185029Spjd 4652185029Spjd 4653168404Spjdint 4654168404Spjdzpool_do_history(int argc, char **argv) 4655168404Spjd{ 4656185029Spjd hist_cbdata_t cbdata = { 0 }; 4657168404Spjd int ret; 4658185029Spjd int c; 4659168404Spjd 4660185029Spjd cbdata.first = B_TRUE; 4661185029Spjd /* check options */ 4662185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 4663185029Spjd switch (c) { 4664185029Spjd case 'l': 4665185029Spjd cbdata.longfmt = 1; 4666185029Spjd break; 4667185029Spjd case 'i': 4668185029Spjd cbdata.internal = 1; 4669185029Spjd break; 4670185029Spjd case '?': 4671185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4672185029Spjd optopt); 4673185029Spjd usage(B_FALSE); 4674185029Spjd } 4675185029Spjd } 4676168404Spjd argc -= optind; 4677168404Spjd argv += optind; 4678168404Spjd 4679168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 4680185029Spjd &cbdata); 4681168404Spjd 4682185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 4683168404Spjd (void) printf(gettext("no pools available\n")); 4684168404Spjd return (0); 4685168404Spjd } 4686168404Spjd 4687168404Spjd return (ret); 4688168404Spjd} 4689168404Spjd 4690168404Spjdstatic int 4691168404Spjdget_callback(zpool_handle_t *zhp, void *data) 4692168404Spjd{ 4693185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 4694168404Spjd char value[MAXNAMELEN]; 4695185029Spjd zprop_source_t srctype; 4696185029Spjd zprop_list_t *pl; 4697168404Spjd 4698168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 4699168404Spjd 4700168404Spjd /* 4701185029Spjd * Skip the special fake placeholder. This will also skip 4702185029Spjd * over the name property when 'all' is specified. 4703168404Spjd */ 4704185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 4705168404Spjd pl == cbp->cb_proplist) 4706168404Spjd continue; 4707168404Spjd 4708168404Spjd if (zpool_get_prop(zhp, pl->pl_prop, 4709168404Spjd value, sizeof (value), &srctype) != 0) 4710168404Spjd continue; 4711168404Spjd 4712185029Spjd zprop_print_one_property(zpool_get_name(zhp), cbp, 4713219089Spjd zpool_prop_to_name(pl->pl_prop), value, srctype, NULL, 4714219089Spjd NULL); 4715168404Spjd } 4716168404Spjd return (0); 4717168404Spjd} 4718168404Spjd 4719168404Spjdint 4720168404Spjdzpool_do_get(int argc, char **argv) 4721168404Spjd{ 4722185029Spjd zprop_get_cbdata_t cb = { 0 }; 4723185029Spjd zprop_list_t fake_name = { 0 }; 4724168404Spjd int ret; 4725168404Spjd 4726168404Spjd if (argc < 3) 4727168404Spjd usage(B_FALSE); 4728168404Spjd 4729168404Spjd cb.cb_first = B_TRUE; 4730185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 4731168404Spjd cb.cb_columns[0] = GET_COL_NAME; 4732168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 4733168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 4734168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 4735185029Spjd cb.cb_type = ZFS_TYPE_POOL; 4736168404Spjd 4737185029Spjd if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 4738185029Spjd ZFS_TYPE_POOL) != 0) 4739168404Spjd usage(B_FALSE); 4740168404Spjd 4741168404Spjd if (cb.cb_proplist != NULL) { 4742185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 4743168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 4744168404Spjd fake_name.pl_next = cb.cb_proplist; 4745168404Spjd cb.cb_proplist = &fake_name; 4746168404Spjd } 4747168404Spjd 4748168404Spjd ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 4749168404Spjd get_callback, &cb); 4750168404Spjd 4751168404Spjd if (cb.cb_proplist == &fake_name) 4752185029Spjd zprop_free_list(fake_name.pl_next); 4753168404Spjd else 4754185029Spjd zprop_free_list(cb.cb_proplist); 4755168404Spjd 4756168404Spjd return (ret); 4757168404Spjd} 4758168404Spjd 4759168404Spjdtypedef struct set_cbdata { 4760168404Spjd char *cb_propname; 4761168404Spjd char *cb_value; 4762168404Spjd boolean_t cb_any_successful; 4763168404Spjd} set_cbdata_t; 4764168404Spjd 4765168404Spjdint 4766168404Spjdset_callback(zpool_handle_t *zhp, void *data) 4767168404Spjd{ 4768168404Spjd int error; 4769168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 4770168404Spjd 4771168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 4772168404Spjd 4773168404Spjd if (!error) 4774168404Spjd cb->cb_any_successful = B_TRUE; 4775168404Spjd 4776168404Spjd return (error); 4777168404Spjd} 4778168404Spjd 4779168404Spjdint 4780168404Spjdzpool_do_set(int argc, char **argv) 4781168404Spjd{ 4782168404Spjd set_cbdata_t cb = { 0 }; 4783168404Spjd int error; 4784168404Spjd 4785168404Spjd if (argc > 1 && argv[1][0] == '-') { 4786168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4787168404Spjd argv[1][1]); 4788168404Spjd usage(B_FALSE); 4789168404Spjd } 4790168404Spjd 4791168404Spjd if (argc < 2) { 4792168404Spjd (void) fprintf(stderr, gettext("missing property=value " 4793168404Spjd "argument\n")); 4794168404Spjd usage(B_FALSE); 4795168404Spjd } 4796168404Spjd 4797168404Spjd if (argc < 3) { 4798168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 4799168404Spjd usage(B_FALSE); 4800168404Spjd } 4801168404Spjd 4802168404Spjd if (argc > 3) { 4803168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 4804168404Spjd usage(B_FALSE); 4805168404Spjd } 4806168404Spjd 4807168404Spjd cb.cb_propname = argv[1]; 4808168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 4809168404Spjd if (cb.cb_value == NULL) { 4810168404Spjd (void) fprintf(stderr, gettext("missing value in " 4811168404Spjd "property=value argument\n")); 4812168404Spjd usage(B_FALSE); 4813168404Spjd } 4814168404Spjd 4815168404Spjd *(cb.cb_value) = '\0'; 4816168404Spjd cb.cb_value++; 4817168404Spjd 4818168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 4819168404Spjd set_callback, &cb); 4820168404Spjd 4821168404Spjd return (error); 4822168404Spjd} 4823168404Spjd 4824168404Spjdstatic int 4825168404Spjdfind_command_idx(char *command, int *idx) 4826168404Spjd{ 4827168404Spjd int i; 4828168404Spjd 4829168404Spjd for (i = 0; i < NCOMMAND; i++) { 4830168404Spjd if (command_table[i].name == NULL) 4831168404Spjd continue; 4832168404Spjd 4833168404Spjd if (strcmp(command, command_table[i].name) == 0) { 4834168404Spjd *idx = i; 4835168404Spjd return (0); 4836168404Spjd } 4837168404Spjd } 4838168404Spjd return (1); 4839168404Spjd} 4840168404Spjd 4841168404Spjdint 4842168404Spjdmain(int argc, char **argv) 4843168404Spjd{ 4844168404Spjd int ret; 4845168404Spjd int i; 4846168404Spjd char *cmdname; 4847168404Spjd 4848168404Spjd (void) setlocale(LC_ALL, ""); 4849168404Spjd (void) textdomain(TEXT_DOMAIN); 4850168404Spjd 4851168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 4852168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 4853168404Spjd "initialize ZFS library\n")); 4854168404Spjd return (1); 4855168404Spjd } 4856168404Spjd 4857168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 4858168404Spjd 4859168404Spjd opterr = 0; 4860168404Spjd 4861168404Spjd /* 4862168404Spjd * Make sure the user has specified some command. 4863168404Spjd */ 4864168404Spjd if (argc < 2) { 4865168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 4866168404Spjd usage(B_FALSE); 4867168404Spjd } 4868168404Spjd 4869168404Spjd cmdname = argv[1]; 4870168404Spjd 4871168404Spjd /* 4872168404Spjd * Special case '-?' 4873168404Spjd */ 4874168404Spjd if (strcmp(cmdname, "-?") == 0) 4875168404Spjd usage(B_TRUE); 4876168404Spjd 4877185029Spjd zpool_set_history_str("zpool", argc, argv, history_str); 4878185029Spjd verify(zpool_stage_history(g_zfs, history_str) == 0); 4879185029Spjd 4880168404Spjd /* 4881168404Spjd * Run the appropriate command. 4882168404Spjd */ 4883168404Spjd if (find_command_idx(cmdname, &i) == 0) { 4884168404Spjd current_command = &command_table[i]; 4885168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 4886185029Spjd } else if (strchr(cmdname, '=')) { 4887185029Spjd verify(find_command_idx("set", &i) == 0); 4888185029Spjd current_command = &command_table[i]; 4889185029Spjd ret = command_table[i].func(argc, argv); 4890185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 4891185029Spjd /* 4892185029Spjd * 'freeze' is a vile debugging abomination, so we treat 4893185029Spjd * it as such. 4894185029Spjd */ 4895168404Spjd char buf[16384]; 4896168404Spjd int fd = open(ZFS_DEV, O_RDWR); 4897168404Spjd (void) strcpy((void *)buf, argv[2]); 4898168404Spjd return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 4899185029Spjd } else { 4900168404Spjd (void) fprintf(stderr, gettext("unrecognized " 4901168404Spjd "command '%s'\n"), cmdname); 4902168404Spjd usage(B_FALSE); 4903168404Spjd } 4904168404Spjd 4905168404Spjd libzfs_fini(g_zfs); 4906168404Spjd 4907168404Spjd /* 4908168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 4909168404Spjd * for the purposes of running ::findleaks. 4910168404Spjd */ 4911168404Spjd if (getenv("ZFS_ABORT") != NULL) { 4912168404Spjd (void) printf("dumping core by request\n"); 4913168404Spjd abort(); 4914168404Spjd } 4915168404Spjd 4916168404Spjd return (ret); 4917168404Spjd} 4918