zpool_main.c revision 235478
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. 25228103Smm * Copyright (c) 2011 by Delphix. All rights reserved. 26228103Smm * Copyright (c) 2011 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 27168404Spjd */ 28168404Spjd 29168404Spjd#include <solaris.h> 30168404Spjd#include <assert.h> 31168404Spjd#include <ctype.h> 32168404Spjd#include <dirent.h> 33168404Spjd#include <errno.h> 34168404Spjd#include <fcntl.h> 35168404Spjd#include <libgen.h> 36168404Spjd#include <libintl.h> 37168404Spjd#include <libuutil.h> 38168404Spjd#include <locale.h> 39168404Spjd#include <stdio.h> 40168404Spjd#include <stdlib.h> 41168404Spjd#include <string.h> 42168404Spjd#include <strings.h> 43168404Spjd#include <unistd.h> 44168404Spjd#include <priv.h> 45185029Spjd#include <pwd.h> 46185029Spjd#include <zone.h> 47168404Spjd#include <sys/time.h> 48168404Spjd#include <sys/fs/zfs.h> 49168404Spjd#include <sys/stat.h> 50168404Spjd 51168404Spjd#include <libzfs.h> 52168404Spjd 53168404Spjd#include "zpool_util.h" 54185029Spjd#include "zfs_comutil.h" 55168404Spjd 56219089Spjd#include "statcommon.h" 57219089Spjd 58168404Spjdstatic int zpool_do_create(int, char **); 59168404Spjdstatic int zpool_do_destroy(int, char **); 60168404Spjd 61168404Spjdstatic int zpool_do_add(int, char **); 62168404Spjdstatic int zpool_do_remove(int, char **); 63224171Sgibbsstatic int zpool_do_labelclear(int, char **); 64168404Spjd 65168404Spjdstatic int zpool_do_list(int, char **); 66168404Spjdstatic int zpool_do_iostat(int, char **); 67168404Spjdstatic int zpool_do_status(int, char **); 68168404Spjd 69168404Spjdstatic int zpool_do_online(int, char **); 70168404Spjdstatic int zpool_do_offline(int, char **); 71168404Spjdstatic int zpool_do_clear(int, char **); 72168404Spjd 73228103Smmstatic int zpool_do_reguid(int, char **); 74228103Smm 75168404Spjdstatic int zpool_do_attach(int, char **); 76168404Spjdstatic int zpool_do_detach(int, char **); 77168404Spjdstatic int zpool_do_replace(int, char **); 78219089Spjdstatic int zpool_do_split(int, char **); 79168404Spjd 80168404Spjdstatic int zpool_do_scrub(int, char **); 81168404Spjd 82168404Spjdstatic int zpool_do_import(int, char **); 83168404Spjdstatic int zpool_do_export(int, char **); 84168404Spjd 85168404Spjdstatic int zpool_do_upgrade(int, char **); 86168404Spjd 87168404Spjdstatic int zpool_do_history(int, char **); 88168404Spjd 89168404Spjdstatic int zpool_do_get(int, char **); 90168404Spjdstatic int zpool_do_set(int, char **); 91168404Spjd 92168404Spjd/* 93168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 94168404Spjd * debugging facilities. 95168404Spjd */ 96185029Spjd 97185029Spjd#ifdef DEBUG 98168404Spjdconst char * 99168404Spjd_umem_debug_init(void) 100168404Spjd{ 101168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 102168404Spjd} 103168404Spjd 104168404Spjdconst char * 105168404Spjd_umem_logging_init(void) 106168404Spjd{ 107168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 108168404Spjd} 109185029Spjd#endif 110168404Spjd 111168404Spjdtypedef enum { 112168404Spjd HELP_ADD, 113168404Spjd HELP_ATTACH, 114168404Spjd HELP_CLEAR, 115168404Spjd HELP_CREATE, 116168404Spjd HELP_DESTROY, 117168404Spjd HELP_DETACH, 118168404Spjd HELP_EXPORT, 119168404Spjd HELP_HISTORY, 120168404Spjd HELP_IMPORT, 121168404Spjd HELP_IOSTAT, 122224171Sgibbs HELP_LABELCLEAR, 123168404Spjd HELP_LIST, 124168404Spjd HELP_OFFLINE, 125168404Spjd HELP_ONLINE, 126168404Spjd HELP_REPLACE, 127168404Spjd HELP_REMOVE, 128168404Spjd HELP_SCRUB, 129168404Spjd HELP_STATUS, 130168404Spjd HELP_UPGRADE, 131168404Spjd HELP_GET, 132219089Spjd HELP_SET, 133228103Smm HELP_SPLIT, 134228103Smm HELP_REGUID 135168404Spjd} zpool_help_t; 136168404Spjd 137168404Spjd 138168404Spjdtypedef struct zpool_command { 139168404Spjd const char *name; 140168404Spjd int (*func)(int, char **); 141168404Spjd zpool_help_t usage; 142168404Spjd} zpool_command_t; 143168404Spjd 144168404Spjd/* 145168404Spjd * Master command table. Each ZFS command has a name, associated function, and 146168404Spjd * usage message. The usage messages need to be internationalized, so we have 147168404Spjd * to have a function to return the usage message based on a command index. 148168404Spjd * 149168404Spjd * These commands are organized according to how they are displayed in the usage 150168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 151168404Spjd * the generic usage message. 152168404Spjd */ 153168404Spjdstatic zpool_command_t command_table[] = { 154168404Spjd { "create", zpool_do_create, HELP_CREATE }, 155168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 156168404Spjd { NULL }, 157168404Spjd { "add", zpool_do_add, HELP_ADD }, 158168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 159168404Spjd { NULL }, 160224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 161224171Sgibbs { NULL }, 162168404Spjd { "list", zpool_do_list, HELP_LIST }, 163168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 164168404Spjd { "status", zpool_do_status, HELP_STATUS }, 165168404Spjd { NULL }, 166168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 167168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 168168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 169168404Spjd { NULL }, 170168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 171168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 172168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 173219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 174168404Spjd { NULL }, 175168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 176168404Spjd { NULL }, 177168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 178168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 179168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 180228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 181168404Spjd { NULL }, 182168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 183168404Spjd { "get", zpool_do_get, HELP_GET }, 184168404Spjd { "set", zpool_do_set, HELP_SET }, 185168404Spjd}; 186168404Spjd 187168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 188168404Spjd 189168404Spjdzpool_command_t *current_command; 190185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 191168404Spjd 192219089Spjdstatic uint_t timestamp_fmt = NODATE; 193219089Spjd 194168404Spjdstatic const char * 195168404Spjdget_usage(zpool_help_t idx) { 196168404Spjd switch (idx) { 197168404Spjd case HELP_ADD: 198168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 199168404Spjd case HELP_ATTACH: 200168404Spjd return (gettext("\tattach [-f] <pool> <device> " 201185029Spjd "<new-device>\n")); 202168404Spjd case HELP_CLEAR: 203219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 204168404Spjd case HELP_CREATE: 205185029Spjd return (gettext("\tcreate [-fn] [-o property=value] ... \n" 206185029Spjd "\t [-O file-system-property=value] ... \n" 207185029Spjd "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 208168404Spjd case HELP_DESTROY: 209168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 210168404Spjd case HELP_DETACH: 211168404Spjd return (gettext("\tdetach <pool> <device>\n")); 212168404Spjd case HELP_EXPORT: 213168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 214168404Spjd case HELP_HISTORY: 215185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 216168404Spjd case HELP_IMPORT: 217168404Spjd return (gettext("\timport [-d dir] [-D]\n" 218219089Spjd "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 219185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 220219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 221219089Spjd "[-R root] [-F [-n]] -a\n" 222185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 223219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 224219089Spjd "[-R root] [-F [-n]]\n" 225219089Spjd "\t <pool | id> [newpool]\n")); 226168404Spjd case HELP_IOSTAT: 227219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 228168404Spjd "[count]]\n")); 229224171Sgibbs case HELP_LABELCLEAR: 230224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 231168404Spjd case HELP_LIST: 232185029Spjd return (gettext("\tlist [-H] [-o property[,...]] " 233219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 234168404Spjd case HELP_OFFLINE: 235168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 236168404Spjd case HELP_ONLINE: 237228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 238168404Spjd case HELP_REPLACE: 239168404Spjd return (gettext("\treplace [-f] <pool> <device> " 240185029Spjd "[new-device]\n")); 241168404Spjd case HELP_REMOVE: 242185029Spjd return (gettext("\tremove <pool> <device> ...\n")); 243168404Spjd case HELP_SCRUB: 244168404Spjd return (gettext("\tscrub [-s] <pool> ...\n")); 245168404Spjd case HELP_STATUS: 246219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 247219089Spjd "[count]]\n")); 248168404Spjd case HELP_UPGRADE: 249228020Smm return (gettext("\tupgrade [-v]\n" 250185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 251168404Spjd case HELP_GET: 252185029Spjd return (gettext("\tget <\"all\" | property[,...]> " 253168404Spjd "<pool> ...\n")); 254168404Spjd case HELP_SET: 255168404Spjd return (gettext("\tset <property=value> <pool> \n")); 256219089Spjd case HELP_SPLIT: 257219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 258219089Spjd "\t [-o property=value] <pool> <newpool> " 259219089Spjd "[<device> ...]\n")); 260228103Smm case HELP_REGUID: 261228103Smm return (gettext("\treguid <pool>\n")); 262168404Spjd } 263168404Spjd 264168404Spjd abort(); 265168404Spjd /* NOTREACHED */ 266168404Spjd} 267168404Spjd 268168404Spjd 269168404Spjd/* 270168404Spjd * Callback routine that will print out a pool property value. 271168404Spjd */ 272185029Spjdstatic int 273185029Spjdprint_prop_cb(int prop, void *cb) 274168404Spjd{ 275168404Spjd FILE *fp = cb; 276168404Spjd 277219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 278168404Spjd 279185029Spjd if (zpool_prop_readonly(prop)) 280185029Spjd (void) fprintf(fp, " NO "); 281185029Spjd else 282219089Spjd (void) fprintf(fp, " YES "); 283185029Spjd 284168404Spjd if (zpool_prop_values(prop) == NULL) 285168404Spjd (void) fprintf(fp, "-\n"); 286168404Spjd else 287168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 288168404Spjd 289185029Spjd return (ZPROP_CONT); 290168404Spjd} 291168404Spjd 292168404Spjd/* 293168404Spjd * Display usage message. If we're inside a command, display only the usage for 294168404Spjd * that command. Otherwise, iterate over the entire command table and display 295168404Spjd * a complete usage message. 296168404Spjd */ 297168404Spjdvoid 298168404Spjdusage(boolean_t requested) 299168404Spjd{ 300168404Spjd FILE *fp = requested ? stdout : stderr; 301168404Spjd 302168404Spjd if (current_command == NULL) { 303168404Spjd int i; 304168404Spjd 305168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 306168404Spjd (void) fprintf(fp, 307168404Spjd gettext("where 'command' is one of the following:\n\n")); 308168404Spjd 309168404Spjd for (i = 0; i < NCOMMAND; i++) { 310168404Spjd if (command_table[i].name == NULL) 311168404Spjd (void) fprintf(fp, "\n"); 312168404Spjd else 313168404Spjd (void) fprintf(fp, "%s", 314168404Spjd get_usage(command_table[i].usage)); 315168404Spjd } 316168404Spjd } else { 317168404Spjd (void) fprintf(fp, gettext("usage:\n")); 318168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 319168404Spjd } 320168404Spjd 321168404Spjd if (current_command != NULL && 322168404Spjd ((strcmp(current_command->name, "set") == 0) || 323185029Spjd (strcmp(current_command->name, "get") == 0) || 324185029Spjd (strcmp(current_command->name, "list") == 0))) { 325168404Spjd 326168404Spjd (void) fprintf(fp, 327168404Spjd gettext("\nthe following properties are supported:\n")); 328168404Spjd 329219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 330185029Spjd "PROPERTY", "EDIT", "VALUES"); 331168404Spjd 332168404Spjd /* Iterate over all properties */ 333185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 334185029Spjd ZFS_TYPE_POOL); 335168404Spjd } 336168404Spjd 337168404Spjd /* 338168404Spjd * See comments at end of main(). 339168404Spjd */ 340168404Spjd if (getenv("ZFS_ABORT") != NULL) { 341168404Spjd (void) printf("dumping core by request\n"); 342168404Spjd abort(); 343168404Spjd } 344168404Spjd 345168404Spjd exit(requested ? 0 : 2); 346168404Spjd} 347168404Spjd 348168404Spjdvoid 349185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 350185029Spjd boolean_t print_logs) 351168404Spjd{ 352168404Spjd nvlist_t **child; 353168404Spjd uint_t c, children; 354168404Spjd char *vname; 355168404Spjd 356168404Spjd if (name != NULL) 357168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 358168404Spjd 359168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 360168404Spjd &child, &children) != 0) 361168404Spjd return; 362168404Spjd 363168404Spjd for (c = 0; c < children; c++) { 364185029Spjd uint64_t is_log = B_FALSE; 365185029Spjd 366185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 367185029Spjd &is_log); 368185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 369185029Spjd continue; 370185029Spjd 371219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 372185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 373185029Spjd B_FALSE); 374168404Spjd free(vname); 375168404Spjd } 376168404Spjd} 377168404Spjd 378168404Spjd/* 379185029Spjd * Add a property pair (name, string-value) into a property nvlist. 380185029Spjd */ 381185029Spjdstatic int 382185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 383185029Spjd boolean_t poolprop) 384185029Spjd{ 385185029Spjd zpool_prop_t prop = ZPROP_INVAL; 386185029Spjd zfs_prop_t fprop; 387185029Spjd nvlist_t *proplist; 388185029Spjd const char *normnm; 389185029Spjd char *strval; 390185029Spjd 391185029Spjd if (*props == NULL && 392185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 393185029Spjd (void) fprintf(stderr, 394185029Spjd gettext("internal error: out of memory\n")); 395185029Spjd return (1); 396185029Spjd } 397185029Spjd 398185029Spjd proplist = *props; 399185029Spjd 400185029Spjd if (poolprop) { 401185029Spjd if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 402185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 403185029Spjd "not a valid pool property\n"), propname); 404185029Spjd return (2); 405185029Spjd } 406185029Spjd normnm = zpool_prop_to_name(prop); 407185029Spjd } else { 408209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 409209962Smm normnm = zfs_prop_to_name(fprop); 410209962Smm } else { 411209962Smm normnm = propname; 412185029Spjd } 413185029Spjd } 414185029Spjd 415185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 416185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 417185029Spjd (void) fprintf(stderr, gettext("property '%s' " 418185029Spjd "specified multiple times\n"), propname); 419185029Spjd return (2); 420185029Spjd } 421185029Spjd 422185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 423185029Spjd (void) fprintf(stderr, gettext("internal " 424185029Spjd "error: out of memory\n")); 425185029Spjd return (1); 426185029Spjd } 427185029Spjd 428185029Spjd return (0); 429185029Spjd} 430185029Spjd 431185029Spjd/* 432168404Spjd * zpool add [-fn] <pool> <vdev> ... 433168404Spjd * 434168404Spjd * -f Force addition of devices, even if they appear in use 435168404Spjd * -n Do not add the devices, but display the resulting layout if 436168404Spjd * they were to be added. 437168404Spjd * 438168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 439168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 440168404Spjd * libzfs. 441168404Spjd */ 442168404Spjdint 443168404Spjdzpool_do_add(int argc, char **argv) 444168404Spjd{ 445168404Spjd boolean_t force = B_FALSE; 446168404Spjd boolean_t dryrun = B_FALSE; 447168404Spjd int c; 448168404Spjd nvlist_t *nvroot; 449168404Spjd char *poolname; 450168404Spjd int ret; 451168404Spjd zpool_handle_t *zhp; 452168404Spjd nvlist_t *config; 453168404Spjd 454168404Spjd /* check options */ 455168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 456168404Spjd switch (c) { 457168404Spjd case 'f': 458168404Spjd force = B_TRUE; 459168404Spjd break; 460168404Spjd case 'n': 461168404Spjd dryrun = B_TRUE; 462168404Spjd break; 463168404Spjd case '?': 464168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 465168404Spjd optopt); 466168404Spjd usage(B_FALSE); 467168404Spjd } 468168404Spjd } 469168404Spjd 470168404Spjd argc -= optind; 471168404Spjd argv += optind; 472168404Spjd 473168404Spjd /* get pool name and check number of arguments */ 474168404Spjd if (argc < 1) { 475168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 476168404Spjd usage(B_FALSE); 477168404Spjd } 478168404Spjd if (argc < 2) { 479168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 480168404Spjd usage(B_FALSE); 481168404Spjd } 482168404Spjd 483168404Spjd poolname = argv[0]; 484168404Spjd 485168404Spjd argc--; 486168404Spjd argv++; 487168404Spjd 488168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 489168404Spjd return (1); 490168404Spjd 491168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 492168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 493168404Spjd poolname); 494168404Spjd zpool_close(zhp); 495168404Spjd return (1); 496168404Spjd } 497168404Spjd 498168404Spjd /* pass off to get_vdev_spec for processing */ 499185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 500185029Spjd argc, argv); 501168404Spjd if (nvroot == NULL) { 502168404Spjd zpool_close(zhp); 503168404Spjd return (1); 504168404Spjd } 505168404Spjd 506168404Spjd if (dryrun) { 507168404Spjd nvlist_t *poolnvroot; 508168404Spjd 509168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 510168404Spjd &poolnvroot) == 0); 511168404Spjd 512168404Spjd (void) printf(gettext("would update '%s' to the following " 513168404Spjd "configuration:\n"), zpool_get_name(zhp)); 514168404Spjd 515185029Spjd /* print original main pool and new tree */ 516185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 517185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 518168404Spjd 519185029Spjd /* Do the same for the logs */ 520185029Spjd if (num_logs(poolnvroot) > 0) { 521185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 522185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 523185029Spjd } else if (num_logs(nvroot) > 0) { 524185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 525185029Spjd } 526185029Spjd 527168404Spjd ret = 0; 528168404Spjd } else { 529168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 530168404Spjd } 531168404Spjd 532168404Spjd nvlist_free(nvroot); 533168404Spjd zpool_close(zhp); 534168404Spjd 535168404Spjd return (ret); 536168404Spjd} 537168404Spjd 538168404Spjd/* 539219089Spjd * zpool remove <pool> <vdev> ... 540168404Spjd * 541219089Spjd * Removes the given vdev from the pool. Currently, this supports removing 542219089Spjd * spares, cache, and log devices from the pool. 543168404Spjd */ 544168404Spjdint 545168404Spjdzpool_do_remove(int argc, char **argv) 546168404Spjd{ 547168404Spjd char *poolname; 548185029Spjd int i, ret = 0; 549168404Spjd zpool_handle_t *zhp; 550168404Spjd 551168404Spjd argc--; 552168404Spjd argv++; 553168404Spjd 554168404Spjd /* get pool name and check number of arguments */ 555168404Spjd if (argc < 1) { 556168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 557168404Spjd usage(B_FALSE); 558168404Spjd } 559168404Spjd if (argc < 2) { 560168404Spjd (void) fprintf(stderr, gettext("missing device\n")); 561168404Spjd usage(B_FALSE); 562168404Spjd } 563168404Spjd 564168404Spjd poolname = argv[0]; 565168404Spjd 566168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 567168404Spjd return (1); 568168404Spjd 569185029Spjd for (i = 1; i < argc; i++) { 570185029Spjd if (zpool_vdev_remove(zhp, argv[i]) != 0) 571185029Spjd ret = 1; 572168404Spjd } 573168404Spjd 574168404Spjd return (ret); 575168404Spjd} 576168404Spjd 577168404Spjd/* 578224171Sgibbs * zpool labelclear <vdev> 579224171Sgibbs * 580224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 581224171Sgibbs * on the device. 582224171Sgibbs */ 583224171Sgibbsint 584224171Sgibbszpool_do_labelclear(int argc, char **argv) 585224171Sgibbs{ 586224171Sgibbs char *vdev, *name; 587224171Sgibbs int c, fd = -1, ret = 0; 588224171Sgibbs pool_state_t state; 589224171Sgibbs boolean_t inuse = B_FALSE; 590224171Sgibbs boolean_t force = B_FALSE; 591224171Sgibbs 592224171Sgibbs /* check options */ 593224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 594224171Sgibbs switch (c) { 595224171Sgibbs case 'f': 596224171Sgibbs force = B_TRUE; 597224171Sgibbs break; 598224171Sgibbs default: 599224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 600224171Sgibbs optopt); 601224171Sgibbs usage(B_FALSE); 602224171Sgibbs } 603224171Sgibbs } 604224171Sgibbs 605224171Sgibbs argc -= optind; 606224171Sgibbs argv += optind; 607224171Sgibbs 608224171Sgibbs /* get vdev name */ 609224171Sgibbs if (argc < 1) { 610224171Sgibbs (void) fprintf(stderr, gettext("missing vdev device name\n")); 611224171Sgibbs usage(B_FALSE); 612224171Sgibbs } 613224171Sgibbs 614224171Sgibbs vdev = argv[0]; 615224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 616224171Sgibbs (void) fprintf(stderr, gettext("Unable to open %s\n"), vdev); 617224171Sgibbs return (B_FALSE); 618224171Sgibbs } 619224171Sgibbs 620224171Sgibbs name = NULL; 621224171Sgibbs if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) { 622224171Sgibbs if (force) 623224171Sgibbs goto wipe_label; 624224171Sgibbs 625224171Sgibbs (void) fprintf(stderr, 626224171Sgibbs gettext("Unable to determine pool state for %s\n" 627224171Sgibbs "Use -f to force the clearing any label data\n"), vdev); 628224171Sgibbs 629224171Sgibbs return (1); 630224171Sgibbs } 631224171Sgibbs 632224171Sgibbs if (inuse) { 633224171Sgibbs switch (state) { 634224171Sgibbs default: 635224171Sgibbs case POOL_STATE_ACTIVE: 636224171Sgibbs case POOL_STATE_SPARE: 637224171Sgibbs case POOL_STATE_L2CACHE: 638224171Sgibbs (void) fprintf(stderr, 639224171Sgibbsgettext("labelclear operation failed.\n" 640224171Sgibbs "\tVdev %s is a member (%s), of pool \"%s\".\n" 641224171Sgibbs "\tTo remove label information from this device, export or destroy\n" 642224171Sgibbs "\tthe pool, or remove %s from the configuration of this pool\n" 643224171Sgibbs "\tand retry the labelclear operation\n"), 644224171Sgibbs vdev, zpool_pool_state_to_name(state), name, vdev); 645224171Sgibbs ret = 1; 646224171Sgibbs goto errout; 647224171Sgibbs 648224171Sgibbs case POOL_STATE_EXPORTED: 649224171Sgibbs if (force) 650224171Sgibbs break; 651224171Sgibbs 652224171Sgibbs (void) fprintf(stderr, 653224171Sgibbsgettext("labelclear operation failed.\n" 654224171Sgibbs "\tVdev %s is a member of the exported pool \"%s\".\n" 655224171Sgibbs "\tUse \"zpool labelclear -f %s\" to force the removal of label\n" 656224171Sgibbs "\tinformation.\n"), 657224171Sgibbs vdev, name, vdev); 658224171Sgibbs ret = 1; 659224171Sgibbs goto errout; 660224171Sgibbs 661224171Sgibbs case POOL_STATE_POTENTIALLY_ACTIVE: 662224171Sgibbs if (force) 663224171Sgibbs break; 664224171Sgibbs 665224171Sgibbs (void) fprintf(stderr, 666224171Sgibbsgettext("labelclear operation failed.\n" 667224171Sgibbs "\tVdev %s is a member of the pool \"%s\".\n" 668224171Sgibbs "\tThis pool is unknown to this system, but may be active on\n" 669224171Sgibbs "\tanother system. Use \'zpool labelclear -f %s\' to force the\n" 670224171Sgibbs "\tremoval of label information.\n"), 671224171Sgibbs vdev, name, vdev); 672224171Sgibbs ret = 1; 673224171Sgibbs goto errout; 674224171Sgibbs 675224171Sgibbs case POOL_STATE_DESTROYED: 676224171Sgibbs /* inuse should never be set for a destoryed pool... */ 677224171Sgibbs break; 678224171Sgibbs } 679224171Sgibbs } 680224171Sgibbs 681224171Sgibbswipe_label: 682224171Sgibbs if (zpool_clear_label(fd) != 0) { 683224171Sgibbs (void) fprintf(stderr, 684224171Sgibbs gettext("Label clear failed on vdev %s\n"), vdev); 685224171Sgibbs ret = 1; 686224171Sgibbs } 687224171Sgibbs 688224171Sgibbserrout: 689224171Sgibbs close(fd); 690224171Sgibbs if (name != NULL) 691224171Sgibbs free(name); 692224171Sgibbs 693224171Sgibbs return (ret); 694224171Sgibbs} 695224171Sgibbs 696224171Sgibbs/* 697185029Spjd * zpool create [-fn] [-o property=value] ... 698185029Spjd * [-O file-system-property=value] ... 699185029Spjd * [-R root] [-m mountpoint] <pool> <dev> ... 700168404Spjd * 701168404Spjd * -f Force creation, even if devices appear in use 702168404Spjd * -n Do not create the pool, but display the resulting layout if it 703168404Spjd * were to be created. 704168404Spjd * -R Create a pool under an alternate root 705168404Spjd * -m Set default mountpoint for the root dataset. By default it's 706168404Spjd * '/<pool>' 707185029Spjd * -o Set property=value. 708185029Spjd * -O Set fsproperty=value in the pool's root file system 709168404Spjd * 710168404Spjd * Creates the named pool according to the given vdev specification. The 711168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 712168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 713168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 714168404Spjd */ 715168404Spjdint 716168404Spjdzpool_do_create(int argc, char **argv) 717168404Spjd{ 718168404Spjd boolean_t force = B_FALSE; 719168404Spjd boolean_t dryrun = B_FALSE; 720168404Spjd int c; 721185029Spjd nvlist_t *nvroot = NULL; 722168404Spjd char *poolname; 723185029Spjd int ret = 1; 724168404Spjd char *altroot = NULL; 725168404Spjd char *mountpoint = NULL; 726185029Spjd nvlist_t *fsprops = NULL; 727185029Spjd nvlist_t *props = NULL; 728185029Spjd char *propval; 729168404Spjd 730168404Spjd /* check options */ 731185029Spjd while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) { 732168404Spjd switch (c) { 733168404Spjd case 'f': 734168404Spjd force = B_TRUE; 735168404Spjd break; 736168404Spjd case 'n': 737168404Spjd dryrun = B_TRUE; 738168404Spjd break; 739168404Spjd case 'R': 740168404Spjd altroot = optarg; 741185029Spjd if (add_prop_list(zpool_prop_to_name( 742185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 743185029Spjd goto errout; 744185029Spjd if (nvlist_lookup_string(props, 745185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 746185029Spjd &propval) == 0) 747185029Spjd break; 748185029Spjd if (add_prop_list(zpool_prop_to_name( 749185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 750185029Spjd goto errout; 751168404Spjd break; 752168404Spjd case 'm': 753168404Spjd mountpoint = optarg; 754168404Spjd break; 755185029Spjd case 'o': 756185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 757185029Spjd (void) fprintf(stderr, gettext("missing " 758185029Spjd "'=' for -o option\n")); 759185029Spjd goto errout; 760185029Spjd } 761185029Spjd *propval = '\0'; 762185029Spjd propval++; 763185029Spjd 764185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 765185029Spjd goto errout; 766185029Spjd break; 767185029Spjd case 'O': 768185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 769185029Spjd (void) fprintf(stderr, gettext("missing " 770185029Spjd "'=' for -O option\n")); 771185029Spjd goto errout; 772185029Spjd } 773185029Spjd *propval = '\0'; 774185029Spjd propval++; 775185029Spjd 776185029Spjd if (add_prop_list(optarg, propval, &fsprops, B_FALSE)) 777185029Spjd goto errout; 778185029Spjd break; 779168404Spjd case ':': 780168404Spjd (void) fprintf(stderr, gettext("missing argument for " 781168404Spjd "'%c' option\n"), optopt); 782185029Spjd goto badusage; 783168404Spjd case '?': 784168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 785168404Spjd optopt); 786185029Spjd goto badusage; 787168404Spjd } 788168404Spjd } 789168404Spjd 790168404Spjd argc -= optind; 791168404Spjd argv += optind; 792168404Spjd 793168404Spjd /* get pool name and check number of arguments */ 794168404Spjd if (argc < 1) { 795168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 796185029Spjd goto badusage; 797168404Spjd } 798168404Spjd if (argc < 2) { 799168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 800185029Spjd goto badusage; 801168404Spjd } 802168404Spjd 803168404Spjd poolname = argv[0]; 804168404Spjd 805168404Spjd /* 806168404Spjd * As a special case, check for use of '/' in the name, and direct the 807168404Spjd * user to use 'zfs create' instead. 808168404Spjd */ 809168404Spjd if (strchr(poolname, '/') != NULL) { 810168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 811168404Spjd "character '/' in pool name\n"), poolname); 812168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 813168404Spjd "create a dataset\n")); 814185029Spjd goto errout; 815168404Spjd } 816168404Spjd 817168404Spjd /* pass off to get_vdev_spec for bulk processing */ 818185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 819185029Spjd argc - 1, argv + 1); 820168404Spjd if (nvroot == NULL) 821185029Spjd goto errout; 822168404Spjd 823168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 824185029Spjd if (!zfs_allocatable_devs(nvroot)) { 825168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 826168404Spjd "specification: at least one toplevel vdev must be " 827168404Spjd "specified\n")); 828185029Spjd goto errout; 829168404Spjd } 830168404Spjd 831168404Spjd 832168404Spjd if (altroot != NULL && altroot[0] != '/') { 833168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 834168404Spjd "must be an absolute path\n"), altroot); 835185029Spjd goto errout; 836168404Spjd } 837168404Spjd 838168404Spjd /* 839168404Spjd * Check the validity of the mountpoint and direct the user to use the 840168404Spjd * '-m' mountpoint option if it looks like its in use. 841168404Spjd */ 842168404Spjd if (mountpoint == NULL || 843168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 844168404Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 845168404Spjd char buf[MAXPATHLEN]; 846185029Spjd DIR *dirp; 847168404Spjd 848168404Spjd if (mountpoint && mountpoint[0] != '/') { 849168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 850168404Spjd "'%s': must be an absolute path, 'legacy', or " 851168404Spjd "'none'\n"), mountpoint); 852185029Spjd goto errout; 853168404Spjd } 854168404Spjd 855168404Spjd if (mountpoint == NULL) { 856168404Spjd if (altroot != NULL) 857168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 858168404Spjd altroot, poolname); 859168404Spjd else 860168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 861168404Spjd poolname); 862168404Spjd } else { 863168404Spjd if (altroot != NULL) 864168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 865168404Spjd altroot, mountpoint); 866168404Spjd else 867168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 868168404Spjd mountpoint); 869168404Spjd } 870168404Spjd 871185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 872185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 873185029Spjd "%s\n"), buf, strerror(errno)); 874185029Spjd (void) fprintf(stderr, gettext("use '-m' " 875185029Spjd "option to provide a different default\n")); 876185029Spjd goto errout; 877185029Spjd } else if (dirp) { 878185029Spjd int count = 0; 879185029Spjd 880185029Spjd while (count < 3 && readdir(dirp) != NULL) 881185029Spjd count++; 882185029Spjd (void) closedir(dirp); 883185029Spjd 884185029Spjd if (count > 2) { 885168404Spjd (void) fprintf(stderr, gettext("mountpoint " 886168404Spjd "'%s' exists and is not empty\n"), buf); 887185029Spjd (void) fprintf(stderr, gettext("use '-m' " 888185029Spjd "option to provide a " 889185029Spjd "different default\n")); 890185029Spjd goto errout; 891185029Spjd } 892168404Spjd } 893168404Spjd } 894168404Spjd 895168404Spjd if (dryrun) { 896168404Spjd /* 897168404Spjd * For a dry run invocation, print out a basic message and run 898168404Spjd * through all the vdevs in the list and print out in an 899168404Spjd * appropriate hierarchy. 900168404Spjd */ 901168404Spjd (void) printf(gettext("would create '%s' with the " 902168404Spjd "following layout:\n\n"), poolname); 903168404Spjd 904185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 905185029Spjd if (num_logs(nvroot) > 0) 906185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 907168404Spjd 908168404Spjd ret = 0; 909168404Spjd } else { 910168404Spjd /* 911168404Spjd * Hand off to libzfs. 912168404Spjd */ 913185029Spjd if (zpool_create(g_zfs, poolname, 914185029Spjd nvroot, props, fsprops) == 0) { 915168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 916168404Spjd ZFS_TYPE_FILESYSTEM); 917168404Spjd if (pool != NULL) { 918168404Spjd if (mountpoint != NULL) 919168404Spjd verify(zfs_prop_set(pool, 920168404Spjd zfs_prop_to_name( 921168404Spjd ZFS_PROP_MOUNTPOINT), 922168404Spjd mountpoint) == 0); 923168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 924185029Spjd ret = zfs_shareall(pool); 925168404Spjd zfs_close(pool); 926168404Spjd } 927168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 928168404Spjd (void) fprintf(stderr, gettext("pool name may have " 929168404Spjd "been omitted\n")); 930168404Spjd } 931168404Spjd } 932168404Spjd 933185029Spjderrout: 934168404Spjd nvlist_free(nvroot); 935185029Spjd nvlist_free(fsprops); 936185029Spjd nvlist_free(props); 937168404Spjd return (ret); 938185029Spjdbadusage: 939185029Spjd nvlist_free(fsprops); 940185029Spjd nvlist_free(props); 941185029Spjd usage(B_FALSE); 942185029Spjd return (2); 943168404Spjd} 944168404Spjd 945168404Spjd/* 946168404Spjd * zpool destroy <pool> 947168404Spjd * 948168404Spjd * -f Forcefully unmount any datasets 949168404Spjd * 950168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 951168404Spjd */ 952168404Spjdint 953168404Spjdzpool_do_destroy(int argc, char **argv) 954168404Spjd{ 955168404Spjd boolean_t force = B_FALSE; 956168404Spjd int c; 957168404Spjd char *pool; 958168404Spjd zpool_handle_t *zhp; 959168404Spjd int ret; 960168404Spjd 961168404Spjd /* check options */ 962168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 963168404Spjd switch (c) { 964168404Spjd case 'f': 965168404Spjd force = B_TRUE; 966168404Spjd break; 967168404Spjd case '?': 968168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 969168404Spjd optopt); 970168404Spjd usage(B_FALSE); 971168404Spjd } 972168404Spjd } 973168404Spjd 974168404Spjd argc -= optind; 975168404Spjd argv += optind; 976168404Spjd 977168404Spjd /* check arguments */ 978168404Spjd if (argc < 1) { 979168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 980168404Spjd usage(B_FALSE); 981168404Spjd } 982168404Spjd if (argc > 1) { 983168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 984168404Spjd usage(B_FALSE); 985168404Spjd } 986168404Spjd 987168404Spjd pool = argv[0]; 988168404Spjd 989168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 990168404Spjd /* 991168404Spjd * As a special case, check for use of '/' in the name, and 992168404Spjd * direct the user to use 'zfs destroy' instead. 993168404Spjd */ 994168404Spjd if (strchr(pool, '/') != NULL) 995168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 996168404Spjd "destroy a dataset\n")); 997168404Spjd return (1); 998168404Spjd } 999168404Spjd 1000168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1001168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1002168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1003168404Spjd return (1); 1004168404Spjd } 1005168404Spjd 1006168404Spjd ret = (zpool_destroy(zhp) != 0); 1007168404Spjd 1008168404Spjd zpool_close(zhp); 1009168404Spjd 1010168404Spjd return (ret); 1011168404Spjd} 1012168404Spjd 1013168404Spjd/* 1014168404Spjd * zpool export [-f] <pool> ... 1015168404Spjd * 1016168404Spjd * -f Forcefully unmount datasets 1017168404Spjd * 1018168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1019168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1020168404Spjd * then the datasets will be forcefully unmounted. 1021168404Spjd */ 1022168404Spjdint 1023168404Spjdzpool_do_export(int argc, char **argv) 1024168404Spjd{ 1025168404Spjd boolean_t force = B_FALSE; 1026207670Smm boolean_t hardforce = B_FALSE; 1027168404Spjd int c; 1028168404Spjd zpool_handle_t *zhp; 1029168404Spjd int ret; 1030168404Spjd int i; 1031168404Spjd 1032168404Spjd /* check options */ 1033207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1034168404Spjd switch (c) { 1035168404Spjd case 'f': 1036168404Spjd force = B_TRUE; 1037168404Spjd break; 1038207670Smm case 'F': 1039207670Smm hardforce = B_TRUE; 1040207670Smm break; 1041168404Spjd case '?': 1042168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1043168404Spjd optopt); 1044168404Spjd usage(B_FALSE); 1045168404Spjd } 1046168404Spjd } 1047168404Spjd 1048168404Spjd argc -= optind; 1049168404Spjd argv += optind; 1050168404Spjd 1051168404Spjd /* check arguments */ 1052168404Spjd if (argc < 1) { 1053168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1054168404Spjd usage(B_FALSE); 1055168404Spjd } 1056168404Spjd 1057168404Spjd ret = 0; 1058168404Spjd for (i = 0; i < argc; i++) { 1059168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1060168404Spjd ret = 1; 1061168404Spjd continue; 1062168404Spjd } 1063168404Spjd 1064168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1065168404Spjd ret = 1; 1066168404Spjd zpool_close(zhp); 1067168404Spjd continue; 1068168404Spjd } 1069168404Spjd 1070207670Smm if (hardforce) { 1071207670Smm if (zpool_export_force(zhp) != 0) 1072207670Smm ret = 1; 1073207670Smm } else if (zpool_export(zhp, force) != 0) { 1074168404Spjd ret = 1; 1075207670Smm } 1076168404Spjd 1077168404Spjd zpool_close(zhp); 1078168404Spjd } 1079168404Spjd 1080168404Spjd return (ret); 1081168404Spjd} 1082168404Spjd 1083168404Spjd/* 1084168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1085168404Spjd * name column. 1086168404Spjd */ 1087168404Spjdstatic int 1088168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1089168404Spjd{ 1090219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1091168404Spjd nvlist_t **child; 1092168404Spjd uint_t c, children; 1093168404Spjd int ret; 1094168404Spjd 1095168404Spjd if (strlen(name) + depth > max) 1096168404Spjd max = strlen(name) + depth; 1097168404Spjd 1098168404Spjd free(name); 1099168404Spjd 1100168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1101168404Spjd &child, &children) == 0) { 1102168404Spjd for (c = 0; c < children; c++) 1103168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1104168404Spjd max)) > max) 1105168404Spjd max = ret; 1106168404Spjd } 1107168404Spjd 1108185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1109185029Spjd &child, &children) == 0) { 1110185029Spjd for (c = 0; c < children; c++) 1111185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1112185029Spjd max)) > max) 1113185029Spjd max = ret; 1114185029Spjd } 1115185029Spjd 1116168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1117168404Spjd &child, &children) == 0) { 1118168404Spjd for (c = 0; c < children; c++) 1119168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1120168404Spjd max)) > max) 1121168404Spjd max = ret; 1122168404Spjd } 1123168404Spjd 1124168404Spjd 1125168404Spjd return (max); 1126168404Spjd} 1127168404Spjd 1128213197Smmtypedef struct spare_cbdata { 1129213197Smm uint64_t cb_guid; 1130213197Smm zpool_handle_t *cb_zhp; 1131213197Smm} spare_cbdata_t; 1132168404Spjd 1133213197Smmstatic boolean_t 1134213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1135213197Smm{ 1136213197Smm uint64_t guid; 1137213197Smm nvlist_t **child; 1138213197Smm uint_t c, children; 1139213197Smm 1140213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1141213197Smm search == guid) 1142213197Smm return (B_TRUE); 1143213197Smm 1144213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1145213197Smm &child, &children) == 0) { 1146213197Smm for (c = 0; c < children; c++) 1147213197Smm if (find_vdev(child[c], search)) 1148213197Smm return (B_TRUE); 1149213197Smm } 1150213197Smm 1151213197Smm return (B_FALSE); 1152213197Smm} 1153213197Smm 1154213197Smmstatic int 1155213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1156213197Smm{ 1157213197Smm spare_cbdata_t *cbp = data; 1158213197Smm nvlist_t *config, *nvroot; 1159213197Smm 1160213197Smm config = zpool_get_config(zhp, NULL); 1161213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1162213197Smm &nvroot) == 0); 1163213197Smm 1164213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1165213197Smm cbp->cb_zhp = zhp; 1166213197Smm return (1); 1167213197Smm } 1168213197Smm 1169213197Smm zpool_close(zhp); 1170213197Smm return (0); 1171213197Smm} 1172213197Smm 1173168404Spjd/* 1174213197Smm * Print out configuration state as requested by status_callback. 1175213197Smm */ 1176213197Smmvoid 1177213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1178213197Smm int namewidth, int depth, boolean_t isspare) 1179213197Smm{ 1180213197Smm nvlist_t **child; 1181213197Smm uint_t c, children; 1182219089Spjd pool_scan_stat_t *ps = NULL; 1183213197Smm vdev_stat_t *vs; 1184219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1185213197Smm char *vname; 1186213197Smm uint64_t notpresent; 1187213197Smm spare_cbdata_t cb; 1188224169Sgibbs const char *state; 1189213197Smm 1190213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1191213197Smm &child, &children) != 0) 1192213197Smm children = 0; 1193213197Smm 1194219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1195219089Spjd (uint64_t **)&vs, &c) == 0); 1196219089Spjd 1197213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1198213197Smm if (isspare) { 1199213197Smm /* 1200213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1201213197Smm * online drives. 1202213197Smm */ 1203213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1204213197Smm state = "INUSE"; 1205213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1206213197Smm state = "AVAIL"; 1207213197Smm } 1208213197Smm 1209213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1210213197Smm name, state); 1211213197Smm 1212213197Smm if (!isspare) { 1213213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1214213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1215213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1216213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1217213197Smm } 1218213197Smm 1219213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1220224170Sgibbs ¬present) == 0 || 1221224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1222213197Smm char *path; 1223224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1224224170Sgibbs (void) printf(" was %s", path); 1225213197Smm } else if (vs->vs_aux != 0) { 1226213197Smm (void) printf(" "); 1227213197Smm 1228213197Smm switch (vs->vs_aux) { 1229213197Smm case VDEV_AUX_OPEN_FAILED: 1230213197Smm (void) printf(gettext("cannot open")); 1231213197Smm break; 1232213197Smm 1233213197Smm case VDEV_AUX_BAD_GUID_SUM: 1234213197Smm (void) printf(gettext("missing device")); 1235213197Smm break; 1236213197Smm 1237213197Smm case VDEV_AUX_NO_REPLICAS: 1238213197Smm (void) printf(gettext("insufficient replicas")); 1239213197Smm break; 1240213197Smm 1241213197Smm case VDEV_AUX_VERSION_NEWER: 1242213197Smm (void) printf(gettext("newer version")); 1243213197Smm break; 1244213197Smm 1245213197Smm case VDEV_AUX_SPARED: 1246213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1247213197Smm &cb.cb_guid) == 0); 1248213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1249213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1250213197Smm zpool_get_name(zhp)) == 0) 1251213197Smm (void) printf(gettext("currently in " 1252213197Smm "use")); 1253213197Smm else 1254213197Smm (void) printf(gettext("in use by " 1255213197Smm "pool '%s'"), 1256213197Smm zpool_get_name(cb.cb_zhp)); 1257213197Smm zpool_close(cb.cb_zhp); 1258213197Smm } else { 1259213197Smm (void) printf(gettext("currently in use")); 1260213197Smm } 1261213197Smm break; 1262213197Smm 1263213197Smm case VDEV_AUX_ERR_EXCEEDED: 1264213197Smm (void) printf(gettext("too many errors")); 1265213197Smm break; 1266213197Smm 1267213197Smm case VDEV_AUX_IO_FAILURE: 1268213197Smm (void) printf(gettext("experienced I/O failures")); 1269213197Smm break; 1270213197Smm 1271213197Smm case VDEV_AUX_BAD_LOG: 1272213197Smm (void) printf(gettext("bad intent log")); 1273213197Smm break; 1274213197Smm 1275219089Spjd case VDEV_AUX_EXTERNAL: 1276219089Spjd (void) printf(gettext("external device fault")); 1277219089Spjd break; 1278219089Spjd 1279219089Spjd case VDEV_AUX_SPLIT_POOL: 1280219089Spjd (void) printf(gettext("split into new pool")); 1281219089Spjd break; 1282219089Spjd 1283213197Smm default: 1284213197Smm (void) printf(gettext("corrupted data")); 1285213197Smm break; 1286213197Smm } 1287213197Smm } 1288213197Smm 1289219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1290219089Spjd (uint64_t **)&ps, &c); 1291219089Spjd 1292219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1293219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1294219089Spjd (void) printf(gettext(" (%s)"), 1295219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1296219089Spjd "resilvering" : "repairing"); 1297219089Spjd } 1298219089Spjd 1299213197Smm (void) printf("\n"); 1300213197Smm 1301213197Smm for (c = 0; c < children; c++) { 1302219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1303213197Smm 1304219089Spjd /* Don't print logs or holes here */ 1305213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1306219089Spjd &islog); 1307219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1308219089Spjd &ishole); 1309219089Spjd if (islog || ishole) 1310213197Smm continue; 1311219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1312213197Smm print_status_config(zhp, vname, child[c], 1313213197Smm namewidth, depth + 2, isspare); 1314213197Smm free(vname); 1315213197Smm } 1316213197Smm} 1317213197Smm 1318213197Smm 1319213197Smm/* 1320168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1321168404Spjd * pool, printing out the name and status for each one. 1322168404Spjd */ 1323168404Spjdvoid 1324213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1325168404Spjd{ 1326168404Spjd nvlist_t **child; 1327168404Spjd uint_t c, children; 1328168404Spjd vdev_stat_t *vs; 1329168404Spjd char *type, *vname; 1330168404Spjd 1331168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1332219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1333219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1334168404Spjd return; 1335168404Spjd 1336219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1337168404Spjd (uint64_t **)&vs, &c) == 0); 1338168404Spjd 1339168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1340185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1341168404Spjd 1342168404Spjd if (vs->vs_aux != 0) { 1343185029Spjd (void) printf(" "); 1344168404Spjd 1345168404Spjd switch (vs->vs_aux) { 1346168404Spjd case VDEV_AUX_OPEN_FAILED: 1347168404Spjd (void) printf(gettext("cannot open")); 1348168404Spjd break; 1349168404Spjd 1350168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1351168404Spjd (void) printf(gettext("missing device")); 1352168404Spjd break; 1353168404Spjd 1354168404Spjd case VDEV_AUX_NO_REPLICAS: 1355168404Spjd (void) printf(gettext("insufficient replicas")); 1356168404Spjd break; 1357168404Spjd 1358168404Spjd case VDEV_AUX_VERSION_NEWER: 1359168404Spjd (void) printf(gettext("newer version")); 1360168404Spjd break; 1361168404Spjd 1362185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1363185029Spjd (void) printf(gettext("too many errors")); 1364185029Spjd break; 1365185029Spjd 1366168404Spjd default: 1367168404Spjd (void) printf(gettext("corrupted data")); 1368168404Spjd break; 1369168404Spjd } 1370168404Spjd } 1371168404Spjd (void) printf("\n"); 1372168404Spjd 1373168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1374168404Spjd &child, &children) != 0) 1375168404Spjd return; 1376168404Spjd 1377168404Spjd for (c = 0; c < children; c++) { 1378185029Spjd uint64_t is_log = B_FALSE; 1379185029Spjd 1380185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1381185029Spjd &is_log); 1382213197Smm if (is_log) 1383185029Spjd continue; 1384185029Spjd 1385219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1386213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1387168404Spjd free(vname); 1388168404Spjd } 1389168404Spjd 1390185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1391185029Spjd &child, &children) == 0) { 1392185029Spjd (void) printf(gettext("\tcache\n")); 1393185029Spjd for (c = 0; c < children; c++) { 1394219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1395185029Spjd (void) printf("\t %s\n", vname); 1396185029Spjd free(vname); 1397185029Spjd } 1398185029Spjd } 1399185029Spjd 1400168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1401185029Spjd &child, &children) == 0) { 1402185029Spjd (void) printf(gettext("\tspares\n")); 1403185029Spjd for (c = 0; c < children; c++) { 1404219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1405185029Spjd (void) printf("\t %s\n", vname); 1406185029Spjd free(vname); 1407185029Spjd } 1408168404Spjd } 1409168404Spjd} 1410168404Spjd 1411168404Spjd/* 1412213197Smm * Print log vdevs. 1413213197Smm * Logs are recorded as top level vdevs in the main pool child array 1414213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1415213197Smm * print_import_config() to print the top level logs then any log 1416213197Smm * children (eg mirrored slogs) are printed recursively - which 1417213197Smm * works because only the top level vdev is marked "is_log" 1418213197Smm */ 1419213197Smmstatic void 1420213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1421213197Smm{ 1422213197Smm uint_t c, children; 1423213197Smm nvlist_t **child; 1424213197Smm 1425213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1426213197Smm &children) != 0) 1427213197Smm return; 1428213197Smm 1429213197Smm (void) printf(gettext("\tlogs\n")); 1430213197Smm 1431213197Smm for (c = 0; c < children; c++) { 1432213197Smm uint64_t is_log = B_FALSE; 1433213197Smm char *name; 1434213197Smm 1435213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1436213197Smm &is_log); 1437213197Smm if (!is_log) 1438213197Smm continue; 1439219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1440213197Smm if (verbose) 1441213197Smm print_status_config(zhp, name, child[c], namewidth, 1442213197Smm 2, B_FALSE); 1443213197Smm else 1444213197Smm print_import_config(name, child[c], namewidth, 2); 1445213197Smm free(name); 1446213197Smm } 1447213197Smm} 1448219089Spjd 1449213197Smm/* 1450168404Spjd * Display the status for the given pool. 1451168404Spjd */ 1452168404Spjdstatic void 1453168404Spjdshow_import(nvlist_t *config) 1454168404Spjd{ 1455168404Spjd uint64_t pool_state; 1456168404Spjd vdev_stat_t *vs; 1457168404Spjd char *name; 1458168404Spjd uint64_t guid; 1459168404Spjd char *msgid; 1460168404Spjd nvlist_t *nvroot; 1461168404Spjd int reason; 1462168404Spjd const char *health; 1463168404Spjd uint_t vsc; 1464168404Spjd int namewidth; 1465228103Smm char *comment; 1466168404Spjd 1467168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1468168404Spjd &name) == 0); 1469168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1470168404Spjd &guid) == 0); 1471168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1472168404Spjd &pool_state) == 0); 1473168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1474168404Spjd &nvroot) == 0); 1475168404Spjd 1476219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1477168404Spjd (uint64_t **)&vs, &vsc) == 0); 1478185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1479168404Spjd 1480168404Spjd reason = zpool_import_status(config, &msgid); 1481168404Spjd 1482228103Smm (void) printf(gettext(" pool: %s\n"), name); 1483228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1484228103Smm (void) printf(gettext(" state: %s"), health); 1485168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1486168404Spjd (void) printf(gettext(" (DESTROYED)")); 1487168404Spjd (void) printf("\n"); 1488168404Spjd 1489168404Spjd switch (reason) { 1490168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1491168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1492168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1493228103Smm (void) printf(gettext(" status: One or more devices are " 1494228103Smm "missing from the system.\n")); 1495168404Spjd break; 1496168404Spjd 1497168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1498168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1499228103Smm (void) printf(gettext(" status: One or more devices contains " 1500168404Spjd "corrupted data.\n")); 1501168404Spjd break; 1502168404Spjd 1503168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1504228103Smm (void) printf( 1505228103Smm gettext(" status: The pool data is corrupted.\n")); 1506168404Spjd break; 1507168404Spjd 1508168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1509228103Smm (void) printf(gettext(" status: One or more devices " 1510168404Spjd "are offlined.\n")); 1511168404Spjd break; 1512168404Spjd 1513168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1514228103Smm (void) printf(gettext(" status: The pool metadata is " 1515168404Spjd "corrupted.\n")); 1516168404Spjd break; 1517168404Spjd 1518168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1519228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1520168404Spjd "older on-disk version.\n")); 1521168404Spjd break; 1522168404Spjd 1523168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1524228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1525168404Spjd "incompatible version.\n")); 1526168404Spjd break; 1527168404Spjd 1528168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1529228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1530168498Spjd "another system.\n")); 1531168498Spjd break; 1532185029Spjd 1533185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1534185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1535228103Smm (void) printf(gettext(" status: One or more devices are " 1536185029Spjd "faulted.\n")); 1537185029Spjd break; 1538185029Spjd 1539185029Spjd case ZPOOL_STATUS_BAD_LOG: 1540228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1541185029Spjd "read.\n")); 1542185029Spjd break; 1543185029Spjd 1544219089Spjd case ZPOOL_STATUS_RESILVERING: 1545228103Smm (void) printf(gettext(" status: One or more devices were being " 1546219089Spjd "resilvered.\n")); 1547219089Spjd break; 1548219089Spjd 1549168404Spjd default: 1550168404Spjd /* 1551168404Spjd * No other status can be seen when importing pools. 1552168404Spjd */ 1553168404Spjd assert(reason == ZPOOL_STATUS_OK); 1554168404Spjd } 1555168404Spjd 1556168404Spjd /* 1557168404Spjd * Print out an action according to the overall state of the pool. 1558168404Spjd */ 1559168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1560168404Spjd if (reason == ZPOOL_STATUS_VERSION_OLDER) 1561228103Smm (void) printf(gettext(" action: The pool can be " 1562168404Spjd "imported using its name or numeric identifier, " 1563168404Spjd "though\n\tsome features will not be available " 1564168404Spjd "without an explicit 'zpool upgrade'.\n")); 1565168498Spjd else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 1566228103Smm (void) printf(gettext(" action: The pool can be " 1567168498Spjd "imported using its name or numeric " 1568168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1569168404Spjd else 1570228103Smm (void) printf(gettext(" action: The pool can be " 1571168404Spjd "imported using its name or numeric " 1572168404Spjd "identifier.\n")); 1573168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1574228103Smm (void) printf(gettext(" action: The pool can be imported " 1575168404Spjd "despite missing or damaged devices. The\n\tfault " 1576168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1577168404Spjd } else { 1578168404Spjd switch (reason) { 1579168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1580228103Smm (void) printf(gettext(" action: The pool cannot be " 1581168404Spjd "imported. Access the pool on a system running " 1582168404Spjd "newer\n\tsoftware, or recreate the pool from " 1583168404Spjd "backup.\n")); 1584168404Spjd break; 1585168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1586168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1587168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1588228103Smm (void) printf(gettext(" action: The pool cannot be " 1589168404Spjd "imported. Attach the missing\n\tdevices and try " 1590168404Spjd "again.\n")); 1591168404Spjd break; 1592168404Spjd default: 1593228103Smm (void) printf(gettext(" action: The pool cannot be " 1594168404Spjd "imported due to damaged devices or data.\n")); 1595168404Spjd } 1596168404Spjd } 1597168404Spjd 1598228103Smm /* Print the comment attached to the pool. */ 1599228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 1600228103Smm (void) printf(gettext("comment: %s\n"), comment); 1601228103Smm 1602168404Spjd /* 1603168404Spjd * If the state is "closed" or "can't open", and the aux state 1604168404Spjd * is "corrupt data": 1605168404Spjd */ 1606168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1607168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1608168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1609168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1610168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1611168404Spjd "but can be imported using the '-Df' flags.\n")); 1612168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1613168404Spjd (void) printf(gettext("\tThe pool may be active on " 1614185029Spjd "another system, but can be imported using\n\t" 1615168404Spjd "the '-f' flag.\n")); 1616168404Spjd } 1617168404Spjd 1618168404Spjd if (msgid != NULL) 1619168404Spjd (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1620168404Spjd msgid); 1621168404Spjd 1622228103Smm (void) printf(gettext(" config:\n\n")); 1623168404Spjd 1624168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1625168404Spjd if (namewidth < 10) 1626168404Spjd namewidth = 10; 1627168404Spjd 1628213197Smm print_import_config(name, nvroot, namewidth, 0); 1629213197Smm if (num_logs(nvroot) > 0) 1630213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1631185029Spjd 1632168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1633168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1634168404Spjd "be part of this pool, though their\n\texact " 1635168404Spjd "configuration cannot be determined.\n")); 1636168404Spjd } 1637168404Spjd} 1638168404Spjd 1639168404Spjd/* 1640168404Spjd * Perform the import for the given configuration. This passes the heavy 1641185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1642185029Spjd * within the pool. 1643168404Spjd */ 1644168404Spjdstatic int 1645168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1646219089Spjd nvlist_t *props, int flags) 1647168404Spjd{ 1648168404Spjd zpool_handle_t *zhp; 1649168404Spjd char *name; 1650168404Spjd uint64_t state; 1651168404Spjd uint64_t version; 1652168404Spjd 1653168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1654168404Spjd &name) == 0); 1655168404Spjd 1656168404Spjd verify(nvlist_lookup_uint64(config, 1657168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1658168404Spjd verify(nvlist_lookup_uint64(config, 1659168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1660185029Spjd if (version > SPA_VERSION) { 1661168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1662168404Spjd "is formatted using a newer ZFS version\n"), name); 1663168404Spjd return (1); 1664219089Spjd } else if (state != POOL_STATE_EXPORTED && 1665219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 1666168498Spjd uint64_t hostid; 1667168498Spjd 1668168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1669168498Spjd &hostid) == 0) { 1670168498Spjd if ((unsigned long)hostid != gethostid()) { 1671168498Spjd char *hostname; 1672168498Spjd uint64_t timestamp; 1673168498Spjd time_t t; 1674168498Spjd 1675168498Spjd verify(nvlist_lookup_string(config, 1676168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1677168498Spjd verify(nvlist_lookup_uint64(config, 1678168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1679168498Spjd t = timestamp; 1680168498Spjd (void) fprintf(stderr, gettext("cannot import " 1681168498Spjd "'%s': pool may be in use from other " 1682168498Spjd "system, it was last accessed by %s " 1683168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1684168498Spjd (unsigned long)hostid, 1685168498Spjd asctime(localtime(&t))); 1686168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1687168498Spjd "import anyway\n")); 1688168498Spjd return (1); 1689168498Spjd } 1690168498Spjd } else { 1691168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1692168498Spjd "pool may be in use from other system\n"), name); 1693168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1694168498Spjd "anyway\n")); 1695168498Spjd return (1); 1696168498Spjd } 1697168404Spjd } 1698168404Spjd 1699219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1700168404Spjd return (1); 1701168404Spjd 1702168404Spjd if (newname != NULL) 1703168404Spjd name = (char *)newname; 1704168404Spjd 1705209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 1706209962Smm return (1); 1707168404Spjd 1708209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1709219089Spjd !(flags & ZFS_IMPORT_ONLY) && 1710209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1711168404Spjd zpool_close(zhp); 1712168404Spjd return (1); 1713168404Spjd } 1714168404Spjd 1715168404Spjd zpool_close(zhp); 1716219089Spjd return (0); 1717168404Spjd} 1718168404Spjd 1719168404Spjd/* 1720168404Spjd * zpool import [-d dir] [-D] 1721185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1722185029Spjd * [-d dir | -c cachefile] [-f] -a 1723185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1724219089Spjd * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 1725168404Spjd * 1726185029Spjd * -c Read pool information from a cachefile instead of searching 1727185029Spjd * devices. 1728185029Spjd * 1729168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1730168404Spjd * one directory can be specified using multiple '-d' options. 1731168404Spjd * 1732168404Spjd * -D Scan for previously destroyed pools or import all or only 1733168404Spjd * specified destroyed pools. 1734168404Spjd * 1735168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1736168404Spjd * the given root. The pool will remain exported when the machine 1737168404Spjd * is rebooted. 1738168404Spjd * 1739219089Spjd * -V Import even in the presence of faulted vdevs. This is an 1740185029Spjd * intentionally undocumented option for testing purposes, and 1741185029Spjd * treats the pool configuration as complete, leaving any bad 1742209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 1743209962Smm * import. 1744185029Spjd * 1745219089Spjd * -f Force import, even if it appears that the pool is active. 1746219089Spjd * 1747219089Spjd * -F Attempt rewind if necessary. 1748219089Spjd * 1749219089Spjd * -n See if rewind would work, but don't actually rewind. 1750219089Spjd * 1751219089Spjd * -N Import the pool but don't mount datasets. 1752219089Spjd * 1753219089Spjd * -T Specify a starting txg to use for import. This option is 1754219089Spjd * intentionally undocumented option for testing purposes. 1755219089Spjd * 1756168404Spjd * -a Import all pools found. 1757168404Spjd * 1758185029Spjd * -o Set property=value and/or temporary mount options (without '='). 1759185029Spjd * 1760168404Spjd * The import command scans for pools to import, and import pools based on pool 1761168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 1762168404Spjd */ 1763168404Spjdint 1764168404Spjdzpool_do_import(int argc, char **argv) 1765168404Spjd{ 1766168404Spjd char **searchdirs = NULL; 1767168404Spjd int nsearch = 0; 1768168404Spjd int c; 1769219089Spjd int err = 0; 1770185029Spjd nvlist_t *pools = NULL; 1771168404Spjd boolean_t do_all = B_FALSE; 1772168404Spjd boolean_t do_destroyed = B_FALSE; 1773168404Spjd char *mntopts = NULL; 1774168404Spjd nvpair_t *elem; 1775168404Spjd nvlist_t *config; 1776185029Spjd uint64_t searchguid = 0; 1777185029Spjd char *searchname = NULL; 1778185029Spjd char *propval; 1779168404Spjd nvlist_t *found_config; 1780219089Spjd nvlist_t *policy = NULL; 1781185029Spjd nvlist_t *props = NULL; 1782168404Spjd boolean_t first; 1783219089Spjd int flags = ZFS_IMPORT_NORMAL; 1784219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 1785219089Spjd boolean_t dryrun = B_FALSE; 1786219089Spjd boolean_t do_rewind = B_FALSE; 1787219089Spjd boolean_t xtreme_rewind = B_FALSE; 1788219089Spjd uint64_t pool_state, txg = -1ULL; 1789185029Spjd char *cachefile = NULL; 1790219089Spjd importargs_t idata = { 0 }; 1791219089Spjd char *endptr; 1792168404Spjd 1793168404Spjd /* check options */ 1794219089Spjd while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) { 1795168404Spjd switch (c) { 1796168404Spjd case 'a': 1797168404Spjd do_all = B_TRUE; 1798168404Spjd break; 1799185029Spjd case 'c': 1800185029Spjd cachefile = optarg; 1801185029Spjd break; 1802168404Spjd case 'd': 1803168404Spjd if (searchdirs == NULL) { 1804168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1805168404Spjd } else { 1806168404Spjd char **tmp = safe_malloc((nsearch + 1) * 1807168404Spjd sizeof (char *)); 1808168404Spjd bcopy(searchdirs, tmp, nsearch * 1809168404Spjd sizeof (char *)); 1810168404Spjd free(searchdirs); 1811168404Spjd searchdirs = tmp; 1812168404Spjd } 1813168404Spjd searchdirs[nsearch++] = optarg; 1814168404Spjd break; 1815168404Spjd case 'D': 1816168404Spjd do_destroyed = B_TRUE; 1817168404Spjd break; 1818168404Spjd case 'f': 1819219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 1820168404Spjd break; 1821185029Spjd case 'F': 1822219089Spjd do_rewind = B_TRUE; 1823185029Spjd break; 1824219089Spjd case 'm': 1825219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 1826219089Spjd break; 1827219089Spjd case 'n': 1828219089Spjd dryrun = B_TRUE; 1829219089Spjd break; 1830219089Spjd case 'N': 1831219089Spjd flags |= ZFS_IMPORT_ONLY; 1832219089Spjd break; 1833168404Spjd case 'o': 1834185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 1835185029Spjd *propval = '\0'; 1836185029Spjd propval++; 1837185029Spjd if (add_prop_list(optarg, propval, 1838185029Spjd &props, B_TRUE)) 1839185029Spjd goto error; 1840185029Spjd } else { 1841185029Spjd mntopts = optarg; 1842185029Spjd } 1843168404Spjd break; 1844168404Spjd case 'R': 1845185029Spjd if (add_prop_list(zpool_prop_to_name( 1846185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 1847185029Spjd goto error; 1848185029Spjd if (nvlist_lookup_string(props, 1849185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 1850185029Spjd &propval) == 0) 1851185029Spjd break; 1852185029Spjd if (add_prop_list(zpool_prop_to_name( 1853185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1854185029Spjd goto error; 1855168404Spjd break; 1856219089Spjd case 'T': 1857219089Spjd errno = 0; 1858219089Spjd txg = strtoull(optarg, &endptr, 10); 1859219089Spjd if (errno != 0 || *endptr != '\0') { 1860219089Spjd (void) fprintf(stderr, 1861219089Spjd gettext("invalid txg value\n")); 1862219089Spjd usage(B_FALSE); 1863219089Spjd } 1864219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 1865219089Spjd break; 1866219089Spjd case 'V': 1867219089Spjd flags |= ZFS_IMPORT_VERBATIM; 1868219089Spjd break; 1869219089Spjd case 'X': 1870219089Spjd xtreme_rewind = B_TRUE; 1871219089Spjd break; 1872168404Spjd case ':': 1873168404Spjd (void) fprintf(stderr, gettext("missing argument for " 1874168404Spjd "'%c' option\n"), optopt); 1875168404Spjd usage(B_FALSE); 1876168404Spjd break; 1877168404Spjd case '?': 1878168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1879168404Spjd optopt); 1880168404Spjd usage(B_FALSE); 1881168404Spjd } 1882168404Spjd } 1883168404Spjd 1884168404Spjd argc -= optind; 1885168404Spjd argv += optind; 1886168404Spjd 1887185029Spjd if (cachefile && nsearch != 0) { 1888185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 1889185029Spjd usage(B_FALSE); 1890185029Spjd } 1891185029Spjd 1892219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 1893219089Spjd (void) fprintf(stderr, 1894219089Spjd gettext("-n or -X only meaningful with -F\n")); 1895219089Spjd usage(B_FALSE); 1896219089Spjd } 1897219089Spjd if (dryrun) 1898219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 1899219089Spjd else if (do_rewind) 1900219089Spjd rewind_policy = ZPOOL_DO_REWIND; 1901219089Spjd if (xtreme_rewind) 1902219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 1903219089Spjd 1904219089Spjd /* In the future, we can capture further policy and include it here */ 1905219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 1906219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 1907219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 1908219089Spjd goto error; 1909219089Spjd 1910168404Spjd if (searchdirs == NULL) { 1911168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1912235478Savg searchdirs[0] = "/dev"; 1913168404Spjd nsearch = 1; 1914168404Spjd } 1915168404Spjd 1916168404Spjd /* check argument count */ 1917168404Spjd if (do_all) { 1918168404Spjd if (argc != 0) { 1919168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1920168404Spjd usage(B_FALSE); 1921168404Spjd } 1922168404Spjd } else { 1923168404Spjd if (argc > 2) { 1924168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1925168404Spjd usage(B_FALSE); 1926168404Spjd } 1927168404Spjd 1928168404Spjd /* 1929168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 1930168404Spjd * here because otherwise any attempt to discover pools will 1931168404Spjd * silently fail. 1932168404Spjd */ 1933168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1934168404Spjd (void) fprintf(stderr, gettext("cannot " 1935168404Spjd "discover pools: permission denied\n")); 1936168404Spjd free(searchdirs); 1937219089Spjd nvlist_free(policy); 1938168404Spjd return (1); 1939168404Spjd } 1940168404Spjd } 1941168404Spjd 1942168404Spjd /* 1943168404Spjd * Depending on the arguments given, we do one of the following: 1944168404Spjd * 1945168404Spjd * <none> Iterate through all pools and display information about 1946168404Spjd * each one. 1947168404Spjd * 1948168404Spjd * -a Iterate through all pools and try to import each one. 1949168404Spjd * 1950168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 1951168404Spjd * name and import that one. 1952168404Spjd * 1953168404Spjd * -D Above options applies only to destroyed pools. 1954168404Spjd */ 1955168404Spjd if (argc != 0) { 1956168404Spjd char *endptr; 1957168404Spjd 1958168404Spjd errno = 0; 1959168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 1960168404Spjd if (errno != 0 || *endptr != '\0') 1961168404Spjd searchname = argv[0]; 1962168404Spjd found_config = NULL; 1963168404Spjd 1964185029Spjd /* 1965219089Spjd * User specified a name or guid. Ensure it's unique. 1966185029Spjd */ 1967219089Spjd idata.unique = B_TRUE; 1968185029Spjd } 1969185029Spjd 1970219089Spjd 1971219089Spjd idata.path = searchdirs; 1972219089Spjd idata.paths = nsearch; 1973219089Spjd idata.poolname = searchname; 1974219089Spjd idata.guid = searchguid; 1975219089Spjd idata.cachefile = cachefile; 1976219089Spjd 1977219089Spjd pools = zpool_search_import(g_zfs, &idata); 1978219089Spjd 1979219089Spjd if (pools != NULL && idata.exists && 1980219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 1981219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1982219089Spjd "a pool with that name already exists\n"), 1983219089Spjd argv[0]); 1984219089Spjd (void) fprintf(stderr, gettext("use the form '%s " 1985219089Spjd "<pool | id> <newpool>' to give it a new name\n"), 1986219089Spjd "zpool import"); 1987219089Spjd err = 1; 1988219089Spjd } else if (pools == NULL && idata.exists) { 1989219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1990219089Spjd "a pool with that name is already created/imported,\n"), 1991219089Spjd argv[0]); 1992219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 1993219089Spjd "with that name were found\n")); 1994219089Spjd err = 1; 1995219089Spjd } else if (pools == NULL) { 1996185029Spjd if (argc != 0) { 1997185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1998185029Spjd "no such pool available\n"), argv[0]); 1999185029Spjd } 2000219089Spjd err = 1; 2001219089Spjd } 2002219089Spjd 2003219089Spjd if (err == 1) { 2004185029Spjd free(searchdirs); 2005219089Spjd nvlist_free(policy); 2006185029Spjd return (1); 2007185029Spjd } 2008185029Spjd 2009185029Spjd /* 2010185029Spjd * At this point we have a list of import candidate configs. Even if 2011185029Spjd * we were searching by pool name or guid, we still need to 2012185029Spjd * post-process the list to deal with pool state and possible 2013185029Spjd * duplicate names. 2014185029Spjd */ 2015168404Spjd err = 0; 2016168404Spjd elem = NULL; 2017168404Spjd first = B_TRUE; 2018168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2019168404Spjd 2020168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2021168404Spjd 2022168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2023168404Spjd &pool_state) == 0); 2024168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2025168404Spjd continue; 2026168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2027168404Spjd continue; 2028168404Spjd 2029219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2030219089Spjd policy) == 0); 2031219089Spjd 2032168404Spjd if (argc == 0) { 2033168404Spjd if (first) 2034168404Spjd first = B_FALSE; 2035168404Spjd else if (!do_all) 2036168404Spjd (void) printf("\n"); 2037168404Spjd 2038219089Spjd if (do_all) { 2039168404Spjd err |= do_import(config, NULL, mntopts, 2040219089Spjd props, flags); 2041219089Spjd } else { 2042168404Spjd show_import(config); 2043219089Spjd } 2044168404Spjd } else if (searchname != NULL) { 2045168404Spjd char *name; 2046168404Spjd 2047168404Spjd /* 2048168404Spjd * We are searching for a pool based on name. 2049168404Spjd */ 2050168404Spjd verify(nvlist_lookup_string(config, 2051168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2052168404Spjd 2053168404Spjd if (strcmp(name, searchname) == 0) { 2054168404Spjd if (found_config != NULL) { 2055168404Spjd (void) fprintf(stderr, gettext( 2056168404Spjd "cannot import '%s': more than " 2057168404Spjd "one matching pool\n"), searchname); 2058168404Spjd (void) fprintf(stderr, gettext( 2059168404Spjd "import by numeric ID instead\n")); 2060168404Spjd err = B_TRUE; 2061168404Spjd } 2062168404Spjd found_config = config; 2063168404Spjd } 2064168404Spjd } else { 2065168404Spjd uint64_t guid; 2066168404Spjd 2067168404Spjd /* 2068168404Spjd * Search for a pool by guid. 2069168404Spjd */ 2070168404Spjd verify(nvlist_lookup_uint64(config, 2071168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2072168404Spjd 2073168404Spjd if (guid == searchguid) 2074168404Spjd found_config = config; 2075168404Spjd } 2076168404Spjd } 2077168404Spjd 2078168404Spjd /* 2079168404Spjd * If we were searching for a specific pool, verify that we found a 2080168404Spjd * pool, and then do the import. 2081168404Spjd */ 2082168404Spjd if (argc != 0 && err == 0) { 2083168404Spjd if (found_config == NULL) { 2084168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2085168404Spjd "no such pool available\n"), argv[0]); 2086168404Spjd err = B_TRUE; 2087168404Spjd } else { 2088168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2089219089Spjd argv[1], mntopts, props, flags); 2090168404Spjd } 2091168404Spjd } 2092168404Spjd 2093168404Spjd /* 2094168404Spjd * If we were just looking for pools, report an error if none were 2095168404Spjd * found. 2096168404Spjd */ 2097168404Spjd if (argc == 0 && first) 2098168404Spjd (void) fprintf(stderr, 2099168404Spjd gettext("no pools available to import\n")); 2100168404Spjd 2101185029Spjderror: 2102185029Spjd nvlist_free(props); 2103168404Spjd nvlist_free(pools); 2104219089Spjd nvlist_free(policy); 2105168404Spjd free(searchdirs); 2106168404Spjd 2107168404Spjd return (err ? 1 : 0); 2108168404Spjd} 2109168404Spjd 2110168404Spjdtypedef struct iostat_cbdata { 2111168404Spjd zpool_list_t *cb_list; 2112168404Spjd int cb_verbose; 2113168404Spjd int cb_iteration; 2114168404Spjd int cb_namewidth; 2115168404Spjd} iostat_cbdata_t; 2116168404Spjd 2117168404Spjdstatic void 2118168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2119168404Spjd{ 2120168404Spjd int i = 0; 2121168404Spjd 2122168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2123168404Spjd (void) printf("-"); 2124168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2125168404Spjd} 2126168404Spjd 2127168404Spjdstatic void 2128168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2129168404Spjd{ 2130168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2131168404Spjd cb->cb_namewidth, ""); 2132219089Spjd (void) printf("%-*s alloc free read write read write\n", 2133168404Spjd cb->cb_namewidth, "pool"); 2134168404Spjd print_iostat_separator(cb); 2135168404Spjd} 2136168404Spjd 2137168404Spjd/* 2138168404Spjd * Display a single statistic. 2139168404Spjd */ 2140185029Spjdstatic void 2141168404Spjdprint_one_stat(uint64_t value) 2142168404Spjd{ 2143168404Spjd char buf[64]; 2144168404Spjd 2145168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2146168404Spjd (void) printf(" %5s", buf); 2147168404Spjd} 2148168404Spjd 2149168404Spjd/* 2150168404Spjd * Print out all the statistics for the given vdev. This can either be the 2151168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2152168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2153168404Spjd */ 2154168404Spjdvoid 2155168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2156168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2157168404Spjd{ 2158168404Spjd nvlist_t **oldchild, **newchild; 2159168404Spjd uint_t c, children; 2160168404Spjd vdev_stat_t *oldvs, *newvs; 2161168404Spjd vdev_stat_t zerovs = { 0 }; 2162168404Spjd uint64_t tdelta; 2163168404Spjd double scale; 2164168404Spjd char *vname; 2165168404Spjd 2166168404Spjd if (oldnv != NULL) { 2167219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2168219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2169168404Spjd } else { 2170168404Spjd oldvs = &zerovs; 2171168404Spjd } 2172168404Spjd 2173219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2174168404Spjd (uint64_t **)&newvs, &c) == 0); 2175168404Spjd 2176168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2177168404Spjd (void) printf("%*s%s", depth, "", name); 2178168404Spjd else 2179168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2180168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2181168404Spjd 2182168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2183168404Spjd 2184168404Spjd if (tdelta == 0) 2185168404Spjd scale = 1.0; 2186168404Spjd else 2187168404Spjd scale = (double)NANOSEC / tdelta; 2188168404Spjd 2189168404Spjd /* only toplevel vdevs have capacity stats */ 2190168404Spjd if (newvs->vs_space == 0) { 2191168404Spjd (void) printf(" - -"); 2192168404Spjd } else { 2193168404Spjd print_one_stat(newvs->vs_alloc); 2194168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2195168404Spjd } 2196168404Spjd 2197168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2198168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2199168404Spjd 2200168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2201168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2202168404Spjd 2203168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2204168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2205168404Spjd 2206168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2207168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2208168404Spjd 2209168404Spjd (void) printf("\n"); 2210168404Spjd 2211168404Spjd if (!cb->cb_verbose) 2212168404Spjd return; 2213168404Spjd 2214168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2215168404Spjd &newchild, &children) != 0) 2216168404Spjd return; 2217168404Spjd 2218168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2219168404Spjd &oldchild, &c) != 0) 2220168404Spjd return; 2221168404Spjd 2222168404Spjd for (c = 0; c < children; c++) { 2223227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2224219089Spjd 2225227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2226227497Smm &ishole); 2227227497Smm 2228227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2229227497Smm &islog); 2230227497Smm 2231227497Smm if (ishole || islog) 2232219089Spjd continue; 2233219089Spjd 2234219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2235168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2236168404Spjd newchild[c], cb, depth + 2); 2237168404Spjd free(vname); 2238168404Spjd } 2239185029Spjd 2240185029Spjd /* 2241227497Smm * Log device section 2242227497Smm */ 2243227497Smm 2244227497Smm if (num_logs(newnv) > 0) { 2245227497Smm (void) printf("%-*s - - - - - " 2246227497Smm "-\n", cb->cb_namewidth, "logs"); 2247227497Smm 2248227497Smm for (c = 0; c < children; c++) { 2249227497Smm uint64_t islog = B_FALSE; 2250227497Smm (void) nvlist_lookup_uint64(newchild[c], 2251227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2252227497Smm 2253227497Smm if (islog) { 2254227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2255227497Smm B_FALSE); 2256227497Smm print_vdev_stats(zhp, vname, oldnv ? 2257227497Smm oldchild[c] : NULL, newchild[c], 2258227497Smm cb, depth + 2); 2259227497Smm free(vname); 2260227497Smm } 2261227497Smm } 2262227497Smm 2263227497Smm } 2264227497Smm 2265227497Smm /* 2266185029Spjd * Include level 2 ARC devices in iostat output 2267185029Spjd */ 2268185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2269185029Spjd &newchild, &children) != 0) 2270185029Spjd return; 2271185029Spjd 2272185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2273185029Spjd &oldchild, &c) != 0) 2274185029Spjd return; 2275185029Spjd 2276185029Spjd if (children > 0) { 2277185029Spjd (void) printf("%-*s - - - - - " 2278185029Spjd "-\n", cb->cb_namewidth, "cache"); 2279185029Spjd for (c = 0; c < children; c++) { 2280219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2281219089Spjd B_FALSE); 2282185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2283185029Spjd newchild[c], cb, depth + 2); 2284185029Spjd free(vname); 2285185029Spjd } 2286185029Spjd } 2287168404Spjd} 2288168404Spjd 2289168404Spjdstatic int 2290168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2291168404Spjd{ 2292168404Spjd iostat_cbdata_t *cb = data; 2293168404Spjd boolean_t missing; 2294168404Spjd 2295168404Spjd /* 2296168404Spjd * If the pool has disappeared, remove it from the list and continue. 2297168404Spjd */ 2298168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2299168404Spjd return (-1); 2300168404Spjd 2301168404Spjd if (missing) 2302168404Spjd pool_list_remove(cb->cb_list, zhp); 2303168404Spjd 2304168404Spjd return (0); 2305168404Spjd} 2306168404Spjd 2307168404Spjd/* 2308168404Spjd * Callback to print out the iostats for the given pool. 2309168404Spjd */ 2310168404Spjdint 2311168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2312168404Spjd{ 2313168404Spjd iostat_cbdata_t *cb = data; 2314168404Spjd nvlist_t *oldconfig, *newconfig; 2315168404Spjd nvlist_t *oldnvroot, *newnvroot; 2316168404Spjd 2317168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2318168404Spjd 2319168404Spjd if (cb->cb_iteration == 1) 2320168404Spjd oldconfig = NULL; 2321168404Spjd 2322168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2323168404Spjd &newnvroot) == 0); 2324168404Spjd 2325168404Spjd if (oldconfig == NULL) 2326168404Spjd oldnvroot = NULL; 2327168404Spjd else 2328168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2329168404Spjd &oldnvroot) == 0); 2330168404Spjd 2331168404Spjd /* 2332168404Spjd * Print out the statistics for the pool. 2333168404Spjd */ 2334168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2335168404Spjd 2336168404Spjd if (cb->cb_verbose) 2337168404Spjd print_iostat_separator(cb); 2338168404Spjd 2339168404Spjd return (0); 2340168404Spjd} 2341168404Spjd 2342168404Spjdint 2343168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2344168404Spjd{ 2345168404Spjd iostat_cbdata_t *cb = data; 2346168404Spjd nvlist_t *config, *nvroot; 2347168404Spjd 2348168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2349168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2350168404Spjd &nvroot) == 0); 2351168404Spjd if (!cb->cb_verbose) 2352168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2353168404Spjd else 2354168404Spjd cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 2355168404Spjd } 2356168404Spjd 2357168404Spjd /* 2358168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2359168404Spjd * maximum we can have and still fit in 80 columns. 2360168404Spjd */ 2361168404Spjd if (cb->cb_namewidth < 10) 2362168404Spjd cb->cb_namewidth = 10; 2363168404Spjd if (cb->cb_namewidth > 38) 2364168404Spjd cb->cb_namewidth = 38; 2365168404Spjd 2366168404Spjd return (0); 2367168404Spjd} 2368168404Spjd 2369168404Spjd/* 2370219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2371168404Spjd */ 2372219089Spjdstatic void 2373219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2374219089Spjd unsigned long *cnt) 2375168404Spjd{ 2376168404Spjd unsigned long interval = 0, count = 0; 2377219089Spjd int argc = *argcp, errno; 2378168404Spjd 2379168404Spjd /* 2380168404Spjd * Determine if the last argument is an integer or a pool name 2381168404Spjd */ 2382168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2383168404Spjd char *end; 2384168404Spjd 2385168404Spjd errno = 0; 2386168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2387168404Spjd 2388168404Spjd if (*end == '\0' && errno == 0) { 2389168404Spjd if (interval == 0) { 2390168404Spjd (void) fprintf(stderr, gettext("interval " 2391168404Spjd "cannot be zero\n")); 2392168404Spjd usage(B_FALSE); 2393168404Spjd } 2394168404Spjd /* 2395168404Spjd * Ignore the last parameter 2396168404Spjd */ 2397168404Spjd argc--; 2398168404Spjd } else { 2399168404Spjd /* 2400168404Spjd * If this is not a valid number, just plow on. The 2401168404Spjd * user will get a more informative error message later 2402168404Spjd * on. 2403168404Spjd */ 2404168404Spjd interval = 0; 2405168404Spjd } 2406168404Spjd } 2407168404Spjd 2408168404Spjd /* 2409168404Spjd * If the last argument is also an integer, then we have both a count 2410219089Spjd * and an interval. 2411168404Spjd */ 2412168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2413168404Spjd char *end; 2414168404Spjd 2415168404Spjd errno = 0; 2416168404Spjd count = interval; 2417168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2418168404Spjd 2419168404Spjd if (*end == '\0' && errno == 0) { 2420168404Spjd if (interval == 0) { 2421168404Spjd (void) fprintf(stderr, gettext("interval " 2422168404Spjd "cannot be zero\n")); 2423168404Spjd usage(B_FALSE); 2424168404Spjd } 2425168404Spjd 2426168404Spjd /* 2427168404Spjd * Ignore the last parameter 2428168404Spjd */ 2429168404Spjd argc--; 2430168404Spjd } else { 2431168404Spjd interval = 0; 2432168404Spjd } 2433168404Spjd } 2434168404Spjd 2435219089Spjd *iv = interval; 2436219089Spjd *cnt = count; 2437219089Spjd *argcp = argc; 2438219089Spjd} 2439219089Spjd 2440219089Spjdstatic void 2441219089Spjdget_timestamp_arg(char c) 2442219089Spjd{ 2443219089Spjd if (c == 'u') 2444219089Spjd timestamp_fmt = UDATE; 2445219089Spjd else if (c == 'd') 2446219089Spjd timestamp_fmt = DDATE; 2447219089Spjd else 2448219089Spjd usage(B_FALSE); 2449219089Spjd} 2450219089Spjd 2451219089Spjd/* 2452219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2453219089Spjd * 2454219089Spjd * -v Display statistics for individual vdevs 2455219089Spjd * -T Display a timestamp in date(1) or Unix format 2456219089Spjd * 2457219089Spjd * This command can be tricky because we want to be able to deal with pool 2458219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2459219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2460219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2461219089Spjd * changes are all handled within libzfs. 2462219089Spjd */ 2463219089Spjdint 2464219089Spjdzpool_do_iostat(int argc, char **argv) 2465219089Spjd{ 2466219089Spjd int c; 2467219089Spjd int ret; 2468219089Spjd int npools; 2469219089Spjd unsigned long interval = 0, count = 0; 2470219089Spjd zpool_list_t *list; 2471219089Spjd boolean_t verbose = B_FALSE; 2472219089Spjd iostat_cbdata_t cb; 2473219089Spjd 2474219089Spjd /* check options */ 2475219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2476219089Spjd switch (c) { 2477219089Spjd case 'T': 2478219089Spjd get_timestamp_arg(*optarg); 2479219089Spjd break; 2480219089Spjd case 'v': 2481219089Spjd verbose = B_TRUE; 2482219089Spjd break; 2483219089Spjd case '?': 2484219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2485219089Spjd optopt); 2486219089Spjd usage(B_FALSE); 2487219089Spjd } 2488219089Spjd } 2489219089Spjd 2490219089Spjd argc -= optind; 2491219089Spjd argv += optind; 2492219089Spjd 2493219089Spjd get_interval_count(&argc, argv, &interval, &count); 2494219089Spjd 2495168404Spjd /* 2496168404Spjd * Construct the list of all interesting pools. 2497168404Spjd */ 2498168404Spjd ret = 0; 2499168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2500168404Spjd return (1); 2501168404Spjd 2502168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2503168404Spjd pool_list_free(list); 2504168404Spjd return (1); 2505168404Spjd } 2506168404Spjd 2507168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2508168404Spjd pool_list_free(list); 2509168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2510168404Spjd return (1); 2511168404Spjd } 2512168404Spjd 2513168404Spjd /* 2514168404Spjd * Enter the main iostat loop. 2515168404Spjd */ 2516168404Spjd cb.cb_list = list; 2517168404Spjd cb.cb_verbose = verbose; 2518168404Spjd cb.cb_iteration = 0; 2519168404Spjd cb.cb_namewidth = 0; 2520168404Spjd 2521168404Spjd for (;;) { 2522168404Spjd pool_list_update(list); 2523168404Spjd 2524168404Spjd if ((npools = pool_list_count(list)) == 0) 2525168404Spjd break; 2526168404Spjd 2527168404Spjd /* 2528168404Spjd * Refresh all statistics. This is done as an explicit step 2529168404Spjd * before calculating the maximum name width, so that any 2530168404Spjd * configuration changes are properly accounted for. 2531168404Spjd */ 2532168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2533168404Spjd 2534168404Spjd /* 2535168404Spjd * Iterate over all pools to determine the maximum width 2536168404Spjd * for the pool / device name column across all pools. 2537168404Spjd */ 2538168404Spjd cb.cb_namewidth = 0; 2539168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2540168404Spjd 2541219089Spjd if (timestamp_fmt != NODATE) 2542219089Spjd print_timestamp(timestamp_fmt); 2543219089Spjd 2544168404Spjd /* 2545168404Spjd * If it's the first time, or verbose mode, print the header. 2546168404Spjd */ 2547168404Spjd if (++cb.cb_iteration == 1 || verbose) 2548168404Spjd print_iostat_header(&cb); 2549168404Spjd 2550168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2551168404Spjd 2552168404Spjd /* 2553168404Spjd * If there's more than one pool, and we're not in verbose mode 2554168404Spjd * (which prints a separator for us), then print a separator. 2555168404Spjd */ 2556168404Spjd if (npools > 1 && !verbose) 2557168404Spjd print_iostat_separator(&cb); 2558168404Spjd 2559168404Spjd if (verbose) 2560168404Spjd (void) printf("\n"); 2561168404Spjd 2562168404Spjd /* 2563168404Spjd * Flush the output so that redirection to a file isn't buffered 2564168404Spjd * indefinitely. 2565168404Spjd */ 2566168404Spjd (void) fflush(stdout); 2567168404Spjd 2568168404Spjd if (interval == 0) 2569168404Spjd break; 2570168404Spjd 2571168404Spjd if (count != 0 && --count == 0) 2572168404Spjd break; 2573168404Spjd 2574168404Spjd (void) sleep(interval); 2575168404Spjd } 2576168404Spjd 2577168404Spjd pool_list_free(list); 2578168404Spjd 2579168404Spjd return (ret); 2580168404Spjd} 2581168404Spjd 2582168404Spjdtypedef struct list_cbdata { 2583168404Spjd boolean_t cb_scripted; 2584168404Spjd boolean_t cb_first; 2585185029Spjd zprop_list_t *cb_proplist; 2586168404Spjd} list_cbdata_t; 2587168404Spjd 2588168404Spjd/* 2589168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2590168404Spjd */ 2591185029Spjdstatic void 2592185029Spjdprint_header(zprop_list_t *pl) 2593168404Spjd{ 2594185029Spjd const char *header; 2595185029Spjd boolean_t first = B_TRUE; 2596185029Spjd boolean_t right_justify; 2597168404Spjd 2598185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2599185029Spjd if (pl->pl_prop == ZPROP_INVAL) 2600185029Spjd continue; 2601185029Spjd 2602185029Spjd if (!first) 2603168404Spjd (void) printf(" "); 2604168404Spjd else 2605185029Spjd first = B_FALSE; 2606168404Spjd 2607185029Spjd header = zpool_prop_column_name(pl->pl_prop); 2608185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2609185029Spjd 2610185029Spjd if (pl->pl_next == NULL && !right_justify) 2611185029Spjd (void) printf("%s", header); 2612185029Spjd else if (right_justify) 2613185029Spjd (void) printf("%*s", pl->pl_width, header); 2614185029Spjd else 2615185029Spjd (void) printf("%-*s", pl->pl_width, header); 2616168404Spjd } 2617168404Spjd 2618168404Spjd (void) printf("\n"); 2619168404Spjd} 2620168404Spjd 2621185029Spjd/* 2622185029Spjd * Given a pool and a list of properties, print out all the properties according 2623185029Spjd * to the described layout. 2624185029Spjd */ 2625185029Spjdstatic void 2626185029Spjdprint_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 2627168404Spjd{ 2628185029Spjd boolean_t first = B_TRUE; 2629185029Spjd char property[ZPOOL_MAXPROPLEN]; 2630185029Spjd char *propstr; 2631185029Spjd boolean_t right_justify; 2632185029Spjd int width; 2633168404Spjd 2634185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2635185029Spjd if (!first) { 2636185029Spjd if (scripted) 2637168404Spjd (void) printf("\t"); 2638168404Spjd else 2639168404Spjd (void) printf(" "); 2640185029Spjd } else { 2641185029Spjd first = B_FALSE; 2642168404Spjd } 2643168404Spjd 2644185029Spjd right_justify = B_FALSE; 2645185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2646185029Spjd if (zpool_get_prop(zhp, pl->pl_prop, property, 2647185029Spjd sizeof (property), NULL) != 0) 2648185029Spjd propstr = "-"; 2649168404Spjd else 2650185029Spjd propstr = property; 2651168404Spjd 2652185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2653185029Spjd } else { 2654185029Spjd propstr = "-"; 2655185029Spjd } 2656168404Spjd 2657185029Spjd width = pl->pl_width; 2658168404Spjd 2659185029Spjd /* 2660185029Spjd * If this is being called in scripted mode, or if this is the 2661185029Spjd * last column and it is left-justified, don't include a width 2662185029Spjd * format specifier. 2663185029Spjd */ 2664185029Spjd if (scripted || (pl->pl_next == NULL && !right_justify)) 2665185029Spjd (void) printf("%s", propstr); 2666185029Spjd else if (right_justify) 2667185029Spjd (void) printf("%*s", width, propstr); 2668185029Spjd else 2669185029Spjd (void) printf("%-*s", width, propstr); 2670185029Spjd } 2671168404Spjd 2672185029Spjd (void) printf("\n"); 2673185029Spjd} 2674168404Spjd 2675185029Spjd/* 2676185029Spjd * Generic callback function to list a pool. 2677185029Spjd */ 2678185029Spjdint 2679185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 2680185029Spjd{ 2681185029Spjd list_cbdata_t *cbp = data; 2682168404Spjd 2683185029Spjd if (cbp->cb_first) { 2684185029Spjd if (!cbp->cb_scripted) 2685185029Spjd print_header(cbp->cb_proplist); 2686185029Spjd cbp->cb_first = B_FALSE; 2687168404Spjd } 2688168404Spjd 2689185029Spjd print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2690168404Spjd 2691168404Spjd return (0); 2692168404Spjd} 2693168404Spjd 2694168404Spjd/* 2695219089Spjd * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 2696168404Spjd * 2697185029Spjd * -H Scripted mode. Don't display headers, and separate properties 2698185029Spjd * by a single tab. 2699185029Spjd * -o List of properties to display. Defaults to 2700219089Spjd * "name,size,allocated,free,capacity,health,altroot" 2701219089Spjd * -T Display a timestamp in date(1) or Unix format 2702168404Spjd * 2703168404Spjd * List all pools in the system, whether or not they're healthy. Output space 2704168404Spjd * statistics for each one, as well as health status summary. 2705168404Spjd */ 2706168404Spjdint 2707168404Spjdzpool_do_list(int argc, char **argv) 2708168404Spjd{ 2709168404Spjd int c; 2710168404Spjd int ret; 2711168404Spjd list_cbdata_t cb = { 0 }; 2712185029Spjd static char default_props[] = 2713219089Spjd "name,size,allocated,free,capacity,dedupratio,health,altroot"; 2714185029Spjd char *props = default_props; 2715219089Spjd unsigned long interval = 0, count = 0; 2716168404Spjd 2717168404Spjd /* check options */ 2718219089Spjd while ((c = getopt(argc, argv, ":Ho:T:")) != -1) { 2719168404Spjd switch (c) { 2720168404Spjd case 'H': 2721168404Spjd cb.cb_scripted = B_TRUE; 2722168404Spjd break; 2723168404Spjd case 'o': 2724185029Spjd props = optarg; 2725168404Spjd break; 2726219089Spjd case 'T': 2727219089Spjd get_timestamp_arg(*optarg); 2728219089Spjd break; 2729168404Spjd case ':': 2730168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2731168404Spjd "'%c' option\n"), optopt); 2732168404Spjd usage(B_FALSE); 2733168404Spjd break; 2734168404Spjd case '?': 2735168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2736168404Spjd optopt); 2737168404Spjd usage(B_FALSE); 2738168404Spjd } 2739168404Spjd } 2740168404Spjd 2741168404Spjd argc -= optind; 2742168404Spjd argv += optind; 2743168404Spjd 2744219089Spjd get_interval_count(&argc, argv, &interval, &count); 2745219089Spjd 2746185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 2747185029Spjd usage(B_FALSE); 2748168404Spjd 2749185029Spjd cb.cb_first = B_TRUE; 2750168404Spjd 2751219089Spjd for (;;) { 2752168404Spjd 2753219089Spjd if (timestamp_fmt != NODATE) 2754219089Spjd print_timestamp(timestamp_fmt); 2755168404Spjd 2756219089Spjd ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2757219089Spjd list_callback, &cb); 2758219089Spjd 2759219089Spjd if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2760219089Spjd (void) printf(gettext("no pools available\n")); 2761219089Spjd zprop_free_list(cb.cb_proplist); 2762219089Spjd return (0); 2763219089Spjd } 2764219089Spjd 2765219089Spjd if (interval == 0) 2766219089Spjd break; 2767219089Spjd 2768219089Spjd if (count != 0 && --count == 0) 2769219089Spjd break; 2770219089Spjd 2771219089Spjd (void) sleep(interval); 2772168404Spjd } 2773168404Spjd 2774219089Spjd zprop_free_list(cb.cb_proplist); 2775168404Spjd return (ret); 2776168404Spjd} 2777168404Spjd 2778168404Spjdstatic nvlist_t * 2779168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name) 2780168404Spjd{ 2781168404Spjd nvlist_t **child; 2782168404Spjd uint_t c, children; 2783168404Spjd nvlist_t *match; 2784168404Spjd char *path; 2785168404Spjd 2786168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2787168404Spjd &child, &children) != 0) { 2788168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2789219089Spjd if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 2790219089Spjd name += sizeof(_PATH_DEV) - 1; 2791219089Spjd if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 2792219089Spjd path += sizeof(_PATH_DEV) - 1; 2793168404Spjd if (strcmp(name, path) == 0) 2794168404Spjd return (nv); 2795168404Spjd return (NULL); 2796168404Spjd } 2797168404Spjd 2798168404Spjd for (c = 0; c < children; c++) 2799168404Spjd if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2800168404Spjd return (match); 2801168404Spjd 2802168404Spjd return (NULL); 2803168404Spjd} 2804168404Spjd 2805168404Spjdstatic int 2806168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 2807168404Spjd{ 2808168404Spjd boolean_t force = B_FALSE; 2809168404Spjd int c; 2810168404Spjd nvlist_t *nvroot; 2811168404Spjd char *poolname, *old_disk, *new_disk; 2812168404Spjd zpool_handle_t *zhp; 2813168404Spjd int ret; 2814168404Spjd 2815168404Spjd /* check options */ 2816168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 2817168404Spjd switch (c) { 2818168404Spjd case 'f': 2819168404Spjd force = B_TRUE; 2820168404Spjd break; 2821168404Spjd case '?': 2822168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2823168404Spjd optopt); 2824168404Spjd usage(B_FALSE); 2825168404Spjd } 2826168404Spjd } 2827168404Spjd 2828168404Spjd argc -= optind; 2829168404Spjd argv += optind; 2830168404Spjd 2831168404Spjd /* get pool name and check number of arguments */ 2832168404Spjd if (argc < 1) { 2833168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 2834168404Spjd usage(B_FALSE); 2835168404Spjd } 2836168404Spjd 2837168404Spjd poolname = argv[0]; 2838168404Spjd 2839168404Spjd if (argc < 2) { 2840168404Spjd (void) fprintf(stderr, 2841168404Spjd gettext("missing <device> specification\n")); 2842168404Spjd usage(B_FALSE); 2843168404Spjd } 2844168404Spjd 2845168404Spjd old_disk = argv[1]; 2846168404Spjd 2847168404Spjd if (argc < 3) { 2848168404Spjd if (!replacing) { 2849168404Spjd (void) fprintf(stderr, 2850168404Spjd gettext("missing <new_device> specification\n")); 2851168404Spjd usage(B_FALSE); 2852168404Spjd } 2853168404Spjd new_disk = old_disk; 2854168404Spjd argc -= 1; 2855168404Spjd argv += 1; 2856168404Spjd } else { 2857168404Spjd new_disk = argv[2]; 2858168404Spjd argc -= 2; 2859168404Spjd argv += 2; 2860168404Spjd } 2861168404Spjd 2862168404Spjd if (argc > 1) { 2863168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2864168404Spjd usage(B_FALSE); 2865168404Spjd } 2866168404Spjd 2867168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2868168404Spjd return (1); 2869168404Spjd 2870185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 2871168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2872168404Spjd poolname); 2873168404Spjd zpool_close(zhp); 2874168404Spjd return (1); 2875168404Spjd } 2876168404Spjd 2877185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 2878185029Spjd argc, argv); 2879168404Spjd if (nvroot == NULL) { 2880168404Spjd zpool_close(zhp); 2881168404Spjd return (1); 2882168404Spjd } 2883168404Spjd 2884168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 2885168404Spjd 2886168404Spjd nvlist_free(nvroot); 2887168404Spjd zpool_close(zhp); 2888168404Spjd 2889168404Spjd return (ret); 2890168404Spjd} 2891168404Spjd 2892168404Spjd/* 2893168404Spjd * zpool replace [-f] <pool> <device> <new_device> 2894168404Spjd * 2895168404Spjd * -f Force attach, even if <new_device> appears to be in use. 2896168404Spjd * 2897168404Spjd * Replace <device> with <new_device>. 2898168404Spjd */ 2899168404Spjd/* ARGSUSED */ 2900168404Spjdint 2901168404Spjdzpool_do_replace(int argc, char **argv) 2902168404Spjd{ 2903168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2904168404Spjd} 2905168404Spjd 2906168404Spjd/* 2907168404Spjd * zpool attach [-f] <pool> <device> <new_device> 2908168404Spjd * 2909168404Spjd * -f Force attach, even if <new_device> appears to be in use. 2910168404Spjd * 2911168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 2912168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 2913168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 2914168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 2915168404Spjd */ 2916168404Spjdint 2917168404Spjdzpool_do_attach(int argc, char **argv) 2918168404Spjd{ 2919168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2920168404Spjd} 2921168404Spjd 2922168404Spjd/* 2923168404Spjd * zpool detach [-f] <pool> <device> 2924168404Spjd * 2925168404Spjd * -f Force detach of <device>, even if DTLs argue against it 2926168404Spjd * (not supported yet) 2927168404Spjd * 2928168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 2929168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 2930168404Spjd * has the only valid copy of some data. 2931168404Spjd */ 2932168404Spjd/* ARGSUSED */ 2933168404Spjdint 2934168404Spjdzpool_do_detach(int argc, char **argv) 2935168404Spjd{ 2936168404Spjd int c; 2937168404Spjd char *poolname, *path; 2938168404Spjd zpool_handle_t *zhp; 2939168404Spjd int ret; 2940168404Spjd 2941168404Spjd /* check options */ 2942168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 2943168404Spjd switch (c) { 2944168404Spjd case 'f': 2945168404Spjd case '?': 2946168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2947168404Spjd optopt); 2948168404Spjd usage(B_FALSE); 2949168404Spjd } 2950168404Spjd } 2951168404Spjd 2952168404Spjd argc -= optind; 2953168404Spjd argv += optind; 2954168404Spjd 2955168404Spjd /* get pool name and check number of arguments */ 2956168404Spjd if (argc < 1) { 2957168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 2958168404Spjd usage(B_FALSE); 2959168404Spjd } 2960168404Spjd 2961168404Spjd if (argc < 2) { 2962168404Spjd (void) fprintf(stderr, 2963168404Spjd gettext("missing <device> specification\n")); 2964168404Spjd usage(B_FALSE); 2965168404Spjd } 2966168404Spjd 2967168404Spjd poolname = argv[0]; 2968168404Spjd path = argv[1]; 2969168404Spjd 2970168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2971168404Spjd return (1); 2972168404Spjd 2973168404Spjd ret = zpool_vdev_detach(zhp, path); 2974168404Spjd 2975168404Spjd zpool_close(zhp); 2976168404Spjd 2977168404Spjd return (ret); 2978168404Spjd} 2979168404Spjd 2980168404Spjd/* 2981219089Spjd * zpool split [-n] [-o prop=val] ... 2982219089Spjd * [-o mntopt] ... 2983219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 2984219089Spjd * 2985219089Spjd * -n Do not split the pool, but display the resulting layout if 2986219089Spjd * it were to be split. 2987219089Spjd * -o Set property=value, or set mount options. 2988219089Spjd * -R Mount the split-off pool under an alternate root. 2989219089Spjd * 2990219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 2991219089Spjd * off may be listed, provided that no more than one device is specified 2992219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 2993219089Spjd * state unless -R is specified. 2994219089Spjd * 2995219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 2996219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 2997219089Spjd * undergoing a resilvering operation. 2998219089Spjd */ 2999219089Spjdint 3000219089Spjdzpool_do_split(int argc, char **argv) 3001219089Spjd{ 3002219089Spjd char *srcpool, *newpool, *propval; 3003219089Spjd char *mntopts = NULL; 3004219089Spjd splitflags_t flags; 3005219089Spjd int c, ret = 0; 3006219089Spjd zpool_handle_t *zhp; 3007219089Spjd nvlist_t *config, *props = NULL; 3008219089Spjd 3009219089Spjd flags.dryrun = B_FALSE; 3010219089Spjd flags.import = B_FALSE; 3011219089Spjd 3012219089Spjd /* check options */ 3013219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3014219089Spjd switch (c) { 3015219089Spjd case 'R': 3016219089Spjd flags.import = B_TRUE; 3017219089Spjd if (add_prop_list( 3018219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3019219089Spjd &props, B_TRUE) != 0) { 3020219089Spjd if (props) 3021219089Spjd nvlist_free(props); 3022219089Spjd usage(B_FALSE); 3023219089Spjd } 3024219089Spjd break; 3025219089Spjd case 'n': 3026219089Spjd flags.dryrun = B_TRUE; 3027219089Spjd break; 3028219089Spjd case 'o': 3029219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3030219089Spjd *propval = '\0'; 3031219089Spjd propval++; 3032219089Spjd if (add_prop_list(optarg, propval, 3033219089Spjd &props, B_TRUE) != 0) { 3034219089Spjd if (props) 3035219089Spjd nvlist_free(props); 3036219089Spjd usage(B_FALSE); 3037219089Spjd } 3038219089Spjd } else { 3039219089Spjd mntopts = optarg; 3040219089Spjd } 3041219089Spjd break; 3042219089Spjd case ':': 3043219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3044219089Spjd "'%c' option\n"), optopt); 3045219089Spjd usage(B_FALSE); 3046219089Spjd break; 3047219089Spjd case '?': 3048219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3049219089Spjd optopt); 3050219089Spjd usage(B_FALSE); 3051219089Spjd break; 3052219089Spjd } 3053219089Spjd } 3054219089Spjd 3055219089Spjd if (!flags.import && mntopts != NULL) { 3056219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3057219089Spjd "valid when importing the pool\n")); 3058219089Spjd usage(B_FALSE); 3059219089Spjd } 3060219089Spjd 3061219089Spjd argc -= optind; 3062219089Spjd argv += optind; 3063219089Spjd 3064219089Spjd if (argc < 1) { 3065219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3066219089Spjd usage(B_FALSE); 3067219089Spjd } 3068219089Spjd if (argc < 2) { 3069219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3070219089Spjd usage(B_FALSE); 3071219089Spjd } 3072219089Spjd 3073219089Spjd srcpool = argv[0]; 3074219089Spjd newpool = argv[1]; 3075219089Spjd 3076219089Spjd argc -= 2; 3077219089Spjd argv += 2; 3078219089Spjd 3079219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3080219089Spjd return (1); 3081219089Spjd 3082219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3083219089Spjd if (config == NULL) { 3084219089Spjd ret = 1; 3085219089Spjd } else { 3086219089Spjd if (flags.dryrun) { 3087219089Spjd (void) printf(gettext("would create '%s' with the " 3088219089Spjd "following layout:\n\n"), newpool); 3089219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3090219089Spjd } 3091219089Spjd nvlist_free(config); 3092219089Spjd } 3093219089Spjd 3094219089Spjd zpool_close(zhp); 3095219089Spjd 3096219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3097219089Spjd return (ret); 3098219089Spjd 3099219089Spjd /* 3100219089Spjd * The split was successful. Now we need to open the new 3101219089Spjd * pool and import it. 3102219089Spjd */ 3103219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3104219089Spjd return (1); 3105219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3106219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3107219089Spjd ret = 1; 3108219089Spjd (void) fprintf(stderr, gettext("Split was succssful, but " 3109219089Spjd "the datasets could not all be mounted\n")); 3110219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3111219089Spjd "different altroot\n"), "zpool import"); 3112219089Spjd } 3113219089Spjd zpool_close(zhp); 3114219089Spjd 3115219089Spjd return (ret); 3116219089Spjd} 3117219089Spjd 3118219089Spjd 3119219089Spjd 3120219089Spjd/* 3121168404Spjd * zpool online <pool> <device> ... 3122168404Spjd */ 3123168404Spjdint 3124168404Spjdzpool_do_online(int argc, char **argv) 3125168404Spjd{ 3126168404Spjd int c, i; 3127168404Spjd char *poolname; 3128168404Spjd zpool_handle_t *zhp; 3129168404Spjd int ret = 0; 3130185029Spjd vdev_state_t newstate; 3131219089Spjd int flags = 0; 3132168404Spjd 3133168404Spjd /* check options */ 3134219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3135168404Spjd switch (c) { 3136219089Spjd case 'e': 3137219089Spjd flags |= ZFS_ONLINE_EXPAND; 3138219089Spjd break; 3139168404Spjd case 't': 3140168404Spjd case '?': 3141168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3142168404Spjd optopt); 3143168404Spjd usage(B_FALSE); 3144168404Spjd } 3145168404Spjd } 3146168404Spjd 3147168404Spjd argc -= optind; 3148168404Spjd argv += optind; 3149168404Spjd 3150168404Spjd /* get pool name and check number of arguments */ 3151168404Spjd if (argc < 1) { 3152168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3153168404Spjd usage(B_FALSE); 3154168404Spjd } 3155168404Spjd if (argc < 2) { 3156168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3157168404Spjd usage(B_FALSE); 3158168404Spjd } 3159168404Spjd 3160168404Spjd poolname = argv[0]; 3161168404Spjd 3162168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3163168404Spjd return (1); 3164168404Spjd 3165185029Spjd for (i = 1; i < argc; i++) { 3166219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3167185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3168185029Spjd (void) printf(gettext("warning: device '%s' " 3169185029Spjd "onlined, but remains in faulted state\n"), 3170185029Spjd argv[i]); 3171185029Spjd if (newstate == VDEV_STATE_FAULTED) 3172185029Spjd (void) printf(gettext("use 'zpool " 3173185029Spjd "clear' to restore a faulted " 3174185029Spjd "device\n")); 3175185029Spjd else 3176185029Spjd (void) printf(gettext("use 'zpool " 3177185029Spjd "replace' to replace devices " 3178185029Spjd "that are no longer present\n")); 3179185029Spjd } 3180185029Spjd } else { 3181168404Spjd ret = 1; 3182185029Spjd } 3183185029Spjd } 3184168404Spjd 3185168404Spjd zpool_close(zhp); 3186168404Spjd 3187168404Spjd return (ret); 3188168404Spjd} 3189168404Spjd 3190168404Spjd/* 3191168404Spjd * zpool offline [-ft] <pool> <device> ... 3192168404Spjd * 3193168404Spjd * -f Force the device into the offline state, even if doing 3194168404Spjd * so would appear to compromise pool availability. 3195168404Spjd * (not supported yet) 3196168404Spjd * 3197168404Spjd * -t Only take the device off-line temporarily. The offline 3198168404Spjd * state will not be persistent across reboots. 3199168404Spjd */ 3200168404Spjd/* ARGSUSED */ 3201168404Spjdint 3202168404Spjdzpool_do_offline(int argc, char **argv) 3203168404Spjd{ 3204168404Spjd int c, i; 3205168404Spjd char *poolname; 3206168404Spjd zpool_handle_t *zhp; 3207168404Spjd int ret = 0; 3208168404Spjd boolean_t istmp = B_FALSE; 3209168404Spjd 3210168404Spjd /* check options */ 3211168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3212168404Spjd switch (c) { 3213168404Spjd case 't': 3214168404Spjd istmp = B_TRUE; 3215168404Spjd break; 3216168404Spjd case 'f': 3217168404Spjd case '?': 3218168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3219168404Spjd optopt); 3220168404Spjd usage(B_FALSE); 3221168404Spjd } 3222168404Spjd } 3223168404Spjd 3224168404Spjd argc -= optind; 3225168404Spjd argv += optind; 3226168404Spjd 3227168404Spjd /* get pool name and check number of arguments */ 3228168404Spjd if (argc < 1) { 3229168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3230168404Spjd usage(B_FALSE); 3231168404Spjd } 3232168404Spjd if (argc < 2) { 3233168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3234168404Spjd usage(B_FALSE); 3235168404Spjd } 3236168404Spjd 3237168404Spjd poolname = argv[0]; 3238168404Spjd 3239168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3240168404Spjd return (1); 3241168404Spjd 3242185029Spjd for (i = 1; i < argc; i++) { 3243185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3244168404Spjd ret = 1; 3245185029Spjd } 3246168404Spjd 3247168404Spjd zpool_close(zhp); 3248168404Spjd 3249168404Spjd return (ret); 3250168404Spjd} 3251168404Spjd 3252168404Spjd/* 3253168404Spjd * zpool clear <pool> [device] 3254168404Spjd * 3255168404Spjd * Clear all errors associated with a pool or a particular device. 3256168404Spjd */ 3257168404Spjdint 3258168404Spjdzpool_do_clear(int argc, char **argv) 3259168404Spjd{ 3260219089Spjd int c; 3261168404Spjd int ret = 0; 3262219089Spjd boolean_t dryrun = B_FALSE; 3263219089Spjd boolean_t do_rewind = B_FALSE; 3264219089Spjd boolean_t xtreme_rewind = B_FALSE; 3265219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3266219089Spjd nvlist_t *policy = NULL; 3267168404Spjd zpool_handle_t *zhp; 3268168404Spjd char *pool, *device; 3269168404Spjd 3270219089Spjd /* check options */ 3271219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3272219089Spjd switch (c) { 3273219089Spjd case 'F': 3274219089Spjd do_rewind = B_TRUE; 3275219089Spjd break; 3276219089Spjd case 'n': 3277219089Spjd dryrun = B_TRUE; 3278219089Spjd break; 3279219089Spjd case 'X': 3280219089Spjd xtreme_rewind = B_TRUE; 3281219089Spjd break; 3282219089Spjd case '?': 3283219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3284219089Spjd optopt); 3285219089Spjd usage(B_FALSE); 3286219089Spjd } 3287219089Spjd } 3288219089Spjd 3289219089Spjd argc -= optind; 3290219089Spjd argv += optind; 3291219089Spjd 3292219089Spjd if (argc < 1) { 3293168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3294168404Spjd usage(B_FALSE); 3295168404Spjd } 3296168404Spjd 3297219089Spjd if (argc > 2) { 3298168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3299168404Spjd usage(B_FALSE); 3300168404Spjd } 3301168404Spjd 3302219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3303219089Spjd (void) fprintf(stderr, 3304219089Spjd gettext("-n or -X only meaningful with -F\n")); 3305219089Spjd usage(B_FALSE); 3306219089Spjd } 3307219089Spjd if (dryrun) 3308219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3309219089Spjd else if (do_rewind) 3310219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3311219089Spjd if (xtreme_rewind) 3312219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3313168404Spjd 3314219089Spjd /* In future, further rewind policy choices can be passed along here */ 3315219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3316219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3317168404Spjd return (1); 3318168404Spjd 3319219089Spjd pool = argv[0]; 3320219089Spjd device = argc == 2 ? argv[1] : NULL; 3321219089Spjd 3322219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3323219089Spjd nvlist_free(policy); 3324219089Spjd return (1); 3325219089Spjd } 3326219089Spjd 3327219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3328168404Spjd ret = 1; 3329168404Spjd 3330168404Spjd zpool_close(zhp); 3331168404Spjd 3332219089Spjd nvlist_free(policy); 3333219089Spjd 3334168404Spjd return (ret); 3335168404Spjd} 3336168404Spjd 3337228103Smm/* 3338228103Smm * zpool reguid <pool> 3339228103Smm */ 3340228103Smmint 3341228103Smmzpool_do_reguid(int argc, char **argv) 3342228103Smm{ 3343228103Smm int c; 3344228103Smm char *poolname; 3345228103Smm zpool_handle_t *zhp; 3346228103Smm int ret = 0; 3347228103Smm 3348228103Smm /* check options */ 3349228103Smm while ((c = getopt(argc, argv, "")) != -1) { 3350228103Smm switch (c) { 3351228103Smm case '?': 3352228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3353228103Smm optopt); 3354228103Smm usage(B_FALSE); 3355228103Smm } 3356228103Smm } 3357228103Smm 3358228103Smm argc -= optind; 3359228103Smm argv += optind; 3360228103Smm 3361228103Smm /* get pool name and check number of arguments */ 3362228103Smm if (argc < 1) { 3363228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 3364228103Smm usage(B_FALSE); 3365228103Smm } 3366228103Smm 3367228103Smm if (argc > 1) { 3368228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 3369228103Smm usage(B_FALSE); 3370228103Smm } 3371228103Smm 3372228103Smm poolname = argv[0]; 3373228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3374228103Smm return (1); 3375228103Smm 3376228103Smm ret = zpool_reguid(zhp); 3377228103Smm 3378228103Smm zpool_close(zhp); 3379228103Smm return (ret); 3380228103Smm} 3381228103Smm 3382228103Smm 3383168404Spjdtypedef struct scrub_cbdata { 3384168404Spjd int cb_type; 3385168404Spjd int cb_argc; 3386168404Spjd char **cb_argv; 3387168404Spjd} scrub_cbdata_t; 3388168404Spjd 3389168404Spjdint 3390168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3391168404Spjd{ 3392168404Spjd scrub_cbdata_t *cb = data; 3393168404Spjd int err; 3394168404Spjd 3395168404Spjd /* 3396168404Spjd * Ignore faulted pools. 3397168404Spjd */ 3398168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3399168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3400168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 3401168404Spjd return (1); 3402168404Spjd } 3403168404Spjd 3404219089Spjd err = zpool_scan(zhp, cb->cb_type); 3405168404Spjd 3406168404Spjd return (err != 0); 3407168404Spjd} 3408168404Spjd 3409168404Spjd/* 3410168404Spjd * zpool scrub [-s] <pool> ... 3411168404Spjd * 3412168404Spjd * -s Stop. Stops any in-progress scrub. 3413168404Spjd */ 3414168404Spjdint 3415168404Spjdzpool_do_scrub(int argc, char **argv) 3416168404Spjd{ 3417168404Spjd int c; 3418168404Spjd scrub_cbdata_t cb; 3419168404Spjd 3420219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 3421168404Spjd 3422168404Spjd /* check options */ 3423168404Spjd while ((c = getopt(argc, argv, "s")) != -1) { 3424168404Spjd switch (c) { 3425168404Spjd case 's': 3426219089Spjd cb.cb_type = POOL_SCAN_NONE; 3427168404Spjd break; 3428168404Spjd case '?': 3429168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3430168404Spjd optopt); 3431168404Spjd usage(B_FALSE); 3432168404Spjd } 3433168404Spjd } 3434168404Spjd 3435168404Spjd cb.cb_argc = argc; 3436168404Spjd cb.cb_argv = argv; 3437168404Spjd argc -= optind; 3438168404Spjd argv += optind; 3439168404Spjd 3440168404Spjd if (argc < 1) { 3441168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3442168404Spjd usage(B_FALSE); 3443168404Spjd } 3444168404Spjd 3445168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3446168404Spjd} 3447168404Spjd 3448168404Spjdtypedef struct status_cbdata { 3449168404Spjd int cb_count; 3450168404Spjd boolean_t cb_allpools; 3451168404Spjd boolean_t cb_verbose; 3452168404Spjd boolean_t cb_explain; 3453168404Spjd boolean_t cb_first; 3454219089Spjd boolean_t cb_dedup_stats; 3455168404Spjd} status_cbdata_t; 3456168404Spjd 3457168404Spjd/* 3458168404Spjd * Print out detailed scrub status. 3459168404Spjd */ 3460168404Spjdvoid 3461219089Spjdprint_scan_status(pool_scan_stat_t *ps) 3462168404Spjd{ 3463219089Spjd time_t start, end; 3464219089Spjd uint64_t elapsed, mins_left, hours_left; 3465219089Spjd uint64_t pass_exam, examined, total; 3466219089Spjd uint_t rate; 3467168404Spjd double fraction_done; 3468219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3469168404Spjd 3470226583Spjd (void) printf(gettext(" scan: ")); 3471168404Spjd 3472219089Spjd /* If there's never been a scan, there's not much to say. */ 3473219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 3474219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 3475168404Spjd (void) printf(gettext("none requested\n")); 3476168404Spjd return; 3477168404Spjd } 3478168404Spjd 3479219089Spjd start = ps->pss_start_time; 3480219089Spjd end = ps->pss_end_time; 3481219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3482168404Spjd 3483219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 3484219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 3485219089Spjd /* 3486219089Spjd * Scan is finished or canceled. 3487219089Spjd */ 3488219089Spjd if (ps->pss_state == DSS_FINISHED) { 3489219089Spjd uint64_t minutes_taken = (end - start) / 60; 3490219089Spjd char *fmt; 3491168404Spjd 3492219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3493219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 3494219089Spjd "%llu errors on %s"); 3495219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3496219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 3497219089Spjd "%llu errors on %s"); 3498219089Spjd } 3499219089Spjd /* LINTED */ 3500219089Spjd (void) printf(fmt, processed_buf, 3501185029Spjd (u_longlong_t)(minutes_taken / 60), 3502185029Spjd (uint_t)(minutes_taken % 60), 3503219089Spjd (u_longlong_t)ps->pss_errors, 3504219089Spjd ctime((time_t *)&end)); 3505168404Spjd return; 3506219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 3507219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3508219089Spjd (void) printf(gettext("scrub canceled on %s"), 3509219089Spjd ctime(&end)); 3510219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3511219089Spjd (void) printf(gettext("resilver canceled on %s"), 3512219089Spjd ctime(&end)); 3513219089Spjd } 3514219089Spjd return; 3515168404Spjd } 3516168404Spjd 3517219089Spjd assert(ps->pss_state == DSS_SCANNING); 3518168404Spjd 3519219089Spjd /* 3520219089Spjd * Scan is in progress. 3521219089Spjd */ 3522219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3523219089Spjd (void) printf(gettext("scrub in progress since %s"), 3524219089Spjd ctime(&start)); 3525219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3526219089Spjd (void) printf(gettext("resilver in progress since %s"), 3527219089Spjd ctime(&start)); 3528219089Spjd } 3529219089Spjd 3530219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 3531219089Spjd total = ps->pss_to_examine; 3532168404Spjd fraction_done = (double)examined / total; 3533168404Spjd 3534219089Spjd /* elapsed time for this pass */ 3535219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 3536219089Spjd elapsed = elapsed ? elapsed : 1; 3537219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 3538219089Spjd rate = pass_exam / elapsed; 3539219089Spjd rate = rate ? rate : 1; 3540219089Spjd mins_left = ((total - examined) / rate) / 60; 3541219089Spjd hours_left = mins_left / 60; 3542219089Spjd 3543219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 3544219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 3545219089Spjd zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 3546219089Spjd 3547219089Spjd /* 3548219089Spjd * do not print estimated time if hours_left is more than 30 days 3549219089Spjd */ 3550226583Spjd (void) printf(gettext(" %s scanned out of %s at %s/s"), 3551219089Spjd examined_buf, total_buf, rate_buf); 3552219089Spjd if (hours_left < (30 * 24)) { 3553219089Spjd (void) printf(gettext(", %lluh%um to go\n"), 3554219089Spjd (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 3555219089Spjd } else { 3556219089Spjd (void) printf(gettext( 3557219089Spjd ", (scan is slow, no estimated time)\n")); 3558219089Spjd } 3559219089Spjd 3560219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 3561226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 3562219089Spjd processed_buf, 100 * fraction_done); 3563219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 3564226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 3565219089Spjd processed_buf, 100 * fraction_done); 3566219089Spjd } 3567168404Spjd} 3568168404Spjd 3569168404Spjdstatic void 3570168404Spjdprint_error_log(zpool_handle_t *zhp) 3571168404Spjd{ 3572185029Spjd nvlist_t *nverrlist = NULL; 3573168404Spjd nvpair_t *elem; 3574168404Spjd char *pathname; 3575168404Spjd size_t len = MAXPATHLEN * 2; 3576168404Spjd 3577168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 3578168404Spjd (void) printf("errors: List of errors unavailable " 3579168404Spjd "(insufficient privileges)\n"); 3580168404Spjd return; 3581168404Spjd } 3582168404Spjd 3583168404Spjd (void) printf("errors: Permanent errors have been " 3584168404Spjd "detected in the following files:\n\n"); 3585168404Spjd 3586168404Spjd pathname = safe_malloc(len); 3587168404Spjd elem = NULL; 3588168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 3589168404Spjd nvlist_t *nv; 3590168404Spjd uint64_t dsobj, obj; 3591168404Spjd 3592168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 3593168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 3594168404Spjd &dsobj) == 0); 3595168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 3596168404Spjd &obj) == 0); 3597168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 3598168404Spjd (void) printf("%7s %s\n", "", pathname); 3599168404Spjd } 3600168404Spjd free(pathname); 3601168404Spjd nvlist_free(nverrlist); 3602168404Spjd} 3603168404Spjd 3604168404Spjdstatic void 3605168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 3606168404Spjd int namewidth) 3607168404Spjd{ 3608168404Spjd uint_t i; 3609168404Spjd char *name; 3610168404Spjd 3611168404Spjd if (nspares == 0) 3612168404Spjd return; 3613168404Spjd 3614168404Spjd (void) printf(gettext("\tspares\n")); 3615168404Spjd 3616168404Spjd for (i = 0; i < nspares; i++) { 3617219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 3618168404Spjd print_status_config(zhp, name, spares[i], 3619209962Smm namewidth, 2, B_TRUE); 3620168404Spjd free(name); 3621168404Spjd } 3622168404Spjd} 3623168404Spjd 3624185029Spjdstatic void 3625185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 3626185029Spjd int namewidth) 3627185029Spjd{ 3628185029Spjd uint_t i; 3629185029Spjd char *name; 3630185029Spjd 3631185029Spjd if (nl2cache == 0) 3632185029Spjd return; 3633185029Spjd 3634185029Spjd (void) printf(gettext("\tcache\n")); 3635185029Spjd 3636185029Spjd for (i = 0; i < nl2cache; i++) { 3637219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 3638185029Spjd print_status_config(zhp, name, l2cache[i], 3639209962Smm namewidth, 2, B_FALSE); 3640185029Spjd free(name); 3641185029Spjd } 3642185029Spjd} 3643185029Spjd 3644219089Spjdstatic void 3645219089Spjdprint_dedup_stats(nvlist_t *config) 3646219089Spjd{ 3647219089Spjd ddt_histogram_t *ddh; 3648219089Spjd ddt_stat_t *dds; 3649219089Spjd ddt_object_t *ddo; 3650219089Spjd uint_t c; 3651219089Spjd 3652219089Spjd /* 3653219089Spjd * If the pool was faulted then we may not have been able to 3654219089Spjd * obtain the config. Otherwise, if have anything in the dedup 3655219089Spjd * table continue processing the stats. 3656219089Spjd */ 3657219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 3658227497Smm (uint64_t **)&ddo, &c) != 0) 3659219089Spjd return; 3660219089Spjd 3661219089Spjd (void) printf("\n"); 3662227497Smm (void) printf(gettext(" dedup: ")); 3663227497Smm if (ddo->ddo_count == 0) { 3664227497Smm (void) printf(gettext("no DDT entries\n")); 3665227497Smm return; 3666227497Smm } 3667227497Smm 3668219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 3669219089Spjd (u_longlong_t)ddo->ddo_count, 3670219089Spjd (u_longlong_t)ddo->ddo_dspace, 3671219089Spjd (u_longlong_t)ddo->ddo_mspace); 3672219089Spjd 3673219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 3674219089Spjd (uint64_t **)&dds, &c) == 0); 3675219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 3676219089Spjd (uint64_t **)&ddh, &c) == 0); 3677219089Spjd zpool_dump_ddt(dds, ddh); 3678219089Spjd} 3679219089Spjd 3680168404Spjd/* 3681168404Spjd * Display a summary of pool status. Displays a summary such as: 3682168404Spjd * 3683168404Spjd * pool: tank 3684168404Spjd * status: DEGRADED 3685168404Spjd * reason: One or more devices ... 3686168404Spjd * see: http://www.sun.com/msg/ZFS-xxxx-01 3687168404Spjd * config: 3688168404Spjd * mirror DEGRADED 3689168404Spjd * c1t0d0 OK 3690168404Spjd * c2t0d0 UNAVAIL 3691168404Spjd * 3692168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 3693168404Spjd * option is specified, then we print out error rate information as well. 3694168404Spjd */ 3695168404Spjdint 3696168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 3697168404Spjd{ 3698168404Spjd status_cbdata_t *cbp = data; 3699168404Spjd nvlist_t *config, *nvroot; 3700168404Spjd char *msgid; 3701168404Spjd int reason; 3702168404Spjd const char *health; 3703168404Spjd uint_t c; 3704168404Spjd vdev_stat_t *vs; 3705168404Spjd 3706168404Spjd config = zpool_get_config(zhp, NULL); 3707168404Spjd reason = zpool_get_status(zhp, &msgid); 3708168404Spjd 3709168404Spjd cbp->cb_count++; 3710168404Spjd 3711168404Spjd /* 3712168404Spjd * If we were given 'zpool status -x', only report those pools with 3713168404Spjd * problems. 3714168404Spjd */ 3715168404Spjd if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 3716168404Spjd if (!cbp->cb_allpools) { 3717168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 3718168404Spjd zpool_get_name(zhp)); 3719168404Spjd if (cbp->cb_first) 3720168404Spjd cbp->cb_first = B_FALSE; 3721168404Spjd } 3722168404Spjd return (0); 3723168404Spjd } 3724168404Spjd 3725168404Spjd if (cbp->cb_first) 3726168404Spjd cbp->cb_first = B_FALSE; 3727168404Spjd else 3728168404Spjd (void) printf("\n"); 3729168404Spjd 3730168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3731168404Spjd &nvroot) == 0); 3732219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 3733168404Spjd (uint64_t **)&vs, &c) == 0); 3734185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 3735168404Spjd 3736168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 3737168404Spjd (void) printf(gettext(" state: %s\n"), health); 3738168404Spjd 3739168404Spjd switch (reason) { 3740168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 3741168404Spjd (void) printf(gettext("status: One or more devices could not " 3742168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 3743168404Spjd "continue functioning in a degraded state.\n")); 3744168404Spjd (void) printf(gettext("action: Attach the missing device and " 3745168404Spjd "online it using 'zpool online'.\n")); 3746168404Spjd break; 3747168404Spjd 3748168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 3749168404Spjd (void) printf(gettext("status: One or more devices could not " 3750168404Spjd "be opened. There are insufficient\n\treplicas for the " 3751168404Spjd "pool to continue functioning.\n")); 3752168404Spjd (void) printf(gettext("action: Attach the missing device and " 3753168404Spjd "online it using 'zpool online'.\n")); 3754168404Spjd break; 3755168404Spjd 3756168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 3757168404Spjd (void) printf(gettext("status: One or more devices could not " 3758168404Spjd "be used because the label is missing or\n\tinvalid. " 3759168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 3760168404Spjd "functioning in a degraded state.\n")); 3761168404Spjd (void) printf(gettext("action: Replace the device using " 3762168404Spjd "'zpool replace'.\n")); 3763168404Spjd break; 3764168404Spjd 3765168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 3766168404Spjd (void) printf(gettext("status: One or more devices could not " 3767168404Spjd "be used because the label is missing \n\tor invalid. " 3768168404Spjd "There are insufficient replicas for the pool to " 3769168404Spjd "continue\n\tfunctioning.\n")); 3770219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 3771219089Spjd zpool_get_name(zhp), reason, config); 3772168404Spjd break; 3773168404Spjd 3774168404Spjd case ZPOOL_STATUS_FAILING_DEV: 3775168404Spjd (void) printf(gettext("status: One or more devices has " 3776168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 3777168404Spjd "made to correct the error. Applications are " 3778168404Spjd "unaffected.\n")); 3779168404Spjd (void) printf(gettext("action: Determine if the device needs " 3780168404Spjd "to be replaced, and clear the errors\n\tusing " 3781168404Spjd "'zpool clear' or replace the device with 'zpool " 3782168404Spjd "replace'.\n")); 3783168404Spjd break; 3784168404Spjd 3785168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 3786168404Spjd (void) printf(gettext("status: One or more devices has " 3787168404Spjd "been taken offline by the administrator.\n\tSufficient " 3788168404Spjd "replicas exist for the pool to continue functioning in " 3789168404Spjd "a\n\tdegraded state.\n")); 3790168404Spjd (void) printf(gettext("action: Online the device using " 3791168404Spjd "'zpool online' or replace the device with\n\t'zpool " 3792168404Spjd "replace'.\n")); 3793168404Spjd break; 3794168404Spjd 3795219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 3796219089Spjd (void) printf(gettext("status: One or more devices has " 3797219089Spjd "been removed by the administrator.\n\tSufficient " 3798219089Spjd "replicas exist for the pool to continue functioning in " 3799219089Spjd "a\n\tdegraded state.\n")); 3800219089Spjd (void) printf(gettext("action: Online the device using " 3801219089Spjd "'zpool online' or replace the device with\n\t'zpool " 3802219089Spjd "replace'.\n")); 3803219089Spjd break; 3804219089Spjd 3805168404Spjd case ZPOOL_STATUS_RESILVERING: 3806168404Spjd (void) printf(gettext("status: One or more devices is " 3807168404Spjd "currently being resilvered. The pool will\n\tcontinue " 3808168404Spjd "to function, possibly in a degraded state.\n")); 3809168404Spjd (void) printf(gettext("action: Wait for the resilver to " 3810168404Spjd "complete.\n")); 3811168404Spjd break; 3812168404Spjd 3813168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 3814168404Spjd (void) printf(gettext("status: One or more devices has " 3815168404Spjd "experienced an error resulting in data\n\tcorruption. " 3816168404Spjd "Applications may be affected.\n")); 3817168404Spjd (void) printf(gettext("action: Restore the file in question " 3818168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 3819168404Spjd "backup.\n")); 3820168404Spjd break; 3821168404Spjd 3822168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 3823168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 3824168404Spjd "and the pool cannot be opened.\n")); 3825219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 3826219089Spjd zpool_get_name(zhp), reason, config); 3827168404Spjd break; 3828168404Spjd 3829168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 3830168404Spjd (void) printf(gettext("status: The pool is formatted using an " 3831168404Spjd "older on-disk format. The pool can\n\tstill be used, but " 3832168404Spjd "some features are unavailable.\n")); 3833168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 3834168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 3835168404Spjd "be accessible on older software versions.\n")); 3836168404Spjd break; 3837168404Spjd 3838168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 3839168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 3840168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 3841168404Spjd "be accessed on this system.\n")); 3842168404Spjd (void) printf(gettext("action: Access the pool from a system " 3843168404Spjd "running more recent software, or\n\trestore the pool from " 3844168404Spjd "backup.\n")); 3845168404Spjd break; 3846168404Spjd 3847185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 3848185029Spjd (void) printf(gettext("status: One or more devices are " 3849185029Spjd "faulted in response to persistent errors.\n\tSufficient " 3850185029Spjd "replicas exist for the pool to continue functioning " 3851185029Spjd "in a\n\tdegraded state.\n")); 3852185029Spjd (void) printf(gettext("action: Replace the faulted device, " 3853185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 3854185029Spjd break; 3855185029Spjd 3856185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 3857185029Spjd (void) printf(gettext("status: One or more devices are " 3858185029Spjd "faulted in response to persistent errors. There are " 3859185029Spjd "insufficient replicas for the pool to\n\tcontinue " 3860185029Spjd "functioning.\n")); 3861185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 3862185029Spjd "from a backup source. Manually marking the device\n" 3863185029Spjd "\trepaired using 'zpool clear' may allow some data " 3864185029Spjd "to be recovered.\n")); 3865185029Spjd break; 3866185029Spjd 3867185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 3868185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 3869185029Spjd (void) printf(gettext("status: One or more devices are " 3870185029Spjd "faulted in response to IO failures.\n")); 3871185029Spjd (void) printf(gettext("action: Make sure the affected devices " 3872185029Spjd "are connected, then run 'zpool clear'.\n")); 3873185029Spjd break; 3874185029Spjd 3875185029Spjd case ZPOOL_STATUS_BAD_LOG: 3876185029Spjd (void) printf(gettext("status: An intent log record " 3877185029Spjd "could not be read.\n" 3878185029Spjd "\tWaiting for adminstrator intervention to fix the " 3879185029Spjd "faulted pool.\n")); 3880185029Spjd (void) printf(gettext("action: Either restore the affected " 3881185029Spjd "device(s) and run 'zpool online',\n" 3882185029Spjd "\tor ignore the intent log records by running " 3883185029Spjd "'zpool clear'.\n")); 3884185029Spjd break; 3885185029Spjd 3886168404Spjd default: 3887168404Spjd /* 3888168404Spjd * The remaining errors can't actually be generated, yet. 3889168404Spjd */ 3890168404Spjd assert(reason == ZPOOL_STATUS_OK); 3891168404Spjd } 3892168404Spjd 3893168404Spjd if (msgid != NULL) 3894168404Spjd (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3895168404Spjd msgid); 3896168404Spjd 3897168404Spjd if (config != NULL) { 3898168404Spjd int namewidth; 3899168404Spjd uint64_t nerr; 3900185029Spjd nvlist_t **spares, **l2cache; 3901185029Spjd uint_t nspares, nl2cache; 3902219089Spjd pool_scan_stat_t *ps = NULL; 3903168404Spjd 3904219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 3905219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 3906219089Spjd print_scan_status(ps); 3907168404Spjd 3908168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 3909168404Spjd if (namewidth < 10) 3910168404Spjd namewidth = 10; 3911168404Spjd 3912168404Spjd (void) printf(gettext("config:\n\n")); 3913168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3914168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3915168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 3916209962Smm namewidth, 0, B_FALSE); 3917209962Smm 3918185029Spjd if (num_logs(nvroot) > 0) 3919213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 3920185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 3921185029Spjd &l2cache, &nl2cache) == 0) 3922185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 3923185029Spjd 3924168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 3925168404Spjd &spares, &nspares) == 0) 3926168404Spjd print_spares(zhp, spares, nspares, namewidth); 3927168404Spjd 3928168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3929168404Spjd &nerr) == 0) { 3930168404Spjd nvlist_t *nverrlist = NULL; 3931168404Spjd 3932168404Spjd /* 3933168404Spjd * If the approximate error count is small, get a 3934168404Spjd * precise count by fetching the entire log and 3935168404Spjd * uniquifying the results. 3936168404Spjd */ 3937185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 3938168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 3939168404Spjd nvpair_t *elem; 3940168404Spjd 3941168404Spjd elem = NULL; 3942168404Spjd nerr = 0; 3943168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 3944168404Spjd elem)) != NULL) { 3945168404Spjd nerr++; 3946168404Spjd } 3947168404Spjd } 3948168404Spjd nvlist_free(nverrlist); 3949168404Spjd 3950168404Spjd (void) printf("\n"); 3951168404Spjd 3952168404Spjd if (nerr == 0) 3953168404Spjd (void) printf(gettext("errors: No known data " 3954168404Spjd "errors\n")); 3955168404Spjd else if (!cbp->cb_verbose) 3956168404Spjd (void) printf(gettext("errors: %llu data " 3957168404Spjd "errors, use '-v' for a list\n"), 3958168404Spjd (u_longlong_t)nerr); 3959168404Spjd else 3960168404Spjd print_error_log(zhp); 3961168404Spjd } 3962219089Spjd 3963219089Spjd if (cbp->cb_dedup_stats) 3964219089Spjd print_dedup_stats(config); 3965168404Spjd } else { 3966168404Spjd (void) printf(gettext("config: The configuration cannot be " 3967168404Spjd "determined.\n")); 3968168404Spjd } 3969168404Spjd 3970168404Spjd return (0); 3971168404Spjd} 3972168404Spjd 3973168404Spjd/* 3974219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 3975168404Spjd * 3976168404Spjd * -v Display complete error logs 3977168404Spjd * -x Display only pools with potential problems 3978219089Spjd * -D Display dedup status (undocumented) 3979219089Spjd * -T Display a timestamp in date(1) or Unix format 3980168404Spjd * 3981168404Spjd * Describes the health status of all pools or some subset. 3982168404Spjd */ 3983168404Spjdint 3984168404Spjdzpool_do_status(int argc, char **argv) 3985168404Spjd{ 3986168404Spjd int c; 3987168404Spjd int ret; 3988219089Spjd unsigned long interval = 0, count = 0; 3989168404Spjd status_cbdata_t cb = { 0 }; 3990168404Spjd 3991168404Spjd /* check options */ 3992219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 3993168404Spjd switch (c) { 3994168404Spjd case 'v': 3995168404Spjd cb.cb_verbose = B_TRUE; 3996168404Spjd break; 3997168404Spjd case 'x': 3998168404Spjd cb.cb_explain = B_TRUE; 3999168404Spjd break; 4000219089Spjd case 'D': 4001219089Spjd cb.cb_dedup_stats = B_TRUE; 4002219089Spjd break; 4003219089Spjd case 'T': 4004219089Spjd get_timestamp_arg(*optarg); 4005219089Spjd break; 4006168404Spjd case '?': 4007168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4008168404Spjd optopt); 4009168404Spjd usage(B_FALSE); 4010168404Spjd } 4011168404Spjd } 4012168404Spjd 4013168404Spjd argc -= optind; 4014168404Spjd argv += optind; 4015168404Spjd 4016219089Spjd get_interval_count(&argc, argv, &interval, &count); 4017168404Spjd 4018168404Spjd if (argc == 0) 4019168404Spjd cb.cb_allpools = B_TRUE; 4020168404Spjd 4021219089Spjd cb.cb_first = B_TRUE; 4022168404Spjd 4023219089Spjd for (;;) { 4024219089Spjd if (timestamp_fmt != NODATE) 4025219089Spjd print_timestamp(timestamp_fmt); 4026168404Spjd 4027219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 4028219089Spjd status_callback, &cb); 4029219089Spjd 4030219089Spjd if (argc == 0 && cb.cb_count == 0) 4031219089Spjd (void) printf(gettext("no pools available\n")); 4032219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 4033219089Spjd (void) printf(gettext("all pools are healthy\n")); 4034219089Spjd 4035219089Spjd if (ret != 0) 4036219089Spjd return (ret); 4037219089Spjd 4038219089Spjd if (interval == 0) 4039219089Spjd break; 4040219089Spjd 4041219089Spjd if (count != 0 && --count == 0) 4042219089Spjd break; 4043219089Spjd 4044219089Spjd (void) sleep(interval); 4045219089Spjd } 4046219089Spjd 4047219089Spjd return (0); 4048168404Spjd} 4049168404Spjd 4050168404Spjdtypedef struct upgrade_cbdata { 4051168404Spjd int cb_all; 4052168404Spjd int cb_first; 4053168404Spjd int cb_newer; 4054212050Spjd char cb_poolname[ZPOOL_MAXNAMELEN]; 4055168404Spjd int cb_argc; 4056185029Spjd uint64_t cb_version; 4057168404Spjd char **cb_argv; 4058168404Spjd} upgrade_cbdata_t; 4059168404Spjd 4060168404Spjdstatic int 4061212050Spjdis_root_pool(zpool_handle_t *zhp) 4062212050Spjd{ 4063212050Spjd static struct statfs sfs; 4064212050Spjd static char *poolname = NULL; 4065212050Spjd static boolean_t stated = B_FALSE; 4066212050Spjd char *slash; 4067212050Spjd 4068212067Spjd if (!stated) { 4069212050Spjd stated = B_TRUE; 4070212050Spjd if (statfs("/", &sfs) == -1) { 4071212050Spjd (void) fprintf(stderr, 4072212050Spjd "Unable to stat root file system: %s.\n", 4073212050Spjd strerror(errno)); 4074212067Spjd return (0); 4075212050Spjd } 4076212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4077212067Spjd return (0); 4078212050Spjd poolname = sfs.f_mntfromname; 4079212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4080212050Spjd *slash = '\0'; 4081212050Spjd } 4082212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4083212050Spjd} 4084212050Spjd 4085212050Spjdstatic int 4086168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4087168404Spjd{ 4088168404Spjd upgrade_cbdata_t *cbp = arg; 4089168404Spjd nvlist_t *config; 4090168404Spjd uint64_t version; 4091168404Spjd int ret = 0; 4092168404Spjd 4093168404Spjd config = zpool_get_config(zhp, NULL); 4094168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4095168404Spjd &version) == 0); 4096168404Spjd 4097185029Spjd if (!cbp->cb_newer && version < SPA_VERSION) { 4098168404Spjd if (!cbp->cb_all) { 4099168404Spjd if (cbp->cb_first) { 4100168404Spjd (void) printf(gettext("The following pools are " 4101168404Spjd "out of date, and can be upgraded. After " 4102168404Spjd "being\nupgraded, these pools will no " 4103168404Spjd "longer be accessible by older software " 4104168404Spjd "versions.\n\n")); 4105168404Spjd (void) printf(gettext("VER POOL\n")); 4106168404Spjd (void) printf(gettext("--- ------------\n")); 4107168404Spjd cbp->cb_first = B_FALSE; 4108168404Spjd } 4109168404Spjd 4110168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4111168404Spjd zpool_get_name(zhp)); 4112168404Spjd } else { 4113168404Spjd cbp->cb_first = B_FALSE; 4114185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 4115168404Spjd if (!ret) { 4116168404Spjd (void) printf(gettext("Successfully upgraded " 4117185029Spjd "'%s'\n\n"), zpool_get_name(zhp)); 4118212050Spjd if (cbp->cb_poolname[0] == '\0' && 4119212050Spjd is_root_pool(zhp)) { 4120212050Spjd (void) strlcpy(cbp->cb_poolname, 4121212050Spjd zpool_get_name(zhp), 4122212050Spjd sizeof(cbp->cb_poolname)); 4123212050Spjd } 4124168404Spjd } 4125168404Spjd } 4126185029Spjd } else if (cbp->cb_newer && version > SPA_VERSION) { 4127168404Spjd assert(!cbp->cb_all); 4128168404Spjd 4129168404Spjd if (cbp->cb_first) { 4130168404Spjd (void) printf(gettext("The following pools are " 4131168404Spjd "formatted using a newer software version and\n" 4132168404Spjd "cannot be accessed on the current system.\n\n")); 4133168404Spjd (void) printf(gettext("VER POOL\n")); 4134168404Spjd (void) printf(gettext("--- ------------\n")); 4135168404Spjd cbp->cb_first = B_FALSE; 4136168404Spjd } 4137168404Spjd 4138168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4139168404Spjd zpool_get_name(zhp)); 4140168404Spjd } 4141168404Spjd 4142168404Spjd zpool_close(zhp); 4143168404Spjd return (ret); 4144168404Spjd} 4145168404Spjd 4146168404Spjd/* ARGSUSED */ 4147168404Spjdstatic int 4148168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 4149168404Spjd{ 4150185029Spjd upgrade_cbdata_t *cbp = data; 4151185029Spjd uint64_t cur_version; 4152168404Spjd int ret; 4153168404Spjd 4154185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 4155185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 4156185029Spjd "Pool 'log' must be renamed using export and import" 4157185029Spjd " to upgrade.\n")); 4158185029Spjd return (1); 4159185029Spjd } 4160168404Spjd 4161185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4162185029Spjd if (cur_version > cbp->cb_version) { 4163168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 4164185029Spjd "using more current version '%llu'.\n"), 4165185029Spjd zpool_get_name(zhp), cur_version); 4166185029Spjd return (0); 4167185029Spjd } 4168185029Spjd if (cur_version == cbp->cb_version) { 4169185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 4170168404Spjd "using the current version.\n"), zpool_get_name(zhp)); 4171168404Spjd return (0); 4172168404Spjd } 4173168404Spjd 4174185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 4175168404Spjd 4176168404Spjd if (!ret) { 4177168404Spjd (void) printf(gettext("Successfully upgraded '%s' " 4178185029Spjd "from version %llu to version %llu\n\n"), 4179185029Spjd zpool_get_name(zhp), (u_longlong_t)cur_version, 4180185029Spjd (u_longlong_t)cbp->cb_version); 4181212050Spjd if (cbp->cb_poolname[0] == '\0' && is_root_pool(zhp)) { 4182212050Spjd (void) strlcpy(cbp->cb_poolname, zpool_get_name(zhp), 4183212050Spjd sizeof(cbp->cb_poolname)); 4184212050Spjd } 4185168404Spjd } 4186168404Spjd 4187168404Spjd return (ret != 0); 4188168404Spjd} 4189168404Spjd 4190168404Spjd/* 4191168404Spjd * zpool upgrade 4192168404Spjd * zpool upgrade -v 4193185029Spjd * zpool upgrade [-V version] <-a | pool ...> 4194168404Spjd * 4195168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 4196168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 4197168404Spjd * upgrade all pools. 4198168404Spjd */ 4199168404Spjdint 4200168404Spjdzpool_do_upgrade(int argc, char **argv) 4201168404Spjd{ 4202168404Spjd int c; 4203168404Spjd upgrade_cbdata_t cb = { 0 }; 4204168404Spjd int ret = 0; 4205168404Spjd boolean_t showversions = B_FALSE; 4206185029Spjd char *end; 4207168404Spjd 4208185029Spjd 4209168404Spjd /* check options */ 4210219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 4211168404Spjd switch (c) { 4212168404Spjd case 'a': 4213168404Spjd cb.cb_all = B_TRUE; 4214168404Spjd break; 4215168404Spjd case 'v': 4216168404Spjd showversions = B_TRUE; 4217168404Spjd break; 4218185029Spjd case 'V': 4219185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 4220185029Spjd if (*end != '\0' || cb.cb_version > SPA_VERSION || 4221185029Spjd cb.cb_version < SPA_VERSION_1) { 4222185029Spjd (void) fprintf(stderr, 4223185029Spjd gettext("invalid version '%s'\n"), optarg); 4224185029Spjd usage(B_FALSE); 4225185029Spjd } 4226185029Spjd break; 4227219089Spjd case ':': 4228219089Spjd (void) fprintf(stderr, gettext("missing argument for " 4229219089Spjd "'%c' option\n"), optopt); 4230219089Spjd usage(B_FALSE); 4231219089Spjd break; 4232168404Spjd case '?': 4233168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4234168404Spjd optopt); 4235168404Spjd usage(B_FALSE); 4236168404Spjd } 4237168404Spjd } 4238168404Spjd 4239168404Spjd cb.cb_argc = argc; 4240168404Spjd cb.cb_argv = argv; 4241168404Spjd argc -= optind; 4242168404Spjd argv += optind; 4243168404Spjd 4244185029Spjd if (cb.cb_version == 0) { 4245185029Spjd cb.cb_version = SPA_VERSION; 4246185029Spjd } else if (!cb.cb_all && argc == 0) { 4247185029Spjd (void) fprintf(stderr, gettext("-V option is " 4248185029Spjd "incompatible with other arguments\n")); 4249185029Spjd usage(B_FALSE); 4250185029Spjd } 4251185029Spjd 4252168404Spjd if (showversions) { 4253168404Spjd if (cb.cb_all || argc != 0) { 4254168404Spjd (void) fprintf(stderr, gettext("-v option is " 4255168404Spjd "incompatible with other arguments\n")); 4256168404Spjd usage(B_FALSE); 4257168404Spjd } 4258168404Spjd } else if (cb.cb_all) { 4259168404Spjd if (argc != 0) { 4260185029Spjd (void) fprintf(stderr, gettext("-a option should not " 4261185029Spjd "be used along with a pool name\n")); 4262168404Spjd usage(B_FALSE); 4263168404Spjd } 4264168404Spjd } 4265168404Spjd 4266185029Spjd (void) printf(gettext("This system is currently running " 4267185029Spjd "ZFS pool version %llu.\n\n"), SPA_VERSION); 4268168404Spjd cb.cb_first = B_TRUE; 4269168404Spjd if (showversions) { 4270168404Spjd (void) printf(gettext("The following versions are " 4271168404Spjd "supported:\n\n")); 4272168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 4273168404Spjd (void) printf("--- -----------------------------------------" 4274168404Spjd "---------------\n"); 4275168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 4276168404Spjd (void) printf(gettext(" 2 Ditto blocks " 4277168404Spjd "(replicated metadata)\n")); 4278168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 4279168404Spjd "RAID-Z\n")); 4280168404Spjd (void) printf(gettext(" 4 zpool history\n")); 4281168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 4282168404Spjd "algorithm\n")); 4283185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 4284185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 4285185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 4286185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 4287185029Spjd "properties\n")); 4288185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 4289185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 4290185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 4291185029Spjd (void) printf(gettext(" 13 snapused property\n")); 4292209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 4293209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 4294219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 4295219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 4296219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 4297219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 4298219089Spjd (void) printf(gettext(" 20 Compression using zle " 4299219089Spjd "(zero-length encoding)\n")); 4300219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 4301219089Spjd (void) printf(gettext(" 22 Received properties\n")); 4302219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 4303219089Spjd (void) printf(gettext(" 24 System attributes\n")); 4304219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 4305219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 4306219089Spjd "performance\n")); 4307219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 4308219089Spjd "performance\n")); 4309219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 4310219089Spjd (void) printf(gettext("\nFor more information on a particular " 4311219089Spjd "version, including supported releases,\n")); 4312219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 4313168404Spjd } else if (argc == 0) { 4314168404Spjd int notfound; 4315168404Spjd 4316168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4317168404Spjd notfound = cb.cb_first; 4318168404Spjd 4319168404Spjd if (!cb.cb_all && ret == 0) { 4320168404Spjd if (!cb.cb_first) 4321168404Spjd (void) printf("\n"); 4322168404Spjd cb.cb_first = B_TRUE; 4323168404Spjd cb.cb_newer = B_TRUE; 4324168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4325168404Spjd if (!cb.cb_first) { 4326168404Spjd notfound = B_FALSE; 4327168404Spjd (void) printf("\n"); 4328168404Spjd } 4329168404Spjd } 4330168404Spjd 4331168404Spjd if (ret == 0) { 4332168404Spjd if (notfound) 4333168404Spjd (void) printf(gettext("All pools are formatted " 4334168404Spjd "using this version.\n")); 4335168404Spjd else if (!cb.cb_all) 4336168404Spjd (void) printf(gettext("Use 'zpool upgrade -v' " 4337168404Spjd "for a list of available versions and " 4338168404Spjd "their associated\nfeatures.\n")); 4339168404Spjd } 4340168404Spjd } else { 4341168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, 4342168404Spjd upgrade_one, &cb); 4343168404Spjd } 4344168404Spjd 4345212050Spjd if (cb.cb_poolname[0] != '\0') { 4346212050Spjd (void) printf( 4347212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 4348212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 4349212050Spjd "the following command will do it:\n" 4350212050Spjd "\n" 4351212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 4352212050Spjd cb.cb_poolname); 4353212050Spjd } 4354212050Spjd 4355168404Spjd return (ret); 4356168404Spjd} 4357168404Spjd 4358185029Spjdtypedef struct hist_cbdata { 4359185029Spjd boolean_t first; 4360185029Spjd int longfmt; 4361185029Spjd int internal; 4362185029Spjd} hist_cbdata_t; 4363185029Spjd 4364168404Spjd/* 4365168404Spjd * Print out the command history for a specific pool. 4366168404Spjd */ 4367168404Spjdstatic int 4368168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 4369168404Spjd{ 4370168404Spjd nvlist_t *nvhis; 4371168404Spjd nvlist_t **records; 4372168404Spjd uint_t numrecords; 4373168404Spjd char *cmdstr; 4374185029Spjd char *pathstr; 4375168404Spjd uint64_t dst_time; 4376168404Spjd time_t tsec; 4377168404Spjd struct tm t; 4378168404Spjd char tbuf[30]; 4379168404Spjd int ret, i; 4380185029Spjd uint64_t who; 4381185029Spjd struct passwd *pwd; 4382185029Spjd char *hostname; 4383185029Spjd char *zonename; 4384185029Spjd char internalstr[MAXPATHLEN]; 4385185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 4386185029Spjd uint64_t txg; 4387185029Spjd uint64_t ievent; 4388168404Spjd 4389185029Spjd cb->first = B_FALSE; 4390168404Spjd 4391168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 4392168404Spjd 4393168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 4394168404Spjd return (ret); 4395168404Spjd 4396168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 4397168404Spjd &records, &numrecords) == 0); 4398168404Spjd for (i = 0; i < numrecords; i++) { 4399168404Spjd if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 4400185029Spjd &dst_time) != 0) 4401185029Spjd continue; 4402185029Spjd 4403185029Spjd /* is it an internal event or a standard event? */ 4404185029Spjd if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 4405185029Spjd &cmdstr) != 0) { 4406185029Spjd if (cb->internal == 0) 4407185029Spjd continue; 4408185029Spjd 4409185029Spjd if (nvlist_lookup_uint64(records[i], 4410185029Spjd ZPOOL_HIST_INT_EVENT, &ievent) != 0) 4411185029Spjd continue; 4412185029Spjd verify(nvlist_lookup_uint64(records[i], 4413185029Spjd ZPOOL_HIST_TXG, &txg) == 0); 4414185029Spjd verify(nvlist_lookup_string(records[i], 4415185029Spjd ZPOOL_HIST_INT_STR, &pathstr) == 0); 4416185029Spjd if (ievent >= LOG_END) 4417185029Spjd continue; 4418185029Spjd (void) snprintf(internalstr, 4419185029Spjd sizeof (internalstr), 4420185029Spjd "[internal %s txg:%lld] %s", 4421219089Spjd zfs_history_event_names[ievent], txg, 4422185029Spjd pathstr); 4423185029Spjd cmdstr = internalstr; 4424168404Spjd } 4425185029Spjd tsec = dst_time; 4426185029Spjd (void) localtime_r(&tsec, &t); 4427185029Spjd (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 4428185029Spjd (void) printf("%s %s", tbuf, cmdstr); 4429185029Spjd 4430185029Spjd if (!cb->longfmt) { 4431185029Spjd (void) printf("\n"); 4432185029Spjd continue; 4433185029Spjd } 4434185029Spjd (void) printf(" ["); 4435185029Spjd if (nvlist_lookup_uint64(records[i], 4436185029Spjd ZPOOL_HIST_WHO, &who) == 0) { 4437185029Spjd pwd = getpwuid((uid_t)who); 4438185029Spjd if (pwd) 4439185029Spjd (void) printf("user %s on", 4440185029Spjd pwd->pw_name); 4441185029Spjd else 4442185029Spjd (void) printf("user %d on", 4443185029Spjd (int)who); 4444185029Spjd } else { 4445185029Spjd (void) printf(gettext("no info]\n")); 4446185029Spjd continue; 4447185029Spjd } 4448185029Spjd if (nvlist_lookup_string(records[i], 4449185029Spjd ZPOOL_HIST_HOST, &hostname) == 0) { 4450185029Spjd (void) printf(" %s", hostname); 4451185029Spjd } 4452185029Spjd if (nvlist_lookup_string(records[i], 4453185029Spjd ZPOOL_HIST_ZONE, &zonename) == 0) { 4454185029Spjd (void) printf(":%s", zonename); 4455185029Spjd } 4456185029Spjd 4457185029Spjd (void) printf("]"); 4458185029Spjd (void) printf("\n"); 4459168404Spjd } 4460168404Spjd (void) printf("\n"); 4461168404Spjd nvlist_free(nvhis); 4462168404Spjd 4463168404Spjd return (ret); 4464168404Spjd} 4465168404Spjd 4466168404Spjd/* 4467168404Spjd * zpool history <pool> 4468168404Spjd * 4469168404Spjd * Displays the history of commands that modified pools. 4470168404Spjd */ 4471185029Spjd 4472185029Spjd 4473168404Spjdint 4474168404Spjdzpool_do_history(int argc, char **argv) 4475168404Spjd{ 4476185029Spjd hist_cbdata_t cbdata = { 0 }; 4477168404Spjd int ret; 4478185029Spjd int c; 4479168404Spjd 4480185029Spjd cbdata.first = B_TRUE; 4481185029Spjd /* check options */ 4482185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 4483185029Spjd switch (c) { 4484185029Spjd case 'l': 4485185029Spjd cbdata.longfmt = 1; 4486185029Spjd break; 4487185029Spjd case 'i': 4488185029Spjd cbdata.internal = 1; 4489185029Spjd break; 4490185029Spjd case '?': 4491185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4492185029Spjd optopt); 4493185029Spjd usage(B_FALSE); 4494185029Spjd } 4495185029Spjd } 4496168404Spjd argc -= optind; 4497168404Spjd argv += optind; 4498168404Spjd 4499168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 4500185029Spjd &cbdata); 4501168404Spjd 4502185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 4503168404Spjd (void) printf(gettext("no pools available\n")); 4504168404Spjd return (0); 4505168404Spjd } 4506168404Spjd 4507168404Spjd return (ret); 4508168404Spjd} 4509168404Spjd 4510168404Spjdstatic int 4511168404Spjdget_callback(zpool_handle_t *zhp, void *data) 4512168404Spjd{ 4513185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 4514168404Spjd char value[MAXNAMELEN]; 4515185029Spjd zprop_source_t srctype; 4516185029Spjd zprop_list_t *pl; 4517168404Spjd 4518168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 4519168404Spjd 4520168404Spjd /* 4521185029Spjd * Skip the special fake placeholder. This will also skip 4522185029Spjd * over the name property when 'all' is specified. 4523168404Spjd */ 4524185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 4525168404Spjd pl == cbp->cb_proplist) 4526168404Spjd continue; 4527168404Spjd 4528168404Spjd if (zpool_get_prop(zhp, pl->pl_prop, 4529168404Spjd value, sizeof (value), &srctype) != 0) 4530168404Spjd continue; 4531168404Spjd 4532185029Spjd zprop_print_one_property(zpool_get_name(zhp), cbp, 4533219089Spjd zpool_prop_to_name(pl->pl_prop), value, srctype, NULL, 4534219089Spjd NULL); 4535168404Spjd } 4536168404Spjd return (0); 4537168404Spjd} 4538168404Spjd 4539168404Spjdint 4540168404Spjdzpool_do_get(int argc, char **argv) 4541168404Spjd{ 4542185029Spjd zprop_get_cbdata_t cb = { 0 }; 4543185029Spjd zprop_list_t fake_name = { 0 }; 4544168404Spjd int ret; 4545168404Spjd 4546168404Spjd if (argc < 3) 4547168404Spjd usage(B_FALSE); 4548168404Spjd 4549168404Spjd cb.cb_first = B_TRUE; 4550185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 4551168404Spjd cb.cb_columns[0] = GET_COL_NAME; 4552168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 4553168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 4554168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 4555185029Spjd cb.cb_type = ZFS_TYPE_POOL; 4556168404Spjd 4557185029Spjd if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 4558185029Spjd ZFS_TYPE_POOL) != 0) 4559168404Spjd usage(B_FALSE); 4560168404Spjd 4561168404Spjd if (cb.cb_proplist != NULL) { 4562185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 4563168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 4564168404Spjd fake_name.pl_next = cb.cb_proplist; 4565168404Spjd cb.cb_proplist = &fake_name; 4566168404Spjd } 4567168404Spjd 4568168404Spjd ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 4569168404Spjd get_callback, &cb); 4570168404Spjd 4571168404Spjd if (cb.cb_proplist == &fake_name) 4572185029Spjd zprop_free_list(fake_name.pl_next); 4573168404Spjd else 4574185029Spjd zprop_free_list(cb.cb_proplist); 4575168404Spjd 4576168404Spjd return (ret); 4577168404Spjd} 4578168404Spjd 4579168404Spjdtypedef struct set_cbdata { 4580168404Spjd char *cb_propname; 4581168404Spjd char *cb_value; 4582168404Spjd boolean_t cb_any_successful; 4583168404Spjd} set_cbdata_t; 4584168404Spjd 4585168404Spjdint 4586168404Spjdset_callback(zpool_handle_t *zhp, void *data) 4587168404Spjd{ 4588168404Spjd int error; 4589168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 4590168404Spjd 4591168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 4592168404Spjd 4593168404Spjd if (!error) 4594168404Spjd cb->cb_any_successful = B_TRUE; 4595168404Spjd 4596168404Spjd return (error); 4597168404Spjd} 4598168404Spjd 4599168404Spjdint 4600168404Spjdzpool_do_set(int argc, char **argv) 4601168404Spjd{ 4602168404Spjd set_cbdata_t cb = { 0 }; 4603168404Spjd int error; 4604168404Spjd 4605168404Spjd if (argc > 1 && argv[1][0] == '-') { 4606168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4607168404Spjd argv[1][1]); 4608168404Spjd usage(B_FALSE); 4609168404Spjd } 4610168404Spjd 4611168404Spjd if (argc < 2) { 4612168404Spjd (void) fprintf(stderr, gettext("missing property=value " 4613168404Spjd "argument\n")); 4614168404Spjd usage(B_FALSE); 4615168404Spjd } 4616168404Spjd 4617168404Spjd if (argc < 3) { 4618168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 4619168404Spjd usage(B_FALSE); 4620168404Spjd } 4621168404Spjd 4622168404Spjd if (argc > 3) { 4623168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 4624168404Spjd usage(B_FALSE); 4625168404Spjd } 4626168404Spjd 4627168404Spjd cb.cb_propname = argv[1]; 4628168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 4629168404Spjd if (cb.cb_value == NULL) { 4630168404Spjd (void) fprintf(stderr, gettext("missing value in " 4631168404Spjd "property=value argument\n")); 4632168404Spjd usage(B_FALSE); 4633168404Spjd } 4634168404Spjd 4635168404Spjd *(cb.cb_value) = '\0'; 4636168404Spjd cb.cb_value++; 4637168404Spjd 4638168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 4639168404Spjd set_callback, &cb); 4640168404Spjd 4641168404Spjd return (error); 4642168404Spjd} 4643168404Spjd 4644168404Spjdstatic int 4645168404Spjdfind_command_idx(char *command, int *idx) 4646168404Spjd{ 4647168404Spjd int i; 4648168404Spjd 4649168404Spjd for (i = 0; i < NCOMMAND; i++) { 4650168404Spjd if (command_table[i].name == NULL) 4651168404Spjd continue; 4652168404Spjd 4653168404Spjd if (strcmp(command, command_table[i].name) == 0) { 4654168404Spjd *idx = i; 4655168404Spjd return (0); 4656168404Spjd } 4657168404Spjd } 4658168404Spjd return (1); 4659168404Spjd} 4660168404Spjd 4661168404Spjdint 4662168404Spjdmain(int argc, char **argv) 4663168404Spjd{ 4664168404Spjd int ret; 4665168404Spjd int i; 4666168404Spjd char *cmdname; 4667168404Spjd 4668168404Spjd (void) setlocale(LC_ALL, ""); 4669168404Spjd (void) textdomain(TEXT_DOMAIN); 4670168404Spjd 4671168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 4672168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 4673168404Spjd "initialize ZFS library\n")); 4674168404Spjd return (1); 4675168404Spjd } 4676168404Spjd 4677168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 4678168404Spjd 4679168404Spjd opterr = 0; 4680168404Spjd 4681168404Spjd /* 4682168404Spjd * Make sure the user has specified some command. 4683168404Spjd */ 4684168404Spjd if (argc < 2) { 4685168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 4686168404Spjd usage(B_FALSE); 4687168404Spjd } 4688168404Spjd 4689168404Spjd cmdname = argv[1]; 4690168404Spjd 4691168404Spjd /* 4692168404Spjd * Special case '-?' 4693168404Spjd */ 4694168404Spjd if (strcmp(cmdname, "-?") == 0) 4695168404Spjd usage(B_TRUE); 4696168404Spjd 4697185029Spjd zpool_set_history_str("zpool", argc, argv, history_str); 4698185029Spjd verify(zpool_stage_history(g_zfs, history_str) == 0); 4699185029Spjd 4700168404Spjd /* 4701168404Spjd * Run the appropriate command. 4702168404Spjd */ 4703168404Spjd if (find_command_idx(cmdname, &i) == 0) { 4704168404Spjd current_command = &command_table[i]; 4705168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 4706185029Spjd } else if (strchr(cmdname, '=')) { 4707185029Spjd verify(find_command_idx("set", &i) == 0); 4708185029Spjd current_command = &command_table[i]; 4709185029Spjd ret = command_table[i].func(argc, argv); 4710185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 4711185029Spjd /* 4712185029Spjd * 'freeze' is a vile debugging abomination, so we treat 4713185029Spjd * it as such. 4714185029Spjd */ 4715168404Spjd char buf[16384]; 4716168404Spjd int fd = open(ZFS_DEV, O_RDWR); 4717168404Spjd (void) strcpy((void *)buf, argv[2]); 4718168404Spjd return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 4719185029Spjd } else { 4720168404Spjd (void) fprintf(stderr, gettext("unrecognized " 4721168404Spjd "command '%s'\n"), cmdname); 4722168404Spjd usage(B_FALSE); 4723168404Spjd } 4724168404Spjd 4725168404Spjd libzfs_fini(g_zfs); 4726168404Spjd 4727168404Spjd /* 4728168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 4729168404Spjd * for the purposes of running ::findleaks. 4730168404Spjd */ 4731168404Spjd if (getenv("ZFS_ABORT") != NULL) { 4732168404Spjd (void) printf("dumping core by request\n"); 4733168404Spjd abort(); 4734168404Spjd } 4735168404Spjd 4736168404Spjd return (ret); 4737168404Spjd} 4738