zpool_main.c revision 228020
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. 25168404Spjd */ 26168404Spjd 27168404Spjd#include <solaris.h> 28168404Spjd#include <assert.h> 29168404Spjd#include <ctype.h> 30168404Spjd#include <dirent.h> 31168404Spjd#include <errno.h> 32168404Spjd#include <fcntl.h> 33168404Spjd#include <libgen.h> 34168404Spjd#include <libintl.h> 35168404Spjd#include <libuutil.h> 36168404Spjd#include <locale.h> 37168404Spjd#include <stdio.h> 38168404Spjd#include <stdlib.h> 39168404Spjd#include <string.h> 40168404Spjd#include <strings.h> 41168404Spjd#include <unistd.h> 42168404Spjd#include <priv.h> 43185029Spjd#include <pwd.h> 44185029Spjd#include <zone.h> 45168404Spjd#include <sys/time.h> 46168404Spjd#include <sys/fs/zfs.h> 47168404Spjd#include <sys/stat.h> 48168404Spjd 49168404Spjd#include <libzfs.h> 50168404Spjd 51168404Spjd#include "zpool_util.h" 52185029Spjd#include "zfs_comutil.h" 53168404Spjd 54219089Spjd#include "statcommon.h" 55219089Spjd 56168404Spjdstatic int zpool_do_create(int, char **); 57168404Spjdstatic int zpool_do_destroy(int, char **); 58168404Spjd 59168404Spjdstatic int zpool_do_add(int, char **); 60168404Spjdstatic int zpool_do_remove(int, char **); 61224171Sgibbsstatic int zpool_do_labelclear(int, char **); 62168404Spjd 63168404Spjdstatic int zpool_do_list(int, char **); 64168404Spjdstatic int zpool_do_iostat(int, char **); 65168404Spjdstatic int zpool_do_status(int, char **); 66168404Spjd 67168404Spjdstatic int zpool_do_online(int, char **); 68168404Spjdstatic int zpool_do_offline(int, char **); 69168404Spjdstatic int zpool_do_clear(int, char **); 70168404Spjd 71168404Spjdstatic int zpool_do_attach(int, char **); 72168404Spjdstatic int zpool_do_detach(int, char **); 73168404Spjdstatic int zpool_do_replace(int, char **); 74219089Spjdstatic int zpool_do_split(int, char **); 75168404Spjd 76168404Spjdstatic int zpool_do_scrub(int, char **); 77168404Spjd 78168404Spjdstatic int zpool_do_import(int, char **); 79168404Spjdstatic int zpool_do_export(int, char **); 80168404Spjd 81168404Spjdstatic int zpool_do_upgrade(int, char **); 82168404Spjd 83168404Spjdstatic int zpool_do_history(int, char **); 84168404Spjd 85168404Spjdstatic int zpool_do_get(int, char **); 86168404Spjdstatic int zpool_do_set(int, char **); 87168404Spjd 88168404Spjd/* 89168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 90168404Spjd * debugging facilities. 91168404Spjd */ 92185029Spjd 93185029Spjd#ifdef DEBUG 94168404Spjdconst char * 95168404Spjd_umem_debug_init(void) 96168404Spjd{ 97168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 98168404Spjd} 99168404Spjd 100168404Spjdconst char * 101168404Spjd_umem_logging_init(void) 102168404Spjd{ 103168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 104168404Spjd} 105185029Spjd#endif 106168404Spjd 107168404Spjdtypedef enum { 108168404Spjd HELP_ADD, 109168404Spjd HELP_ATTACH, 110168404Spjd HELP_CLEAR, 111168404Spjd HELP_CREATE, 112168404Spjd HELP_DESTROY, 113168404Spjd HELP_DETACH, 114168404Spjd HELP_EXPORT, 115168404Spjd HELP_HISTORY, 116168404Spjd HELP_IMPORT, 117168404Spjd HELP_IOSTAT, 118224171Sgibbs HELP_LABELCLEAR, 119168404Spjd HELP_LIST, 120168404Spjd HELP_OFFLINE, 121168404Spjd HELP_ONLINE, 122168404Spjd HELP_REPLACE, 123168404Spjd HELP_REMOVE, 124168404Spjd HELP_SCRUB, 125168404Spjd HELP_STATUS, 126168404Spjd HELP_UPGRADE, 127168404Spjd HELP_GET, 128219089Spjd HELP_SET, 129219089Spjd HELP_SPLIT 130168404Spjd} zpool_help_t; 131168404Spjd 132168404Spjd 133168404Spjdtypedef struct zpool_command { 134168404Spjd const char *name; 135168404Spjd int (*func)(int, char **); 136168404Spjd zpool_help_t usage; 137168404Spjd} zpool_command_t; 138168404Spjd 139168404Spjd/* 140168404Spjd * Master command table. Each ZFS command has a name, associated function, and 141168404Spjd * usage message. The usage messages need to be internationalized, so we have 142168404Spjd * to have a function to return the usage message based on a command index. 143168404Spjd * 144168404Spjd * These commands are organized according to how they are displayed in the usage 145168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 146168404Spjd * the generic usage message. 147168404Spjd */ 148168404Spjdstatic zpool_command_t command_table[] = { 149168404Spjd { "create", zpool_do_create, HELP_CREATE }, 150168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 151168404Spjd { NULL }, 152168404Spjd { "add", zpool_do_add, HELP_ADD }, 153168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 154168404Spjd { NULL }, 155224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 156224171Sgibbs { NULL }, 157168404Spjd { "list", zpool_do_list, HELP_LIST }, 158168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 159168404Spjd { "status", zpool_do_status, HELP_STATUS }, 160168404Spjd { NULL }, 161168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 162168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 163168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 164168404Spjd { NULL }, 165168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 166168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 167168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 168219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 169168404Spjd { NULL }, 170168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 171168404Spjd { NULL }, 172168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 173168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 174168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 175168404Spjd { NULL }, 176168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 177168404Spjd { "get", zpool_do_get, HELP_GET }, 178168404Spjd { "set", zpool_do_set, HELP_SET }, 179168404Spjd}; 180168404Spjd 181168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 182168404Spjd 183168404Spjdzpool_command_t *current_command; 184185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 185168404Spjd 186219089Spjdstatic uint_t timestamp_fmt = NODATE; 187219089Spjd 188168404Spjdstatic const char * 189168404Spjdget_usage(zpool_help_t idx) { 190168404Spjd switch (idx) { 191168404Spjd case HELP_ADD: 192168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 193168404Spjd case HELP_ATTACH: 194168404Spjd return (gettext("\tattach [-f] <pool> <device> " 195185029Spjd "<new-device>\n")); 196168404Spjd case HELP_CLEAR: 197219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 198168404Spjd case HELP_CREATE: 199185029Spjd return (gettext("\tcreate [-fn] [-o property=value] ... \n" 200185029Spjd "\t [-O file-system-property=value] ... \n" 201185029Spjd "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 202168404Spjd case HELP_DESTROY: 203168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 204168404Spjd case HELP_DETACH: 205168404Spjd return (gettext("\tdetach <pool> <device>\n")); 206168404Spjd case HELP_EXPORT: 207168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 208168404Spjd case HELP_HISTORY: 209185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 210168404Spjd case HELP_IMPORT: 211168404Spjd return (gettext("\timport [-d dir] [-D]\n" 212219089Spjd "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 213185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 214219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 215219089Spjd "[-R root] [-F [-n]] -a\n" 216185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 217219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 218219089Spjd "[-R root] [-F [-n]]\n" 219219089Spjd "\t <pool | id> [newpool]\n")); 220168404Spjd case HELP_IOSTAT: 221219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 222168404Spjd "[count]]\n")); 223224171Sgibbs case HELP_LABELCLEAR: 224224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 225168404Spjd case HELP_LIST: 226185029Spjd return (gettext("\tlist [-H] [-o property[,...]] " 227219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 228168404Spjd case HELP_OFFLINE: 229168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 230168404Spjd case HELP_ONLINE: 231228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 232168404Spjd case HELP_REPLACE: 233168404Spjd return (gettext("\treplace [-f] <pool> <device> " 234185029Spjd "[new-device]\n")); 235168404Spjd case HELP_REMOVE: 236185029Spjd return (gettext("\tremove <pool> <device> ...\n")); 237168404Spjd case HELP_SCRUB: 238168404Spjd return (gettext("\tscrub [-s] <pool> ...\n")); 239168404Spjd case HELP_STATUS: 240219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 241219089Spjd "[count]]\n")); 242168404Spjd case HELP_UPGRADE: 243228020Smm return (gettext("\tupgrade [-v]\n" 244185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 245168404Spjd case HELP_GET: 246185029Spjd return (gettext("\tget <\"all\" | property[,...]> " 247168404Spjd "<pool> ...\n")); 248168404Spjd case HELP_SET: 249168404Spjd return (gettext("\tset <property=value> <pool> \n")); 250219089Spjd case HELP_SPLIT: 251219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 252219089Spjd "\t [-o property=value] <pool> <newpool> " 253219089Spjd "[<device> ...]\n")); 254168404Spjd } 255168404Spjd 256168404Spjd abort(); 257168404Spjd /* NOTREACHED */ 258168404Spjd} 259168404Spjd 260168404Spjd 261168404Spjd/* 262168404Spjd * Callback routine that will print out a pool property value. 263168404Spjd */ 264185029Spjdstatic int 265185029Spjdprint_prop_cb(int prop, void *cb) 266168404Spjd{ 267168404Spjd FILE *fp = cb; 268168404Spjd 269219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 270168404Spjd 271185029Spjd if (zpool_prop_readonly(prop)) 272185029Spjd (void) fprintf(fp, " NO "); 273185029Spjd else 274219089Spjd (void) fprintf(fp, " YES "); 275185029Spjd 276168404Spjd if (zpool_prop_values(prop) == NULL) 277168404Spjd (void) fprintf(fp, "-\n"); 278168404Spjd else 279168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 280168404Spjd 281185029Spjd return (ZPROP_CONT); 282168404Spjd} 283168404Spjd 284168404Spjd/* 285168404Spjd * Display usage message. If we're inside a command, display only the usage for 286168404Spjd * that command. Otherwise, iterate over the entire command table and display 287168404Spjd * a complete usage message. 288168404Spjd */ 289168404Spjdvoid 290168404Spjdusage(boolean_t requested) 291168404Spjd{ 292168404Spjd FILE *fp = requested ? stdout : stderr; 293168404Spjd 294168404Spjd if (current_command == NULL) { 295168404Spjd int i; 296168404Spjd 297168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 298168404Spjd (void) fprintf(fp, 299168404Spjd gettext("where 'command' is one of the following:\n\n")); 300168404Spjd 301168404Spjd for (i = 0; i < NCOMMAND; i++) { 302168404Spjd if (command_table[i].name == NULL) 303168404Spjd (void) fprintf(fp, "\n"); 304168404Spjd else 305168404Spjd (void) fprintf(fp, "%s", 306168404Spjd get_usage(command_table[i].usage)); 307168404Spjd } 308168404Spjd } else { 309168404Spjd (void) fprintf(fp, gettext("usage:\n")); 310168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 311168404Spjd } 312168404Spjd 313168404Spjd if (current_command != NULL && 314168404Spjd ((strcmp(current_command->name, "set") == 0) || 315185029Spjd (strcmp(current_command->name, "get") == 0) || 316185029Spjd (strcmp(current_command->name, "list") == 0))) { 317168404Spjd 318168404Spjd (void) fprintf(fp, 319168404Spjd gettext("\nthe following properties are supported:\n")); 320168404Spjd 321219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 322185029Spjd "PROPERTY", "EDIT", "VALUES"); 323168404Spjd 324168404Spjd /* Iterate over all properties */ 325185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 326185029Spjd ZFS_TYPE_POOL); 327168404Spjd } 328168404Spjd 329168404Spjd /* 330168404Spjd * See comments at end of main(). 331168404Spjd */ 332168404Spjd if (getenv("ZFS_ABORT") != NULL) { 333168404Spjd (void) printf("dumping core by request\n"); 334168404Spjd abort(); 335168404Spjd } 336168404Spjd 337168404Spjd exit(requested ? 0 : 2); 338168404Spjd} 339168404Spjd 340168404Spjdvoid 341185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 342185029Spjd boolean_t print_logs) 343168404Spjd{ 344168404Spjd nvlist_t **child; 345168404Spjd uint_t c, children; 346168404Spjd char *vname; 347168404Spjd 348168404Spjd if (name != NULL) 349168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 350168404Spjd 351168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 352168404Spjd &child, &children) != 0) 353168404Spjd return; 354168404Spjd 355168404Spjd for (c = 0; c < children; c++) { 356185029Spjd uint64_t is_log = B_FALSE; 357185029Spjd 358185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 359185029Spjd &is_log); 360185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 361185029Spjd continue; 362185029Spjd 363219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 364185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 365185029Spjd B_FALSE); 366168404Spjd free(vname); 367168404Spjd } 368168404Spjd} 369168404Spjd 370168404Spjd/* 371185029Spjd * Add a property pair (name, string-value) into a property nvlist. 372185029Spjd */ 373185029Spjdstatic int 374185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 375185029Spjd boolean_t poolprop) 376185029Spjd{ 377185029Spjd zpool_prop_t prop = ZPROP_INVAL; 378185029Spjd zfs_prop_t fprop; 379185029Spjd nvlist_t *proplist; 380185029Spjd const char *normnm; 381185029Spjd char *strval; 382185029Spjd 383185029Spjd if (*props == NULL && 384185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 385185029Spjd (void) fprintf(stderr, 386185029Spjd gettext("internal error: out of memory\n")); 387185029Spjd return (1); 388185029Spjd } 389185029Spjd 390185029Spjd proplist = *props; 391185029Spjd 392185029Spjd if (poolprop) { 393185029Spjd if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 394185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 395185029Spjd "not a valid pool property\n"), propname); 396185029Spjd return (2); 397185029Spjd } 398185029Spjd normnm = zpool_prop_to_name(prop); 399185029Spjd } else { 400209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 401209962Smm normnm = zfs_prop_to_name(fprop); 402209962Smm } else { 403209962Smm normnm = propname; 404185029Spjd } 405185029Spjd } 406185029Spjd 407185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 408185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 409185029Spjd (void) fprintf(stderr, gettext("property '%s' " 410185029Spjd "specified multiple times\n"), propname); 411185029Spjd return (2); 412185029Spjd } 413185029Spjd 414185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 415185029Spjd (void) fprintf(stderr, gettext("internal " 416185029Spjd "error: out of memory\n")); 417185029Spjd return (1); 418185029Spjd } 419185029Spjd 420185029Spjd return (0); 421185029Spjd} 422185029Spjd 423185029Spjd/* 424168404Spjd * zpool add [-fn] <pool> <vdev> ... 425168404Spjd * 426168404Spjd * -f Force addition of devices, even if they appear in use 427168404Spjd * -n Do not add the devices, but display the resulting layout if 428168404Spjd * they were to be added. 429168404Spjd * 430168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 431168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 432168404Spjd * libzfs. 433168404Spjd */ 434168404Spjdint 435168404Spjdzpool_do_add(int argc, char **argv) 436168404Spjd{ 437168404Spjd boolean_t force = B_FALSE; 438168404Spjd boolean_t dryrun = B_FALSE; 439168404Spjd int c; 440168404Spjd nvlist_t *nvroot; 441168404Spjd char *poolname; 442168404Spjd int ret; 443168404Spjd zpool_handle_t *zhp; 444168404Spjd nvlist_t *config; 445168404Spjd 446168404Spjd /* check options */ 447168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 448168404Spjd switch (c) { 449168404Spjd case 'f': 450168404Spjd force = B_TRUE; 451168404Spjd break; 452168404Spjd case 'n': 453168404Spjd dryrun = B_TRUE; 454168404Spjd break; 455168404Spjd case '?': 456168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 457168404Spjd optopt); 458168404Spjd usage(B_FALSE); 459168404Spjd } 460168404Spjd } 461168404Spjd 462168404Spjd argc -= optind; 463168404Spjd argv += optind; 464168404Spjd 465168404Spjd /* get pool name and check number of arguments */ 466168404Spjd if (argc < 1) { 467168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 468168404Spjd usage(B_FALSE); 469168404Spjd } 470168404Spjd if (argc < 2) { 471168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 472168404Spjd usage(B_FALSE); 473168404Spjd } 474168404Spjd 475168404Spjd poolname = argv[0]; 476168404Spjd 477168404Spjd argc--; 478168404Spjd argv++; 479168404Spjd 480168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 481168404Spjd return (1); 482168404Spjd 483168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 484168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 485168404Spjd poolname); 486168404Spjd zpool_close(zhp); 487168404Spjd return (1); 488168404Spjd } 489168404Spjd 490168404Spjd /* pass off to get_vdev_spec for processing */ 491185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 492185029Spjd argc, argv); 493168404Spjd if (nvroot == NULL) { 494168404Spjd zpool_close(zhp); 495168404Spjd return (1); 496168404Spjd } 497168404Spjd 498168404Spjd if (dryrun) { 499168404Spjd nvlist_t *poolnvroot; 500168404Spjd 501168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 502168404Spjd &poolnvroot) == 0); 503168404Spjd 504168404Spjd (void) printf(gettext("would update '%s' to the following " 505168404Spjd "configuration:\n"), zpool_get_name(zhp)); 506168404Spjd 507185029Spjd /* print original main pool and new tree */ 508185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 509185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 510168404Spjd 511185029Spjd /* Do the same for the logs */ 512185029Spjd if (num_logs(poolnvroot) > 0) { 513185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 514185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 515185029Spjd } else if (num_logs(nvroot) > 0) { 516185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 517185029Spjd } 518185029Spjd 519168404Spjd ret = 0; 520168404Spjd } else { 521168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 522168404Spjd } 523168404Spjd 524168404Spjd nvlist_free(nvroot); 525168404Spjd zpool_close(zhp); 526168404Spjd 527168404Spjd return (ret); 528168404Spjd} 529168404Spjd 530168404Spjd/* 531219089Spjd * zpool remove <pool> <vdev> ... 532168404Spjd * 533219089Spjd * Removes the given vdev from the pool. Currently, this supports removing 534219089Spjd * spares, cache, and log devices from the pool. 535168404Spjd */ 536168404Spjdint 537168404Spjdzpool_do_remove(int argc, char **argv) 538168404Spjd{ 539168404Spjd char *poolname; 540185029Spjd int i, ret = 0; 541168404Spjd zpool_handle_t *zhp; 542168404Spjd 543168404Spjd argc--; 544168404Spjd argv++; 545168404Spjd 546168404Spjd /* get pool name and check number of arguments */ 547168404Spjd if (argc < 1) { 548168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 549168404Spjd usage(B_FALSE); 550168404Spjd } 551168404Spjd if (argc < 2) { 552168404Spjd (void) fprintf(stderr, gettext("missing device\n")); 553168404Spjd usage(B_FALSE); 554168404Spjd } 555168404Spjd 556168404Spjd poolname = argv[0]; 557168404Spjd 558168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 559168404Spjd return (1); 560168404Spjd 561185029Spjd for (i = 1; i < argc; i++) { 562185029Spjd if (zpool_vdev_remove(zhp, argv[i]) != 0) 563185029Spjd ret = 1; 564168404Spjd } 565168404Spjd 566168404Spjd return (ret); 567168404Spjd} 568168404Spjd 569168404Spjd/* 570224171Sgibbs * zpool labelclear <vdev> 571224171Sgibbs * 572224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 573224171Sgibbs * on the device. 574224171Sgibbs */ 575224171Sgibbsint 576224171Sgibbszpool_do_labelclear(int argc, char **argv) 577224171Sgibbs{ 578224171Sgibbs char *vdev, *name; 579224171Sgibbs int c, fd = -1, ret = 0; 580224171Sgibbs pool_state_t state; 581224171Sgibbs boolean_t inuse = B_FALSE; 582224171Sgibbs boolean_t force = B_FALSE; 583224171Sgibbs 584224171Sgibbs /* check options */ 585224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 586224171Sgibbs switch (c) { 587224171Sgibbs case 'f': 588224171Sgibbs force = B_TRUE; 589224171Sgibbs break; 590224171Sgibbs default: 591224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 592224171Sgibbs optopt); 593224171Sgibbs usage(B_FALSE); 594224171Sgibbs } 595224171Sgibbs } 596224171Sgibbs 597224171Sgibbs argc -= optind; 598224171Sgibbs argv += optind; 599224171Sgibbs 600224171Sgibbs /* get vdev name */ 601224171Sgibbs if (argc < 1) { 602224171Sgibbs (void) fprintf(stderr, gettext("missing vdev device name\n")); 603224171Sgibbs usage(B_FALSE); 604224171Sgibbs } 605224171Sgibbs 606224171Sgibbs vdev = argv[0]; 607224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 608224171Sgibbs (void) fprintf(stderr, gettext("Unable to open %s\n"), vdev); 609224171Sgibbs return (B_FALSE); 610224171Sgibbs } 611224171Sgibbs 612224171Sgibbs name = NULL; 613224171Sgibbs if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) { 614224171Sgibbs if (force) 615224171Sgibbs goto wipe_label; 616224171Sgibbs 617224171Sgibbs (void) fprintf(stderr, 618224171Sgibbs gettext("Unable to determine pool state for %s\n" 619224171Sgibbs "Use -f to force the clearing any label data\n"), vdev); 620224171Sgibbs 621224171Sgibbs return (1); 622224171Sgibbs } 623224171Sgibbs 624224171Sgibbs if (inuse) { 625224171Sgibbs switch (state) { 626224171Sgibbs default: 627224171Sgibbs case POOL_STATE_ACTIVE: 628224171Sgibbs case POOL_STATE_SPARE: 629224171Sgibbs case POOL_STATE_L2CACHE: 630224171Sgibbs (void) fprintf(stderr, 631224171Sgibbsgettext("labelclear operation failed.\n" 632224171Sgibbs "\tVdev %s is a member (%s), of pool \"%s\".\n" 633224171Sgibbs "\tTo remove label information from this device, export or destroy\n" 634224171Sgibbs "\tthe pool, or remove %s from the configuration of this pool\n" 635224171Sgibbs "\tand retry the labelclear operation\n"), 636224171Sgibbs vdev, zpool_pool_state_to_name(state), name, vdev); 637224171Sgibbs ret = 1; 638224171Sgibbs goto errout; 639224171Sgibbs 640224171Sgibbs case POOL_STATE_EXPORTED: 641224171Sgibbs if (force) 642224171Sgibbs break; 643224171Sgibbs 644224171Sgibbs (void) fprintf(stderr, 645224171Sgibbsgettext("labelclear operation failed.\n" 646224171Sgibbs "\tVdev %s is a member of the exported pool \"%s\".\n" 647224171Sgibbs "\tUse \"zpool labelclear -f %s\" to force the removal of label\n" 648224171Sgibbs "\tinformation.\n"), 649224171Sgibbs vdev, name, vdev); 650224171Sgibbs ret = 1; 651224171Sgibbs goto errout; 652224171Sgibbs 653224171Sgibbs case POOL_STATE_POTENTIALLY_ACTIVE: 654224171Sgibbs if (force) 655224171Sgibbs break; 656224171Sgibbs 657224171Sgibbs (void) fprintf(stderr, 658224171Sgibbsgettext("labelclear operation failed.\n" 659224171Sgibbs "\tVdev %s is a member of the pool \"%s\".\n" 660224171Sgibbs "\tThis pool is unknown to this system, but may be active on\n" 661224171Sgibbs "\tanother system. Use \'zpool labelclear -f %s\' to force the\n" 662224171Sgibbs "\tremoval of label information.\n"), 663224171Sgibbs vdev, name, vdev); 664224171Sgibbs ret = 1; 665224171Sgibbs goto errout; 666224171Sgibbs 667224171Sgibbs case POOL_STATE_DESTROYED: 668224171Sgibbs /* inuse should never be set for a destoryed pool... */ 669224171Sgibbs break; 670224171Sgibbs } 671224171Sgibbs } 672224171Sgibbs 673224171Sgibbswipe_label: 674224171Sgibbs if (zpool_clear_label(fd) != 0) { 675224171Sgibbs (void) fprintf(stderr, 676224171Sgibbs gettext("Label clear failed on vdev %s\n"), vdev); 677224171Sgibbs ret = 1; 678224171Sgibbs } 679224171Sgibbs 680224171Sgibbserrout: 681224171Sgibbs close(fd); 682224171Sgibbs if (name != NULL) 683224171Sgibbs free(name); 684224171Sgibbs 685224171Sgibbs return (ret); 686224171Sgibbs} 687224171Sgibbs 688224171Sgibbs/* 689185029Spjd * zpool create [-fn] [-o property=value] ... 690185029Spjd * [-O file-system-property=value] ... 691185029Spjd * [-R root] [-m mountpoint] <pool> <dev> ... 692168404Spjd * 693168404Spjd * -f Force creation, even if devices appear in use 694168404Spjd * -n Do not create the pool, but display the resulting layout if it 695168404Spjd * were to be created. 696168404Spjd * -R Create a pool under an alternate root 697168404Spjd * -m Set default mountpoint for the root dataset. By default it's 698168404Spjd * '/<pool>' 699185029Spjd * -o Set property=value. 700185029Spjd * -O Set fsproperty=value in the pool's root file system 701168404Spjd * 702168404Spjd * Creates the named pool according to the given vdev specification. The 703168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 704168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 705168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 706168404Spjd */ 707168404Spjdint 708168404Spjdzpool_do_create(int argc, char **argv) 709168404Spjd{ 710168404Spjd boolean_t force = B_FALSE; 711168404Spjd boolean_t dryrun = B_FALSE; 712168404Spjd int c; 713185029Spjd nvlist_t *nvroot = NULL; 714168404Spjd char *poolname; 715185029Spjd int ret = 1; 716168404Spjd char *altroot = NULL; 717168404Spjd char *mountpoint = NULL; 718185029Spjd nvlist_t *fsprops = NULL; 719185029Spjd nvlist_t *props = NULL; 720185029Spjd char *propval; 721168404Spjd 722168404Spjd /* check options */ 723185029Spjd while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) { 724168404Spjd switch (c) { 725168404Spjd case 'f': 726168404Spjd force = B_TRUE; 727168404Spjd break; 728168404Spjd case 'n': 729168404Spjd dryrun = B_TRUE; 730168404Spjd break; 731168404Spjd case 'R': 732168404Spjd altroot = optarg; 733185029Spjd if (add_prop_list(zpool_prop_to_name( 734185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 735185029Spjd goto errout; 736185029Spjd if (nvlist_lookup_string(props, 737185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 738185029Spjd &propval) == 0) 739185029Spjd break; 740185029Spjd if (add_prop_list(zpool_prop_to_name( 741185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 742185029Spjd goto errout; 743168404Spjd break; 744168404Spjd case 'm': 745168404Spjd mountpoint = optarg; 746168404Spjd break; 747185029Spjd case 'o': 748185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 749185029Spjd (void) fprintf(stderr, gettext("missing " 750185029Spjd "'=' for -o option\n")); 751185029Spjd goto errout; 752185029Spjd } 753185029Spjd *propval = '\0'; 754185029Spjd propval++; 755185029Spjd 756185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 757185029Spjd goto errout; 758185029Spjd break; 759185029Spjd case 'O': 760185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 761185029Spjd (void) fprintf(stderr, gettext("missing " 762185029Spjd "'=' for -O option\n")); 763185029Spjd goto errout; 764185029Spjd } 765185029Spjd *propval = '\0'; 766185029Spjd propval++; 767185029Spjd 768185029Spjd if (add_prop_list(optarg, propval, &fsprops, B_FALSE)) 769185029Spjd goto errout; 770185029Spjd break; 771168404Spjd case ':': 772168404Spjd (void) fprintf(stderr, gettext("missing argument for " 773168404Spjd "'%c' option\n"), optopt); 774185029Spjd goto badusage; 775168404Spjd case '?': 776168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 777168404Spjd optopt); 778185029Spjd goto badusage; 779168404Spjd } 780168404Spjd } 781168404Spjd 782168404Spjd argc -= optind; 783168404Spjd argv += optind; 784168404Spjd 785168404Spjd /* get pool name and check number of arguments */ 786168404Spjd if (argc < 1) { 787168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 788185029Spjd goto badusage; 789168404Spjd } 790168404Spjd if (argc < 2) { 791168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 792185029Spjd goto badusage; 793168404Spjd } 794168404Spjd 795168404Spjd poolname = argv[0]; 796168404Spjd 797168404Spjd /* 798168404Spjd * As a special case, check for use of '/' in the name, and direct the 799168404Spjd * user to use 'zfs create' instead. 800168404Spjd */ 801168404Spjd if (strchr(poolname, '/') != NULL) { 802168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 803168404Spjd "character '/' in pool name\n"), poolname); 804168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 805168404Spjd "create a dataset\n")); 806185029Spjd goto errout; 807168404Spjd } 808168404Spjd 809168404Spjd /* pass off to get_vdev_spec for bulk processing */ 810185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 811185029Spjd argc - 1, argv + 1); 812168404Spjd if (nvroot == NULL) 813185029Spjd goto errout; 814168404Spjd 815168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 816185029Spjd if (!zfs_allocatable_devs(nvroot)) { 817168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 818168404Spjd "specification: at least one toplevel vdev must be " 819168404Spjd "specified\n")); 820185029Spjd goto errout; 821168404Spjd } 822168404Spjd 823168404Spjd 824168404Spjd if (altroot != NULL && altroot[0] != '/') { 825168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 826168404Spjd "must be an absolute path\n"), altroot); 827185029Spjd goto errout; 828168404Spjd } 829168404Spjd 830168404Spjd /* 831168404Spjd * Check the validity of the mountpoint and direct the user to use the 832168404Spjd * '-m' mountpoint option if it looks like its in use. 833168404Spjd */ 834168404Spjd if (mountpoint == NULL || 835168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 836168404Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 837168404Spjd char buf[MAXPATHLEN]; 838185029Spjd DIR *dirp; 839168404Spjd 840168404Spjd if (mountpoint && mountpoint[0] != '/') { 841168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 842168404Spjd "'%s': must be an absolute path, 'legacy', or " 843168404Spjd "'none'\n"), mountpoint); 844185029Spjd goto errout; 845168404Spjd } 846168404Spjd 847168404Spjd if (mountpoint == NULL) { 848168404Spjd if (altroot != NULL) 849168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 850168404Spjd altroot, poolname); 851168404Spjd else 852168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 853168404Spjd poolname); 854168404Spjd } else { 855168404Spjd if (altroot != NULL) 856168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 857168404Spjd altroot, mountpoint); 858168404Spjd else 859168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 860168404Spjd mountpoint); 861168404Spjd } 862168404Spjd 863185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 864185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 865185029Spjd "%s\n"), buf, strerror(errno)); 866185029Spjd (void) fprintf(stderr, gettext("use '-m' " 867185029Spjd "option to provide a different default\n")); 868185029Spjd goto errout; 869185029Spjd } else if (dirp) { 870185029Spjd int count = 0; 871185029Spjd 872185029Spjd while (count < 3 && readdir(dirp) != NULL) 873185029Spjd count++; 874185029Spjd (void) closedir(dirp); 875185029Spjd 876185029Spjd if (count > 2) { 877168404Spjd (void) fprintf(stderr, gettext("mountpoint " 878168404Spjd "'%s' exists and is not empty\n"), buf); 879185029Spjd (void) fprintf(stderr, gettext("use '-m' " 880185029Spjd "option to provide a " 881185029Spjd "different default\n")); 882185029Spjd goto errout; 883185029Spjd } 884168404Spjd } 885168404Spjd } 886168404Spjd 887168404Spjd if (dryrun) { 888168404Spjd /* 889168404Spjd * For a dry run invocation, print out a basic message and run 890168404Spjd * through all the vdevs in the list and print out in an 891168404Spjd * appropriate hierarchy. 892168404Spjd */ 893168404Spjd (void) printf(gettext("would create '%s' with the " 894168404Spjd "following layout:\n\n"), poolname); 895168404Spjd 896185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 897185029Spjd if (num_logs(nvroot) > 0) 898185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 899168404Spjd 900168404Spjd ret = 0; 901168404Spjd } else { 902168404Spjd /* 903168404Spjd * Hand off to libzfs. 904168404Spjd */ 905185029Spjd if (zpool_create(g_zfs, poolname, 906185029Spjd nvroot, props, fsprops) == 0) { 907168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 908168404Spjd ZFS_TYPE_FILESYSTEM); 909168404Spjd if (pool != NULL) { 910168404Spjd if (mountpoint != NULL) 911168404Spjd verify(zfs_prop_set(pool, 912168404Spjd zfs_prop_to_name( 913168404Spjd ZFS_PROP_MOUNTPOINT), 914168404Spjd mountpoint) == 0); 915168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 916185029Spjd ret = zfs_shareall(pool); 917168404Spjd zfs_close(pool); 918168404Spjd } 919168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 920168404Spjd (void) fprintf(stderr, gettext("pool name may have " 921168404Spjd "been omitted\n")); 922168404Spjd } 923168404Spjd } 924168404Spjd 925185029Spjderrout: 926168404Spjd nvlist_free(nvroot); 927185029Spjd nvlist_free(fsprops); 928185029Spjd nvlist_free(props); 929168404Spjd return (ret); 930185029Spjdbadusage: 931185029Spjd nvlist_free(fsprops); 932185029Spjd nvlist_free(props); 933185029Spjd usage(B_FALSE); 934185029Spjd return (2); 935168404Spjd} 936168404Spjd 937168404Spjd/* 938168404Spjd * zpool destroy <pool> 939168404Spjd * 940168404Spjd * -f Forcefully unmount any datasets 941168404Spjd * 942168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 943168404Spjd */ 944168404Spjdint 945168404Spjdzpool_do_destroy(int argc, char **argv) 946168404Spjd{ 947168404Spjd boolean_t force = B_FALSE; 948168404Spjd int c; 949168404Spjd char *pool; 950168404Spjd zpool_handle_t *zhp; 951168404Spjd int ret; 952168404Spjd 953168404Spjd /* check options */ 954168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 955168404Spjd switch (c) { 956168404Spjd case 'f': 957168404Spjd force = B_TRUE; 958168404Spjd break; 959168404Spjd case '?': 960168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 961168404Spjd optopt); 962168404Spjd usage(B_FALSE); 963168404Spjd } 964168404Spjd } 965168404Spjd 966168404Spjd argc -= optind; 967168404Spjd argv += optind; 968168404Spjd 969168404Spjd /* check arguments */ 970168404Spjd if (argc < 1) { 971168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 972168404Spjd usage(B_FALSE); 973168404Spjd } 974168404Spjd if (argc > 1) { 975168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 976168404Spjd usage(B_FALSE); 977168404Spjd } 978168404Spjd 979168404Spjd pool = argv[0]; 980168404Spjd 981168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 982168404Spjd /* 983168404Spjd * As a special case, check for use of '/' in the name, and 984168404Spjd * direct the user to use 'zfs destroy' instead. 985168404Spjd */ 986168404Spjd if (strchr(pool, '/') != NULL) 987168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 988168404Spjd "destroy a dataset\n")); 989168404Spjd return (1); 990168404Spjd } 991168404Spjd 992168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 993168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 994168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 995168404Spjd return (1); 996168404Spjd } 997168404Spjd 998168404Spjd ret = (zpool_destroy(zhp) != 0); 999168404Spjd 1000168404Spjd zpool_close(zhp); 1001168404Spjd 1002168404Spjd return (ret); 1003168404Spjd} 1004168404Spjd 1005168404Spjd/* 1006168404Spjd * zpool export [-f] <pool> ... 1007168404Spjd * 1008168404Spjd * -f Forcefully unmount datasets 1009168404Spjd * 1010168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1011168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1012168404Spjd * then the datasets will be forcefully unmounted. 1013168404Spjd */ 1014168404Spjdint 1015168404Spjdzpool_do_export(int argc, char **argv) 1016168404Spjd{ 1017168404Spjd boolean_t force = B_FALSE; 1018207670Smm boolean_t hardforce = B_FALSE; 1019168404Spjd int c; 1020168404Spjd zpool_handle_t *zhp; 1021168404Spjd int ret; 1022168404Spjd int i; 1023168404Spjd 1024168404Spjd /* check options */ 1025207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1026168404Spjd switch (c) { 1027168404Spjd case 'f': 1028168404Spjd force = B_TRUE; 1029168404Spjd break; 1030207670Smm case 'F': 1031207670Smm hardforce = B_TRUE; 1032207670Smm break; 1033168404Spjd case '?': 1034168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1035168404Spjd optopt); 1036168404Spjd usage(B_FALSE); 1037168404Spjd } 1038168404Spjd } 1039168404Spjd 1040168404Spjd argc -= optind; 1041168404Spjd argv += optind; 1042168404Spjd 1043168404Spjd /* check arguments */ 1044168404Spjd if (argc < 1) { 1045168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1046168404Spjd usage(B_FALSE); 1047168404Spjd } 1048168404Spjd 1049168404Spjd ret = 0; 1050168404Spjd for (i = 0; i < argc; i++) { 1051168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1052168404Spjd ret = 1; 1053168404Spjd continue; 1054168404Spjd } 1055168404Spjd 1056168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1057168404Spjd ret = 1; 1058168404Spjd zpool_close(zhp); 1059168404Spjd continue; 1060168404Spjd } 1061168404Spjd 1062207670Smm if (hardforce) { 1063207670Smm if (zpool_export_force(zhp) != 0) 1064207670Smm ret = 1; 1065207670Smm } else if (zpool_export(zhp, force) != 0) { 1066168404Spjd ret = 1; 1067207670Smm } 1068168404Spjd 1069168404Spjd zpool_close(zhp); 1070168404Spjd } 1071168404Spjd 1072168404Spjd return (ret); 1073168404Spjd} 1074168404Spjd 1075168404Spjd/* 1076168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1077168404Spjd * name column. 1078168404Spjd */ 1079168404Spjdstatic int 1080168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1081168404Spjd{ 1082219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1083168404Spjd nvlist_t **child; 1084168404Spjd uint_t c, children; 1085168404Spjd int ret; 1086168404Spjd 1087168404Spjd if (strlen(name) + depth > max) 1088168404Spjd max = strlen(name) + depth; 1089168404Spjd 1090168404Spjd free(name); 1091168404Spjd 1092168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1093168404Spjd &child, &children) == 0) { 1094168404Spjd for (c = 0; c < children; c++) 1095168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1096168404Spjd max)) > max) 1097168404Spjd max = ret; 1098168404Spjd } 1099168404Spjd 1100185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1101185029Spjd &child, &children) == 0) { 1102185029Spjd for (c = 0; c < children; c++) 1103185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1104185029Spjd max)) > max) 1105185029Spjd max = ret; 1106185029Spjd } 1107185029Spjd 1108168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1109168404Spjd &child, &children) == 0) { 1110168404Spjd for (c = 0; c < children; c++) 1111168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1112168404Spjd max)) > max) 1113168404Spjd max = ret; 1114168404Spjd } 1115168404Spjd 1116168404Spjd 1117168404Spjd return (max); 1118168404Spjd} 1119168404Spjd 1120213197Smmtypedef struct spare_cbdata { 1121213197Smm uint64_t cb_guid; 1122213197Smm zpool_handle_t *cb_zhp; 1123213197Smm} spare_cbdata_t; 1124168404Spjd 1125213197Smmstatic boolean_t 1126213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1127213197Smm{ 1128213197Smm uint64_t guid; 1129213197Smm nvlist_t **child; 1130213197Smm uint_t c, children; 1131213197Smm 1132213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1133213197Smm search == guid) 1134213197Smm return (B_TRUE); 1135213197Smm 1136213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1137213197Smm &child, &children) == 0) { 1138213197Smm for (c = 0; c < children; c++) 1139213197Smm if (find_vdev(child[c], search)) 1140213197Smm return (B_TRUE); 1141213197Smm } 1142213197Smm 1143213197Smm return (B_FALSE); 1144213197Smm} 1145213197Smm 1146213197Smmstatic int 1147213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1148213197Smm{ 1149213197Smm spare_cbdata_t *cbp = data; 1150213197Smm nvlist_t *config, *nvroot; 1151213197Smm 1152213197Smm config = zpool_get_config(zhp, NULL); 1153213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1154213197Smm &nvroot) == 0); 1155213197Smm 1156213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1157213197Smm cbp->cb_zhp = zhp; 1158213197Smm return (1); 1159213197Smm } 1160213197Smm 1161213197Smm zpool_close(zhp); 1162213197Smm return (0); 1163213197Smm} 1164213197Smm 1165168404Spjd/* 1166213197Smm * Print out configuration state as requested by status_callback. 1167213197Smm */ 1168213197Smmvoid 1169213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1170213197Smm int namewidth, int depth, boolean_t isspare) 1171213197Smm{ 1172213197Smm nvlist_t **child; 1173213197Smm uint_t c, children; 1174219089Spjd pool_scan_stat_t *ps = NULL; 1175213197Smm vdev_stat_t *vs; 1176219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1177213197Smm char *vname; 1178213197Smm uint64_t notpresent; 1179213197Smm spare_cbdata_t cb; 1180224169Sgibbs const char *state; 1181213197Smm 1182213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1183213197Smm &child, &children) != 0) 1184213197Smm children = 0; 1185213197Smm 1186219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1187219089Spjd (uint64_t **)&vs, &c) == 0); 1188219089Spjd 1189213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1190213197Smm if (isspare) { 1191213197Smm /* 1192213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1193213197Smm * online drives. 1194213197Smm */ 1195213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1196213197Smm state = "INUSE"; 1197213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1198213197Smm state = "AVAIL"; 1199213197Smm } 1200213197Smm 1201213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1202213197Smm name, state); 1203213197Smm 1204213197Smm if (!isspare) { 1205213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1206213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1207213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1208213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1209213197Smm } 1210213197Smm 1211213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1212224170Sgibbs ¬present) == 0 || 1213224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1214213197Smm char *path; 1215224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1216224170Sgibbs (void) printf(" was %s", path); 1217213197Smm } else if (vs->vs_aux != 0) { 1218213197Smm (void) printf(" "); 1219213197Smm 1220213197Smm switch (vs->vs_aux) { 1221213197Smm case VDEV_AUX_OPEN_FAILED: 1222213197Smm (void) printf(gettext("cannot open")); 1223213197Smm break; 1224213197Smm 1225213197Smm case VDEV_AUX_BAD_GUID_SUM: 1226213197Smm (void) printf(gettext("missing device")); 1227213197Smm break; 1228213197Smm 1229213197Smm case VDEV_AUX_NO_REPLICAS: 1230213197Smm (void) printf(gettext("insufficient replicas")); 1231213197Smm break; 1232213197Smm 1233213197Smm case VDEV_AUX_VERSION_NEWER: 1234213197Smm (void) printf(gettext("newer version")); 1235213197Smm break; 1236213197Smm 1237213197Smm case VDEV_AUX_SPARED: 1238213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1239213197Smm &cb.cb_guid) == 0); 1240213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1241213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1242213197Smm zpool_get_name(zhp)) == 0) 1243213197Smm (void) printf(gettext("currently in " 1244213197Smm "use")); 1245213197Smm else 1246213197Smm (void) printf(gettext("in use by " 1247213197Smm "pool '%s'"), 1248213197Smm zpool_get_name(cb.cb_zhp)); 1249213197Smm zpool_close(cb.cb_zhp); 1250213197Smm } else { 1251213197Smm (void) printf(gettext("currently in use")); 1252213197Smm } 1253213197Smm break; 1254213197Smm 1255213197Smm case VDEV_AUX_ERR_EXCEEDED: 1256213197Smm (void) printf(gettext("too many errors")); 1257213197Smm break; 1258213197Smm 1259213197Smm case VDEV_AUX_IO_FAILURE: 1260213197Smm (void) printf(gettext("experienced I/O failures")); 1261213197Smm break; 1262213197Smm 1263213197Smm case VDEV_AUX_BAD_LOG: 1264213197Smm (void) printf(gettext("bad intent log")); 1265213197Smm break; 1266213197Smm 1267219089Spjd case VDEV_AUX_EXTERNAL: 1268219089Spjd (void) printf(gettext("external device fault")); 1269219089Spjd break; 1270219089Spjd 1271219089Spjd case VDEV_AUX_SPLIT_POOL: 1272219089Spjd (void) printf(gettext("split into new pool")); 1273219089Spjd break; 1274219089Spjd 1275213197Smm default: 1276213197Smm (void) printf(gettext("corrupted data")); 1277213197Smm break; 1278213197Smm } 1279213197Smm } 1280213197Smm 1281219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1282219089Spjd (uint64_t **)&ps, &c); 1283219089Spjd 1284219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1285219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1286219089Spjd (void) printf(gettext(" (%s)"), 1287219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1288219089Spjd "resilvering" : "repairing"); 1289219089Spjd } 1290219089Spjd 1291213197Smm (void) printf("\n"); 1292213197Smm 1293213197Smm for (c = 0; c < children; c++) { 1294219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1295213197Smm 1296219089Spjd /* Don't print logs or holes here */ 1297213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1298219089Spjd &islog); 1299219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1300219089Spjd &ishole); 1301219089Spjd if (islog || ishole) 1302213197Smm continue; 1303219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1304213197Smm print_status_config(zhp, vname, child[c], 1305213197Smm namewidth, depth + 2, isspare); 1306213197Smm free(vname); 1307213197Smm } 1308213197Smm} 1309213197Smm 1310213197Smm 1311213197Smm/* 1312168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1313168404Spjd * pool, printing out the name and status for each one. 1314168404Spjd */ 1315168404Spjdvoid 1316213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1317168404Spjd{ 1318168404Spjd nvlist_t **child; 1319168404Spjd uint_t c, children; 1320168404Spjd vdev_stat_t *vs; 1321168404Spjd char *type, *vname; 1322168404Spjd 1323168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1324219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1325219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1326168404Spjd return; 1327168404Spjd 1328219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1329168404Spjd (uint64_t **)&vs, &c) == 0); 1330168404Spjd 1331168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1332185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1333168404Spjd 1334168404Spjd if (vs->vs_aux != 0) { 1335185029Spjd (void) printf(" "); 1336168404Spjd 1337168404Spjd switch (vs->vs_aux) { 1338168404Spjd case VDEV_AUX_OPEN_FAILED: 1339168404Spjd (void) printf(gettext("cannot open")); 1340168404Spjd break; 1341168404Spjd 1342168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1343168404Spjd (void) printf(gettext("missing device")); 1344168404Spjd break; 1345168404Spjd 1346168404Spjd case VDEV_AUX_NO_REPLICAS: 1347168404Spjd (void) printf(gettext("insufficient replicas")); 1348168404Spjd break; 1349168404Spjd 1350168404Spjd case VDEV_AUX_VERSION_NEWER: 1351168404Spjd (void) printf(gettext("newer version")); 1352168404Spjd break; 1353168404Spjd 1354185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1355185029Spjd (void) printf(gettext("too many errors")); 1356185029Spjd break; 1357185029Spjd 1358168404Spjd default: 1359168404Spjd (void) printf(gettext("corrupted data")); 1360168404Spjd break; 1361168404Spjd } 1362168404Spjd } 1363168404Spjd (void) printf("\n"); 1364168404Spjd 1365168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1366168404Spjd &child, &children) != 0) 1367168404Spjd return; 1368168404Spjd 1369168404Spjd for (c = 0; c < children; c++) { 1370185029Spjd uint64_t is_log = B_FALSE; 1371185029Spjd 1372185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1373185029Spjd &is_log); 1374213197Smm if (is_log) 1375185029Spjd continue; 1376185029Spjd 1377219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1378213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1379168404Spjd free(vname); 1380168404Spjd } 1381168404Spjd 1382185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1383185029Spjd &child, &children) == 0) { 1384185029Spjd (void) printf(gettext("\tcache\n")); 1385185029Spjd for (c = 0; c < children; c++) { 1386219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1387185029Spjd (void) printf("\t %s\n", vname); 1388185029Spjd free(vname); 1389185029Spjd } 1390185029Spjd } 1391185029Spjd 1392168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1393185029Spjd &child, &children) == 0) { 1394185029Spjd (void) printf(gettext("\tspares\n")); 1395185029Spjd for (c = 0; c < children; c++) { 1396219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1397185029Spjd (void) printf("\t %s\n", vname); 1398185029Spjd free(vname); 1399185029Spjd } 1400168404Spjd } 1401168404Spjd} 1402168404Spjd 1403168404Spjd/* 1404213197Smm * Print log vdevs. 1405213197Smm * Logs are recorded as top level vdevs in the main pool child array 1406213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1407213197Smm * print_import_config() to print the top level logs then any log 1408213197Smm * children (eg mirrored slogs) are printed recursively - which 1409213197Smm * works because only the top level vdev is marked "is_log" 1410213197Smm */ 1411213197Smmstatic void 1412213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1413213197Smm{ 1414213197Smm uint_t c, children; 1415213197Smm nvlist_t **child; 1416213197Smm 1417213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1418213197Smm &children) != 0) 1419213197Smm return; 1420213197Smm 1421213197Smm (void) printf(gettext("\tlogs\n")); 1422213197Smm 1423213197Smm for (c = 0; c < children; c++) { 1424213197Smm uint64_t is_log = B_FALSE; 1425213197Smm char *name; 1426213197Smm 1427213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1428213197Smm &is_log); 1429213197Smm if (!is_log) 1430213197Smm continue; 1431219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1432213197Smm if (verbose) 1433213197Smm print_status_config(zhp, name, child[c], namewidth, 1434213197Smm 2, B_FALSE); 1435213197Smm else 1436213197Smm print_import_config(name, child[c], namewidth, 2); 1437213197Smm free(name); 1438213197Smm } 1439213197Smm} 1440219089Spjd 1441213197Smm/* 1442168404Spjd * Display the status for the given pool. 1443168404Spjd */ 1444168404Spjdstatic void 1445168404Spjdshow_import(nvlist_t *config) 1446168404Spjd{ 1447168404Spjd uint64_t pool_state; 1448168404Spjd vdev_stat_t *vs; 1449168404Spjd char *name; 1450168404Spjd uint64_t guid; 1451168404Spjd char *msgid; 1452168404Spjd nvlist_t *nvroot; 1453168404Spjd int reason; 1454168404Spjd const char *health; 1455168404Spjd uint_t vsc; 1456168404Spjd int namewidth; 1457168404Spjd 1458168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1459168404Spjd &name) == 0); 1460168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1461168404Spjd &guid) == 0); 1462168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1463168404Spjd &pool_state) == 0); 1464168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1465168404Spjd &nvroot) == 0); 1466168404Spjd 1467219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1468168404Spjd (uint64_t **)&vs, &vsc) == 0); 1469185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1470168404Spjd 1471168404Spjd reason = zpool_import_status(config, &msgid); 1472168404Spjd 1473168404Spjd (void) printf(gettext(" pool: %s\n"), name); 1474168404Spjd (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1475168404Spjd (void) printf(gettext(" state: %s"), health); 1476168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1477168404Spjd (void) printf(gettext(" (DESTROYED)")); 1478168404Spjd (void) printf("\n"); 1479168404Spjd 1480168404Spjd switch (reason) { 1481168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1482168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1483168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1484168404Spjd (void) printf(gettext("status: One or more devices are missing " 1485168404Spjd "from the system.\n")); 1486168404Spjd break; 1487168404Spjd 1488168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1489168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1490168404Spjd (void) printf(gettext("status: One or more devices contains " 1491168404Spjd "corrupted data.\n")); 1492168404Spjd break; 1493168404Spjd 1494168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1495168404Spjd (void) printf(gettext("status: The pool data is corrupted.\n")); 1496168404Spjd break; 1497168404Spjd 1498168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1499168404Spjd (void) printf(gettext("status: One or more devices " 1500168404Spjd "are offlined.\n")); 1501168404Spjd break; 1502168404Spjd 1503168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1504168404Spjd (void) printf(gettext("status: The pool metadata is " 1505168404Spjd "corrupted.\n")); 1506168404Spjd break; 1507168404Spjd 1508168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1509168404Spjd (void) printf(gettext("status: The pool is formatted using an " 1510168404Spjd "older on-disk version.\n")); 1511168404Spjd break; 1512168404Spjd 1513168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1514168404Spjd (void) printf(gettext("status: The pool is formatted using an " 1515168404Spjd "incompatible version.\n")); 1516168404Spjd break; 1517168404Spjd 1518168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1519168498Spjd (void) printf(gettext("status: The pool was last accessed by " 1520168498Spjd "another system.\n")); 1521168498Spjd break; 1522185029Spjd 1523185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1524185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1525185029Spjd (void) printf(gettext("status: One or more devices are " 1526185029Spjd "faulted.\n")); 1527185029Spjd break; 1528185029Spjd 1529185029Spjd case ZPOOL_STATUS_BAD_LOG: 1530185029Spjd (void) printf(gettext("status: An intent log record cannot be " 1531185029Spjd "read.\n")); 1532185029Spjd break; 1533185029Spjd 1534219089Spjd case ZPOOL_STATUS_RESILVERING: 1535219089Spjd (void) printf(gettext("status: One or more devices were being " 1536219089Spjd "resilvered.\n")); 1537219089Spjd break; 1538219089Spjd 1539168404Spjd default: 1540168404Spjd /* 1541168404Spjd * No other status can be seen when importing pools. 1542168404Spjd */ 1543168404Spjd assert(reason == ZPOOL_STATUS_OK); 1544168404Spjd } 1545168404Spjd 1546168404Spjd /* 1547168404Spjd * Print out an action according to the overall state of the pool. 1548168404Spjd */ 1549168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1550168404Spjd if (reason == ZPOOL_STATUS_VERSION_OLDER) 1551168404Spjd (void) printf(gettext("action: The pool can be " 1552168404Spjd "imported using its name or numeric identifier, " 1553168404Spjd "though\n\tsome features will not be available " 1554168404Spjd "without an explicit 'zpool upgrade'.\n")); 1555168498Spjd else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 1556168498Spjd (void) printf(gettext("action: The pool can be " 1557168498Spjd "imported using its name or numeric " 1558168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1559168404Spjd else 1560168404Spjd (void) printf(gettext("action: The pool can be " 1561168404Spjd "imported using its name or numeric " 1562168404Spjd "identifier.\n")); 1563168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1564168404Spjd (void) printf(gettext("action: The pool can be imported " 1565168404Spjd "despite missing or damaged devices. The\n\tfault " 1566168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1567168404Spjd } else { 1568168404Spjd switch (reason) { 1569168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1570168404Spjd (void) printf(gettext("action: The pool cannot be " 1571168404Spjd "imported. Access the pool on a system running " 1572168404Spjd "newer\n\tsoftware, or recreate the pool from " 1573168404Spjd "backup.\n")); 1574168404Spjd break; 1575168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1576168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1577168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1578168404Spjd (void) printf(gettext("action: The pool cannot be " 1579168404Spjd "imported. Attach the missing\n\tdevices and try " 1580168404Spjd "again.\n")); 1581168404Spjd break; 1582168404Spjd default: 1583168404Spjd (void) printf(gettext("action: The pool cannot be " 1584168404Spjd "imported due to damaged devices or data.\n")); 1585168404Spjd } 1586168404Spjd } 1587168404Spjd 1588168404Spjd /* 1589168404Spjd * If the state is "closed" or "can't open", and the aux state 1590168404Spjd * is "corrupt data": 1591168404Spjd */ 1592168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1593168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1594168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1595168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1596168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1597168404Spjd "but can be imported using the '-Df' flags.\n")); 1598168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1599168404Spjd (void) printf(gettext("\tThe pool may be active on " 1600185029Spjd "another system, but can be imported using\n\t" 1601168404Spjd "the '-f' flag.\n")); 1602168404Spjd } 1603168404Spjd 1604168404Spjd if (msgid != NULL) 1605168404Spjd (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1606168404Spjd msgid); 1607168404Spjd 1608168404Spjd (void) printf(gettext("config:\n\n")); 1609168404Spjd 1610168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1611168404Spjd if (namewidth < 10) 1612168404Spjd namewidth = 10; 1613168404Spjd 1614213197Smm print_import_config(name, nvroot, namewidth, 0); 1615213197Smm if (num_logs(nvroot) > 0) 1616213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1617185029Spjd 1618168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1619168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1620168404Spjd "be part of this pool, though their\n\texact " 1621168404Spjd "configuration cannot be determined.\n")); 1622168404Spjd } 1623168404Spjd} 1624168404Spjd 1625168404Spjd/* 1626168404Spjd * Perform the import for the given configuration. This passes the heavy 1627185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1628185029Spjd * within the pool. 1629168404Spjd */ 1630168404Spjdstatic int 1631168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1632219089Spjd nvlist_t *props, int flags) 1633168404Spjd{ 1634168404Spjd zpool_handle_t *zhp; 1635168404Spjd char *name; 1636168404Spjd uint64_t state; 1637168404Spjd uint64_t version; 1638168404Spjd 1639168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1640168404Spjd &name) == 0); 1641168404Spjd 1642168404Spjd verify(nvlist_lookup_uint64(config, 1643168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1644168404Spjd verify(nvlist_lookup_uint64(config, 1645168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1646185029Spjd if (version > SPA_VERSION) { 1647168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1648168404Spjd "is formatted using a newer ZFS version\n"), name); 1649168404Spjd return (1); 1650219089Spjd } else if (state != POOL_STATE_EXPORTED && 1651219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 1652168498Spjd uint64_t hostid; 1653168498Spjd 1654168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1655168498Spjd &hostid) == 0) { 1656168498Spjd if ((unsigned long)hostid != gethostid()) { 1657168498Spjd char *hostname; 1658168498Spjd uint64_t timestamp; 1659168498Spjd time_t t; 1660168498Spjd 1661168498Spjd verify(nvlist_lookup_string(config, 1662168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1663168498Spjd verify(nvlist_lookup_uint64(config, 1664168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1665168498Spjd t = timestamp; 1666168498Spjd (void) fprintf(stderr, gettext("cannot import " 1667168498Spjd "'%s': pool may be in use from other " 1668168498Spjd "system, it was last accessed by %s " 1669168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1670168498Spjd (unsigned long)hostid, 1671168498Spjd asctime(localtime(&t))); 1672168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1673168498Spjd "import anyway\n")); 1674168498Spjd return (1); 1675168498Spjd } 1676168498Spjd } else { 1677168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1678168498Spjd "pool may be in use from other system\n"), name); 1679168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1680168498Spjd "anyway\n")); 1681168498Spjd return (1); 1682168498Spjd } 1683168404Spjd } 1684168404Spjd 1685219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1686168404Spjd return (1); 1687168404Spjd 1688168404Spjd if (newname != NULL) 1689168404Spjd name = (char *)newname; 1690168404Spjd 1691209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 1692209962Smm return (1); 1693168404Spjd 1694209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1695219089Spjd !(flags & ZFS_IMPORT_ONLY) && 1696209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1697168404Spjd zpool_close(zhp); 1698168404Spjd return (1); 1699168404Spjd } 1700168404Spjd 1701168404Spjd zpool_close(zhp); 1702219089Spjd return (0); 1703168404Spjd} 1704168404Spjd 1705168404Spjd/* 1706168404Spjd * zpool import [-d dir] [-D] 1707185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1708185029Spjd * [-d dir | -c cachefile] [-f] -a 1709185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1710219089Spjd * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 1711168404Spjd * 1712185029Spjd * -c Read pool information from a cachefile instead of searching 1713185029Spjd * devices. 1714185029Spjd * 1715168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1716168404Spjd * one directory can be specified using multiple '-d' options. 1717168404Spjd * 1718168404Spjd * -D Scan for previously destroyed pools or import all or only 1719168404Spjd * specified destroyed pools. 1720168404Spjd * 1721168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1722168404Spjd * the given root. The pool will remain exported when the machine 1723168404Spjd * is rebooted. 1724168404Spjd * 1725219089Spjd * -V Import even in the presence of faulted vdevs. This is an 1726185029Spjd * intentionally undocumented option for testing purposes, and 1727185029Spjd * treats the pool configuration as complete, leaving any bad 1728209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 1729209962Smm * import. 1730185029Spjd * 1731219089Spjd * -f Force import, even if it appears that the pool is active. 1732219089Spjd * 1733219089Spjd * -F Attempt rewind if necessary. 1734219089Spjd * 1735219089Spjd * -n See if rewind would work, but don't actually rewind. 1736219089Spjd * 1737219089Spjd * -N Import the pool but don't mount datasets. 1738219089Spjd * 1739219089Spjd * -T Specify a starting txg to use for import. This option is 1740219089Spjd * intentionally undocumented option for testing purposes. 1741219089Spjd * 1742168404Spjd * -a Import all pools found. 1743168404Spjd * 1744185029Spjd * -o Set property=value and/or temporary mount options (without '='). 1745185029Spjd * 1746168404Spjd * The import command scans for pools to import, and import pools based on pool 1747168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 1748168404Spjd */ 1749168404Spjdint 1750168404Spjdzpool_do_import(int argc, char **argv) 1751168404Spjd{ 1752168404Spjd char **searchdirs = NULL; 1753168404Spjd int nsearch = 0; 1754168404Spjd int c; 1755219089Spjd int err = 0; 1756185029Spjd nvlist_t *pools = NULL; 1757168404Spjd boolean_t do_all = B_FALSE; 1758168404Spjd boolean_t do_destroyed = B_FALSE; 1759168404Spjd char *mntopts = NULL; 1760168404Spjd nvpair_t *elem; 1761168404Spjd nvlist_t *config; 1762185029Spjd uint64_t searchguid = 0; 1763185029Spjd char *searchname = NULL; 1764185029Spjd char *propval; 1765168404Spjd nvlist_t *found_config; 1766219089Spjd nvlist_t *policy = NULL; 1767185029Spjd nvlist_t *props = NULL; 1768168404Spjd boolean_t first; 1769219089Spjd int flags = ZFS_IMPORT_NORMAL; 1770219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 1771219089Spjd boolean_t dryrun = B_FALSE; 1772219089Spjd boolean_t do_rewind = B_FALSE; 1773219089Spjd boolean_t xtreme_rewind = B_FALSE; 1774219089Spjd uint64_t pool_state, txg = -1ULL; 1775185029Spjd char *cachefile = NULL; 1776219089Spjd importargs_t idata = { 0 }; 1777219089Spjd char *endptr; 1778168404Spjd 1779168404Spjd /* check options */ 1780219089Spjd while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) { 1781168404Spjd switch (c) { 1782168404Spjd case 'a': 1783168404Spjd do_all = B_TRUE; 1784168404Spjd break; 1785185029Spjd case 'c': 1786185029Spjd cachefile = optarg; 1787185029Spjd break; 1788168404Spjd case 'd': 1789168404Spjd if (searchdirs == NULL) { 1790168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1791168404Spjd } else { 1792168404Spjd char **tmp = safe_malloc((nsearch + 1) * 1793168404Spjd sizeof (char *)); 1794168404Spjd bcopy(searchdirs, tmp, nsearch * 1795168404Spjd sizeof (char *)); 1796168404Spjd free(searchdirs); 1797168404Spjd searchdirs = tmp; 1798168404Spjd } 1799168404Spjd searchdirs[nsearch++] = optarg; 1800168404Spjd break; 1801168404Spjd case 'D': 1802168404Spjd do_destroyed = B_TRUE; 1803168404Spjd break; 1804168404Spjd case 'f': 1805219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 1806168404Spjd break; 1807185029Spjd case 'F': 1808219089Spjd do_rewind = B_TRUE; 1809185029Spjd break; 1810219089Spjd case 'm': 1811219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 1812219089Spjd break; 1813219089Spjd case 'n': 1814219089Spjd dryrun = B_TRUE; 1815219089Spjd break; 1816219089Spjd case 'N': 1817219089Spjd flags |= ZFS_IMPORT_ONLY; 1818219089Spjd break; 1819168404Spjd case 'o': 1820185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 1821185029Spjd *propval = '\0'; 1822185029Spjd propval++; 1823185029Spjd if (add_prop_list(optarg, propval, 1824185029Spjd &props, B_TRUE)) 1825185029Spjd goto error; 1826185029Spjd } else { 1827185029Spjd mntopts = optarg; 1828185029Spjd } 1829168404Spjd break; 1830168404Spjd case 'R': 1831185029Spjd if (add_prop_list(zpool_prop_to_name( 1832185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 1833185029Spjd goto error; 1834185029Spjd if (nvlist_lookup_string(props, 1835185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 1836185029Spjd &propval) == 0) 1837185029Spjd break; 1838185029Spjd if (add_prop_list(zpool_prop_to_name( 1839185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1840185029Spjd goto error; 1841168404Spjd break; 1842219089Spjd case 'T': 1843219089Spjd errno = 0; 1844219089Spjd txg = strtoull(optarg, &endptr, 10); 1845219089Spjd if (errno != 0 || *endptr != '\0') { 1846219089Spjd (void) fprintf(stderr, 1847219089Spjd gettext("invalid txg value\n")); 1848219089Spjd usage(B_FALSE); 1849219089Spjd } 1850219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 1851219089Spjd break; 1852219089Spjd case 'V': 1853219089Spjd flags |= ZFS_IMPORT_VERBATIM; 1854219089Spjd break; 1855219089Spjd case 'X': 1856219089Spjd xtreme_rewind = B_TRUE; 1857219089Spjd break; 1858168404Spjd case ':': 1859168404Spjd (void) fprintf(stderr, gettext("missing argument for " 1860168404Spjd "'%c' option\n"), optopt); 1861168404Spjd usage(B_FALSE); 1862168404Spjd break; 1863168404Spjd case '?': 1864168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1865168404Spjd optopt); 1866168404Spjd usage(B_FALSE); 1867168404Spjd } 1868168404Spjd } 1869168404Spjd 1870168404Spjd argc -= optind; 1871168404Spjd argv += optind; 1872168404Spjd 1873185029Spjd if (cachefile && nsearch != 0) { 1874185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 1875185029Spjd usage(B_FALSE); 1876185029Spjd } 1877185029Spjd 1878219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 1879219089Spjd (void) fprintf(stderr, 1880219089Spjd gettext("-n or -X only meaningful with -F\n")); 1881219089Spjd usage(B_FALSE); 1882219089Spjd } 1883219089Spjd if (dryrun) 1884219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 1885219089Spjd else if (do_rewind) 1886219089Spjd rewind_policy = ZPOOL_DO_REWIND; 1887219089Spjd if (xtreme_rewind) 1888219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 1889219089Spjd 1890219089Spjd /* In the future, we can capture further policy and include it here */ 1891219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 1892219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 1893219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 1894219089Spjd goto error; 1895219089Spjd 1896168404Spjd if (searchdirs == NULL) { 1897168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1898185029Spjd searchdirs[0] = "/dev/dsk"; 1899168404Spjd nsearch = 1; 1900168404Spjd } 1901168404Spjd 1902168404Spjd /* check argument count */ 1903168404Spjd if (do_all) { 1904168404Spjd if (argc != 0) { 1905168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1906168404Spjd usage(B_FALSE); 1907168404Spjd } 1908168404Spjd } else { 1909168404Spjd if (argc > 2) { 1910168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1911168404Spjd usage(B_FALSE); 1912168404Spjd } 1913168404Spjd 1914168404Spjd /* 1915168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 1916168404Spjd * here because otherwise any attempt to discover pools will 1917168404Spjd * silently fail. 1918168404Spjd */ 1919168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1920168404Spjd (void) fprintf(stderr, gettext("cannot " 1921168404Spjd "discover pools: permission denied\n")); 1922168404Spjd free(searchdirs); 1923219089Spjd nvlist_free(policy); 1924168404Spjd return (1); 1925168404Spjd } 1926168404Spjd } 1927168404Spjd 1928168404Spjd /* 1929168404Spjd * Depending on the arguments given, we do one of the following: 1930168404Spjd * 1931168404Spjd * <none> Iterate through all pools and display information about 1932168404Spjd * each one. 1933168404Spjd * 1934168404Spjd * -a Iterate through all pools and try to import each one. 1935168404Spjd * 1936168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 1937168404Spjd * name and import that one. 1938168404Spjd * 1939168404Spjd * -D Above options applies only to destroyed pools. 1940168404Spjd */ 1941168404Spjd if (argc != 0) { 1942168404Spjd char *endptr; 1943168404Spjd 1944168404Spjd errno = 0; 1945168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 1946168404Spjd if (errno != 0 || *endptr != '\0') 1947168404Spjd searchname = argv[0]; 1948168404Spjd found_config = NULL; 1949168404Spjd 1950185029Spjd /* 1951219089Spjd * User specified a name or guid. Ensure it's unique. 1952185029Spjd */ 1953219089Spjd idata.unique = B_TRUE; 1954185029Spjd } 1955185029Spjd 1956219089Spjd 1957219089Spjd idata.path = searchdirs; 1958219089Spjd idata.paths = nsearch; 1959219089Spjd idata.poolname = searchname; 1960219089Spjd idata.guid = searchguid; 1961219089Spjd idata.cachefile = cachefile; 1962219089Spjd 1963219089Spjd pools = zpool_search_import(g_zfs, &idata); 1964219089Spjd 1965219089Spjd if (pools != NULL && idata.exists && 1966219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 1967219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1968219089Spjd "a pool with that name already exists\n"), 1969219089Spjd argv[0]); 1970219089Spjd (void) fprintf(stderr, gettext("use the form '%s " 1971219089Spjd "<pool | id> <newpool>' to give it a new name\n"), 1972219089Spjd "zpool import"); 1973219089Spjd err = 1; 1974219089Spjd } else if (pools == NULL && idata.exists) { 1975219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1976219089Spjd "a pool with that name is already created/imported,\n"), 1977219089Spjd argv[0]); 1978219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 1979219089Spjd "with that name were found\n")); 1980219089Spjd err = 1; 1981219089Spjd } else if (pools == NULL) { 1982185029Spjd if (argc != 0) { 1983185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1984185029Spjd "no such pool available\n"), argv[0]); 1985185029Spjd } 1986219089Spjd err = 1; 1987219089Spjd } 1988219089Spjd 1989219089Spjd if (err == 1) { 1990185029Spjd free(searchdirs); 1991219089Spjd nvlist_free(policy); 1992185029Spjd return (1); 1993185029Spjd } 1994185029Spjd 1995185029Spjd /* 1996185029Spjd * At this point we have a list of import candidate configs. Even if 1997185029Spjd * we were searching by pool name or guid, we still need to 1998185029Spjd * post-process the list to deal with pool state and possible 1999185029Spjd * duplicate names. 2000185029Spjd */ 2001168404Spjd err = 0; 2002168404Spjd elem = NULL; 2003168404Spjd first = B_TRUE; 2004168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2005168404Spjd 2006168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2007168404Spjd 2008168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2009168404Spjd &pool_state) == 0); 2010168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2011168404Spjd continue; 2012168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2013168404Spjd continue; 2014168404Spjd 2015219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2016219089Spjd policy) == 0); 2017219089Spjd 2018168404Spjd if (argc == 0) { 2019168404Spjd if (first) 2020168404Spjd first = B_FALSE; 2021168404Spjd else if (!do_all) 2022168404Spjd (void) printf("\n"); 2023168404Spjd 2024219089Spjd if (do_all) { 2025168404Spjd err |= do_import(config, NULL, mntopts, 2026219089Spjd props, flags); 2027219089Spjd } else { 2028168404Spjd show_import(config); 2029219089Spjd } 2030168404Spjd } else if (searchname != NULL) { 2031168404Spjd char *name; 2032168404Spjd 2033168404Spjd /* 2034168404Spjd * We are searching for a pool based on name. 2035168404Spjd */ 2036168404Spjd verify(nvlist_lookup_string(config, 2037168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2038168404Spjd 2039168404Spjd if (strcmp(name, searchname) == 0) { 2040168404Spjd if (found_config != NULL) { 2041168404Spjd (void) fprintf(stderr, gettext( 2042168404Spjd "cannot import '%s': more than " 2043168404Spjd "one matching pool\n"), searchname); 2044168404Spjd (void) fprintf(stderr, gettext( 2045168404Spjd "import by numeric ID instead\n")); 2046168404Spjd err = B_TRUE; 2047168404Spjd } 2048168404Spjd found_config = config; 2049168404Spjd } 2050168404Spjd } else { 2051168404Spjd uint64_t guid; 2052168404Spjd 2053168404Spjd /* 2054168404Spjd * Search for a pool by guid. 2055168404Spjd */ 2056168404Spjd verify(nvlist_lookup_uint64(config, 2057168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2058168404Spjd 2059168404Spjd if (guid == searchguid) 2060168404Spjd found_config = config; 2061168404Spjd } 2062168404Spjd } 2063168404Spjd 2064168404Spjd /* 2065168404Spjd * If we were searching for a specific pool, verify that we found a 2066168404Spjd * pool, and then do the import. 2067168404Spjd */ 2068168404Spjd if (argc != 0 && err == 0) { 2069168404Spjd if (found_config == NULL) { 2070168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2071168404Spjd "no such pool available\n"), argv[0]); 2072168404Spjd err = B_TRUE; 2073168404Spjd } else { 2074168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2075219089Spjd argv[1], mntopts, props, flags); 2076168404Spjd } 2077168404Spjd } 2078168404Spjd 2079168404Spjd /* 2080168404Spjd * If we were just looking for pools, report an error if none were 2081168404Spjd * found. 2082168404Spjd */ 2083168404Spjd if (argc == 0 && first) 2084168404Spjd (void) fprintf(stderr, 2085168404Spjd gettext("no pools available to import\n")); 2086168404Spjd 2087185029Spjderror: 2088185029Spjd nvlist_free(props); 2089168404Spjd nvlist_free(pools); 2090219089Spjd nvlist_free(policy); 2091168404Spjd free(searchdirs); 2092168404Spjd 2093168404Spjd return (err ? 1 : 0); 2094168404Spjd} 2095168404Spjd 2096168404Spjdtypedef struct iostat_cbdata { 2097168404Spjd zpool_list_t *cb_list; 2098168404Spjd int cb_verbose; 2099168404Spjd int cb_iteration; 2100168404Spjd int cb_namewidth; 2101168404Spjd} iostat_cbdata_t; 2102168404Spjd 2103168404Spjdstatic void 2104168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2105168404Spjd{ 2106168404Spjd int i = 0; 2107168404Spjd 2108168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2109168404Spjd (void) printf("-"); 2110168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2111168404Spjd} 2112168404Spjd 2113168404Spjdstatic void 2114168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2115168404Spjd{ 2116168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2117168404Spjd cb->cb_namewidth, ""); 2118219089Spjd (void) printf("%-*s alloc free read write read write\n", 2119168404Spjd cb->cb_namewidth, "pool"); 2120168404Spjd print_iostat_separator(cb); 2121168404Spjd} 2122168404Spjd 2123168404Spjd/* 2124168404Spjd * Display a single statistic. 2125168404Spjd */ 2126185029Spjdstatic void 2127168404Spjdprint_one_stat(uint64_t value) 2128168404Spjd{ 2129168404Spjd char buf[64]; 2130168404Spjd 2131168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2132168404Spjd (void) printf(" %5s", buf); 2133168404Spjd} 2134168404Spjd 2135168404Spjd/* 2136168404Spjd * Print out all the statistics for the given vdev. This can either be the 2137168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2138168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2139168404Spjd */ 2140168404Spjdvoid 2141168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2142168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2143168404Spjd{ 2144168404Spjd nvlist_t **oldchild, **newchild; 2145168404Spjd uint_t c, children; 2146168404Spjd vdev_stat_t *oldvs, *newvs; 2147168404Spjd vdev_stat_t zerovs = { 0 }; 2148168404Spjd uint64_t tdelta; 2149168404Spjd double scale; 2150168404Spjd char *vname; 2151168404Spjd 2152168404Spjd if (oldnv != NULL) { 2153219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2154219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2155168404Spjd } else { 2156168404Spjd oldvs = &zerovs; 2157168404Spjd } 2158168404Spjd 2159219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2160168404Spjd (uint64_t **)&newvs, &c) == 0); 2161168404Spjd 2162168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2163168404Spjd (void) printf("%*s%s", depth, "", name); 2164168404Spjd else 2165168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2166168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2167168404Spjd 2168168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2169168404Spjd 2170168404Spjd if (tdelta == 0) 2171168404Spjd scale = 1.0; 2172168404Spjd else 2173168404Spjd scale = (double)NANOSEC / tdelta; 2174168404Spjd 2175168404Spjd /* only toplevel vdevs have capacity stats */ 2176168404Spjd if (newvs->vs_space == 0) { 2177168404Spjd (void) printf(" - -"); 2178168404Spjd } else { 2179168404Spjd print_one_stat(newvs->vs_alloc); 2180168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2181168404Spjd } 2182168404Spjd 2183168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2184168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2185168404Spjd 2186168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2187168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2188168404Spjd 2189168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2190168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2191168404Spjd 2192168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2193168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2194168404Spjd 2195168404Spjd (void) printf("\n"); 2196168404Spjd 2197168404Spjd if (!cb->cb_verbose) 2198168404Spjd return; 2199168404Spjd 2200168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2201168404Spjd &newchild, &children) != 0) 2202168404Spjd return; 2203168404Spjd 2204168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2205168404Spjd &oldchild, &c) != 0) 2206168404Spjd return; 2207168404Spjd 2208168404Spjd for (c = 0; c < children; c++) { 2209227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2210219089Spjd 2211227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2212227497Smm &ishole); 2213227497Smm 2214227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2215227497Smm &islog); 2216227497Smm 2217227497Smm if (ishole || islog) 2218219089Spjd continue; 2219219089Spjd 2220219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2221168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2222168404Spjd newchild[c], cb, depth + 2); 2223168404Spjd free(vname); 2224168404Spjd } 2225185029Spjd 2226185029Spjd /* 2227227497Smm * Log device section 2228227497Smm */ 2229227497Smm 2230227497Smm if (num_logs(newnv) > 0) { 2231227497Smm (void) printf("%-*s - - - - - " 2232227497Smm "-\n", cb->cb_namewidth, "logs"); 2233227497Smm 2234227497Smm for (c = 0; c < children; c++) { 2235227497Smm uint64_t islog = B_FALSE; 2236227497Smm (void) nvlist_lookup_uint64(newchild[c], 2237227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2238227497Smm 2239227497Smm if (islog) { 2240227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2241227497Smm B_FALSE); 2242227497Smm print_vdev_stats(zhp, vname, oldnv ? 2243227497Smm oldchild[c] : NULL, newchild[c], 2244227497Smm cb, depth + 2); 2245227497Smm free(vname); 2246227497Smm } 2247227497Smm } 2248227497Smm 2249227497Smm } 2250227497Smm 2251227497Smm /* 2252185029Spjd * Include level 2 ARC devices in iostat output 2253185029Spjd */ 2254185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2255185029Spjd &newchild, &children) != 0) 2256185029Spjd return; 2257185029Spjd 2258185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2259185029Spjd &oldchild, &c) != 0) 2260185029Spjd return; 2261185029Spjd 2262185029Spjd if (children > 0) { 2263185029Spjd (void) printf("%-*s - - - - - " 2264185029Spjd "-\n", cb->cb_namewidth, "cache"); 2265185029Spjd for (c = 0; c < children; c++) { 2266219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2267219089Spjd B_FALSE); 2268185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2269185029Spjd newchild[c], cb, depth + 2); 2270185029Spjd free(vname); 2271185029Spjd } 2272185029Spjd } 2273168404Spjd} 2274168404Spjd 2275168404Spjdstatic int 2276168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2277168404Spjd{ 2278168404Spjd iostat_cbdata_t *cb = data; 2279168404Spjd boolean_t missing; 2280168404Spjd 2281168404Spjd /* 2282168404Spjd * If the pool has disappeared, remove it from the list and continue. 2283168404Spjd */ 2284168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2285168404Spjd return (-1); 2286168404Spjd 2287168404Spjd if (missing) 2288168404Spjd pool_list_remove(cb->cb_list, zhp); 2289168404Spjd 2290168404Spjd return (0); 2291168404Spjd} 2292168404Spjd 2293168404Spjd/* 2294168404Spjd * Callback to print out the iostats for the given pool. 2295168404Spjd */ 2296168404Spjdint 2297168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2298168404Spjd{ 2299168404Spjd iostat_cbdata_t *cb = data; 2300168404Spjd nvlist_t *oldconfig, *newconfig; 2301168404Spjd nvlist_t *oldnvroot, *newnvroot; 2302168404Spjd 2303168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2304168404Spjd 2305168404Spjd if (cb->cb_iteration == 1) 2306168404Spjd oldconfig = NULL; 2307168404Spjd 2308168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2309168404Spjd &newnvroot) == 0); 2310168404Spjd 2311168404Spjd if (oldconfig == NULL) 2312168404Spjd oldnvroot = NULL; 2313168404Spjd else 2314168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2315168404Spjd &oldnvroot) == 0); 2316168404Spjd 2317168404Spjd /* 2318168404Spjd * Print out the statistics for the pool. 2319168404Spjd */ 2320168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2321168404Spjd 2322168404Spjd if (cb->cb_verbose) 2323168404Spjd print_iostat_separator(cb); 2324168404Spjd 2325168404Spjd return (0); 2326168404Spjd} 2327168404Spjd 2328168404Spjdint 2329168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2330168404Spjd{ 2331168404Spjd iostat_cbdata_t *cb = data; 2332168404Spjd nvlist_t *config, *nvroot; 2333168404Spjd 2334168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2335168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2336168404Spjd &nvroot) == 0); 2337168404Spjd if (!cb->cb_verbose) 2338168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2339168404Spjd else 2340168404Spjd cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 2341168404Spjd } 2342168404Spjd 2343168404Spjd /* 2344168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2345168404Spjd * maximum we can have and still fit in 80 columns. 2346168404Spjd */ 2347168404Spjd if (cb->cb_namewidth < 10) 2348168404Spjd cb->cb_namewidth = 10; 2349168404Spjd if (cb->cb_namewidth > 38) 2350168404Spjd cb->cb_namewidth = 38; 2351168404Spjd 2352168404Spjd return (0); 2353168404Spjd} 2354168404Spjd 2355168404Spjd/* 2356219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2357168404Spjd */ 2358219089Spjdstatic void 2359219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2360219089Spjd unsigned long *cnt) 2361168404Spjd{ 2362168404Spjd unsigned long interval = 0, count = 0; 2363219089Spjd int argc = *argcp, errno; 2364168404Spjd 2365168404Spjd /* 2366168404Spjd * Determine if the last argument is an integer or a pool name 2367168404Spjd */ 2368168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2369168404Spjd char *end; 2370168404Spjd 2371168404Spjd errno = 0; 2372168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2373168404Spjd 2374168404Spjd if (*end == '\0' && errno == 0) { 2375168404Spjd if (interval == 0) { 2376168404Spjd (void) fprintf(stderr, gettext("interval " 2377168404Spjd "cannot be zero\n")); 2378168404Spjd usage(B_FALSE); 2379168404Spjd } 2380168404Spjd /* 2381168404Spjd * Ignore the last parameter 2382168404Spjd */ 2383168404Spjd argc--; 2384168404Spjd } else { 2385168404Spjd /* 2386168404Spjd * If this is not a valid number, just plow on. The 2387168404Spjd * user will get a more informative error message later 2388168404Spjd * on. 2389168404Spjd */ 2390168404Spjd interval = 0; 2391168404Spjd } 2392168404Spjd } 2393168404Spjd 2394168404Spjd /* 2395168404Spjd * If the last argument is also an integer, then we have both a count 2396219089Spjd * and an interval. 2397168404Spjd */ 2398168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2399168404Spjd char *end; 2400168404Spjd 2401168404Spjd errno = 0; 2402168404Spjd count = interval; 2403168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2404168404Spjd 2405168404Spjd if (*end == '\0' && errno == 0) { 2406168404Spjd if (interval == 0) { 2407168404Spjd (void) fprintf(stderr, gettext("interval " 2408168404Spjd "cannot be zero\n")); 2409168404Spjd usage(B_FALSE); 2410168404Spjd } 2411168404Spjd 2412168404Spjd /* 2413168404Spjd * Ignore the last parameter 2414168404Spjd */ 2415168404Spjd argc--; 2416168404Spjd } else { 2417168404Spjd interval = 0; 2418168404Spjd } 2419168404Spjd } 2420168404Spjd 2421219089Spjd *iv = interval; 2422219089Spjd *cnt = count; 2423219089Spjd *argcp = argc; 2424219089Spjd} 2425219089Spjd 2426219089Spjdstatic void 2427219089Spjdget_timestamp_arg(char c) 2428219089Spjd{ 2429219089Spjd if (c == 'u') 2430219089Spjd timestamp_fmt = UDATE; 2431219089Spjd else if (c == 'd') 2432219089Spjd timestamp_fmt = DDATE; 2433219089Spjd else 2434219089Spjd usage(B_FALSE); 2435219089Spjd} 2436219089Spjd 2437219089Spjd/* 2438219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2439219089Spjd * 2440219089Spjd * -v Display statistics for individual vdevs 2441219089Spjd * -T Display a timestamp in date(1) or Unix format 2442219089Spjd * 2443219089Spjd * This command can be tricky because we want to be able to deal with pool 2444219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2445219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2446219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2447219089Spjd * changes are all handled within libzfs. 2448219089Spjd */ 2449219089Spjdint 2450219089Spjdzpool_do_iostat(int argc, char **argv) 2451219089Spjd{ 2452219089Spjd int c; 2453219089Spjd int ret; 2454219089Spjd int npools; 2455219089Spjd unsigned long interval = 0, count = 0; 2456219089Spjd zpool_list_t *list; 2457219089Spjd boolean_t verbose = B_FALSE; 2458219089Spjd iostat_cbdata_t cb; 2459219089Spjd 2460219089Spjd /* check options */ 2461219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2462219089Spjd switch (c) { 2463219089Spjd case 'T': 2464219089Spjd get_timestamp_arg(*optarg); 2465219089Spjd break; 2466219089Spjd case 'v': 2467219089Spjd verbose = B_TRUE; 2468219089Spjd break; 2469219089Spjd case '?': 2470219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2471219089Spjd optopt); 2472219089Spjd usage(B_FALSE); 2473219089Spjd } 2474219089Spjd } 2475219089Spjd 2476219089Spjd argc -= optind; 2477219089Spjd argv += optind; 2478219089Spjd 2479219089Spjd get_interval_count(&argc, argv, &interval, &count); 2480219089Spjd 2481168404Spjd /* 2482168404Spjd * Construct the list of all interesting pools. 2483168404Spjd */ 2484168404Spjd ret = 0; 2485168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2486168404Spjd return (1); 2487168404Spjd 2488168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2489168404Spjd pool_list_free(list); 2490168404Spjd return (1); 2491168404Spjd } 2492168404Spjd 2493168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2494168404Spjd pool_list_free(list); 2495168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2496168404Spjd return (1); 2497168404Spjd } 2498168404Spjd 2499168404Spjd /* 2500168404Spjd * Enter the main iostat loop. 2501168404Spjd */ 2502168404Spjd cb.cb_list = list; 2503168404Spjd cb.cb_verbose = verbose; 2504168404Spjd cb.cb_iteration = 0; 2505168404Spjd cb.cb_namewidth = 0; 2506168404Spjd 2507168404Spjd for (;;) { 2508168404Spjd pool_list_update(list); 2509168404Spjd 2510168404Spjd if ((npools = pool_list_count(list)) == 0) 2511168404Spjd break; 2512168404Spjd 2513168404Spjd /* 2514168404Spjd * Refresh all statistics. This is done as an explicit step 2515168404Spjd * before calculating the maximum name width, so that any 2516168404Spjd * configuration changes are properly accounted for. 2517168404Spjd */ 2518168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2519168404Spjd 2520168404Spjd /* 2521168404Spjd * Iterate over all pools to determine the maximum width 2522168404Spjd * for the pool / device name column across all pools. 2523168404Spjd */ 2524168404Spjd cb.cb_namewidth = 0; 2525168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2526168404Spjd 2527219089Spjd if (timestamp_fmt != NODATE) 2528219089Spjd print_timestamp(timestamp_fmt); 2529219089Spjd 2530168404Spjd /* 2531168404Spjd * If it's the first time, or verbose mode, print the header. 2532168404Spjd */ 2533168404Spjd if (++cb.cb_iteration == 1 || verbose) 2534168404Spjd print_iostat_header(&cb); 2535168404Spjd 2536168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2537168404Spjd 2538168404Spjd /* 2539168404Spjd * If there's more than one pool, and we're not in verbose mode 2540168404Spjd * (which prints a separator for us), then print a separator. 2541168404Spjd */ 2542168404Spjd if (npools > 1 && !verbose) 2543168404Spjd print_iostat_separator(&cb); 2544168404Spjd 2545168404Spjd if (verbose) 2546168404Spjd (void) printf("\n"); 2547168404Spjd 2548168404Spjd /* 2549168404Spjd * Flush the output so that redirection to a file isn't buffered 2550168404Spjd * indefinitely. 2551168404Spjd */ 2552168404Spjd (void) fflush(stdout); 2553168404Spjd 2554168404Spjd if (interval == 0) 2555168404Spjd break; 2556168404Spjd 2557168404Spjd if (count != 0 && --count == 0) 2558168404Spjd break; 2559168404Spjd 2560168404Spjd (void) sleep(interval); 2561168404Spjd } 2562168404Spjd 2563168404Spjd pool_list_free(list); 2564168404Spjd 2565168404Spjd return (ret); 2566168404Spjd} 2567168404Spjd 2568168404Spjdtypedef struct list_cbdata { 2569168404Spjd boolean_t cb_scripted; 2570168404Spjd boolean_t cb_first; 2571185029Spjd zprop_list_t *cb_proplist; 2572168404Spjd} list_cbdata_t; 2573168404Spjd 2574168404Spjd/* 2575168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2576168404Spjd */ 2577185029Spjdstatic void 2578185029Spjdprint_header(zprop_list_t *pl) 2579168404Spjd{ 2580185029Spjd const char *header; 2581185029Spjd boolean_t first = B_TRUE; 2582185029Spjd boolean_t right_justify; 2583168404Spjd 2584185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2585185029Spjd if (pl->pl_prop == ZPROP_INVAL) 2586185029Spjd continue; 2587185029Spjd 2588185029Spjd if (!first) 2589168404Spjd (void) printf(" "); 2590168404Spjd else 2591185029Spjd first = B_FALSE; 2592168404Spjd 2593185029Spjd header = zpool_prop_column_name(pl->pl_prop); 2594185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2595185029Spjd 2596185029Spjd if (pl->pl_next == NULL && !right_justify) 2597185029Spjd (void) printf("%s", header); 2598185029Spjd else if (right_justify) 2599185029Spjd (void) printf("%*s", pl->pl_width, header); 2600185029Spjd else 2601185029Spjd (void) printf("%-*s", pl->pl_width, header); 2602168404Spjd } 2603168404Spjd 2604168404Spjd (void) printf("\n"); 2605168404Spjd} 2606168404Spjd 2607185029Spjd/* 2608185029Spjd * Given a pool and a list of properties, print out all the properties according 2609185029Spjd * to the described layout. 2610185029Spjd */ 2611185029Spjdstatic void 2612185029Spjdprint_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 2613168404Spjd{ 2614185029Spjd boolean_t first = B_TRUE; 2615185029Spjd char property[ZPOOL_MAXPROPLEN]; 2616185029Spjd char *propstr; 2617185029Spjd boolean_t right_justify; 2618185029Spjd int width; 2619168404Spjd 2620185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2621185029Spjd if (!first) { 2622185029Spjd if (scripted) 2623168404Spjd (void) printf("\t"); 2624168404Spjd else 2625168404Spjd (void) printf(" "); 2626185029Spjd } else { 2627185029Spjd first = B_FALSE; 2628168404Spjd } 2629168404Spjd 2630185029Spjd right_justify = B_FALSE; 2631185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2632185029Spjd if (zpool_get_prop(zhp, pl->pl_prop, property, 2633185029Spjd sizeof (property), NULL) != 0) 2634185029Spjd propstr = "-"; 2635168404Spjd else 2636185029Spjd propstr = property; 2637168404Spjd 2638185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2639185029Spjd } else { 2640185029Spjd propstr = "-"; 2641185029Spjd } 2642168404Spjd 2643185029Spjd width = pl->pl_width; 2644168404Spjd 2645185029Spjd /* 2646185029Spjd * If this is being called in scripted mode, or if this is the 2647185029Spjd * last column and it is left-justified, don't include a width 2648185029Spjd * format specifier. 2649185029Spjd */ 2650185029Spjd if (scripted || (pl->pl_next == NULL && !right_justify)) 2651185029Spjd (void) printf("%s", propstr); 2652185029Spjd else if (right_justify) 2653185029Spjd (void) printf("%*s", width, propstr); 2654185029Spjd else 2655185029Spjd (void) printf("%-*s", width, propstr); 2656185029Spjd } 2657168404Spjd 2658185029Spjd (void) printf("\n"); 2659185029Spjd} 2660168404Spjd 2661185029Spjd/* 2662185029Spjd * Generic callback function to list a pool. 2663185029Spjd */ 2664185029Spjdint 2665185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 2666185029Spjd{ 2667185029Spjd list_cbdata_t *cbp = data; 2668168404Spjd 2669185029Spjd if (cbp->cb_first) { 2670185029Spjd if (!cbp->cb_scripted) 2671185029Spjd print_header(cbp->cb_proplist); 2672185029Spjd cbp->cb_first = B_FALSE; 2673168404Spjd } 2674168404Spjd 2675185029Spjd print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2676168404Spjd 2677168404Spjd return (0); 2678168404Spjd} 2679168404Spjd 2680168404Spjd/* 2681219089Spjd * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 2682168404Spjd * 2683185029Spjd * -H Scripted mode. Don't display headers, and separate properties 2684185029Spjd * by a single tab. 2685185029Spjd * -o List of properties to display. Defaults to 2686219089Spjd * "name,size,allocated,free,capacity,health,altroot" 2687219089Spjd * -T Display a timestamp in date(1) or Unix format 2688168404Spjd * 2689168404Spjd * List all pools in the system, whether or not they're healthy. Output space 2690168404Spjd * statistics for each one, as well as health status summary. 2691168404Spjd */ 2692168404Spjdint 2693168404Spjdzpool_do_list(int argc, char **argv) 2694168404Spjd{ 2695168404Spjd int c; 2696168404Spjd int ret; 2697168404Spjd list_cbdata_t cb = { 0 }; 2698185029Spjd static char default_props[] = 2699219089Spjd "name,size,allocated,free,capacity,dedupratio,health,altroot"; 2700185029Spjd char *props = default_props; 2701219089Spjd unsigned long interval = 0, count = 0; 2702168404Spjd 2703168404Spjd /* check options */ 2704219089Spjd while ((c = getopt(argc, argv, ":Ho:T:")) != -1) { 2705168404Spjd switch (c) { 2706168404Spjd case 'H': 2707168404Spjd cb.cb_scripted = B_TRUE; 2708168404Spjd break; 2709168404Spjd case 'o': 2710185029Spjd props = optarg; 2711168404Spjd break; 2712219089Spjd case 'T': 2713219089Spjd get_timestamp_arg(*optarg); 2714219089Spjd break; 2715168404Spjd case ':': 2716168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2717168404Spjd "'%c' option\n"), optopt); 2718168404Spjd usage(B_FALSE); 2719168404Spjd break; 2720168404Spjd case '?': 2721168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2722168404Spjd optopt); 2723168404Spjd usage(B_FALSE); 2724168404Spjd } 2725168404Spjd } 2726168404Spjd 2727168404Spjd argc -= optind; 2728168404Spjd argv += optind; 2729168404Spjd 2730219089Spjd get_interval_count(&argc, argv, &interval, &count); 2731219089Spjd 2732185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 2733185029Spjd usage(B_FALSE); 2734168404Spjd 2735185029Spjd cb.cb_first = B_TRUE; 2736168404Spjd 2737219089Spjd for (;;) { 2738168404Spjd 2739219089Spjd if (timestamp_fmt != NODATE) 2740219089Spjd print_timestamp(timestamp_fmt); 2741168404Spjd 2742219089Spjd ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2743219089Spjd list_callback, &cb); 2744219089Spjd 2745219089Spjd if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2746219089Spjd (void) printf(gettext("no pools available\n")); 2747219089Spjd zprop_free_list(cb.cb_proplist); 2748219089Spjd return (0); 2749219089Spjd } 2750219089Spjd 2751219089Spjd if (interval == 0) 2752219089Spjd break; 2753219089Spjd 2754219089Spjd if (count != 0 && --count == 0) 2755219089Spjd break; 2756219089Spjd 2757219089Spjd (void) sleep(interval); 2758168404Spjd } 2759168404Spjd 2760219089Spjd zprop_free_list(cb.cb_proplist); 2761168404Spjd return (ret); 2762168404Spjd} 2763168404Spjd 2764168404Spjdstatic nvlist_t * 2765168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name) 2766168404Spjd{ 2767168404Spjd nvlist_t **child; 2768168404Spjd uint_t c, children; 2769168404Spjd nvlist_t *match; 2770168404Spjd char *path; 2771168404Spjd 2772168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2773168404Spjd &child, &children) != 0) { 2774168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2775219089Spjd if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 2776219089Spjd name += sizeof(_PATH_DEV) - 1; 2777219089Spjd if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 2778219089Spjd path += sizeof(_PATH_DEV) - 1; 2779168404Spjd if (strcmp(name, path) == 0) 2780168404Spjd return (nv); 2781168404Spjd return (NULL); 2782168404Spjd } 2783168404Spjd 2784168404Spjd for (c = 0; c < children; c++) 2785168404Spjd if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2786168404Spjd return (match); 2787168404Spjd 2788168404Spjd return (NULL); 2789168404Spjd} 2790168404Spjd 2791168404Spjdstatic int 2792168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 2793168404Spjd{ 2794168404Spjd boolean_t force = B_FALSE; 2795168404Spjd int c; 2796168404Spjd nvlist_t *nvroot; 2797168404Spjd char *poolname, *old_disk, *new_disk; 2798168404Spjd zpool_handle_t *zhp; 2799168404Spjd int ret; 2800168404Spjd 2801168404Spjd /* check options */ 2802168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 2803168404Spjd switch (c) { 2804168404Spjd case 'f': 2805168404Spjd force = B_TRUE; 2806168404Spjd break; 2807168404Spjd case '?': 2808168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2809168404Spjd optopt); 2810168404Spjd usage(B_FALSE); 2811168404Spjd } 2812168404Spjd } 2813168404Spjd 2814168404Spjd argc -= optind; 2815168404Spjd argv += optind; 2816168404Spjd 2817168404Spjd /* get pool name and check number of arguments */ 2818168404Spjd if (argc < 1) { 2819168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 2820168404Spjd usage(B_FALSE); 2821168404Spjd } 2822168404Spjd 2823168404Spjd poolname = argv[0]; 2824168404Spjd 2825168404Spjd if (argc < 2) { 2826168404Spjd (void) fprintf(stderr, 2827168404Spjd gettext("missing <device> specification\n")); 2828168404Spjd usage(B_FALSE); 2829168404Spjd } 2830168404Spjd 2831168404Spjd old_disk = argv[1]; 2832168404Spjd 2833168404Spjd if (argc < 3) { 2834168404Spjd if (!replacing) { 2835168404Spjd (void) fprintf(stderr, 2836168404Spjd gettext("missing <new_device> specification\n")); 2837168404Spjd usage(B_FALSE); 2838168404Spjd } 2839168404Spjd new_disk = old_disk; 2840168404Spjd argc -= 1; 2841168404Spjd argv += 1; 2842168404Spjd } else { 2843168404Spjd new_disk = argv[2]; 2844168404Spjd argc -= 2; 2845168404Spjd argv += 2; 2846168404Spjd } 2847168404Spjd 2848168404Spjd if (argc > 1) { 2849168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2850168404Spjd usage(B_FALSE); 2851168404Spjd } 2852168404Spjd 2853168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2854168404Spjd return (1); 2855168404Spjd 2856185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 2857168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2858168404Spjd poolname); 2859168404Spjd zpool_close(zhp); 2860168404Spjd return (1); 2861168404Spjd } 2862168404Spjd 2863185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 2864185029Spjd argc, argv); 2865168404Spjd if (nvroot == NULL) { 2866168404Spjd zpool_close(zhp); 2867168404Spjd return (1); 2868168404Spjd } 2869168404Spjd 2870168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 2871168404Spjd 2872168404Spjd nvlist_free(nvroot); 2873168404Spjd zpool_close(zhp); 2874168404Spjd 2875168404Spjd return (ret); 2876168404Spjd} 2877168404Spjd 2878168404Spjd/* 2879168404Spjd * zpool replace [-f] <pool> <device> <new_device> 2880168404Spjd * 2881168404Spjd * -f Force attach, even if <new_device> appears to be in use. 2882168404Spjd * 2883168404Spjd * Replace <device> with <new_device>. 2884168404Spjd */ 2885168404Spjd/* ARGSUSED */ 2886168404Spjdint 2887168404Spjdzpool_do_replace(int argc, char **argv) 2888168404Spjd{ 2889168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2890168404Spjd} 2891168404Spjd 2892168404Spjd/* 2893168404Spjd * zpool attach [-f] <pool> <device> <new_device> 2894168404Spjd * 2895168404Spjd * -f Force attach, even if <new_device> appears to be in use. 2896168404Spjd * 2897168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 2898168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 2899168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 2900168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 2901168404Spjd */ 2902168404Spjdint 2903168404Spjdzpool_do_attach(int argc, char **argv) 2904168404Spjd{ 2905168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2906168404Spjd} 2907168404Spjd 2908168404Spjd/* 2909168404Spjd * zpool detach [-f] <pool> <device> 2910168404Spjd * 2911168404Spjd * -f Force detach of <device>, even if DTLs argue against it 2912168404Spjd * (not supported yet) 2913168404Spjd * 2914168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 2915168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 2916168404Spjd * has the only valid copy of some data. 2917168404Spjd */ 2918168404Spjd/* ARGSUSED */ 2919168404Spjdint 2920168404Spjdzpool_do_detach(int argc, char **argv) 2921168404Spjd{ 2922168404Spjd int c; 2923168404Spjd char *poolname, *path; 2924168404Spjd zpool_handle_t *zhp; 2925168404Spjd int ret; 2926168404Spjd 2927168404Spjd /* check options */ 2928168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 2929168404Spjd switch (c) { 2930168404Spjd case 'f': 2931168404Spjd case '?': 2932168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2933168404Spjd optopt); 2934168404Spjd usage(B_FALSE); 2935168404Spjd } 2936168404Spjd } 2937168404Spjd 2938168404Spjd argc -= optind; 2939168404Spjd argv += optind; 2940168404Spjd 2941168404Spjd /* get pool name and check number of arguments */ 2942168404Spjd if (argc < 1) { 2943168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 2944168404Spjd usage(B_FALSE); 2945168404Spjd } 2946168404Spjd 2947168404Spjd if (argc < 2) { 2948168404Spjd (void) fprintf(stderr, 2949168404Spjd gettext("missing <device> specification\n")); 2950168404Spjd usage(B_FALSE); 2951168404Spjd } 2952168404Spjd 2953168404Spjd poolname = argv[0]; 2954168404Spjd path = argv[1]; 2955168404Spjd 2956168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2957168404Spjd return (1); 2958168404Spjd 2959168404Spjd ret = zpool_vdev_detach(zhp, path); 2960168404Spjd 2961168404Spjd zpool_close(zhp); 2962168404Spjd 2963168404Spjd return (ret); 2964168404Spjd} 2965168404Spjd 2966168404Spjd/* 2967219089Spjd * zpool split [-n] [-o prop=val] ... 2968219089Spjd * [-o mntopt] ... 2969219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 2970219089Spjd * 2971219089Spjd * -n Do not split the pool, but display the resulting layout if 2972219089Spjd * it were to be split. 2973219089Spjd * -o Set property=value, or set mount options. 2974219089Spjd * -R Mount the split-off pool under an alternate root. 2975219089Spjd * 2976219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 2977219089Spjd * off may be listed, provided that no more than one device is specified 2978219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 2979219089Spjd * state unless -R is specified. 2980219089Spjd * 2981219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 2982219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 2983219089Spjd * undergoing a resilvering operation. 2984219089Spjd */ 2985219089Spjdint 2986219089Spjdzpool_do_split(int argc, char **argv) 2987219089Spjd{ 2988219089Spjd char *srcpool, *newpool, *propval; 2989219089Spjd char *mntopts = NULL; 2990219089Spjd splitflags_t flags; 2991219089Spjd int c, ret = 0; 2992219089Spjd zpool_handle_t *zhp; 2993219089Spjd nvlist_t *config, *props = NULL; 2994219089Spjd 2995219089Spjd flags.dryrun = B_FALSE; 2996219089Spjd flags.import = B_FALSE; 2997219089Spjd 2998219089Spjd /* check options */ 2999219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3000219089Spjd switch (c) { 3001219089Spjd case 'R': 3002219089Spjd flags.import = B_TRUE; 3003219089Spjd if (add_prop_list( 3004219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3005219089Spjd &props, B_TRUE) != 0) { 3006219089Spjd if (props) 3007219089Spjd nvlist_free(props); 3008219089Spjd usage(B_FALSE); 3009219089Spjd } 3010219089Spjd break; 3011219089Spjd case 'n': 3012219089Spjd flags.dryrun = B_TRUE; 3013219089Spjd break; 3014219089Spjd case 'o': 3015219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3016219089Spjd *propval = '\0'; 3017219089Spjd propval++; 3018219089Spjd if (add_prop_list(optarg, propval, 3019219089Spjd &props, B_TRUE) != 0) { 3020219089Spjd if (props) 3021219089Spjd nvlist_free(props); 3022219089Spjd usage(B_FALSE); 3023219089Spjd } 3024219089Spjd } else { 3025219089Spjd mntopts = optarg; 3026219089Spjd } 3027219089Spjd break; 3028219089Spjd case ':': 3029219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3030219089Spjd "'%c' option\n"), optopt); 3031219089Spjd usage(B_FALSE); 3032219089Spjd break; 3033219089Spjd case '?': 3034219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3035219089Spjd optopt); 3036219089Spjd usage(B_FALSE); 3037219089Spjd break; 3038219089Spjd } 3039219089Spjd } 3040219089Spjd 3041219089Spjd if (!flags.import && mntopts != NULL) { 3042219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3043219089Spjd "valid when importing the pool\n")); 3044219089Spjd usage(B_FALSE); 3045219089Spjd } 3046219089Spjd 3047219089Spjd argc -= optind; 3048219089Spjd argv += optind; 3049219089Spjd 3050219089Spjd if (argc < 1) { 3051219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3052219089Spjd usage(B_FALSE); 3053219089Spjd } 3054219089Spjd if (argc < 2) { 3055219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3056219089Spjd usage(B_FALSE); 3057219089Spjd } 3058219089Spjd 3059219089Spjd srcpool = argv[0]; 3060219089Spjd newpool = argv[1]; 3061219089Spjd 3062219089Spjd argc -= 2; 3063219089Spjd argv += 2; 3064219089Spjd 3065219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3066219089Spjd return (1); 3067219089Spjd 3068219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3069219089Spjd if (config == NULL) { 3070219089Spjd ret = 1; 3071219089Spjd } else { 3072219089Spjd if (flags.dryrun) { 3073219089Spjd (void) printf(gettext("would create '%s' with the " 3074219089Spjd "following layout:\n\n"), newpool); 3075219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3076219089Spjd } 3077219089Spjd nvlist_free(config); 3078219089Spjd } 3079219089Spjd 3080219089Spjd zpool_close(zhp); 3081219089Spjd 3082219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3083219089Spjd return (ret); 3084219089Spjd 3085219089Spjd /* 3086219089Spjd * The split was successful. Now we need to open the new 3087219089Spjd * pool and import it. 3088219089Spjd */ 3089219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3090219089Spjd return (1); 3091219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3092219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3093219089Spjd ret = 1; 3094219089Spjd (void) fprintf(stderr, gettext("Split was succssful, but " 3095219089Spjd "the datasets could not all be mounted\n")); 3096219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3097219089Spjd "different altroot\n"), "zpool import"); 3098219089Spjd } 3099219089Spjd zpool_close(zhp); 3100219089Spjd 3101219089Spjd return (ret); 3102219089Spjd} 3103219089Spjd 3104219089Spjd 3105219089Spjd 3106219089Spjd/* 3107168404Spjd * zpool online <pool> <device> ... 3108168404Spjd */ 3109168404Spjdint 3110168404Spjdzpool_do_online(int argc, char **argv) 3111168404Spjd{ 3112168404Spjd int c, i; 3113168404Spjd char *poolname; 3114168404Spjd zpool_handle_t *zhp; 3115168404Spjd int ret = 0; 3116185029Spjd vdev_state_t newstate; 3117219089Spjd int flags = 0; 3118168404Spjd 3119168404Spjd /* check options */ 3120219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3121168404Spjd switch (c) { 3122219089Spjd case 'e': 3123219089Spjd flags |= ZFS_ONLINE_EXPAND; 3124219089Spjd break; 3125168404Spjd case 't': 3126168404Spjd case '?': 3127168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3128168404Spjd optopt); 3129168404Spjd usage(B_FALSE); 3130168404Spjd } 3131168404Spjd } 3132168404Spjd 3133168404Spjd argc -= optind; 3134168404Spjd argv += optind; 3135168404Spjd 3136168404Spjd /* get pool name and check number of arguments */ 3137168404Spjd if (argc < 1) { 3138168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3139168404Spjd usage(B_FALSE); 3140168404Spjd } 3141168404Spjd if (argc < 2) { 3142168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3143168404Spjd usage(B_FALSE); 3144168404Spjd } 3145168404Spjd 3146168404Spjd poolname = argv[0]; 3147168404Spjd 3148168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3149168404Spjd return (1); 3150168404Spjd 3151185029Spjd for (i = 1; i < argc; i++) { 3152219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3153185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3154185029Spjd (void) printf(gettext("warning: device '%s' " 3155185029Spjd "onlined, but remains in faulted state\n"), 3156185029Spjd argv[i]); 3157185029Spjd if (newstate == VDEV_STATE_FAULTED) 3158185029Spjd (void) printf(gettext("use 'zpool " 3159185029Spjd "clear' to restore a faulted " 3160185029Spjd "device\n")); 3161185029Spjd else 3162185029Spjd (void) printf(gettext("use 'zpool " 3163185029Spjd "replace' to replace devices " 3164185029Spjd "that are no longer present\n")); 3165185029Spjd } 3166185029Spjd } else { 3167168404Spjd ret = 1; 3168185029Spjd } 3169185029Spjd } 3170168404Spjd 3171168404Spjd zpool_close(zhp); 3172168404Spjd 3173168404Spjd return (ret); 3174168404Spjd} 3175168404Spjd 3176168404Spjd/* 3177168404Spjd * zpool offline [-ft] <pool> <device> ... 3178168404Spjd * 3179168404Spjd * -f Force the device into the offline state, even if doing 3180168404Spjd * so would appear to compromise pool availability. 3181168404Spjd * (not supported yet) 3182168404Spjd * 3183168404Spjd * -t Only take the device off-line temporarily. The offline 3184168404Spjd * state will not be persistent across reboots. 3185168404Spjd */ 3186168404Spjd/* ARGSUSED */ 3187168404Spjdint 3188168404Spjdzpool_do_offline(int argc, char **argv) 3189168404Spjd{ 3190168404Spjd int c, i; 3191168404Spjd char *poolname; 3192168404Spjd zpool_handle_t *zhp; 3193168404Spjd int ret = 0; 3194168404Spjd boolean_t istmp = B_FALSE; 3195168404Spjd 3196168404Spjd /* check options */ 3197168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3198168404Spjd switch (c) { 3199168404Spjd case 't': 3200168404Spjd istmp = B_TRUE; 3201168404Spjd break; 3202168404Spjd case 'f': 3203168404Spjd case '?': 3204168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3205168404Spjd optopt); 3206168404Spjd usage(B_FALSE); 3207168404Spjd } 3208168404Spjd } 3209168404Spjd 3210168404Spjd argc -= optind; 3211168404Spjd argv += optind; 3212168404Spjd 3213168404Spjd /* get pool name and check number of arguments */ 3214168404Spjd if (argc < 1) { 3215168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3216168404Spjd usage(B_FALSE); 3217168404Spjd } 3218168404Spjd if (argc < 2) { 3219168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3220168404Spjd usage(B_FALSE); 3221168404Spjd } 3222168404Spjd 3223168404Spjd poolname = argv[0]; 3224168404Spjd 3225168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3226168404Spjd return (1); 3227168404Spjd 3228185029Spjd for (i = 1; i < argc; i++) { 3229185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3230168404Spjd ret = 1; 3231185029Spjd } 3232168404Spjd 3233168404Spjd zpool_close(zhp); 3234168404Spjd 3235168404Spjd return (ret); 3236168404Spjd} 3237168404Spjd 3238168404Spjd/* 3239168404Spjd * zpool clear <pool> [device] 3240168404Spjd * 3241168404Spjd * Clear all errors associated with a pool or a particular device. 3242168404Spjd */ 3243168404Spjdint 3244168404Spjdzpool_do_clear(int argc, char **argv) 3245168404Spjd{ 3246219089Spjd int c; 3247168404Spjd int ret = 0; 3248219089Spjd boolean_t dryrun = B_FALSE; 3249219089Spjd boolean_t do_rewind = B_FALSE; 3250219089Spjd boolean_t xtreme_rewind = B_FALSE; 3251219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3252219089Spjd nvlist_t *policy = NULL; 3253168404Spjd zpool_handle_t *zhp; 3254168404Spjd char *pool, *device; 3255168404Spjd 3256219089Spjd /* check options */ 3257219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3258219089Spjd switch (c) { 3259219089Spjd case 'F': 3260219089Spjd do_rewind = B_TRUE; 3261219089Spjd break; 3262219089Spjd case 'n': 3263219089Spjd dryrun = B_TRUE; 3264219089Spjd break; 3265219089Spjd case 'X': 3266219089Spjd xtreme_rewind = B_TRUE; 3267219089Spjd break; 3268219089Spjd case '?': 3269219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3270219089Spjd optopt); 3271219089Spjd usage(B_FALSE); 3272219089Spjd } 3273219089Spjd } 3274219089Spjd 3275219089Spjd argc -= optind; 3276219089Spjd argv += optind; 3277219089Spjd 3278219089Spjd if (argc < 1) { 3279168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3280168404Spjd usage(B_FALSE); 3281168404Spjd } 3282168404Spjd 3283219089Spjd if (argc > 2) { 3284168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3285168404Spjd usage(B_FALSE); 3286168404Spjd } 3287168404Spjd 3288219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3289219089Spjd (void) fprintf(stderr, 3290219089Spjd gettext("-n or -X only meaningful with -F\n")); 3291219089Spjd usage(B_FALSE); 3292219089Spjd } 3293219089Spjd if (dryrun) 3294219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3295219089Spjd else if (do_rewind) 3296219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3297219089Spjd if (xtreme_rewind) 3298219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3299168404Spjd 3300219089Spjd /* In future, further rewind policy choices can be passed along here */ 3301219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3302219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3303168404Spjd return (1); 3304168404Spjd 3305219089Spjd pool = argv[0]; 3306219089Spjd device = argc == 2 ? argv[1] : NULL; 3307219089Spjd 3308219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3309219089Spjd nvlist_free(policy); 3310219089Spjd return (1); 3311219089Spjd } 3312219089Spjd 3313219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3314168404Spjd ret = 1; 3315168404Spjd 3316168404Spjd zpool_close(zhp); 3317168404Spjd 3318219089Spjd nvlist_free(policy); 3319219089Spjd 3320168404Spjd return (ret); 3321168404Spjd} 3322168404Spjd 3323168404Spjdtypedef struct scrub_cbdata { 3324168404Spjd int cb_type; 3325168404Spjd int cb_argc; 3326168404Spjd char **cb_argv; 3327168404Spjd} scrub_cbdata_t; 3328168404Spjd 3329168404Spjdint 3330168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3331168404Spjd{ 3332168404Spjd scrub_cbdata_t *cb = data; 3333168404Spjd int err; 3334168404Spjd 3335168404Spjd /* 3336168404Spjd * Ignore faulted pools. 3337168404Spjd */ 3338168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3339168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3340168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 3341168404Spjd return (1); 3342168404Spjd } 3343168404Spjd 3344219089Spjd err = zpool_scan(zhp, cb->cb_type); 3345168404Spjd 3346168404Spjd return (err != 0); 3347168404Spjd} 3348168404Spjd 3349168404Spjd/* 3350168404Spjd * zpool scrub [-s] <pool> ... 3351168404Spjd * 3352168404Spjd * -s Stop. Stops any in-progress scrub. 3353168404Spjd */ 3354168404Spjdint 3355168404Spjdzpool_do_scrub(int argc, char **argv) 3356168404Spjd{ 3357168404Spjd int c; 3358168404Spjd scrub_cbdata_t cb; 3359168404Spjd 3360219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 3361168404Spjd 3362168404Spjd /* check options */ 3363168404Spjd while ((c = getopt(argc, argv, "s")) != -1) { 3364168404Spjd switch (c) { 3365168404Spjd case 's': 3366219089Spjd cb.cb_type = POOL_SCAN_NONE; 3367168404Spjd break; 3368168404Spjd case '?': 3369168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3370168404Spjd optopt); 3371168404Spjd usage(B_FALSE); 3372168404Spjd } 3373168404Spjd } 3374168404Spjd 3375168404Spjd cb.cb_argc = argc; 3376168404Spjd cb.cb_argv = argv; 3377168404Spjd argc -= optind; 3378168404Spjd argv += optind; 3379168404Spjd 3380168404Spjd if (argc < 1) { 3381168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3382168404Spjd usage(B_FALSE); 3383168404Spjd } 3384168404Spjd 3385168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3386168404Spjd} 3387168404Spjd 3388168404Spjdtypedef struct status_cbdata { 3389168404Spjd int cb_count; 3390168404Spjd boolean_t cb_allpools; 3391168404Spjd boolean_t cb_verbose; 3392168404Spjd boolean_t cb_explain; 3393168404Spjd boolean_t cb_first; 3394219089Spjd boolean_t cb_dedup_stats; 3395168404Spjd} status_cbdata_t; 3396168404Spjd 3397168404Spjd/* 3398168404Spjd * Print out detailed scrub status. 3399168404Spjd */ 3400168404Spjdvoid 3401219089Spjdprint_scan_status(pool_scan_stat_t *ps) 3402168404Spjd{ 3403219089Spjd time_t start, end; 3404219089Spjd uint64_t elapsed, mins_left, hours_left; 3405219089Spjd uint64_t pass_exam, examined, total; 3406219089Spjd uint_t rate; 3407168404Spjd double fraction_done; 3408219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3409168404Spjd 3410226583Spjd (void) printf(gettext(" scan: ")); 3411168404Spjd 3412219089Spjd /* If there's never been a scan, there's not much to say. */ 3413219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 3414219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 3415168404Spjd (void) printf(gettext("none requested\n")); 3416168404Spjd return; 3417168404Spjd } 3418168404Spjd 3419219089Spjd start = ps->pss_start_time; 3420219089Spjd end = ps->pss_end_time; 3421219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3422168404Spjd 3423219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 3424219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 3425219089Spjd /* 3426219089Spjd * Scan is finished or canceled. 3427219089Spjd */ 3428219089Spjd if (ps->pss_state == DSS_FINISHED) { 3429219089Spjd uint64_t minutes_taken = (end - start) / 60; 3430219089Spjd char *fmt; 3431168404Spjd 3432219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3433219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 3434219089Spjd "%llu errors on %s"); 3435219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3436219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 3437219089Spjd "%llu errors on %s"); 3438219089Spjd } 3439219089Spjd /* LINTED */ 3440219089Spjd (void) printf(fmt, processed_buf, 3441185029Spjd (u_longlong_t)(minutes_taken / 60), 3442185029Spjd (uint_t)(minutes_taken % 60), 3443219089Spjd (u_longlong_t)ps->pss_errors, 3444219089Spjd ctime((time_t *)&end)); 3445168404Spjd return; 3446219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 3447219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3448219089Spjd (void) printf(gettext("scrub canceled on %s"), 3449219089Spjd ctime(&end)); 3450219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3451219089Spjd (void) printf(gettext("resilver canceled on %s"), 3452219089Spjd ctime(&end)); 3453219089Spjd } 3454219089Spjd return; 3455168404Spjd } 3456168404Spjd 3457219089Spjd assert(ps->pss_state == DSS_SCANNING); 3458168404Spjd 3459219089Spjd /* 3460219089Spjd * Scan is in progress. 3461219089Spjd */ 3462219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3463219089Spjd (void) printf(gettext("scrub in progress since %s"), 3464219089Spjd ctime(&start)); 3465219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3466219089Spjd (void) printf(gettext("resilver in progress since %s"), 3467219089Spjd ctime(&start)); 3468219089Spjd } 3469219089Spjd 3470219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 3471219089Spjd total = ps->pss_to_examine; 3472168404Spjd fraction_done = (double)examined / total; 3473168404Spjd 3474219089Spjd /* elapsed time for this pass */ 3475219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 3476219089Spjd elapsed = elapsed ? elapsed : 1; 3477219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 3478219089Spjd rate = pass_exam / elapsed; 3479219089Spjd rate = rate ? rate : 1; 3480219089Spjd mins_left = ((total - examined) / rate) / 60; 3481219089Spjd hours_left = mins_left / 60; 3482219089Spjd 3483219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 3484219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 3485219089Spjd zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 3486219089Spjd 3487219089Spjd /* 3488219089Spjd * do not print estimated time if hours_left is more than 30 days 3489219089Spjd */ 3490226583Spjd (void) printf(gettext(" %s scanned out of %s at %s/s"), 3491219089Spjd examined_buf, total_buf, rate_buf); 3492219089Spjd if (hours_left < (30 * 24)) { 3493219089Spjd (void) printf(gettext(", %lluh%um to go\n"), 3494219089Spjd (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 3495219089Spjd } else { 3496219089Spjd (void) printf(gettext( 3497219089Spjd ", (scan is slow, no estimated time)\n")); 3498219089Spjd } 3499219089Spjd 3500219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 3501226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 3502219089Spjd processed_buf, 100 * fraction_done); 3503219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 3504226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 3505219089Spjd processed_buf, 100 * fraction_done); 3506219089Spjd } 3507168404Spjd} 3508168404Spjd 3509168404Spjdstatic void 3510168404Spjdprint_error_log(zpool_handle_t *zhp) 3511168404Spjd{ 3512185029Spjd nvlist_t *nverrlist = NULL; 3513168404Spjd nvpair_t *elem; 3514168404Spjd char *pathname; 3515168404Spjd size_t len = MAXPATHLEN * 2; 3516168404Spjd 3517168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 3518168404Spjd (void) printf("errors: List of errors unavailable " 3519168404Spjd "(insufficient privileges)\n"); 3520168404Spjd return; 3521168404Spjd } 3522168404Spjd 3523168404Spjd (void) printf("errors: Permanent errors have been " 3524168404Spjd "detected in the following files:\n\n"); 3525168404Spjd 3526168404Spjd pathname = safe_malloc(len); 3527168404Spjd elem = NULL; 3528168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 3529168404Spjd nvlist_t *nv; 3530168404Spjd uint64_t dsobj, obj; 3531168404Spjd 3532168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 3533168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 3534168404Spjd &dsobj) == 0); 3535168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 3536168404Spjd &obj) == 0); 3537168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 3538168404Spjd (void) printf("%7s %s\n", "", pathname); 3539168404Spjd } 3540168404Spjd free(pathname); 3541168404Spjd nvlist_free(nverrlist); 3542168404Spjd} 3543168404Spjd 3544168404Spjdstatic void 3545168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 3546168404Spjd int namewidth) 3547168404Spjd{ 3548168404Spjd uint_t i; 3549168404Spjd char *name; 3550168404Spjd 3551168404Spjd if (nspares == 0) 3552168404Spjd return; 3553168404Spjd 3554168404Spjd (void) printf(gettext("\tspares\n")); 3555168404Spjd 3556168404Spjd for (i = 0; i < nspares; i++) { 3557219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 3558168404Spjd print_status_config(zhp, name, spares[i], 3559209962Smm namewidth, 2, B_TRUE); 3560168404Spjd free(name); 3561168404Spjd } 3562168404Spjd} 3563168404Spjd 3564185029Spjdstatic void 3565185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 3566185029Spjd int namewidth) 3567185029Spjd{ 3568185029Spjd uint_t i; 3569185029Spjd char *name; 3570185029Spjd 3571185029Spjd if (nl2cache == 0) 3572185029Spjd return; 3573185029Spjd 3574185029Spjd (void) printf(gettext("\tcache\n")); 3575185029Spjd 3576185029Spjd for (i = 0; i < nl2cache; i++) { 3577219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 3578185029Spjd print_status_config(zhp, name, l2cache[i], 3579209962Smm namewidth, 2, B_FALSE); 3580185029Spjd free(name); 3581185029Spjd } 3582185029Spjd} 3583185029Spjd 3584219089Spjdstatic void 3585219089Spjdprint_dedup_stats(nvlist_t *config) 3586219089Spjd{ 3587219089Spjd ddt_histogram_t *ddh; 3588219089Spjd ddt_stat_t *dds; 3589219089Spjd ddt_object_t *ddo; 3590219089Spjd uint_t c; 3591219089Spjd 3592219089Spjd /* 3593219089Spjd * If the pool was faulted then we may not have been able to 3594219089Spjd * obtain the config. Otherwise, if have anything in the dedup 3595219089Spjd * table continue processing the stats. 3596219089Spjd */ 3597219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 3598227497Smm (uint64_t **)&ddo, &c) != 0) 3599219089Spjd return; 3600219089Spjd 3601219089Spjd (void) printf("\n"); 3602227497Smm (void) printf(gettext(" dedup: ")); 3603227497Smm if (ddo->ddo_count == 0) { 3604227497Smm (void) printf(gettext("no DDT entries\n")); 3605227497Smm return; 3606227497Smm } 3607227497Smm 3608219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 3609219089Spjd (u_longlong_t)ddo->ddo_count, 3610219089Spjd (u_longlong_t)ddo->ddo_dspace, 3611219089Spjd (u_longlong_t)ddo->ddo_mspace); 3612219089Spjd 3613219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 3614219089Spjd (uint64_t **)&dds, &c) == 0); 3615219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 3616219089Spjd (uint64_t **)&ddh, &c) == 0); 3617219089Spjd zpool_dump_ddt(dds, ddh); 3618219089Spjd} 3619219089Spjd 3620168404Spjd/* 3621168404Spjd * Display a summary of pool status. Displays a summary such as: 3622168404Spjd * 3623168404Spjd * pool: tank 3624168404Spjd * status: DEGRADED 3625168404Spjd * reason: One or more devices ... 3626168404Spjd * see: http://www.sun.com/msg/ZFS-xxxx-01 3627168404Spjd * config: 3628168404Spjd * mirror DEGRADED 3629168404Spjd * c1t0d0 OK 3630168404Spjd * c2t0d0 UNAVAIL 3631168404Spjd * 3632168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 3633168404Spjd * option is specified, then we print out error rate information as well. 3634168404Spjd */ 3635168404Spjdint 3636168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 3637168404Spjd{ 3638168404Spjd status_cbdata_t *cbp = data; 3639168404Spjd nvlist_t *config, *nvroot; 3640168404Spjd char *msgid; 3641168404Spjd int reason; 3642168404Spjd const char *health; 3643168404Spjd uint_t c; 3644168404Spjd vdev_stat_t *vs; 3645168404Spjd 3646168404Spjd config = zpool_get_config(zhp, NULL); 3647168404Spjd reason = zpool_get_status(zhp, &msgid); 3648168404Spjd 3649168404Spjd cbp->cb_count++; 3650168404Spjd 3651168404Spjd /* 3652168404Spjd * If we were given 'zpool status -x', only report those pools with 3653168404Spjd * problems. 3654168404Spjd */ 3655168404Spjd if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 3656168404Spjd if (!cbp->cb_allpools) { 3657168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 3658168404Spjd zpool_get_name(zhp)); 3659168404Spjd if (cbp->cb_first) 3660168404Spjd cbp->cb_first = B_FALSE; 3661168404Spjd } 3662168404Spjd return (0); 3663168404Spjd } 3664168404Spjd 3665168404Spjd if (cbp->cb_first) 3666168404Spjd cbp->cb_first = B_FALSE; 3667168404Spjd else 3668168404Spjd (void) printf("\n"); 3669168404Spjd 3670168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3671168404Spjd &nvroot) == 0); 3672219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 3673168404Spjd (uint64_t **)&vs, &c) == 0); 3674185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 3675168404Spjd 3676168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 3677168404Spjd (void) printf(gettext(" state: %s\n"), health); 3678168404Spjd 3679168404Spjd switch (reason) { 3680168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 3681168404Spjd (void) printf(gettext("status: One or more devices could not " 3682168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 3683168404Spjd "continue functioning in a degraded state.\n")); 3684168404Spjd (void) printf(gettext("action: Attach the missing device and " 3685168404Spjd "online it using 'zpool online'.\n")); 3686168404Spjd break; 3687168404Spjd 3688168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 3689168404Spjd (void) printf(gettext("status: One or more devices could not " 3690168404Spjd "be opened. There are insufficient\n\treplicas for the " 3691168404Spjd "pool to continue functioning.\n")); 3692168404Spjd (void) printf(gettext("action: Attach the missing device and " 3693168404Spjd "online it using 'zpool online'.\n")); 3694168404Spjd break; 3695168404Spjd 3696168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 3697168404Spjd (void) printf(gettext("status: One or more devices could not " 3698168404Spjd "be used because the label is missing or\n\tinvalid. " 3699168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 3700168404Spjd "functioning in a degraded state.\n")); 3701168404Spjd (void) printf(gettext("action: Replace the device using " 3702168404Spjd "'zpool replace'.\n")); 3703168404Spjd break; 3704168404Spjd 3705168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 3706168404Spjd (void) printf(gettext("status: One or more devices could not " 3707168404Spjd "be used because the label is missing \n\tor invalid. " 3708168404Spjd "There are insufficient replicas for the pool to " 3709168404Spjd "continue\n\tfunctioning.\n")); 3710219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 3711219089Spjd zpool_get_name(zhp), reason, config); 3712168404Spjd break; 3713168404Spjd 3714168404Spjd case ZPOOL_STATUS_FAILING_DEV: 3715168404Spjd (void) printf(gettext("status: One or more devices has " 3716168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 3717168404Spjd "made to correct the error. Applications are " 3718168404Spjd "unaffected.\n")); 3719168404Spjd (void) printf(gettext("action: Determine if the device needs " 3720168404Spjd "to be replaced, and clear the errors\n\tusing " 3721168404Spjd "'zpool clear' or replace the device with 'zpool " 3722168404Spjd "replace'.\n")); 3723168404Spjd break; 3724168404Spjd 3725168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 3726168404Spjd (void) printf(gettext("status: One or more devices has " 3727168404Spjd "been taken offline by the administrator.\n\tSufficient " 3728168404Spjd "replicas exist for the pool to continue functioning in " 3729168404Spjd "a\n\tdegraded state.\n")); 3730168404Spjd (void) printf(gettext("action: Online the device using " 3731168404Spjd "'zpool online' or replace the device with\n\t'zpool " 3732168404Spjd "replace'.\n")); 3733168404Spjd break; 3734168404Spjd 3735219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 3736219089Spjd (void) printf(gettext("status: One or more devices has " 3737219089Spjd "been removed by the administrator.\n\tSufficient " 3738219089Spjd "replicas exist for the pool to continue functioning in " 3739219089Spjd "a\n\tdegraded state.\n")); 3740219089Spjd (void) printf(gettext("action: Online the device using " 3741219089Spjd "'zpool online' or replace the device with\n\t'zpool " 3742219089Spjd "replace'.\n")); 3743219089Spjd break; 3744219089Spjd 3745168404Spjd case ZPOOL_STATUS_RESILVERING: 3746168404Spjd (void) printf(gettext("status: One or more devices is " 3747168404Spjd "currently being resilvered. The pool will\n\tcontinue " 3748168404Spjd "to function, possibly in a degraded state.\n")); 3749168404Spjd (void) printf(gettext("action: Wait for the resilver to " 3750168404Spjd "complete.\n")); 3751168404Spjd break; 3752168404Spjd 3753168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 3754168404Spjd (void) printf(gettext("status: One or more devices has " 3755168404Spjd "experienced an error resulting in data\n\tcorruption. " 3756168404Spjd "Applications may be affected.\n")); 3757168404Spjd (void) printf(gettext("action: Restore the file in question " 3758168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 3759168404Spjd "backup.\n")); 3760168404Spjd break; 3761168404Spjd 3762168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 3763168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 3764168404Spjd "and the pool cannot be opened.\n")); 3765219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 3766219089Spjd zpool_get_name(zhp), reason, config); 3767168404Spjd break; 3768168404Spjd 3769168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 3770168404Spjd (void) printf(gettext("status: The pool is formatted using an " 3771168404Spjd "older on-disk format. The pool can\n\tstill be used, but " 3772168404Spjd "some features are unavailable.\n")); 3773168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 3774168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 3775168404Spjd "be accessible on older software versions.\n")); 3776168404Spjd break; 3777168404Spjd 3778168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 3779168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 3780168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 3781168404Spjd "be accessed on this system.\n")); 3782168404Spjd (void) printf(gettext("action: Access the pool from a system " 3783168404Spjd "running more recent software, or\n\trestore the pool from " 3784168404Spjd "backup.\n")); 3785168404Spjd break; 3786168404Spjd 3787185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 3788185029Spjd (void) printf(gettext("status: One or more devices are " 3789185029Spjd "faulted in response to persistent errors.\n\tSufficient " 3790185029Spjd "replicas exist for the pool to continue functioning " 3791185029Spjd "in a\n\tdegraded state.\n")); 3792185029Spjd (void) printf(gettext("action: Replace the faulted device, " 3793185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 3794185029Spjd break; 3795185029Spjd 3796185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 3797185029Spjd (void) printf(gettext("status: One or more devices are " 3798185029Spjd "faulted in response to persistent errors. There are " 3799185029Spjd "insufficient replicas for the pool to\n\tcontinue " 3800185029Spjd "functioning.\n")); 3801185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 3802185029Spjd "from a backup source. Manually marking the device\n" 3803185029Spjd "\trepaired using 'zpool clear' may allow some data " 3804185029Spjd "to be recovered.\n")); 3805185029Spjd break; 3806185029Spjd 3807185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 3808185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 3809185029Spjd (void) printf(gettext("status: One or more devices are " 3810185029Spjd "faulted in response to IO failures.\n")); 3811185029Spjd (void) printf(gettext("action: Make sure the affected devices " 3812185029Spjd "are connected, then run 'zpool clear'.\n")); 3813185029Spjd break; 3814185029Spjd 3815185029Spjd case ZPOOL_STATUS_BAD_LOG: 3816185029Spjd (void) printf(gettext("status: An intent log record " 3817185029Spjd "could not be read.\n" 3818185029Spjd "\tWaiting for adminstrator intervention to fix the " 3819185029Spjd "faulted pool.\n")); 3820185029Spjd (void) printf(gettext("action: Either restore the affected " 3821185029Spjd "device(s) and run 'zpool online',\n" 3822185029Spjd "\tor ignore the intent log records by running " 3823185029Spjd "'zpool clear'.\n")); 3824185029Spjd break; 3825185029Spjd 3826168404Spjd default: 3827168404Spjd /* 3828168404Spjd * The remaining errors can't actually be generated, yet. 3829168404Spjd */ 3830168404Spjd assert(reason == ZPOOL_STATUS_OK); 3831168404Spjd } 3832168404Spjd 3833168404Spjd if (msgid != NULL) 3834168404Spjd (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3835168404Spjd msgid); 3836168404Spjd 3837168404Spjd if (config != NULL) { 3838168404Spjd int namewidth; 3839168404Spjd uint64_t nerr; 3840185029Spjd nvlist_t **spares, **l2cache; 3841185029Spjd uint_t nspares, nl2cache; 3842219089Spjd pool_scan_stat_t *ps = NULL; 3843168404Spjd 3844219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 3845219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 3846219089Spjd print_scan_status(ps); 3847168404Spjd 3848168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 3849168404Spjd if (namewidth < 10) 3850168404Spjd namewidth = 10; 3851168404Spjd 3852168404Spjd (void) printf(gettext("config:\n\n")); 3853168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3854168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3855168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 3856209962Smm namewidth, 0, B_FALSE); 3857209962Smm 3858185029Spjd if (num_logs(nvroot) > 0) 3859213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 3860185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 3861185029Spjd &l2cache, &nl2cache) == 0) 3862185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 3863185029Spjd 3864168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 3865168404Spjd &spares, &nspares) == 0) 3866168404Spjd print_spares(zhp, spares, nspares, namewidth); 3867168404Spjd 3868168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3869168404Spjd &nerr) == 0) { 3870168404Spjd nvlist_t *nverrlist = NULL; 3871168404Spjd 3872168404Spjd /* 3873168404Spjd * If the approximate error count is small, get a 3874168404Spjd * precise count by fetching the entire log and 3875168404Spjd * uniquifying the results. 3876168404Spjd */ 3877185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 3878168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 3879168404Spjd nvpair_t *elem; 3880168404Spjd 3881168404Spjd elem = NULL; 3882168404Spjd nerr = 0; 3883168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 3884168404Spjd elem)) != NULL) { 3885168404Spjd nerr++; 3886168404Spjd } 3887168404Spjd } 3888168404Spjd nvlist_free(nverrlist); 3889168404Spjd 3890168404Spjd (void) printf("\n"); 3891168404Spjd 3892168404Spjd if (nerr == 0) 3893168404Spjd (void) printf(gettext("errors: No known data " 3894168404Spjd "errors\n")); 3895168404Spjd else if (!cbp->cb_verbose) 3896168404Spjd (void) printf(gettext("errors: %llu data " 3897168404Spjd "errors, use '-v' for a list\n"), 3898168404Spjd (u_longlong_t)nerr); 3899168404Spjd else 3900168404Spjd print_error_log(zhp); 3901168404Spjd } 3902219089Spjd 3903219089Spjd if (cbp->cb_dedup_stats) 3904219089Spjd print_dedup_stats(config); 3905168404Spjd } else { 3906168404Spjd (void) printf(gettext("config: The configuration cannot be " 3907168404Spjd "determined.\n")); 3908168404Spjd } 3909168404Spjd 3910168404Spjd return (0); 3911168404Spjd} 3912168404Spjd 3913168404Spjd/* 3914219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 3915168404Spjd * 3916168404Spjd * -v Display complete error logs 3917168404Spjd * -x Display only pools with potential problems 3918219089Spjd * -D Display dedup status (undocumented) 3919219089Spjd * -T Display a timestamp in date(1) or Unix format 3920168404Spjd * 3921168404Spjd * Describes the health status of all pools or some subset. 3922168404Spjd */ 3923168404Spjdint 3924168404Spjdzpool_do_status(int argc, char **argv) 3925168404Spjd{ 3926168404Spjd int c; 3927168404Spjd int ret; 3928219089Spjd unsigned long interval = 0, count = 0; 3929168404Spjd status_cbdata_t cb = { 0 }; 3930168404Spjd 3931168404Spjd /* check options */ 3932219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 3933168404Spjd switch (c) { 3934168404Spjd case 'v': 3935168404Spjd cb.cb_verbose = B_TRUE; 3936168404Spjd break; 3937168404Spjd case 'x': 3938168404Spjd cb.cb_explain = B_TRUE; 3939168404Spjd break; 3940219089Spjd case 'D': 3941219089Spjd cb.cb_dedup_stats = B_TRUE; 3942219089Spjd break; 3943219089Spjd case 'T': 3944219089Spjd get_timestamp_arg(*optarg); 3945219089Spjd break; 3946168404Spjd case '?': 3947168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3948168404Spjd optopt); 3949168404Spjd usage(B_FALSE); 3950168404Spjd } 3951168404Spjd } 3952168404Spjd 3953168404Spjd argc -= optind; 3954168404Spjd argv += optind; 3955168404Spjd 3956219089Spjd get_interval_count(&argc, argv, &interval, &count); 3957168404Spjd 3958168404Spjd if (argc == 0) 3959168404Spjd cb.cb_allpools = B_TRUE; 3960168404Spjd 3961219089Spjd cb.cb_first = B_TRUE; 3962168404Spjd 3963219089Spjd for (;;) { 3964219089Spjd if (timestamp_fmt != NODATE) 3965219089Spjd print_timestamp(timestamp_fmt); 3966168404Spjd 3967219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 3968219089Spjd status_callback, &cb); 3969219089Spjd 3970219089Spjd if (argc == 0 && cb.cb_count == 0) 3971219089Spjd (void) printf(gettext("no pools available\n")); 3972219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3973219089Spjd (void) printf(gettext("all pools are healthy\n")); 3974219089Spjd 3975219089Spjd if (ret != 0) 3976219089Spjd return (ret); 3977219089Spjd 3978219089Spjd if (interval == 0) 3979219089Spjd break; 3980219089Spjd 3981219089Spjd if (count != 0 && --count == 0) 3982219089Spjd break; 3983219089Spjd 3984219089Spjd (void) sleep(interval); 3985219089Spjd } 3986219089Spjd 3987219089Spjd return (0); 3988168404Spjd} 3989168404Spjd 3990168404Spjdtypedef struct upgrade_cbdata { 3991168404Spjd int cb_all; 3992168404Spjd int cb_first; 3993168404Spjd int cb_newer; 3994212050Spjd char cb_poolname[ZPOOL_MAXNAMELEN]; 3995168404Spjd int cb_argc; 3996185029Spjd uint64_t cb_version; 3997168404Spjd char **cb_argv; 3998168404Spjd} upgrade_cbdata_t; 3999168404Spjd 4000168404Spjdstatic int 4001212050Spjdis_root_pool(zpool_handle_t *zhp) 4002212050Spjd{ 4003212050Spjd static struct statfs sfs; 4004212050Spjd static char *poolname = NULL; 4005212050Spjd static boolean_t stated = B_FALSE; 4006212050Spjd char *slash; 4007212050Spjd 4008212067Spjd if (!stated) { 4009212050Spjd stated = B_TRUE; 4010212050Spjd if (statfs("/", &sfs) == -1) { 4011212050Spjd (void) fprintf(stderr, 4012212050Spjd "Unable to stat root file system: %s.\n", 4013212050Spjd strerror(errno)); 4014212067Spjd return (0); 4015212050Spjd } 4016212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4017212067Spjd return (0); 4018212050Spjd poolname = sfs.f_mntfromname; 4019212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4020212050Spjd *slash = '\0'; 4021212050Spjd } 4022212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4023212050Spjd} 4024212050Spjd 4025212050Spjdstatic int 4026168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4027168404Spjd{ 4028168404Spjd upgrade_cbdata_t *cbp = arg; 4029168404Spjd nvlist_t *config; 4030168404Spjd uint64_t version; 4031168404Spjd int ret = 0; 4032168404Spjd 4033168404Spjd config = zpool_get_config(zhp, NULL); 4034168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4035168404Spjd &version) == 0); 4036168404Spjd 4037185029Spjd if (!cbp->cb_newer && version < SPA_VERSION) { 4038168404Spjd if (!cbp->cb_all) { 4039168404Spjd if (cbp->cb_first) { 4040168404Spjd (void) printf(gettext("The following pools are " 4041168404Spjd "out of date, and can be upgraded. After " 4042168404Spjd "being\nupgraded, these pools will no " 4043168404Spjd "longer be accessible by older software " 4044168404Spjd "versions.\n\n")); 4045168404Spjd (void) printf(gettext("VER POOL\n")); 4046168404Spjd (void) printf(gettext("--- ------------\n")); 4047168404Spjd cbp->cb_first = B_FALSE; 4048168404Spjd } 4049168404Spjd 4050168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4051168404Spjd zpool_get_name(zhp)); 4052168404Spjd } else { 4053168404Spjd cbp->cb_first = B_FALSE; 4054185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 4055168404Spjd if (!ret) { 4056168404Spjd (void) printf(gettext("Successfully upgraded " 4057185029Spjd "'%s'\n\n"), zpool_get_name(zhp)); 4058212050Spjd if (cbp->cb_poolname[0] == '\0' && 4059212050Spjd is_root_pool(zhp)) { 4060212050Spjd (void) strlcpy(cbp->cb_poolname, 4061212050Spjd zpool_get_name(zhp), 4062212050Spjd sizeof(cbp->cb_poolname)); 4063212050Spjd } 4064168404Spjd } 4065168404Spjd } 4066185029Spjd } else if (cbp->cb_newer && version > SPA_VERSION) { 4067168404Spjd assert(!cbp->cb_all); 4068168404Spjd 4069168404Spjd if (cbp->cb_first) { 4070168404Spjd (void) printf(gettext("The following pools are " 4071168404Spjd "formatted using a newer software version and\n" 4072168404Spjd "cannot be accessed on the current system.\n\n")); 4073168404Spjd (void) printf(gettext("VER POOL\n")); 4074168404Spjd (void) printf(gettext("--- ------------\n")); 4075168404Spjd cbp->cb_first = B_FALSE; 4076168404Spjd } 4077168404Spjd 4078168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4079168404Spjd zpool_get_name(zhp)); 4080168404Spjd } 4081168404Spjd 4082168404Spjd zpool_close(zhp); 4083168404Spjd return (ret); 4084168404Spjd} 4085168404Spjd 4086168404Spjd/* ARGSUSED */ 4087168404Spjdstatic int 4088168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 4089168404Spjd{ 4090185029Spjd upgrade_cbdata_t *cbp = data; 4091185029Spjd uint64_t cur_version; 4092168404Spjd int ret; 4093168404Spjd 4094185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 4095185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 4096185029Spjd "Pool 'log' must be renamed using export and import" 4097185029Spjd " to upgrade.\n")); 4098185029Spjd return (1); 4099185029Spjd } 4100168404Spjd 4101185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4102185029Spjd if (cur_version > cbp->cb_version) { 4103168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 4104185029Spjd "using more current version '%llu'.\n"), 4105185029Spjd zpool_get_name(zhp), cur_version); 4106185029Spjd return (0); 4107185029Spjd } 4108185029Spjd if (cur_version == cbp->cb_version) { 4109185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 4110168404Spjd "using the current version.\n"), zpool_get_name(zhp)); 4111168404Spjd return (0); 4112168404Spjd } 4113168404Spjd 4114185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 4115168404Spjd 4116168404Spjd if (!ret) { 4117168404Spjd (void) printf(gettext("Successfully upgraded '%s' " 4118185029Spjd "from version %llu to version %llu\n\n"), 4119185029Spjd zpool_get_name(zhp), (u_longlong_t)cur_version, 4120185029Spjd (u_longlong_t)cbp->cb_version); 4121212050Spjd if (cbp->cb_poolname[0] == '\0' && is_root_pool(zhp)) { 4122212050Spjd (void) strlcpy(cbp->cb_poolname, zpool_get_name(zhp), 4123212050Spjd sizeof(cbp->cb_poolname)); 4124212050Spjd } 4125168404Spjd } 4126168404Spjd 4127168404Spjd return (ret != 0); 4128168404Spjd} 4129168404Spjd 4130168404Spjd/* 4131168404Spjd * zpool upgrade 4132168404Spjd * zpool upgrade -v 4133185029Spjd * zpool upgrade [-V version] <-a | pool ...> 4134168404Spjd * 4135168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 4136168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 4137168404Spjd * upgrade all pools. 4138168404Spjd */ 4139168404Spjdint 4140168404Spjdzpool_do_upgrade(int argc, char **argv) 4141168404Spjd{ 4142168404Spjd int c; 4143168404Spjd upgrade_cbdata_t cb = { 0 }; 4144168404Spjd int ret = 0; 4145168404Spjd boolean_t showversions = B_FALSE; 4146185029Spjd char *end; 4147168404Spjd 4148185029Spjd 4149168404Spjd /* check options */ 4150219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 4151168404Spjd switch (c) { 4152168404Spjd case 'a': 4153168404Spjd cb.cb_all = B_TRUE; 4154168404Spjd break; 4155168404Spjd case 'v': 4156168404Spjd showversions = B_TRUE; 4157168404Spjd break; 4158185029Spjd case 'V': 4159185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 4160185029Spjd if (*end != '\0' || cb.cb_version > SPA_VERSION || 4161185029Spjd cb.cb_version < SPA_VERSION_1) { 4162185029Spjd (void) fprintf(stderr, 4163185029Spjd gettext("invalid version '%s'\n"), optarg); 4164185029Spjd usage(B_FALSE); 4165185029Spjd } 4166185029Spjd break; 4167219089Spjd case ':': 4168219089Spjd (void) fprintf(stderr, gettext("missing argument for " 4169219089Spjd "'%c' option\n"), optopt); 4170219089Spjd usage(B_FALSE); 4171219089Spjd break; 4172168404Spjd case '?': 4173168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4174168404Spjd optopt); 4175168404Spjd usage(B_FALSE); 4176168404Spjd } 4177168404Spjd } 4178168404Spjd 4179168404Spjd cb.cb_argc = argc; 4180168404Spjd cb.cb_argv = argv; 4181168404Spjd argc -= optind; 4182168404Spjd argv += optind; 4183168404Spjd 4184185029Spjd if (cb.cb_version == 0) { 4185185029Spjd cb.cb_version = SPA_VERSION; 4186185029Spjd } else if (!cb.cb_all && argc == 0) { 4187185029Spjd (void) fprintf(stderr, gettext("-V option is " 4188185029Spjd "incompatible with other arguments\n")); 4189185029Spjd usage(B_FALSE); 4190185029Spjd } 4191185029Spjd 4192168404Spjd if (showversions) { 4193168404Spjd if (cb.cb_all || argc != 0) { 4194168404Spjd (void) fprintf(stderr, gettext("-v option is " 4195168404Spjd "incompatible with other arguments\n")); 4196168404Spjd usage(B_FALSE); 4197168404Spjd } 4198168404Spjd } else if (cb.cb_all) { 4199168404Spjd if (argc != 0) { 4200185029Spjd (void) fprintf(stderr, gettext("-a option should not " 4201185029Spjd "be used along with a pool name\n")); 4202168404Spjd usage(B_FALSE); 4203168404Spjd } 4204168404Spjd } 4205168404Spjd 4206185029Spjd (void) printf(gettext("This system is currently running " 4207185029Spjd "ZFS pool version %llu.\n\n"), SPA_VERSION); 4208168404Spjd cb.cb_first = B_TRUE; 4209168404Spjd if (showversions) { 4210168404Spjd (void) printf(gettext("The following versions are " 4211168404Spjd "supported:\n\n")); 4212168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 4213168404Spjd (void) printf("--- -----------------------------------------" 4214168404Spjd "---------------\n"); 4215168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 4216168404Spjd (void) printf(gettext(" 2 Ditto blocks " 4217168404Spjd "(replicated metadata)\n")); 4218168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 4219168404Spjd "RAID-Z\n")); 4220168404Spjd (void) printf(gettext(" 4 zpool history\n")); 4221168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 4222168404Spjd "algorithm\n")); 4223185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 4224185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 4225185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 4226185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 4227185029Spjd "properties\n")); 4228185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 4229185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 4230185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 4231185029Spjd (void) printf(gettext(" 13 snapused property\n")); 4232209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 4233209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 4234219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 4235219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 4236219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 4237219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 4238219089Spjd (void) printf(gettext(" 20 Compression using zle " 4239219089Spjd "(zero-length encoding)\n")); 4240219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 4241219089Spjd (void) printf(gettext(" 22 Received properties\n")); 4242219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 4243219089Spjd (void) printf(gettext(" 24 System attributes\n")); 4244219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 4245219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 4246219089Spjd "performance\n")); 4247219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 4248219089Spjd "performance\n")); 4249219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 4250219089Spjd (void) printf(gettext("\nFor more information on a particular " 4251219089Spjd "version, including supported releases,\n")); 4252219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 4253168404Spjd } else if (argc == 0) { 4254168404Spjd int notfound; 4255168404Spjd 4256168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4257168404Spjd notfound = cb.cb_first; 4258168404Spjd 4259168404Spjd if (!cb.cb_all && ret == 0) { 4260168404Spjd if (!cb.cb_first) 4261168404Spjd (void) printf("\n"); 4262168404Spjd cb.cb_first = B_TRUE; 4263168404Spjd cb.cb_newer = B_TRUE; 4264168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4265168404Spjd if (!cb.cb_first) { 4266168404Spjd notfound = B_FALSE; 4267168404Spjd (void) printf("\n"); 4268168404Spjd } 4269168404Spjd } 4270168404Spjd 4271168404Spjd if (ret == 0) { 4272168404Spjd if (notfound) 4273168404Spjd (void) printf(gettext("All pools are formatted " 4274168404Spjd "using this version.\n")); 4275168404Spjd else if (!cb.cb_all) 4276168404Spjd (void) printf(gettext("Use 'zpool upgrade -v' " 4277168404Spjd "for a list of available versions and " 4278168404Spjd "their associated\nfeatures.\n")); 4279168404Spjd } 4280168404Spjd } else { 4281168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, 4282168404Spjd upgrade_one, &cb); 4283168404Spjd } 4284168404Spjd 4285212050Spjd if (cb.cb_poolname[0] != '\0') { 4286212050Spjd (void) printf( 4287212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 4288212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 4289212050Spjd "the following command will do it:\n" 4290212050Spjd "\n" 4291212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 4292212050Spjd cb.cb_poolname); 4293212050Spjd } 4294212050Spjd 4295168404Spjd return (ret); 4296168404Spjd} 4297168404Spjd 4298185029Spjdtypedef struct hist_cbdata { 4299185029Spjd boolean_t first; 4300185029Spjd int longfmt; 4301185029Spjd int internal; 4302185029Spjd} hist_cbdata_t; 4303185029Spjd 4304168404Spjd/* 4305168404Spjd * Print out the command history for a specific pool. 4306168404Spjd */ 4307168404Spjdstatic int 4308168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 4309168404Spjd{ 4310168404Spjd nvlist_t *nvhis; 4311168404Spjd nvlist_t **records; 4312168404Spjd uint_t numrecords; 4313168404Spjd char *cmdstr; 4314185029Spjd char *pathstr; 4315168404Spjd uint64_t dst_time; 4316168404Spjd time_t tsec; 4317168404Spjd struct tm t; 4318168404Spjd char tbuf[30]; 4319168404Spjd int ret, i; 4320185029Spjd uint64_t who; 4321185029Spjd struct passwd *pwd; 4322185029Spjd char *hostname; 4323185029Spjd char *zonename; 4324185029Spjd char internalstr[MAXPATHLEN]; 4325185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 4326185029Spjd uint64_t txg; 4327185029Spjd uint64_t ievent; 4328168404Spjd 4329185029Spjd cb->first = B_FALSE; 4330168404Spjd 4331168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 4332168404Spjd 4333168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 4334168404Spjd return (ret); 4335168404Spjd 4336168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 4337168404Spjd &records, &numrecords) == 0); 4338168404Spjd for (i = 0; i < numrecords; i++) { 4339168404Spjd if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 4340185029Spjd &dst_time) != 0) 4341185029Spjd continue; 4342185029Spjd 4343185029Spjd /* is it an internal event or a standard event? */ 4344185029Spjd if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 4345185029Spjd &cmdstr) != 0) { 4346185029Spjd if (cb->internal == 0) 4347185029Spjd continue; 4348185029Spjd 4349185029Spjd if (nvlist_lookup_uint64(records[i], 4350185029Spjd ZPOOL_HIST_INT_EVENT, &ievent) != 0) 4351185029Spjd continue; 4352185029Spjd verify(nvlist_lookup_uint64(records[i], 4353185029Spjd ZPOOL_HIST_TXG, &txg) == 0); 4354185029Spjd verify(nvlist_lookup_string(records[i], 4355185029Spjd ZPOOL_HIST_INT_STR, &pathstr) == 0); 4356185029Spjd if (ievent >= LOG_END) 4357185029Spjd continue; 4358185029Spjd (void) snprintf(internalstr, 4359185029Spjd sizeof (internalstr), 4360185029Spjd "[internal %s txg:%lld] %s", 4361219089Spjd zfs_history_event_names[ievent], txg, 4362185029Spjd pathstr); 4363185029Spjd cmdstr = internalstr; 4364168404Spjd } 4365185029Spjd tsec = dst_time; 4366185029Spjd (void) localtime_r(&tsec, &t); 4367185029Spjd (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 4368185029Spjd (void) printf("%s %s", tbuf, cmdstr); 4369185029Spjd 4370185029Spjd if (!cb->longfmt) { 4371185029Spjd (void) printf("\n"); 4372185029Spjd continue; 4373185029Spjd } 4374185029Spjd (void) printf(" ["); 4375185029Spjd if (nvlist_lookup_uint64(records[i], 4376185029Spjd ZPOOL_HIST_WHO, &who) == 0) { 4377185029Spjd pwd = getpwuid((uid_t)who); 4378185029Spjd if (pwd) 4379185029Spjd (void) printf("user %s on", 4380185029Spjd pwd->pw_name); 4381185029Spjd else 4382185029Spjd (void) printf("user %d on", 4383185029Spjd (int)who); 4384185029Spjd } else { 4385185029Spjd (void) printf(gettext("no info]\n")); 4386185029Spjd continue; 4387185029Spjd } 4388185029Spjd if (nvlist_lookup_string(records[i], 4389185029Spjd ZPOOL_HIST_HOST, &hostname) == 0) { 4390185029Spjd (void) printf(" %s", hostname); 4391185029Spjd } 4392185029Spjd if (nvlist_lookup_string(records[i], 4393185029Spjd ZPOOL_HIST_ZONE, &zonename) == 0) { 4394185029Spjd (void) printf(":%s", zonename); 4395185029Spjd } 4396185029Spjd 4397185029Spjd (void) printf("]"); 4398185029Spjd (void) printf("\n"); 4399168404Spjd } 4400168404Spjd (void) printf("\n"); 4401168404Spjd nvlist_free(nvhis); 4402168404Spjd 4403168404Spjd return (ret); 4404168404Spjd} 4405168404Spjd 4406168404Spjd/* 4407168404Spjd * zpool history <pool> 4408168404Spjd * 4409168404Spjd * Displays the history of commands that modified pools. 4410168404Spjd */ 4411185029Spjd 4412185029Spjd 4413168404Spjdint 4414168404Spjdzpool_do_history(int argc, char **argv) 4415168404Spjd{ 4416185029Spjd hist_cbdata_t cbdata = { 0 }; 4417168404Spjd int ret; 4418185029Spjd int c; 4419168404Spjd 4420185029Spjd cbdata.first = B_TRUE; 4421185029Spjd /* check options */ 4422185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 4423185029Spjd switch (c) { 4424185029Spjd case 'l': 4425185029Spjd cbdata.longfmt = 1; 4426185029Spjd break; 4427185029Spjd case 'i': 4428185029Spjd cbdata.internal = 1; 4429185029Spjd break; 4430185029Spjd case '?': 4431185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4432185029Spjd optopt); 4433185029Spjd usage(B_FALSE); 4434185029Spjd } 4435185029Spjd } 4436168404Spjd argc -= optind; 4437168404Spjd argv += optind; 4438168404Spjd 4439168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 4440185029Spjd &cbdata); 4441168404Spjd 4442185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 4443168404Spjd (void) printf(gettext("no pools available\n")); 4444168404Spjd return (0); 4445168404Spjd } 4446168404Spjd 4447168404Spjd return (ret); 4448168404Spjd} 4449168404Spjd 4450168404Spjdstatic int 4451168404Spjdget_callback(zpool_handle_t *zhp, void *data) 4452168404Spjd{ 4453185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 4454168404Spjd char value[MAXNAMELEN]; 4455185029Spjd zprop_source_t srctype; 4456185029Spjd zprop_list_t *pl; 4457168404Spjd 4458168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 4459168404Spjd 4460168404Spjd /* 4461185029Spjd * Skip the special fake placeholder. This will also skip 4462185029Spjd * over the name property when 'all' is specified. 4463168404Spjd */ 4464185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 4465168404Spjd pl == cbp->cb_proplist) 4466168404Spjd continue; 4467168404Spjd 4468168404Spjd if (zpool_get_prop(zhp, pl->pl_prop, 4469168404Spjd value, sizeof (value), &srctype) != 0) 4470168404Spjd continue; 4471168404Spjd 4472185029Spjd zprop_print_one_property(zpool_get_name(zhp), cbp, 4473219089Spjd zpool_prop_to_name(pl->pl_prop), value, srctype, NULL, 4474219089Spjd NULL); 4475168404Spjd } 4476168404Spjd return (0); 4477168404Spjd} 4478168404Spjd 4479168404Spjdint 4480168404Spjdzpool_do_get(int argc, char **argv) 4481168404Spjd{ 4482185029Spjd zprop_get_cbdata_t cb = { 0 }; 4483185029Spjd zprop_list_t fake_name = { 0 }; 4484168404Spjd int ret; 4485168404Spjd 4486168404Spjd if (argc < 3) 4487168404Spjd usage(B_FALSE); 4488168404Spjd 4489168404Spjd cb.cb_first = B_TRUE; 4490185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 4491168404Spjd cb.cb_columns[0] = GET_COL_NAME; 4492168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 4493168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 4494168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 4495185029Spjd cb.cb_type = ZFS_TYPE_POOL; 4496168404Spjd 4497185029Spjd if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 4498185029Spjd ZFS_TYPE_POOL) != 0) 4499168404Spjd usage(B_FALSE); 4500168404Spjd 4501168404Spjd if (cb.cb_proplist != NULL) { 4502185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 4503168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 4504168404Spjd fake_name.pl_next = cb.cb_proplist; 4505168404Spjd cb.cb_proplist = &fake_name; 4506168404Spjd } 4507168404Spjd 4508168404Spjd ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 4509168404Spjd get_callback, &cb); 4510168404Spjd 4511168404Spjd if (cb.cb_proplist == &fake_name) 4512185029Spjd zprop_free_list(fake_name.pl_next); 4513168404Spjd else 4514185029Spjd zprop_free_list(cb.cb_proplist); 4515168404Spjd 4516168404Spjd return (ret); 4517168404Spjd} 4518168404Spjd 4519168404Spjdtypedef struct set_cbdata { 4520168404Spjd char *cb_propname; 4521168404Spjd char *cb_value; 4522168404Spjd boolean_t cb_any_successful; 4523168404Spjd} set_cbdata_t; 4524168404Spjd 4525168404Spjdint 4526168404Spjdset_callback(zpool_handle_t *zhp, void *data) 4527168404Spjd{ 4528168404Spjd int error; 4529168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 4530168404Spjd 4531168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 4532168404Spjd 4533168404Spjd if (!error) 4534168404Spjd cb->cb_any_successful = B_TRUE; 4535168404Spjd 4536168404Spjd return (error); 4537168404Spjd} 4538168404Spjd 4539168404Spjdint 4540168404Spjdzpool_do_set(int argc, char **argv) 4541168404Spjd{ 4542168404Spjd set_cbdata_t cb = { 0 }; 4543168404Spjd int error; 4544168404Spjd 4545168404Spjd if (argc > 1 && argv[1][0] == '-') { 4546168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4547168404Spjd argv[1][1]); 4548168404Spjd usage(B_FALSE); 4549168404Spjd } 4550168404Spjd 4551168404Spjd if (argc < 2) { 4552168404Spjd (void) fprintf(stderr, gettext("missing property=value " 4553168404Spjd "argument\n")); 4554168404Spjd usage(B_FALSE); 4555168404Spjd } 4556168404Spjd 4557168404Spjd if (argc < 3) { 4558168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 4559168404Spjd usage(B_FALSE); 4560168404Spjd } 4561168404Spjd 4562168404Spjd if (argc > 3) { 4563168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 4564168404Spjd usage(B_FALSE); 4565168404Spjd } 4566168404Spjd 4567168404Spjd cb.cb_propname = argv[1]; 4568168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 4569168404Spjd if (cb.cb_value == NULL) { 4570168404Spjd (void) fprintf(stderr, gettext("missing value in " 4571168404Spjd "property=value argument\n")); 4572168404Spjd usage(B_FALSE); 4573168404Spjd } 4574168404Spjd 4575168404Spjd *(cb.cb_value) = '\0'; 4576168404Spjd cb.cb_value++; 4577168404Spjd 4578168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 4579168404Spjd set_callback, &cb); 4580168404Spjd 4581168404Spjd return (error); 4582168404Spjd} 4583168404Spjd 4584168404Spjdstatic int 4585168404Spjdfind_command_idx(char *command, int *idx) 4586168404Spjd{ 4587168404Spjd int i; 4588168404Spjd 4589168404Spjd for (i = 0; i < NCOMMAND; i++) { 4590168404Spjd if (command_table[i].name == NULL) 4591168404Spjd continue; 4592168404Spjd 4593168404Spjd if (strcmp(command, command_table[i].name) == 0) { 4594168404Spjd *idx = i; 4595168404Spjd return (0); 4596168404Spjd } 4597168404Spjd } 4598168404Spjd return (1); 4599168404Spjd} 4600168404Spjd 4601168404Spjdint 4602168404Spjdmain(int argc, char **argv) 4603168404Spjd{ 4604168404Spjd int ret; 4605168404Spjd int i; 4606168404Spjd char *cmdname; 4607168404Spjd 4608168404Spjd (void) setlocale(LC_ALL, ""); 4609168404Spjd (void) textdomain(TEXT_DOMAIN); 4610168404Spjd 4611168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 4612168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 4613168404Spjd "initialize ZFS library\n")); 4614168404Spjd return (1); 4615168404Spjd } 4616168404Spjd 4617168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 4618168404Spjd 4619168404Spjd opterr = 0; 4620168404Spjd 4621168404Spjd /* 4622168404Spjd * Make sure the user has specified some command. 4623168404Spjd */ 4624168404Spjd if (argc < 2) { 4625168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 4626168404Spjd usage(B_FALSE); 4627168404Spjd } 4628168404Spjd 4629168404Spjd cmdname = argv[1]; 4630168404Spjd 4631168404Spjd /* 4632168404Spjd * Special case '-?' 4633168404Spjd */ 4634168404Spjd if (strcmp(cmdname, "-?") == 0) 4635168404Spjd usage(B_TRUE); 4636168404Spjd 4637185029Spjd zpool_set_history_str("zpool", argc, argv, history_str); 4638185029Spjd verify(zpool_stage_history(g_zfs, history_str) == 0); 4639185029Spjd 4640168404Spjd /* 4641168404Spjd * Run the appropriate command. 4642168404Spjd */ 4643168404Spjd if (find_command_idx(cmdname, &i) == 0) { 4644168404Spjd current_command = &command_table[i]; 4645168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 4646185029Spjd } else if (strchr(cmdname, '=')) { 4647185029Spjd verify(find_command_idx("set", &i) == 0); 4648185029Spjd current_command = &command_table[i]; 4649185029Spjd ret = command_table[i].func(argc, argv); 4650185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 4651185029Spjd /* 4652185029Spjd * 'freeze' is a vile debugging abomination, so we treat 4653185029Spjd * it as such. 4654185029Spjd */ 4655168404Spjd char buf[16384]; 4656168404Spjd int fd = open(ZFS_DEV, O_RDWR); 4657168404Spjd (void) strcpy((void *)buf, argv[2]); 4658168404Spjd return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 4659185029Spjd } else { 4660168404Spjd (void) fprintf(stderr, gettext("unrecognized " 4661168404Spjd "command '%s'\n"), cmdname); 4662168404Spjd usage(B_FALSE); 4663168404Spjd } 4664168404Spjd 4665168404Spjd libzfs_fini(g_zfs); 4666168404Spjd 4667168404Spjd /* 4668168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 4669168404Spjd * for the purposes of running ::findleaks. 4670168404Spjd */ 4671168404Spjd if (getenv("ZFS_ABORT") != NULL) { 4672168404Spjd (void) printf("dumping core by request\n"); 4673168404Spjd abort(); 4674168404Spjd } 4675168404Spjd 4676168404Spjd return (ret); 4677168404Spjd} 4678