zpool_main.c revision 236884
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24227497Smm * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 25236155Smm * Copyright (c) 2012 by Delphix. All rights reserved. 26236145Smm * Copyright (c) 2012 by Frederik Wessels. All rights reserved. 27236155Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 28168404Spjd */ 29168404Spjd 30168404Spjd#include <solaris.h> 31168404Spjd#include <assert.h> 32168404Spjd#include <ctype.h> 33168404Spjd#include <dirent.h> 34168404Spjd#include <errno.h> 35168404Spjd#include <fcntl.h> 36168404Spjd#include <libgen.h> 37168404Spjd#include <libintl.h> 38168404Spjd#include <libuutil.h> 39168404Spjd#include <locale.h> 40168404Spjd#include <stdio.h> 41168404Spjd#include <stdlib.h> 42168404Spjd#include <string.h> 43168404Spjd#include <strings.h> 44168404Spjd#include <unistd.h> 45168404Spjd#include <priv.h> 46185029Spjd#include <pwd.h> 47185029Spjd#include <zone.h> 48168404Spjd#include <sys/time.h> 49236155Smm#include <zfs_prop.h> 50168404Spjd#include <sys/fs/zfs.h> 51168404Spjd#include <sys/stat.h> 52168404Spjd 53168404Spjd#include <libzfs.h> 54168404Spjd 55168404Spjd#include "zpool_util.h" 56185029Spjd#include "zfs_comutil.h" 57236884Smm#include "zfeature_common.h" 58168404Spjd 59219089Spjd#include "statcommon.h" 60219089Spjd 61168404Spjdstatic int zpool_do_create(int, char **); 62168404Spjdstatic int zpool_do_destroy(int, char **); 63168404Spjd 64168404Spjdstatic int zpool_do_add(int, char **); 65168404Spjdstatic int zpool_do_remove(int, char **); 66224171Sgibbsstatic int zpool_do_labelclear(int, char **); 67168404Spjd 68168404Spjdstatic int zpool_do_list(int, char **); 69168404Spjdstatic int zpool_do_iostat(int, char **); 70168404Spjdstatic int zpool_do_status(int, char **); 71168404Spjd 72168404Spjdstatic int zpool_do_online(int, char **); 73168404Spjdstatic int zpool_do_offline(int, char **); 74168404Spjdstatic int zpool_do_clear(int, char **); 75236155Smmstatic int zpool_do_reopen(int, char **); 76168404Spjd 77228103Smmstatic int zpool_do_reguid(int, char **); 78228103Smm 79168404Spjdstatic int zpool_do_attach(int, char **); 80168404Spjdstatic int zpool_do_detach(int, char **); 81168404Spjdstatic int zpool_do_replace(int, char **); 82219089Spjdstatic int zpool_do_split(int, char **); 83168404Spjd 84168404Spjdstatic int zpool_do_scrub(int, char **); 85168404Spjd 86168404Spjdstatic int zpool_do_import(int, char **); 87168404Spjdstatic int zpool_do_export(int, char **); 88168404Spjd 89168404Spjdstatic int zpool_do_upgrade(int, char **); 90168404Spjd 91168404Spjdstatic int zpool_do_history(int, char **); 92168404Spjd 93168404Spjdstatic int zpool_do_get(int, char **); 94168404Spjdstatic int zpool_do_set(int, char **); 95168404Spjd 96168404Spjd/* 97168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 98168404Spjd * debugging facilities. 99168404Spjd */ 100185029Spjd 101185029Spjd#ifdef DEBUG 102168404Spjdconst char * 103168404Spjd_umem_debug_init(void) 104168404Spjd{ 105168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 106168404Spjd} 107168404Spjd 108168404Spjdconst char * 109168404Spjd_umem_logging_init(void) 110168404Spjd{ 111168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 112168404Spjd} 113185029Spjd#endif 114168404Spjd 115168404Spjdtypedef enum { 116168404Spjd HELP_ADD, 117168404Spjd HELP_ATTACH, 118168404Spjd HELP_CLEAR, 119168404Spjd HELP_CREATE, 120168404Spjd HELP_DESTROY, 121168404Spjd HELP_DETACH, 122168404Spjd HELP_EXPORT, 123168404Spjd HELP_HISTORY, 124168404Spjd HELP_IMPORT, 125168404Spjd HELP_IOSTAT, 126224171Sgibbs HELP_LABELCLEAR, 127168404Spjd HELP_LIST, 128168404Spjd HELP_OFFLINE, 129168404Spjd HELP_ONLINE, 130168404Spjd HELP_REPLACE, 131168404Spjd HELP_REMOVE, 132168404Spjd HELP_SCRUB, 133168404Spjd HELP_STATUS, 134168404Spjd HELP_UPGRADE, 135168404Spjd HELP_GET, 136219089Spjd HELP_SET, 137228103Smm HELP_SPLIT, 138236155Smm HELP_REGUID, 139236155Smm HELP_REOPEN 140168404Spjd} zpool_help_t; 141168404Spjd 142168404Spjd 143168404Spjdtypedef struct zpool_command { 144168404Spjd const char *name; 145168404Spjd int (*func)(int, char **); 146168404Spjd zpool_help_t usage; 147168404Spjd} zpool_command_t; 148168404Spjd 149168404Spjd/* 150168404Spjd * Master command table. Each ZFS command has a name, associated function, and 151168404Spjd * usage message. The usage messages need to be internationalized, so we have 152168404Spjd * to have a function to return the usage message based on a command index. 153168404Spjd * 154168404Spjd * These commands are organized according to how they are displayed in the usage 155168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 156168404Spjd * the generic usage message. 157168404Spjd */ 158168404Spjdstatic zpool_command_t command_table[] = { 159168404Spjd { "create", zpool_do_create, HELP_CREATE }, 160168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 161168404Spjd { NULL }, 162168404Spjd { "add", zpool_do_add, HELP_ADD }, 163168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 164168404Spjd { NULL }, 165224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 166224171Sgibbs { NULL }, 167168404Spjd { "list", zpool_do_list, HELP_LIST }, 168168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 169168404Spjd { "status", zpool_do_status, HELP_STATUS }, 170168404Spjd { NULL }, 171168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 172168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 173168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 174236155Smm { "reopen", zpool_do_reopen, HELP_REOPEN }, 175168404Spjd { NULL }, 176168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 177168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 178168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 179219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 180168404Spjd { NULL }, 181168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 182168404Spjd { NULL }, 183168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 184168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 185168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 186228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 187168404Spjd { NULL }, 188168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 189168404Spjd { "get", zpool_do_get, HELP_GET }, 190168404Spjd { "set", zpool_do_set, HELP_SET }, 191168404Spjd}; 192168404Spjd 193168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 194168404Spjd 195168404Spjdzpool_command_t *current_command; 196185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 197168404Spjd 198219089Spjdstatic uint_t timestamp_fmt = NODATE; 199219089Spjd 200168404Spjdstatic const char * 201168404Spjdget_usage(zpool_help_t idx) { 202168404Spjd switch (idx) { 203168404Spjd case HELP_ADD: 204168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 205168404Spjd case HELP_ATTACH: 206168404Spjd return (gettext("\tattach [-f] <pool> <device> " 207185029Spjd "<new-device>\n")); 208168404Spjd case HELP_CLEAR: 209219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 210168404Spjd case HELP_CREATE: 211236884Smm return (gettext("\tcreate [-fnd] [-o property=value] ... \n" 212185029Spjd "\t [-O file-system-property=value] ... \n" 213185029Spjd "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 214168404Spjd case HELP_DESTROY: 215168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 216168404Spjd case HELP_DETACH: 217168404Spjd return (gettext("\tdetach <pool> <device>\n")); 218168404Spjd case HELP_EXPORT: 219168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 220168404Spjd case HELP_HISTORY: 221185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 222168404Spjd case HELP_IMPORT: 223168404Spjd return (gettext("\timport [-d dir] [-D]\n" 224219089Spjd "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 225185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 226219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 227219089Spjd "[-R root] [-F [-n]] -a\n" 228185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 229219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 230219089Spjd "[-R root] [-F [-n]]\n" 231219089Spjd "\t <pool | id> [newpool]\n")); 232168404Spjd case HELP_IOSTAT: 233219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 234168404Spjd "[count]]\n")); 235224171Sgibbs case HELP_LABELCLEAR: 236224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 237168404Spjd case HELP_LIST: 238185029Spjd return (gettext("\tlist [-H] [-o property[,...]] " 239219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 240168404Spjd case HELP_OFFLINE: 241168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 242168404Spjd case HELP_ONLINE: 243228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 244168404Spjd case HELP_REPLACE: 245168404Spjd return (gettext("\treplace [-f] <pool> <device> " 246185029Spjd "[new-device]\n")); 247168404Spjd case HELP_REMOVE: 248185029Spjd return (gettext("\tremove <pool> <device> ...\n")); 249236155Smm case HELP_REOPEN: 250236155Smm return (""); /* Undocumented command */ 251168404Spjd case HELP_SCRUB: 252168404Spjd return (gettext("\tscrub [-s] <pool> ...\n")); 253168404Spjd case HELP_STATUS: 254219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 255219089Spjd "[count]]\n")); 256168404Spjd case HELP_UPGRADE: 257228020Smm return (gettext("\tupgrade [-v]\n" 258185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 259168404Spjd case HELP_GET: 260185029Spjd return (gettext("\tget <\"all\" | property[,...]> " 261168404Spjd "<pool> ...\n")); 262168404Spjd case HELP_SET: 263168404Spjd return (gettext("\tset <property=value> <pool> \n")); 264219089Spjd case HELP_SPLIT: 265219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 266219089Spjd "\t [-o property=value] <pool> <newpool> " 267219089Spjd "[<device> ...]\n")); 268228103Smm case HELP_REGUID: 269228103Smm return (gettext("\treguid <pool>\n")); 270168404Spjd } 271168404Spjd 272168404Spjd abort(); 273168404Spjd /* NOTREACHED */ 274168404Spjd} 275168404Spjd 276168404Spjd 277168404Spjd/* 278168404Spjd * Callback routine that will print out a pool property value. 279168404Spjd */ 280185029Spjdstatic int 281185029Spjdprint_prop_cb(int prop, void *cb) 282168404Spjd{ 283168404Spjd FILE *fp = cb; 284168404Spjd 285219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 286168404Spjd 287185029Spjd if (zpool_prop_readonly(prop)) 288185029Spjd (void) fprintf(fp, " NO "); 289185029Spjd else 290219089Spjd (void) fprintf(fp, " YES "); 291185029Spjd 292168404Spjd if (zpool_prop_values(prop) == NULL) 293168404Spjd (void) fprintf(fp, "-\n"); 294168404Spjd else 295168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 296168404Spjd 297185029Spjd return (ZPROP_CONT); 298168404Spjd} 299168404Spjd 300168404Spjd/* 301168404Spjd * Display usage message. If we're inside a command, display only the usage for 302168404Spjd * that command. Otherwise, iterate over the entire command table and display 303168404Spjd * a complete usage message. 304168404Spjd */ 305168404Spjdvoid 306168404Spjdusage(boolean_t requested) 307168404Spjd{ 308168404Spjd FILE *fp = requested ? stdout : stderr; 309168404Spjd 310168404Spjd if (current_command == NULL) { 311168404Spjd int i; 312168404Spjd 313168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 314168404Spjd (void) fprintf(fp, 315168404Spjd gettext("where 'command' is one of the following:\n\n")); 316168404Spjd 317168404Spjd for (i = 0; i < NCOMMAND; i++) { 318168404Spjd if (command_table[i].name == NULL) 319168404Spjd (void) fprintf(fp, "\n"); 320168404Spjd else 321168404Spjd (void) fprintf(fp, "%s", 322168404Spjd get_usage(command_table[i].usage)); 323168404Spjd } 324168404Spjd } else { 325168404Spjd (void) fprintf(fp, gettext("usage:\n")); 326168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 327168404Spjd } 328168404Spjd 329168404Spjd if (current_command != NULL && 330168404Spjd ((strcmp(current_command->name, "set") == 0) || 331185029Spjd (strcmp(current_command->name, "get") == 0) || 332185029Spjd (strcmp(current_command->name, "list") == 0))) { 333168404Spjd 334168404Spjd (void) fprintf(fp, 335168404Spjd gettext("\nthe following properties are supported:\n")); 336168404Spjd 337219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 338185029Spjd "PROPERTY", "EDIT", "VALUES"); 339168404Spjd 340168404Spjd /* Iterate over all properties */ 341185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 342185029Spjd ZFS_TYPE_POOL); 343236884Smm 344236884Smm (void) fprintf(fp, "\t%-15s ", "feature@..."); 345236884Smm (void) fprintf(fp, "YES disabled | enabled | active\n"); 346236884Smm 347236884Smm (void) fprintf(fp, gettext("\nThe feature@ properties must be " 348236884Smm "appended with a feature name.\nSee zpool-features(5).\n")); 349168404Spjd } 350168404Spjd 351168404Spjd /* 352168404Spjd * See comments at end of main(). 353168404Spjd */ 354168404Spjd if (getenv("ZFS_ABORT") != NULL) { 355168404Spjd (void) printf("dumping core by request\n"); 356168404Spjd abort(); 357168404Spjd } 358168404Spjd 359168404Spjd exit(requested ? 0 : 2); 360168404Spjd} 361168404Spjd 362168404Spjdvoid 363185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 364185029Spjd boolean_t print_logs) 365168404Spjd{ 366168404Spjd nvlist_t **child; 367168404Spjd uint_t c, children; 368168404Spjd char *vname; 369168404Spjd 370168404Spjd if (name != NULL) 371168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 372168404Spjd 373168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 374168404Spjd &child, &children) != 0) 375168404Spjd return; 376168404Spjd 377168404Spjd for (c = 0; c < children; c++) { 378185029Spjd uint64_t is_log = B_FALSE; 379185029Spjd 380185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 381185029Spjd &is_log); 382185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 383185029Spjd continue; 384185029Spjd 385219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 386185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 387185029Spjd B_FALSE); 388168404Spjd free(vname); 389168404Spjd } 390168404Spjd} 391168404Spjd 392168404Spjd/* 393185029Spjd * Add a property pair (name, string-value) into a property nvlist. 394185029Spjd */ 395185029Spjdstatic int 396185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 397185029Spjd boolean_t poolprop) 398185029Spjd{ 399185029Spjd zpool_prop_t prop = ZPROP_INVAL; 400185029Spjd zfs_prop_t fprop; 401185029Spjd nvlist_t *proplist; 402185029Spjd const char *normnm; 403185029Spjd char *strval; 404185029Spjd 405185029Spjd if (*props == NULL && 406185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 407185029Spjd (void) fprintf(stderr, 408185029Spjd gettext("internal error: out of memory\n")); 409185029Spjd return (1); 410185029Spjd } 411185029Spjd 412185029Spjd proplist = *props; 413185029Spjd 414185029Spjd if (poolprop) { 415236884Smm if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 416236884Smm !zpool_prop_feature(propname)) { 417185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 418185029Spjd "not a valid pool property\n"), propname); 419185029Spjd return (2); 420185029Spjd } 421236884Smm if (zpool_prop_feature(propname)) 422236884Smm normnm = propname; 423236884Smm else 424236884Smm normnm = zpool_prop_to_name(prop); 425185029Spjd } else { 426209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 427209962Smm normnm = zfs_prop_to_name(fprop); 428209962Smm } else { 429209962Smm normnm = propname; 430185029Spjd } 431185029Spjd } 432185029Spjd 433185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 434185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 435185029Spjd (void) fprintf(stderr, gettext("property '%s' " 436185029Spjd "specified multiple times\n"), propname); 437185029Spjd return (2); 438185029Spjd } 439185029Spjd 440185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 441185029Spjd (void) fprintf(stderr, gettext("internal " 442185029Spjd "error: out of memory\n")); 443185029Spjd return (1); 444185029Spjd } 445185029Spjd 446185029Spjd return (0); 447185029Spjd} 448185029Spjd 449185029Spjd/* 450168404Spjd * zpool add [-fn] <pool> <vdev> ... 451168404Spjd * 452168404Spjd * -f Force addition of devices, even if they appear in use 453168404Spjd * -n Do not add the devices, but display the resulting layout if 454168404Spjd * they were to be added. 455168404Spjd * 456168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 457168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 458168404Spjd * libzfs. 459168404Spjd */ 460168404Spjdint 461168404Spjdzpool_do_add(int argc, char **argv) 462168404Spjd{ 463168404Spjd boolean_t force = B_FALSE; 464168404Spjd boolean_t dryrun = B_FALSE; 465168404Spjd int c; 466168404Spjd nvlist_t *nvroot; 467168404Spjd char *poolname; 468168404Spjd int ret; 469168404Spjd zpool_handle_t *zhp; 470168404Spjd nvlist_t *config; 471168404Spjd 472168404Spjd /* check options */ 473168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 474168404Spjd switch (c) { 475168404Spjd case 'f': 476168404Spjd force = B_TRUE; 477168404Spjd break; 478168404Spjd case 'n': 479168404Spjd dryrun = B_TRUE; 480168404Spjd break; 481168404Spjd case '?': 482168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 483168404Spjd optopt); 484168404Spjd usage(B_FALSE); 485168404Spjd } 486168404Spjd } 487168404Spjd 488168404Spjd argc -= optind; 489168404Spjd argv += optind; 490168404Spjd 491168404Spjd /* get pool name and check number of arguments */ 492168404Spjd if (argc < 1) { 493168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 494168404Spjd usage(B_FALSE); 495168404Spjd } 496168404Spjd if (argc < 2) { 497168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 498168404Spjd usage(B_FALSE); 499168404Spjd } 500168404Spjd 501168404Spjd poolname = argv[0]; 502168404Spjd 503168404Spjd argc--; 504168404Spjd argv++; 505168404Spjd 506168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 507168404Spjd return (1); 508168404Spjd 509168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 510168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 511168404Spjd poolname); 512168404Spjd zpool_close(zhp); 513168404Spjd return (1); 514168404Spjd } 515168404Spjd 516168404Spjd /* pass off to get_vdev_spec for processing */ 517185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 518185029Spjd argc, argv); 519168404Spjd if (nvroot == NULL) { 520168404Spjd zpool_close(zhp); 521168404Spjd return (1); 522168404Spjd } 523168404Spjd 524168404Spjd if (dryrun) { 525168404Spjd nvlist_t *poolnvroot; 526168404Spjd 527168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 528168404Spjd &poolnvroot) == 0); 529168404Spjd 530168404Spjd (void) printf(gettext("would update '%s' to the following " 531168404Spjd "configuration:\n"), zpool_get_name(zhp)); 532168404Spjd 533185029Spjd /* print original main pool and new tree */ 534185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 535185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 536168404Spjd 537185029Spjd /* Do the same for the logs */ 538185029Spjd if (num_logs(poolnvroot) > 0) { 539185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 540185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 541185029Spjd } else if (num_logs(nvroot) > 0) { 542185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 543185029Spjd } 544185029Spjd 545168404Spjd ret = 0; 546168404Spjd } else { 547168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 548168404Spjd } 549168404Spjd 550168404Spjd nvlist_free(nvroot); 551168404Spjd zpool_close(zhp); 552168404Spjd 553168404Spjd return (ret); 554168404Spjd} 555168404Spjd 556168404Spjd/* 557219089Spjd * zpool remove <pool> <vdev> ... 558168404Spjd * 559219089Spjd * Removes the given vdev from the pool. Currently, this supports removing 560219089Spjd * spares, cache, and log devices from the pool. 561168404Spjd */ 562168404Spjdint 563168404Spjdzpool_do_remove(int argc, char **argv) 564168404Spjd{ 565168404Spjd char *poolname; 566185029Spjd int i, ret = 0; 567168404Spjd zpool_handle_t *zhp; 568168404Spjd 569168404Spjd argc--; 570168404Spjd argv++; 571168404Spjd 572168404Spjd /* get pool name and check number of arguments */ 573168404Spjd if (argc < 1) { 574168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 575168404Spjd usage(B_FALSE); 576168404Spjd } 577168404Spjd if (argc < 2) { 578168404Spjd (void) fprintf(stderr, gettext("missing device\n")); 579168404Spjd usage(B_FALSE); 580168404Spjd } 581168404Spjd 582168404Spjd poolname = argv[0]; 583168404Spjd 584168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 585168404Spjd return (1); 586168404Spjd 587185029Spjd for (i = 1; i < argc; i++) { 588185029Spjd if (zpool_vdev_remove(zhp, argv[i]) != 0) 589185029Spjd ret = 1; 590168404Spjd } 591168404Spjd 592168404Spjd return (ret); 593168404Spjd} 594168404Spjd 595168404Spjd/* 596224171Sgibbs * zpool labelclear <vdev> 597224171Sgibbs * 598224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 599224171Sgibbs * on the device. 600224171Sgibbs */ 601224171Sgibbsint 602224171Sgibbszpool_do_labelclear(int argc, char **argv) 603224171Sgibbs{ 604224171Sgibbs char *vdev, *name; 605224171Sgibbs int c, fd = -1, ret = 0; 606224171Sgibbs pool_state_t state; 607224171Sgibbs boolean_t inuse = B_FALSE; 608224171Sgibbs boolean_t force = B_FALSE; 609224171Sgibbs 610224171Sgibbs /* check options */ 611224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 612224171Sgibbs switch (c) { 613224171Sgibbs case 'f': 614224171Sgibbs force = B_TRUE; 615224171Sgibbs break; 616224171Sgibbs default: 617224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 618224171Sgibbs optopt); 619224171Sgibbs usage(B_FALSE); 620224171Sgibbs } 621224171Sgibbs } 622224171Sgibbs 623224171Sgibbs argc -= optind; 624224171Sgibbs argv += optind; 625224171Sgibbs 626224171Sgibbs /* get vdev name */ 627224171Sgibbs if (argc < 1) { 628224171Sgibbs (void) fprintf(stderr, gettext("missing vdev device name\n")); 629224171Sgibbs usage(B_FALSE); 630224171Sgibbs } 631224171Sgibbs 632224171Sgibbs vdev = argv[0]; 633224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 634224171Sgibbs (void) fprintf(stderr, gettext("Unable to open %s\n"), vdev); 635224171Sgibbs return (B_FALSE); 636224171Sgibbs } 637224171Sgibbs 638224171Sgibbs name = NULL; 639224171Sgibbs if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) { 640224171Sgibbs if (force) 641224171Sgibbs goto wipe_label; 642224171Sgibbs 643224171Sgibbs (void) fprintf(stderr, 644224171Sgibbs gettext("Unable to determine pool state for %s\n" 645224171Sgibbs "Use -f to force the clearing any label data\n"), vdev); 646224171Sgibbs 647224171Sgibbs return (1); 648224171Sgibbs } 649224171Sgibbs 650224171Sgibbs if (inuse) { 651224171Sgibbs switch (state) { 652224171Sgibbs default: 653224171Sgibbs case POOL_STATE_ACTIVE: 654224171Sgibbs case POOL_STATE_SPARE: 655224171Sgibbs case POOL_STATE_L2CACHE: 656224171Sgibbs (void) fprintf(stderr, 657224171Sgibbsgettext("labelclear operation failed.\n" 658224171Sgibbs "\tVdev %s is a member (%s), of pool \"%s\".\n" 659224171Sgibbs "\tTo remove label information from this device, export or destroy\n" 660224171Sgibbs "\tthe pool, or remove %s from the configuration of this pool\n" 661224171Sgibbs "\tand retry the labelclear operation\n"), 662224171Sgibbs vdev, zpool_pool_state_to_name(state), name, vdev); 663224171Sgibbs ret = 1; 664224171Sgibbs goto errout; 665224171Sgibbs 666224171Sgibbs case POOL_STATE_EXPORTED: 667224171Sgibbs if (force) 668224171Sgibbs break; 669224171Sgibbs 670224171Sgibbs (void) fprintf(stderr, 671224171Sgibbsgettext("labelclear operation failed.\n" 672224171Sgibbs "\tVdev %s is a member of the exported pool \"%s\".\n" 673224171Sgibbs "\tUse \"zpool labelclear -f %s\" to force the removal of label\n" 674224171Sgibbs "\tinformation.\n"), 675224171Sgibbs vdev, name, vdev); 676224171Sgibbs ret = 1; 677224171Sgibbs goto errout; 678224171Sgibbs 679224171Sgibbs case POOL_STATE_POTENTIALLY_ACTIVE: 680224171Sgibbs if (force) 681224171Sgibbs break; 682224171Sgibbs 683224171Sgibbs (void) fprintf(stderr, 684224171Sgibbsgettext("labelclear operation failed.\n" 685224171Sgibbs "\tVdev %s is a member of the pool \"%s\".\n" 686224171Sgibbs "\tThis pool is unknown to this system, but may be active on\n" 687224171Sgibbs "\tanother system. Use \'zpool labelclear -f %s\' to force the\n" 688224171Sgibbs "\tremoval of label information.\n"), 689224171Sgibbs vdev, name, vdev); 690224171Sgibbs ret = 1; 691224171Sgibbs goto errout; 692224171Sgibbs 693224171Sgibbs case POOL_STATE_DESTROYED: 694224171Sgibbs /* inuse should never be set for a destoryed pool... */ 695224171Sgibbs break; 696224171Sgibbs } 697224171Sgibbs } 698224171Sgibbs 699224171Sgibbswipe_label: 700224171Sgibbs if (zpool_clear_label(fd) != 0) { 701224171Sgibbs (void) fprintf(stderr, 702224171Sgibbs gettext("Label clear failed on vdev %s\n"), vdev); 703224171Sgibbs ret = 1; 704224171Sgibbs } 705224171Sgibbs 706224171Sgibbserrout: 707224171Sgibbs close(fd); 708224171Sgibbs if (name != NULL) 709224171Sgibbs free(name); 710224171Sgibbs 711224171Sgibbs return (ret); 712224171Sgibbs} 713224171Sgibbs 714224171Sgibbs/* 715236884Smm * zpool create [-fnd] [-o property=value] ... 716185029Spjd * [-O file-system-property=value] ... 717185029Spjd * [-R root] [-m mountpoint] <pool> <dev> ... 718168404Spjd * 719168404Spjd * -f Force creation, even if devices appear in use 720168404Spjd * -n Do not create the pool, but display the resulting layout if it 721168404Spjd * were to be created. 722168404Spjd * -R Create a pool under an alternate root 723168404Spjd * -m Set default mountpoint for the root dataset. By default it's 724236884Smm * '/<pool>' 725185029Spjd * -o Set property=value. 726236884Smm * -d Don't automatically enable all supported pool features 727236884Smm * (individual features can be enabled with -o). 728185029Spjd * -O Set fsproperty=value in the pool's root file system 729168404Spjd * 730168404Spjd * Creates the named pool according to the given vdev specification. The 731168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 732168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 733168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 734168404Spjd */ 735168404Spjdint 736168404Spjdzpool_do_create(int argc, char **argv) 737168404Spjd{ 738168404Spjd boolean_t force = B_FALSE; 739168404Spjd boolean_t dryrun = B_FALSE; 740236884Smm boolean_t enable_all_pool_feat = B_TRUE; 741168404Spjd int c; 742185029Spjd nvlist_t *nvroot = NULL; 743168404Spjd char *poolname; 744185029Spjd int ret = 1; 745168404Spjd char *altroot = NULL; 746168404Spjd char *mountpoint = NULL; 747185029Spjd nvlist_t *fsprops = NULL; 748185029Spjd nvlist_t *props = NULL; 749185029Spjd char *propval; 750168404Spjd 751168404Spjd /* check options */ 752236884Smm while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) { 753168404Spjd switch (c) { 754168404Spjd case 'f': 755168404Spjd force = B_TRUE; 756168404Spjd break; 757168404Spjd case 'n': 758168404Spjd dryrun = B_TRUE; 759168404Spjd break; 760236884Smm case 'd': 761236884Smm enable_all_pool_feat = B_FALSE; 762236884Smm break; 763168404Spjd case 'R': 764168404Spjd altroot = optarg; 765185029Spjd if (add_prop_list(zpool_prop_to_name( 766185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 767185029Spjd goto errout; 768185029Spjd if (nvlist_lookup_string(props, 769185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 770185029Spjd &propval) == 0) 771185029Spjd break; 772185029Spjd if (add_prop_list(zpool_prop_to_name( 773185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 774185029Spjd goto errout; 775168404Spjd break; 776168404Spjd case 'm': 777168404Spjd mountpoint = optarg; 778168404Spjd break; 779185029Spjd case 'o': 780185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 781185029Spjd (void) fprintf(stderr, gettext("missing " 782185029Spjd "'=' for -o option\n")); 783185029Spjd goto errout; 784185029Spjd } 785185029Spjd *propval = '\0'; 786185029Spjd propval++; 787185029Spjd 788185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 789185029Spjd goto errout; 790236884Smm 791236884Smm /* 792236884Smm * If the user is creating a pool that doesn't support 793236884Smm * feature flags, don't enable any features. 794236884Smm */ 795236884Smm if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 796236884Smm char *end; 797236884Smm u_longlong_t ver; 798236884Smm 799236884Smm ver = strtoull(propval, &end, 10); 800236884Smm if (*end == '\0' && 801236884Smm ver < SPA_VERSION_FEATURES) { 802236884Smm enable_all_pool_feat = B_FALSE; 803236884Smm } 804236884Smm } 805185029Spjd break; 806185029Spjd case 'O': 807185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 808185029Spjd (void) fprintf(stderr, gettext("missing " 809185029Spjd "'=' for -O option\n")); 810185029Spjd goto errout; 811185029Spjd } 812185029Spjd *propval = '\0'; 813185029Spjd propval++; 814185029Spjd 815185029Spjd if (add_prop_list(optarg, propval, &fsprops, B_FALSE)) 816185029Spjd goto errout; 817185029Spjd break; 818168404Spjd case ':': 819168404Spjd (void) fprintf(stderr, gettext("missing argument for " 820168404Spjd "'%c' option\n"), optopt); 821185029Spjd goto badusage; 822168404Spjd case '?': 823168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 824168404Spjd optopt); 825185029Spjd goto badusage; 826168404Spjd } 827168404Spjd } 828168404Spjd 829168404Spjd argc -= optind; 830168404Spjd argv += optind; 831168404Spjd 832168404Spjd /* get pool name and check number of arguments */ 833168404Spjd if (argc < 1) { 834168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 835185029Spjd goto badusage; 836168404Spjd } 837168404Spjd if (argc < 2) { 838168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 839185029Spjd goto badusage; 840168404Spjd } 841168404Spjd 842168404Spjd poolname = argv[0]; 843168404Spjd 844168404Spjd /* 845168404Spjd * As a special case, check for use of '/' in the name, and direct the 846168404Spjd * user to use 'zfs create' instead. 847168404Spjd */ 848168404Spjd if (strchr(poolname, '/') != NULL) { 849168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 850168404Spjd "character '/' in pool name\n"), poolname); 851168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 852168404Spjd "create a dataset\n")); 853185029Spjd goto errout; 854168404Spjd } 855168404Spjd 856168404Spjd /* pass off to get_vdev_spec for bulk processing */ 857185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 858185029Spjd argc - 1, argv + 1); 859168404Spjd if (nvroot == NULL) 860185029Spjd goto errout; 861168404Spjd 862168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 863185029Spjd if (!zfs_allocatable_devs(nvroot)) { 864168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 865168404Spjd "specification: at least one toplevel vdev must be " 866168404Spjd "specified\n")); 867185029Spjd goto errout; 868168404Spjd } 869168404Spjd 870168404Spjd if (altroot != NULL && altroot[0] != '/') { 871168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 872168404Spjd "must be an absolute path\n"), altroot); 873185029Spjd goto errout; 874168404Spjd } 875168404Spjd 876168404Spjd /* 877168404Spjd * Check the validity of the mountpoint and direct the user to use the 878168404Spjd * '-m' mountpoint option if it looks like its in use. 879168404Spjd */ 880168404Spjd if (mountpoint == NULL || 881168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 882168404Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 883168404Spjd char buf[MAXPATHLEN]; 884185029Spjd DIR *dirp; 885168404Spjd 886168404Spjd if (mountpoint && mountpoint[0] != '/') { 887168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 888168404Spjd "'%s': must be an absolute path, 'legacy', or " 889168404Spjd "'none'\n"), mountpoint); 890185029Spjd goto errout; 891168404Spjd } 892168404Spjd 893168404Spjd if (mountpoint == NULL) { 894168404Spjd if (altroot != NULL) 895168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 896168404Spjd altroot, poolname); 897168404Spjd else 898168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 899168404Spjd poolname); 900168404Spjd } else { 901168404Spjd if (altroot != NULL) 902168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 903168404Spjd altroot, mountpoint); 904168404Spjd else 905168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 906168404Spjd mountpoint); 907168404Spjd } 908168404Spjd 909185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 910185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 911185029Spjd "%s\n"), buf, strerror(errno)); 912185029Spjd (void) fprintf(stderr, gettext("use '-m' " 913185029Spjd "option to provide a different default\n")); 914185029Spjd goto errout; 915185029Spjd } else if (dirp) { 916185029Spjd int count = 0; 917185029Spjd 918185029Spjd while (count < 3 && readdir(dirp) != NULL) 919185029Spjd count++; 920185029Spjd (void) closedir(dirp); 921185029Spjd 922185029Spjd if (count > 2) { 923168404Spjd (void) fprintf(stderr, gettext("mountpoint " 924168404Spjd "'%s' exists and is not empty\n"), buf); 925185029Spjd (void) fprintf(stderr, gettext("use '-m' " 926185029Spjd "option to provide a " 927185029Spjd "different default\n")); 928185029Spjd goto errout; 929185029Spjd } 930168404Spjd } 931168404Spjd } 932168404Spjd 933168404Spjd if (dryrun) { 934168404Spjd /* 935168404Spjd * For a dry run invocation, print out a basic message and run 936168404Spjd * through all the vdevs in the list and print out in an 937168404Spjd * appropriate hierarchy. 938168404Spjd */ 939168404Spjd (void) printf(gettext("would create '%s' with the " 940168404Spjd "following layout:\n\n"), poolname); 941168404Spjd 942185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 943185029Spjd if (num_logs(nvroot) > 0) 944185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 945168404Spjd 946168404Spjd ret = 0; 947168404Spjd } else { 948168404Spjd /* 949168404Spjd * Hand off to libzfs. 950168404Spjd */ 951236884Smm if (enable_all_pool_feat) { 952236884Smm int i; 953236884Smm for (i = 0; i < SPA_FEATURES; i++) { 954236884Smm char propname[MAXPATHLEN]; 955236884Smm zfeature_info_t *feat = &spa_feature_table[i]; 956236884Smm 957236884Smm (void) snprintf(propname, sizeof (propname), 958236884Smm "feature@%s", feat->fi_uname); 959236884Smm 960236884Smm /* 961236884Smm * Skip feature if user specified it manually 962236884Smm * on the command line. 963236884Smm */ 964236884Smm if (nvlist_exists(props, propname)) 965236884Smm continue; 966236884Smm 967236884Smm if (add_prop_list(propname, ZFS_FEATURE_ENABLED, 968236884Smm &props, B_TRUE) != 0) 969236884Smm goto errout; 970236884Smm } 971236884Smm } 972185029Spjd if (zpool_create(g_zfs, poolname, 973185029Spjd nvroot, props, fsprops) == 0) { 974168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 975168404Spjd ZFS_TYPE_FILESYSTEM); 976168404Spjd if (pool != NULL) { 977168404Spjd if (mountpoint != NULL) 978168404Spjd verify(zfs_prop_set(pool, 979168404Spjd zfs_prop_to_name( 980168404Spjd ZFS_PROP_MOUNTPOINT), 981168404Spjd mountpoint) == 0); 982168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 983185029Spjd ret = zfs_shareall(pool); 984168404Spjd zfs_close(pool); 985168404Spjd } 986168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 987168404Spjd (void) fprintf(stderr, gettext("pool name may have " 988168404Spjd "been omitted\n")); 989168404Spjd } 990168404Spjd } 991168404Spjd 992185029Spjderrout: 993168404Spjd nvlist_free(nvroot); 994185029Spjd nvlist_free(fsprops); 995185029Spjd nvlist_free(props); 996168404Spjd return (ret); 997185029Spjdbadusage: 998185029Spjd nvlist_free(fsprops); 999185029Spjd nvlist_free(props); 1000185029Spjd usage(B_FALSE); 1001185029Spjd return (2); 1002168404Spjd} 1003168404Spjd 1004168404Spjd/* 1005168404Spjd * zpool destroy <pool> 1006168404Spjd * 1007168404Spjd * -f Forcefully unmount any datasets 1008168404Spjd * 1009168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 1010168404Spjd */ 1011168404Spjdint 1012168404Spjdzpool_do_destroy(int argc, char **argv) 1013168404Spjd{ 1014168404Spjd boolean_t force = B_FALSE; 1015168404Spjd int c; 1016168404Spjd char *pool; 1017168404Spjd zpool_handle_t *zhp; 1018168404Spjd int ret; 1019168404Spjd 1020168404Spjd /* check options */ 1021168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 1022168404Spjd switch (c) { 1023168404Spjd case 'f': 1024168404Spjd force = B_TRUE; 1025168404Spjd break; 1026168404Spjd case '?': 1027168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1028168404Spjd optopt); 1029168404Spjd usage(B_FALSE); 1030168404Spjd } 1031168404Spjd } 1032168404Spjd 1033168404Spjd argc -= optind; 1034168404Spjd argv += optind; 1035168404Spjd 1036168404Spjd /* check arguments */ 1037168404Spjd if (argc < 1) { 1038168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1039168404Spjd usage(B_FALSE); 1040168404Spjd } 1041168404Spjd if (argc > 1) { 1042168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1043168404Spjd usage(B_FALSE); 1044168404Spjd } 1045168404Spjd 1046168404Spjd pool = argv[0]; 1047168404Spjd 1048168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1049168404Spjd /* 1050168404Spjd * As a special case, check for use of '/' in the name, and 1051168404Spjd * direct the user to use 'zfs destroy' instead. 1052168404Spjd */ 1053168404Spjd if (strchr(pool, '/') != NULL) 1054168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1055168404Spjd "destroy a dataset\n")); 1056168404Spjd return (1); 1057168404Spjd } 1058168404Spjd 1059168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1060168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1061168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1062168404Spjd return (1); 1063168404Spjd } 1064168404Spjd 1065168404Spjd ret = (zpool_destroy(zhp) != 0); 1066168404Spjd 1067168404Spjd zpool_close(zhp); 1068168404Spjd 1069168404Spjd return (ret); 1070168404Spjd} 1071168404Spjd 1072168404Spjd/* 1073168404Spjd * zpool export [-f] <pool> ... 1074168404Spjd * 1075168404Spjd * -f Forcefully unmount datasets 1076168404Spjd * 1077168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1078168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1079168404Spjd * then the datasets will be forcefully unmounted. 1080168404Spjd */ 1081168404Spjdint 1082168404Spjdzpool_do_export(int argc, char **argv) 1083168404Spjd{ 1084168404Spjd boolean_t force = B_FALSE; 1085207670Smm boolean_t hardforce = B_FALSE; 1086168404Spjd int c; 1087168404Spjd zpool_handle_t *zhp; 1088168404Spjd int ret; 1089168404Spjd int i; 1090168404Spjd 1091168404Spjd /* check options */ 1092207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1093168404Spjd switch (c) { 1094168404Spjd case 'f': 1095168404Spjd force = B_TRUE; 1096168404Spjd break; 1097207670Smm case 'F': 1098207670Smm hardforce = B_TRUE; 1099207670Smm break; 1100168404Spjd case '?': 1101168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1102168404Spjd optopt); 1103168404Spjd usage(B_FALSE); 1104168404Spjd } 1105168404Spjd } 1106168404Spjd 1107168404Spjd argc -= optind; 1108168404Spjd argv += optind; 1109168404Spjd 1110168404Spjd /* check arguments */ 1111168404Spjd if (argc < 1) { 1112168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1113168404Spjd usage(B_FALSE); 1114168404Spjd } 1115168404Spjd 1116168404Spjd ret = 0; 1117168404Spjd for (i = 0; i < argc; i++) { 1118168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1119168404Spjd ret = 1; 1120168404Spjd continue; 1121168404Spjd } 1122168404Spjd 1123168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1124168404Spjd ret = 1; 1125168404Spjd zpool_close(zhp); 1126168404Spjd continue; 1127168404Spjd } 1128168404Spjd 1129207670Smm if (hardforce) { 1130207670Smm if (zpool_export_force(zhp) != 0) 1131207670Smm ret = 1; 1132207670Smm } else if (zpool_export(zhp, force) != 0) { 1133168404Spjd ret = 1; 1134207670Smm } 1135168404Spjd 1136168404Spjd zpool_close(zhp); 1137168404Spjd } 1138168404Spjd 1139168404Spjd return (ret); 1140168404Spjd} 1141168404Spjd 1142168404Spjd/* 1143168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1144168404Spjd * name column. 1145168404Spjd */ 1146168404Spjdstatic int 1147168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1148168404Spjd{ 1149219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1150168404Spjd nvlist_t **child; 1151168404Spjd uint_t c, children; 1152168404Spjd int ret; 1153168404Spjd 1154168404Spjd if (strlen(name) + depth > max) 1155168404Spjd max = strlen(name) + depth; 1156168404Spjd 1157168404Spjd free(name); 1158168404Spjd 1159168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1160168404Spjd &child, &children) == 0) { 1161168404Spjd for (c = 0; c < children; c++) 1162168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1163168404Spjd max)) > max) 1164168404Spjd max = ret; 1165168404Spjd } 1166168404Spjd 1167185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1168185029Spjd &child, &children) == 0) { 1169185029Spjd for (c = 0; c < children; c++) 1170185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1171185029Spjd max)) > max) 1172185029Spjd max = ret; 1173185029Spjd } 1174185029Spjd 1175168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1176168404Spjd &child, &children) == 0) { 1177168404Spjd for (c = 0; c < children; c++) 1178168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1179168404Spjd max)) > max) 1180168404Spjd max = ret; 1181168404Spjd } 1182168404Spjd 1183168404Spjd 1184168404Spjd return (max); 1185168404Spjd} 1186168404Spjd 1187213197Smmtypedef struct spare_cbdata { 1188213197Smm uint64_t cb_guid; 1189213197Smm zpool_handle_t *cb_zhp; 1190213197Smm} spare_cbdata_t; 1191168404Spjd 1192213197Smmstatic boolean_t 1193213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1194213197Smm{ 1195213197Smm uint64_t guid; 1196213197Smm nvlist_t **child; 1197213197Smm uint_t c, children; 1198213197Smm 1199213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1200213197Smm search == guid) 1201213197Smm return (B_TRUE); 1202213197Smm 1203213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1204213197Smm &child, &children) == 0) { 1205213197Smm for (c = 0; c < children; c++) 1206213197Smm if (find_vdev(child[c], search)) 1207213197Smm return (B_TRUE); 1208213197Smm } 1209213197Smm 1210213197Smm return (B_FALSE); 1211213197Smm} 1212213197Smm 1213213197Smmstatic int 1214213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1215213197Smm{ 1216213197Smm spare_cbdata_t *cbp = data; 1217213197Smm nvlist_t *config, *nvroot; 1218213197Smm 1219213197Smm config = zpool_get_config(zhp, NULL); 1220213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1221213197Smm &nvroot) == 0); 1222213197Smm 1223213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1224213197Smm cbp->cb_zhp = zhp; 1225213197Smm return (1); 1226213197Smm } 1227213197Smm 1228213197Smm zpool_close(zhp); 1229213197Smm return (0); 1230213197Smm} 1231213197Smm 1232168404Spjd/* 1233213197Smm * Print out configuration state as requested by status_callback. 1234213197Smm */ 1235213197Smmvoid 1236213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1237213197Smm int namewidth, int depth, boolean_t isspare) 1238213197Smm{ 1239213197Smm nvlist_t **child; 1240213197Smm uint_t c, children; 1241219089Spjd pool_scan_stat_t *ps = NULL; 1242213197Smm vdev_stat_t *vs; 1243219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1244213197Smm char *vname; 1245213197Smm uint64_t notpresent; 1246213197Smm spare_cbdata_t cb; 1247224169Sgibbs const char *state; 1248213197Smm 1249213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1250213197Smm &child, &children) != 0) 1251213197Smm children = 0; 1252213197Smm 1253219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1254219089Spjd (uint64_t **)&vs, &c) == 0); 1255219089Spjd 1256213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1257213197Smm if (isspare) { 1258213197Smm /* 1259213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1260213197Smm * online drives. 1261213197Smm */ 1262213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1263213197Smm state = "INUSE"; 1264213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1265213197Smm state = "AVAIL"; 1266213197Smm } 1267213197Smm 1268213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1269213197Smm name, state); 1270213197Smm 1271213197Smm if (!isspare) { 1272213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1273213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1274213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1275213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1276213197Smm } 1277213197Smm 1278213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1279224170Sgibbs ¬present) == 0 || 1280224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1281213197Smm char *path; 1282224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1283224170Sgibbs (void) printf(" was %s", path); 1284213197Smm } else if (vs->vs_aux != 0) { 1285213197Smm (void) printf(" "); 1286213197Smm 1287213197Smm switch (vs->vs_aux) { 1288213197Smm case VDEV_AUX_OPEN_FAILED: 1289213197Smm (void) printf(gettext("cannot open")); 1290213197Smm break; 1291213197Smm 1292213197Smm case VDEV_AUX_BAD_GUID_SUM: 1293213197Smm (void) printf(gettext("missing device")); 1294213197Smm break; 1295213197Smm 1296213197Smm case VDEV_AUX_NO_REPLICAS: 1297213197Smm (void) printf(gettext("insufficient replicas")); 1298213197Smm break; 1299213197Smm 1300213197Smm case VDEV_AUX_VERSION_NEWER: 1301213197Smm (void) printf(gettext("newer version")); 1302213197Smm break; 1303213197Smm 1304236884Smm case VDEV_AUX_UNSUP_FEAT: 1305236884Smm (void) printf(gettext("unsupported feature(s)")); 1306236884Smm break; 1307236884Smm 1308213197Smm case VDEV_AUX_SPARED: 1309213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1310213197Smm &cb.cb_guid) == 0); 1311213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1312213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1313213197Smm zpool_get_name(zhp)) == 0) 1314213197Smm (void) printf(gettext("currently in " 1315213197Smm "use")); 1316213197Smm else 1317213197Smm (void) printf(gettext("in use by " 1318213197Smm "pool '%s'"), 1319213197Smm zpool_get_name(cb.cb_zhp)); 1320213197Smm zpool_close(cb.cb_zhp); 1321213197Smm } else { 1322213197Smm (void) printf(gettext("currently in use")); 1323213197Smm } 1324213197Smm break; 1325213197Smm 1326213197Smm case VDEV_AUX_ERR_EXCEEDED: 1327213197Smm (void) printf(gettext("too many errors")); 1328213197Smm break; 1329213197Smm 1330213197Smm case VDEV_AUX_IO_FAILURE: 1331213197Smm (void) printf(gettext("experienced I/O failures")); 1332213197Smm break; 1333213197Smm 1334213197Smm case VDEV_AUX_BAD_LOG: 1335213197Smm (void) printf(gettext("bad intent log")); 1336213197Smm break; 1337213197Smm 1338219089Spjd case VDEV_AUX_EXTERNAL: 1339219089Spjd (void) printf(gettext("external device fault")); 1340219089Spjd break; 1341219089Spjd 1342219089Spjd case VDEV_AUX_SPLIT_POOL: 1343219089Spjd (void) printf(gettext("split into new pool")); 1344219089Spjd break; 1345219089Spjd 1346213197Smm default: 1347213197Smm (void) printf(gettext("corrupted data")); 1348213197Smm break; 1349213197Smm } 1350213197Smm } 1351213197Smm 1352219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1353219089Spjd (uint64_t **)&ps, &c); 1354219089Spjd 1355219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1356219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1357219089Spjd (void) printf(gettext(" (%s)"), 1358219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1359219089Spjd "resilvering" : "repairing"); 1360219089Spjd } 1361219089Spjd 1362213197Smm (void) printf("\n"); 1363213197Smm 1364213197Smm for (c = 0; c < children; c++) { 1365219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1366213197Smm 1367219089Spjd /* Don't print logs or holes here */ 1368213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1369219089Spjd &islog); 1370219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1371219089Spjd &ishole); 1372219089Spjd if (islog || ishole) 1373213197Smm continue; 1374219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1375213197Smm print_status_config(zhp, vname, child[c], 1376213197Smm namewidth, depth + 2, isspare); 1377213197Smm free(vname); 1378213197Smm } 1379213197Smm} 1380213197Smm 1381213197Smm 1382213197Smm/* 1383168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1384168404Spjd * pool, printing out the name and status for each one. 1385168404Spjd */ 1386168404Spjdvoid 1387213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1388168404Spjd{ 1389168404Spjd nvlist_t **child; 1390168404Spjd uint_t c, children; 1391168404Spjd vdev_stat_t *vs; 1392168404Spjd char *type, *vname; 1393168404Spjd 1394168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1395219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1396219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1397168404Spjd return; 1398168404Spjd 1399219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1400168404Spjd (uint64_t **)&vs, &c) == 0); 1401168404Spjd 1402168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1403185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1404168404Spjd 1405168404Spjd if (vs->vs_aux != 0) { 1406185029Spjd (void) printf(" "); 1407168404Spjd 1408168404Spjd switch (vs->vs_aux) { 1409168404Spjd case VDEV_AUX_OPEN_FAILED: 1410168404Spjd (void) printf(gettext("cannot open")); 1411168404Spjd break; 1412168404Spjd 1413168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1414168404Spjd (void) printf(gettext("missing device")); 1415168404Spjd break; 1416168404Spjd 1417168404Spjd case VDEV_AUX_NO_REPLICAS: 1418168404Spjd (void) printf(gettext("insufficient replicas")); 1419168404Spjd break; 1420168404Spjd 1421168404Spjd case VDEV_AUX_VERSION_NEWER: 1422168404Spjd (void) printf(gettext("newer version")); 1423168404Spjd break; 1424168404Spjd 1425236884Smm case VDEV_AUX_UNSUP_FEAT: 1426236884Smm (void) printf(gettext("unsupported feature(s)")); 1427236884Smm break; 1428236884Smm 1429185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1430185029Spjd (void) printf(gettext("too many errors")); 1431185029Spjd break; 1432185029Spjd 1433168404Spjd default: 1434168404Spjd (void) printf(gettext("corrupted data")); 1435168404Spjd break; 1436168404Spjd } 1437168404Spjd } 1438168404Spjd (void) printf("\n"); 1439168404Spjd 1440168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1441168404Spjd &child, &children) != 0) 1442168404Spjd return; 1443168404Spjd 1444168404Spjd for (c = 0; c < children; c++) { 1445185029Spjd uint64_t is_log = B_FALSE; 1446185029Spjd 1447185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1448185029Spjd &is_log); 1449213197Smm if (is_log) 1450185029Spjd continue; 1451185029Spjd 1452219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1453213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1454168404Spjd free(vname); 1455168404Spjd } 1456168404Spjd 1457185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1458185029Spjd &child, &children) == 0) { 1459185029Spjd (void) printf(gettext("\tcache\n")); 1460185029Spjd for (c = 0; c < children; c++) { 1461219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1462185029Spjd (void) printf("\t %s\n", vname); 1463185029Spjd free(vname); 1464185029Spjd } 1465185029Spjd } 1466185029Spjd 1467168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1468185029Spjd &child, &children) == 0) { 1469185029Spjd (void) printf(gettext("\tspares\n")); 1470185029Spjd for (c = 0; c < children; c++) { 1471219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1472185029Spjd (void) printf("\t %s\n", vname); 1473185029Spjd free(vname); 1474185029Spjd } 1475168404Spjd } 1476168404Spjd} 1477168404Spjd 1478168404Spjd/* 1479213197Smm * Print log vdevs. 1480213197Smm * Logs are recorded as top level vdevs in the main pool child array 1481213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1482213197Smm * print_import_config() to print the top level logs then any log 1483213197Smm * children (eg mirrored slogs) are printed recursively - which 1484213197Smm * works because only the top level vdev is marked "is_log" 1485213197Smm */ 1486213197Smmstatic void 1487213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1488213197Smm{ 1489213197Smm uint_t c, children; 1490213197Smm nvlist_t **child; 1491213197Smm 1492213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1493213197Smm &children) != 0) 1494213197Smm return; 1495213197Smm 1496213197Smm (void) printf(gettext("\tlogs\n")); 1497213197Smm 1498213197Smm for (c = 0; c < children; c++) { 1499213197Smm uint64_t is_log = B_FALSE; 1500213197Smm char *name; 1501213197Smm 1502213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1503213197Smm &is_log); 1504213197Smm if (!is_log) 1505213197Smm continue; 1506219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1507213197Smm if (verbose) 1508213197Smm print_status_config(zhp, name, child[c], namewidth, 1509213197Smm 2, B_FALSE); 1510213197Smm else 1511213197Smm print_import_config(name, child[c], namewidth, 2); 1512213197Smm free(name); 1513213197Smm } 1514213197Smm} 1515219089Spjd 1516213197Smm/* 1517168404Spjd * Display the status for the given pool. 1518168404Spjd */ 1519168404Spjdstatic void 1520168404Spjdshow_import(nvlist_t *config) 1521168404Spjd{ 1522168404Spjd uint64_t pool_state; 1523168404Spjd vdev_stat_t *vs; 1524168404Spjd char *name; 1525168404Spjd uint64_t guid; 1526168404Spjd char *msgid; 1527168404Spjd nvlist_t *nvroot; 1528168404Spjd int reason; 1529168404Spjd const char *health; 1530168404Spjd uint_t vsc; 1531168404Spjd int namewidth; 1532228103Smm char *comment; 1533168404Spjd 1534168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1535168404Spjd &name) == 0); 1536168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1537168404Spjd &guid) == 0); 1538168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1539168404Spjd &pool_state) == 0); 1540168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1541168404Spjd &nvroot) == 0); 1542168404Spjd 1543219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1544168404Spjd (uint64_t **)&vs, &vsc) == 0); 1545185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1546168404Spjd 1547168404Spjd reason = zpool_import_status(config, &msgid); 1548168404Spjd 1549228103Smm (void) printf(gettext(" pool: %s\n"), name); 1550228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1551228103Smm (void) printf(gettext(" state: %s"), health); 1552168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1553168404Spjd (void) printf(gettext(" (DESTROYED)")); 1554168404Spjd (void) printf("\n"); 1555168404Spjd 1556168404Spjd switch (reason) { 1557168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1558168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1559168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1560228103Smm (void) printf(gettext(" status: One or more devices are " 1561228103Smm "missing from the system.\n")); 1562168404Spjd break; 1563168404Spjd 1564168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1565168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1566228103Smm (void) printf(gettext(" status: One or more devices contains " 1567168404Spjd "corrupted data.\n")); 1568168404Spjd break; 1569168404Spjd 1570168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1571228103Smm (void) printf( 1572228103Smm gettext(" status: The pool data is corrupted.\n")); 1573168404Spjd break; 1574168404Spjd 1575168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1576228103Smm (void) printf(gettext(" status: One or more devices " 1577168404Spjd "are offlined.\n")); 1578168404Spjd break; 1579168404Spjd 1580168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1581228103Smm (void) printf(gettext(" status: The pool metadata is " 1582168404Spjd "corrupted.\n")); 1583168404Spjd break; 1584168404Spjd 1585168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1586228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1587168404Spjd "older on-disk version.\n")); 1588168404Spjd break; 1589168404Spjd 1590168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1591228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1592168404Spjd "incompatible version.\n")); 1593168404Spjd break; 1594168404Spjd 1595236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1596236884Smm (void) printf(gettext("status: The pool uses the following " 1597236884Smm "feature(s) not supported on this sytem:\n")); 1598236884Smm zpool_print_unsup_feat(config); 1599236884Smm break; 1600236884Smm 1601236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1602236884Smm (void) printf(gettext("status: The pool can only be accessed " 1603236884Smm "in read-only mode on this system. It\n\tcannot be " 1604236884Smm "accessed in read-write mode because it uses the " 1605236884Smm "following\n\tfeature(s) not supported on this system:\n")); 1606236884Smm zpool_print_unsup_feat(config); 1607236884Smm break; 1608236884Smm 1609168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1610228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1611168498Spjd "another system.\n")); 1612168498Spjd break; 1613185029Spjd 1614185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1615185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1616228103Smm (void) printf(gettext(" status: One or more devices are " 1617185029Spjd "faulted.\n")); 1618185029Spjd break; 1619185029Spjd 1620185029Spjd case ZPOOL_STATUS_BAD_LOG: 1621228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1622185029Spjd "read.\n")); 1623185029Spjd break; 1624185029Spjd 1625219089Spjd case ZPOOL_STATUS_RESILVERING: 1626228103Smm (void) printf(gettext(" status: One or more devices were being " 1627219089Spjd "resilvered.\n")); 1628219089Spjd break; 1629219089Spjd 1630168404Spjd default: 1631168404Spjd /* 1632168404Spjd * No other status can be seen when importing pools. 1633168404Spjd */ 1634168404Spjd assert(reason == ZPOOL_STATUS_OK); 1635168404Spjd } 1636168404Spjd 1637168404Spjd /* 1638168404Spjd * Print out an action according to the overall state of the pool. 1639168404Spjd */ 1640168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1641168404Spjd if (reason == ZPOOL_STATUS_VERSION_OLDER) 1642228103Smm (void) printf(gettext(" action: The pool can be " 1643168404Spjd "imported using its name or numeric identifier, " 1644168404Spjd "though\n\tsome features will not be available " 1645168404Spjd "without an explicit 'zpool upgrade'.\n")); 1646168498Spjd else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 1647228103Smm (void) printf(gettext(" action: The pool can be " 1648168498Spjd "imported using its name or numeric " 1649168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1650168404Spjd else 1651228103Smm (void) printf(gettext(" action: The pool can be " 1652168404Spjd "imported using its name or numeric " 1653168404Spjd "identifier.\n")); 1654168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1655228103Smm (void) printf(gettext(" action: The pool can be imported " 1656168404Spjd "despite missing or damaged devices. The\n\tfault " 1657168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1658168404Spjd } else { 1659168404Spjd switch (reason) { 1660168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1661228103Smm (void) printf(gettext(" action: The pool cannot be " 1662168404Spjd "imported. Access the pool on a system running " 1663168404Spjd "newer\n\tsoftware, or recreate the pool from " 1664168404Spjd "backup.\n")); 1665168404Spjd break; 1666236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1667236884Smm (void) printf(gettext("action: The pool cannot be " 1668236884Smm "imported. Access the pool on a system that " 1669236884Smm "supports\n\tthe required feature(s), or recreate " 1670236884Smm "the pool from backup.\n")); 1671236884Smm break; 1672236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1673236884Smm (void) printf(gettext("action: The pool cannot be " 1674236884Smm "imported in read-write mode. Import the pool " 1675236884Smm "with\n" 1676236884Smm "\t\"-o readonly=on\", access the pool on a system " 1677236884Smm "that supports the\n\trequired feature(s), or " 1678236884Smm "recreate the pool from backup.\n")); 1679236884Smm break; 1680168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1681168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1682168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1683228103Smm (void) printf(gettext(" action: The pool cannot be " 1684168404Spjd "imported. Attach the missing\n\tdevices and try " 1685168404Spjd "again.\n")); 1686168404Spjd break; 1687168404Spjd default: 1688228103Smm (void) printf(gettext(" action: The pool cannot be " 1689168404Spjd "imported due to damaged devices or data.\n")); 1690168404Spjd } 1691168404Spjd } 1692168404Spjd 1693228103Smm /* Print the comment attached to the pool. */ 1694228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 1695228103Smm (void) printf(gettext("comment: %s\n"), comment); 1696228103Smm 1697168404Spjd /* 1698168404Spjd * If the state is "closed" or "can't open", and the aux state 1699168404Spjd * is "corrupt data": 1700168404Spjd */ 1701168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1702168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1703168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1704168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1705168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1706168404Spjd "but can be imported using the '-Df' flags.\n")); 1707168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1708168404Spjd (void) printf(gettext("\tThe pool may be active on " 1709185029Spjd "another system, but can be imported using\n\t" 1710168404Spjd "the '-f' flag.\n")); 1711168404Spjd } 1712168404Spjd 1713168404Spjd if (msgid != NULL) 1714236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1715168404Spjd msgid); 1716168404Spjd 1717228103Smm (void) printf(gettext(" config:\n\n")); 1718168404Spjd 1719168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1720168404Spjd if (namewidth < 10) 1721168404Spjd namewidth = 10; 1722168404Spjd 1723213197Smm print_import_config(name, nvroot, namewidth, 0); 1724213197Smm if (num_logs(nvroot) > 0) 1725213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1726185029Spjd 1727168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1728168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1729168404Spjd "be part of this pool, though their\n\texact " 1730168404Spjd "configuration cannot be determined.\n")); 1731168404Spjd } 1732168404Spjd} 1733168404Spjd 1734168404Spjd/* 1735168404Spjd * Perform the import for the given configuration. This passes the heavy 1736185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1737185029Spjd * within the pool. 1738168404Spjd */ 1739168404Spjdstatic int 1740168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1741219089Spjd nvlist_t *props, int flags) 1742168404Spjd{ 1743168404Spjd zpool_handle_t *zhp; 1744168404Spjd char *name; 1745168404Spjd uint64_t state; 1746168404Spjd uint64_t version; 1747168404Spjd 1748168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1749168404Spjd &name) == 0); 1750168404Spjd 1751168404Spjd verify(nvlist_lookup_uint64(config, 1752168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1753168404Spjd verify(nvlist_lookup_uint64(config, 1754168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1755236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 1756168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1757236884Smm "is formatted using an unsupported ZFS version\n"), name); 1758168404Spjd return (1); 1759219089Spjd } else if (state != POOL_STATE_EXPORTED && 1760219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 1761168498Spjd uint64_t hostid; 1762168498Spjd 1763168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1764168498Spjd &hostid) == 0) { 1765168498Spjd if ((unsigned long)hostid != gethostid()) { 1766168498Spjd char *hostname; 1767168498Spjd uint64_t timestamp; 1768168498Spjd time_t t; 1769168498Spjd 1770168498Spjd verify(nvlist_lookup_string(config, 1771168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1772168498Spjd verify(nvlist_lookup_uint64(config, 1773168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1774168498Spjd t = timestamp; 1775168498Spjd (void) fprintf(stderr, gettext("cannot import " 1776168498Spjd "'%s': pool may be in use from other " 1777168498Spjd "system, it was last accessed by %s " 1778168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1779168498Spjd (unsigned long)hostid, 1780168498Spjd asctime(localtime(&t))); 1781168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1782168498Spjd "import anyway\n")); 1783168498Spjd return (1); 1784168498Spjd } 1785168498Spjd } else { 1786168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1787168498Spjd "pool may be in use from other system\n"), name); 1788168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1789168498Spjd "anyway\n")); 1790168498Spjd return (1); 1791168498Spjd } 1792168404Spjd } 1793168404Spjd 1794219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1795168404Spjd return (1); 1796168404Spjd 1797168404Spjd if (newname != NULL) 1798168404Spjd name = (char *)newname; 1799168404Spjd 1800209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 1801209962Smm return (1); 1802168404Spjd 1803209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1804219089Spjd !(flags & ZFS_IMPORT_ONLY) && 1805209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1806168404Spjd zpool_close(zhp); 1807168404Spjd return (1); 1808168404Spjd } 1809168404Spjd 1810168404Spjd zpool_close(zhp); 1811219089Spjd return (0); 1812168404Spjd} 1813168404Spjd 1814168404Spjd/* 1815168404Spjd * zpool import [-d dir] [-D] 1816185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1817185029Spjd * [-d dir | -c cachefile] [-f] -a 1818185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1819219089Spjd * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 1820168404Spjd * 1821185029Spjd * -c Read pool information from a cachefile instead of searching 1822185029Spjd * devices. 1823185029Spjd * 1824168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1825168404Spjd * one directory can be specified using multiple '-d' options. 1826168404Spjd * 1827168404Spjd * -D Scan for previously destroyed pools or import all or only 1828168404Spjd * specified destroyed pools. 1829168404Spjd * 1830168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1831168404Spjd * the given root. The pool will remain exported when the machine 1832168404Spjd * is rebooted. 1833168404Spjd * 1834219089Spjd * -V Import even in the presence of faulted vdevs. This is an 1835185029Spjd * intentionally undocumented option for testing purposes, and 1836185029Spjd * treats the pool configuration as complete, leaving any bad 1837209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 1838209962Smm * import. 1839185029Spjd * 1840219089Spjd * -f Force import, even if it appears that the pool is active. 1841219089Spjd * 1842219089Spjd * -F Attempt rewind if necessary. 1843219089Spjd * 1844219089Spjd * -n See if rewind would work, but don't actually rewind. 1845219089Spjd * 1846219089Spjd * -N Import the pool but don't mount datasets. 1847219089Spjd * 1848219089Spjd * -T Specify a starting txg to use for import. This option is 1849219089Spjd * intentionally undocumented option for testing purposes. 1850219089Spjd * 1851168404Spjd * -a Import all pools found. 1852168404Spjd * 1853185029Spjd * -o Set property=value and/or temporary mount options (without '='). 1854185029Spjd * 1855168404Spjd * The import command scans for pools to import, and import pools based on pool 1856168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 1857168404Spjd */ 1858168404Spjdint 1859168404Spjdzpool_do_import(int argc, char **argv) 1860168404Spjd{ 1861168404Spjd char **searchdirs = NULL; 1862168404Spjd int nsearch = 0; 1863168404Spjd int c; 1864219089Spjd int err = 0; 1865185029Spjd nvlist_t *pools = NULL; 1866168404Spjd boolean_t do_all = B_FALSE; 1867168404Spjd boolean_t do_destroyed = B_FALSE; 1868168404Spjd char *mntopts = NULL; 1869168404Spjd nvpair_t *elem; 1870168404Spjd nvlist_t *config; 1871185029Spjd uint64_t searchguid = 0; 1872185029Spjd char *searchname = NULL; 1873185029Spjd char *propval; 1874168404Spjd nvlist_t *found_config; 1875219089Spjd nvlist_t *policy = NULL; 1876185029Spjd nvlist_t *props = NULL; 1877168404Spjd boolean_t first; 1878219089Spjd int flags = ZFS_IMPORT_NORMAL; 1879219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 1880219089Spjd boolean_t dryrun = B_FALSE; 1881219089Spjd boolean_t do_rewind = B_FALSE; 1882219089Spjd boolean_t xtreme_rewind = B_FALSE; 1883219089Spjd uint64_t pool_state, txg = -1ULL; 1884185029Spjd char *cachefile = NULL; 1885219089Spjd importargs_t idata = { 0 }; 1886219089Spjd char *endptr; 1887168404Spjd 1888168404Spjd /* check options */ 1889219089Spjd while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) { 1890168404Spjd switch (c) { 1891168404Spjd case 'a': 1892168404Spjd do_all = B_TRUE; 1893168404Spjd break; 1894185029Spjd case 'c': 1895185029Spjd cachefile = optarg; 1896185029Spjd break; 1897168404Spjd case 'd': 1898168404Spjd if (searchdirs == NULL) { 1899168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1900168404Spjd } else { 1901168404Spjd char **tmp = safe_malloc((nsearch + 1) * 1902168404Spjd sizeof (char *)); 1903168404Spjd bcopy(searchdirs, tmp, nsearch * 1904168404Spjd sizeof (char *)); 1905168404Spjd free(searchdirs); 1906168404Spjd searchdirs = tmp; 1907168404Spjd } 1908168404Spjd searchdirs[nsearch++] = optarg; 1909168404Spjd break; 1910168404Spjd case 'D': 1911168404Spjd do_destroyed = B_TRUE; 1912168404Spjd break; 1913168404Spjd case 'f': 1914219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 1915168404Spjd break; 1916185029Spjd case 'F': 1917219089Spjd do_rewind = B_TRUE; 1918185029Spjd break; 1919219089Spjd case 'm': 1920219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 1921219089Spjd break; 1922219089Spjd case 'n': 1923219089Spjd dryrun = B_TRUE; 1924219089Spjd break; 1925219089Spjd case 'N': 1926219089Spjd flags |= ZFS_IMPORT_ONLY; 1927219089Spjd break; 1928168404Spjd case 'o': 1929185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 1930185029Spjd *propval = '\0'; 1931185029Spjd propval++; 1932185029Spjd if (add_prop_list(optarg, propval, 1933185029Spjd &props, B_TRUE)) 1934185029Spjd goto error; 1935185029Spjd } else { 1936185029Spjd mntopts = optarg; 1937185029Spjd } 1938168404Spjd break; 1939168404Spjd case 'R': 1940185029Spjd if (add_prop_list(zpool_prop_to_name( 1941185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 1942185029Spjd goto error; 1943185029Spjd if (nvlist_lookup_string(props, 1944185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 1945185029Spjd &propval) == 0) 1946185029Spjd break; 1947185029Spjd if (add_prop_list(zpool_prop_to_name( 1948185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1949185029Spjd goto error; 1950168404Spjd break; 1951219089Spjd case 'T': 1952219089Spjd errno = 0; 1953219089Spjd txg = strtoull(optarg, &endptr, 10); 1954219089Spjd if (errno != 0 || *endptr != '\0') { 1955219089Spjd (void) fprintf(stderr, 1956219089Spjd gettext("invalid txg value\n")); 1957219089Spjd usage(B_FALSE); 1958219089Spjd } 1959219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 1960219089Spjd break; 1961219089Spjd case 'V': 1962219089Spjd flags |= ZFS_IMPORT_VERBATIM; 1963219089Spjd break; 1964219089Spjd case 'X': 1965219089Spjd xtreme_rewind = B_TRUE; 1966219089Spjd break; 1967168404Spjd case ':': 1968168404Spjd (void) fprintf(stderr, gettext("missing argument for " 1969168404Spjd "'%c' option\n"), optopt); 1970168404Spjd usage(B_FALSE); 1971168404Spjd break; 1972168404Spjd case '?': 1973168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1974168404Spjd optopt); 1975168404Spjd usage(B_FALSE); 1976168404Spjd } 1977168404Spjd } 1978168404Spjd 1979168404Spjd argc -= optind; 1980168404Spjd argv += optind; 1981168404Spjd 1982185029Spjd if (cachefile && nsearch != 0) { 1983185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 1984185029Spjd usage(B_FALSE); 1985185029Spjd } 1986185029Spjd 1987219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 1988219089Spjd (void) fprintf(stderr, 1989219089Spjd gettext("-n or -X only meaningful with -F\n")); 1990219089Spjd usage(B_FALSE); 1991219089Spjd } 1992219089Spjd if (dryrun) 1993219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 1994219089Spjd else if (do_rewind) 1995219089Spjd rewind_policy = ZPOOL_DO_REWIND; 1996219089Spjd if (xtreme_rewind) 1997219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 1998219089Spjd 1999219089Spjd /* In the future, we can capture further policy and include it here */ 2000219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2001219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 2002219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 2003219089Spjd goto error; 2004219089Spjd 2005168404Spjd if (searchdirs == NULL) { 2006168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2007235478Savg searchdirs[0] = "/dev"; 2008168404Spjd nsearch = 1; 2009168404Spjd } 2010168404Spjd 2011168404Spjd /* check argument count */ 2012168404Spjd if (do_all) { 2013168404Spjd if (argc != 0) { 2014168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2015168404Spjd usage(B_FALSE); 2016168404Spjd } 2017168404Spjd } else { 2018168404Spjd if (argc > 2) { 2019168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2020168404Spjd usage(B_FALSE); 2021168404Spjd } 2022168404Spjd 2023168404Spjd /* 2024168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 2025168404Spjd * here because otherwise any attempt to discover pools will 2026168404Spjd * silently fail. 2027168404Spjd */ 2028168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2029168404Spjd (void) fprintf(stderr, gettext("cannot " 2030168404Spjd "discover pools: permission denied\n")); 2031168404Spjd free(searchdirs); 2032219089Spjd nvlist_free(policy); 2033168404Spjd return (1); 2034168404Spjd } 2035168404Spjd } 2036168404Spjd 2037168404Spjd /* 2038168404Spjd * Depending on the arguments given, we do one of the following: 2039168404Spjd * 2040168404Spjd * <none> Iterate through all pools and display information about 2041168404Spjd * each one. 2042168404Spjd * 2043168404Spjd * -a Iterate through all pools and try to import each one. 2044168404Spjd * 2045168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 2046168404Spjd * name and import that one. 2047168404Spjd * 2048168404Spjd * -D Above options applies only to destroyed pools. 2049168404Spjd */ 2050168404Spjd if (argc != 0) { 2051168404Spjd char *endptr; 2052168404Spjd 2053168404Spjd errno = 0; 2054168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 2055168404Spjd if (errno != 0 || *endptr != '\0') 2056168404Spjd searchname = argv[0]; 2057168404Spjd found_config = NULL; 2058168404Spjd 2059185029Spjd /* 2060219089Spjd * User specified a name or guid. Ensure it's unique. 2061185029Spjd */ 2062219089Spjd idata.unique = B_TRUE; 2063185029Spjd } 2064185029Spjd 2065219089Spjd 2066219089Spjd idata.path = searchdirs; 2067219089Spjd idata.paths = nsearch; 2068219089Spjd idata.poolname = searchname; 2069219089Spjd idata.guid = searchguid; 2070219089Spjd idata.cachefile = cachefile; 2071219089Spjd 2072219089Spjd pools = zpool_search_import(g_zfs, &idata); 2073219089Spjd 2074219089Spjd if (pools != NULL && idata.exists && 2075219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2076219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2077219089Spjd "a pool with that name already exists\n"), 2078219089Spjd argv[0]); 2079219089Spjd (void) fprintf(stderr, gettext("use the form '%s " 2080219089Spjd "<pool | id> <newpool>' to give it a new name\n"), 2081219089Spjd "zpool import"); 2082219089Spjd err = 1; 2083219089Spjd } else if (pools == NULL && idata.exists) { 2084219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2085219089Spjd "a pool with that name is already created/imported,\n"), 2086219089Spjd argv[0]); 2087219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2088219089Spjd "with that name were found\n")); 2089219089Spjd err = 1; 2090219089Spjd } else if (pools == NULL) { 2091185029Spjd if (argc != 0) { 2092185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2093185029Spjd "no such pool available\n"), argv[0]); 2094185029Spjd } 2095219089Spjd err = 1; 2096219089Spjd } 2097219089Spjd 2098219089Spjd if (err == 1) { 2099185029Spjd free(searchdirs); 2100219089Spjd nvlist_free(policy); 2101185029Spjd return (1); 2102185029Spjd } 2103185029Spjd 2104185029Spjd /* 2105185029Spjd * At this point we have a list of import candidate configs. Even if 2106185029Spjd * we were searching by pool name or guid, we still need to 2107185029Spjd * post-process the list to deal with pool state and possible 2108185029Spjd * duplicate names. 2109185029Spjd */ 2110168404Spjd err = 0; 2111168404Spjd elem = NULL; 2112168404Spjd first = B_TRUE; 2113168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2114168404Spjd 2115168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2116168404Spjd 2117168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2118168404Spjd &pool_state) == 0); 2119168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2120168404Spjd continue; 2121168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2122168404Spjd continue; 2123168404Spjd 2124219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2125219089Spjd policy) == 0); 2126219089Spjd 2127168404Spjd if (argc == 0) { 2128168404Spjd if (first) 2129168404Spjd first = B_FALSE; 2130168404Spjd else if (!do_all) 2131168404Spjd (void) printf("\n"); 2132168404Spjd 2133219089Spjd if (do_all) { 2134168404Spjd err |= do_import(config, NULL, mntopts, 2135219089Spjd props, flags); 2136219089Spjd } else { 2137168404Spjd show_import(config); 2138219089Spjd } 2139168404Spjd } else if (searchname != NULL) { 2140168404Spjd char *name; 2141168404Spjd 2142168404Spjd /* 2143168404Spjd * We are searching for a pool based on name. 2144168404Spjd */ 2145168404Spjd verify(nvlist_lookup_string(config, 2146168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2147168404Spjd 2148168404Spjd if (strcmp(name, searchname) == 0) { 2149168404Spjd if (found_config != NULL) { 2150168404Spjd (void) fprintf(stderr, gettext( 2151168404Spjd "cannot import '%s': more than " 2152168404Spjd "one matching pool\n"), searchname); 2153168404Spjd (void) fprintf(stderr, gettext( 2154168404Spjd "import by numeric ID instead\n")); 2155168404Spjd err = B_TRUE; 2156168404Spjd } 2157168404Spjd found_config = config; 2158168404Spjd } 2159168404Spjd } else { 2160168404Spjd uint64_t guid; 2161168404Spjd 2162168404Spjd /* 2163168404Spjd * Search for a pool by guid. 2164168404Spjd */ 2165168404Spjd verify(nvlist_lookup_uint64(config, 2166168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2167168404Spjd 2168168404Spjd if (guid == searchguid) 2169168404Spjd found_config = config; 2170168404Spjd } 2171168404Spjd } 2172168404Spjd 2173168404Spjd /* 2174168404Spjd * If we were searching for a specific pool, verify that we found a 2175168404Spjd * pool, and then do the import. 2176168404Spjd */ 2177168404Spjd if (argc != 0 && err == 0) { 2178168404Spjd if (found_config == NULL) { 2179168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2180168404Spjd "no such pool available\n"), argv[0]); 2181168404Spjd err = B_TRUE; 2182168404Spjd } else { 2183168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2184219089Spjd argv[1], mntopts, props, flags); 2185168404Spjd } 2186168404Spjd } 2187168404Spjd 2188168404Spjd /* 2189168404Spjd * If we were just looking for pools, report an error if none were 2190168404Spjd * found. 2191168404Spjd */ 2192168404Spjd if (argc == 0 && first) 2193168404Spjd (void) fprintf(stderr, 2194168404Spjd gettext("no pools available to import\n")); 2195168404Spjd 2196185029Spjderror: 2197185029Spjd nvlist_free(props); 2198168404Spjd nvlist_free(pools); 2199219089Spjd nvlist_free(policy); 2200168404Spjd free(searchdirs); 2201168404Spjd 2202168404Spjd return (err ? 1 : 0); 2203168404Spjd} 2204168404Spjd 2205168404Spjdtypedef struct iostat_cbdata { 2206236155Smm boolean_t cb_verbose; 2207236155Smm int cb_namewidth; 2208236155Smm int cb_iteration; 2209168404Spjd zpool_list_t *cb_list; 2210168404Spjd} iostat_cbdata_t; 2211168404Spjd 2212168404Spjdstatic void 2213168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2214168404Spjd{ 2215168404Spjd int i = 0; 2216168404Spjd 2217168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2218168404Spjd (void) printf("-"); 2219168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2220168404Spjd} 2221168404Spjd 2222168404Spjdstatic void 2223168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2224168404Spjd{ 2225168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2226168404Spjd cb->cb_namewidth, ""); 2227219089Spjd (void) printf("%-*s alloc free read write read write\n", 2228168404Spjd cb->cb_namewidth, "pool"); 2229168404Spjd print_iostat_separator(cb); 2230168404Spjd} 2231168404Spjd 2232168404Spjd/* 2233168404Spjd * Display a single statistic. 2234168404Spjd */ 2235185029Spjdstatic void 2236168404Spjdprint_one_stat(uint64_t value) 2237168404Spjd{ 2238168404Spjd char buf[64]; 2239168404Spjd 2240168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2241168404Spjd (void) printf(" %5s", buf); 2242168404Spjd} 2243168404Spjd 2244168404Spjd/* 2245168404Spjd * Print out all the statistics for the given vdev. This can either be the 2246168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2247168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2248168404Spjd */ 2249168404Spjdvoid 2250168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2251168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2252168404Spjd{ 2253168404Spjd nvlist_t **oldchild, **newchild; 2254168404Spjd uint_t c, children; 2255168404Spjd vdev_stat_t *oldvs, *newvs; 2256168404Spjd vdev_stat_t zerovs = { 0 }; 2257168404Spjd uint64_t tdelta; 2258168404Spjd double scale; 2259168404Spjd char *vname; 2260168404Spjd 2261168404Spjd if (oldnv != NULL) { 2262219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2263219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2264168404Spjd } else { 2265168404Spjd oldvs = &zerovs; 2266168404Spjd } 2267168404Spjd 2268219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2269168404Spjd (uint64_t **)&newvs, &c) == 0); 2270168404Spjd 2271168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2272168404Spjd (void) printf("%*s%s", depth, "", name); 2273168404Spjd else 2274168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2275168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2276168404Spjd 2277168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2278168404Spjd 2279168404Spjd if (tdelta == 0) 2280168404Spjd scale = 1.0; 2281168404Spjd else 2282168404Spjd scale = (double)NANOSEC / tdelta; 2283168404Spjd 2284168404Spjd /* only toplevel vdevs have capacity stats */ 2285168404Spjd if (newvs->vs_space == 0) { 2286168404Spjd (void) printf(" - -"); 2287168404Spjd } else { 2288168404Spjd print_one_stat(newvs->vs_alloc); 2289168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2290168404Spjd } 2291168404Spjd 2292168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2293168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2294168404Spjd 2295168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2296168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2297168404Spjd 2298168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2299168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2300168404Spjd 2301168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2302168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2303168404Spjd 2304168404Spjd (void) printf("\n"); 2305168404Spjd 2306168404Spjd if (!cb->cb_verbose) 2307168404Spjd return; 2308168404Spjd 2309168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2310168404Spjd &newchild, &children) != 0) 2311168404Spjd return; 2312168404Spjd 2313168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2314168404Spjd &oldchild, &c) != 0) 2315168404Spjd return; 2316168404Spjd 2317168404Spjd for (c = 0; c < children; c++) { 2318227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2319219089Spjd 2320227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2321227497Smm &ishole); 2322227497Smm 2323227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2324227497Smm &islog); 2325227497Smm 2326227497Smm if (ishole || islog) 2327219089Spjd continue; 2328219089Spjd 2329219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2330168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2331168404Spjd newchild[c], cb, depth + 2); 2332168404Spjd free(vname); 2333168404Spjd } 2334185029Spjd 2335185029Spjd /* 2336227497Smm * Log device section 2337227497Smm */ 2338227497Smm 2339227497Smm if (num_logs(newnv) > 0) { 2340227497Smm (void) printf("%-*s - - - - - " 2341227497Smm "-\n", cb->cb_namewidth, "logs"); 2342227497Smm 2343227497Smm for (c = 0; c < children; c++) { 2344227497Smm uint64_t islog = B_FALSE; 2345227497Smm (void) nvlist_lookup_uint64(newchild[c], 2346227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2347227497Smm 2348227497Smm if (islog) { 2349227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2350227497Smm B_FALSE); 2351227497Smm print_vdev_stats(zhp, vname, oldnv ? 2352227497Smm oldchild[c] : NULL, newchild[c], 2353227497Smm cb, depth + 2); 2354227497Smm free(vname); 2355227497Smm } 2356227497Smm } 2357227497Smm 2358227497Smm } 2359227497Smm 2360227497Smm /* 2361185029Spjd * Include level 2 ARC devices in iostat output 2362185029Spjd */ 2363185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2364185029Spjd &newchild, &children) != 0) 2365185029Spjd return; 2366185029Spjd 2367185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2368185029Spjd &oldchild, &c) != 0) 2369185029Spjd return; 2370185029Spjd 2371185029Spjd if (children > 0) { 2372185029Spjd (void) printf("%-*s - - - - - " 2373185029Spjd "-\n", cb->cb_namewidth, "cache"); 2374185029Spjd for (c = 0; c < children; c++) { 2375219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2376219089Spjd B_FALSE); 2377185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2378185029Spjd newchild[c], cb, depth + 2); 2379185029Spjd free(vname); 2380185029Spjd } 2381185029Spjd } 2382168404Spjd} 2383168404Spjd 2384168404Spjdstatic int 2385168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2386168404Spjd{ 2387168404Spjd iostat_cbdata_t *cb = data; 2388168404Spjd boolean_t missing; 2389168404Spjd 2390168404Spjd /* 2391168404Spjd * If the pool has disappeared, remove it from the list and continue. 2392168404Spjd */ 2393168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2394168404Spjd return (-1); 2395168404Spjd 2396168404Spjd if (missing) 2397168404Spjd pool_list_remove(cb->cb_list, zhp); 2398168404Spjd 2399168404Spjd return (0); 2400168404Spjd} 2401168404Spjd 2402168404Spjd/* 2403168404Spjd * Callback to print out the iostats for the given pool. 2404168404Spjd */ 2405168404Spjdint 2406168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2407168404Spjd{ 2408168404Spjd iostat_cbdata_t *cb = data; 2409168404Spjd nvlist_t *oldconfig, *newconfig; 2410168404Spjd nvlist_t *oldnvroot, *newnvroot; 2411168404Spjd 2412168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2413168404Spjd 2414168404Spjd if (cb->cb_iteration == 1) 2415168404Spjd oldconfig = NULL; 2416168404Spjd 2417168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2418168404Spjd &newnvroot) == 0); 2419168404Spjd 2420168404Spjd if (oldconfig == NULL) 2421168404Spjd oldnvroot = NULL; 2422168404Spjd else 2423168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2424168404Spjd &oldnvroot) == 0); 2425168404Spjd 2426168404Spjd /* 2427168404Spjd * Print out the statistics for the pool. 2428168404Spjd */ 2429168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2430168404Spjd 2431168404Spjd if (cb->cb_verbose) 2432168404Spjd print_iostat_separator(cb); 2433168404Spjd 2434168404Spjd return (0); 2435168404Spjd} 2436168404Spjd 2437168404Spjdint 2438168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2439168404Spjd{ 2440168404Spjd iostat_cbdata_t *cb = data; 2441168404Spjd nvlist_t *config, *nvroot; 2442168404Spjd 2443168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2444168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2445168404Spjd &nvroot) == 0); 2446168404Spjd if (!cb->cb_verbose) 2447168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2448168404Spjd else 2449236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2450236145Smm cb->cb_namewidth); 2451168404Spjd } 2452168404Spjd 2453168404Spjd /* 2454168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2455168404Spjd * maximum we can have and still fit in 80 columns. 2456168404Spjd */ 2457168404Spjd if (cb->cb_namewidth < 10) 2458168404Spjd cb->cb_namewidth = 10; 2459168404Spjd if (cb->cb_namewidth > 38) 2460168404Spjd cb->cb_namewidth = 38; 2461168404Spjd 2462168404Spjd return (0); 2463168404Spjd} 2464168404Spjd 2465168404Spjd/* 2466219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2467168404Spjd */ 2468219089Spjdstatic void 2469219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2470219089Spjd unsigned long *cnt) 2471168404Spjd{ 2472168404Spjd unsigned long interval = 0, count = 0; 2473219089Spjd int argc = *argcp, errno; 2474168404Spjd 2475168404Spjd /* 2476168404Spjd * Determine if the last argument is an integer or a pool name 2477168404Spjd */ 2478168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2479168404Spjd char *end; 2480168404Spjd 2481168404Spjd errno = 0; 2482168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2483168404Spjd 2484168404Spjd if (*end == '\0' && errno == 0) { 2485168404Spjd if (interval == 0) { 2486168404Spjd (void) fprintf(stderr, gettext("interval " 2487168404Spjd "cannot be zero\n")); 2488168404Spjd usage(B_FALSE); 2489168404Spjd } 2490168404Spjd /* 2491168404Spjd * Ignore the last parameter 2492168404Spjd */ 2493168404Spjd argc--; 2494168404Spjd } else { 2495168404Spjd /* 2496168404Spjd * If this is not a valid number, just plow on. The 2497168404Spjd * user will get a more informative error message later 2498168404Spjd * on. 2499168404Spjd */ 2500168404Spjd interval = 0; 2501168404Spjd } 2502168404Spjd } 2503168404Spjd 2504168404Spjd /* 2505168404Spjd * If the last argument is also an integer, then we have both a count 2506219089Spjd * and an interval. 2507168404Spjd */ 2508168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2509168404Spjd char *end; 2510168404Spjd 2511168404Spjd errno = 0; 2512168404Spjd count = interval; 2513168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2514168404Spjd 2515168404Spjd if (*end == '\0' && errno == 0) { 2516168404Spjd if (interval == 0) { 2517168404Spjd (void) fprintf(stderr, gettext("interval " 2518168404Spjd "cannot be zero\n")); 2519168404Spjd usage(B_FALSE); 2520168404Spjd } 2521168404Spjd 2522168404Spjd /* 2523168404Spjd * Ignore the last parameter 2524168404Spjd */ 2525168404Spjd argc--; 2526168404Spjd } else { 2527168404Spjd interval = 0; 2528168404Spjd } 2529168404Spjd } 2530168404Spjd 2531219089Spjd *iv = interval; 2532219089Spjd *cnt = count; 2533219089Spjd *argcp = argc; 2534219089Spjd} 2535219089Spjd 2536219089Spjdstatic void 2537219089Spjdget_timestamp_arg(char c) 2538219089Spjd{ 2539219089Spjd if (c == 'u') 2540219089Spjd timestamp_fmt = UDATE; 2541219089Spjd else if (c == 'd') 2542219089Spjd timestamp_fmt = DDATE; 2543219089Spjd else 2544219089Spjd usage(B_FALSE); 2545219089Spjd} 2546219089Spjd 2547219089Spjd/* 2548219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2549219089Spjd * 2550219089Spjd * -v Display statistics for individual vdevs 2551219089Spjd * -T Display a timestamp in date(1) or Unix format 2552219089Spjd * 2553219089Spjd * This command can be tricky because we want to be able to deal with pool 2554219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2555219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2556219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2557219089Spjd * changes are all handled within libzfs. 2558219089Spjd */ 2559219089Spjdint 2560219089Spjdzpool_do_iostat(int argc, char **argv) 2561219089Spjd{ 2562219089Spjd int c; 2563219089Spjd int ret; 2564219089Spjd int npools; 2565219089Spjd unsigned long interval = 0, count = 0; 2566219089Spjd zpool_list_t *list; 2567219089Spjd boolean_t verbose = B_FALSE; 2568219089Spjd iostat_cbdata_t cb; 2569219089Spjd 2570219089Spjd /* check options */ 2571219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2572219089Spjd switch (c) { 2573219089Spjd case 'T': 2574219089Spjd get_timestamp_arg(*optarg); 2575219089Spjd break; 2576219089Spjd case 'v': 2577219089Spjd verbose = B_TRUE; 2578219089Spjd break; 2579219089Spjd case '?': 2580219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2581219089Spjd optopt); 2582219089Spjd usage(B_FALSE); 2583219089Spjd } 2584219089Spjd } 2585219089Spjd 2586219089Spjd argc -= optind; 2587219089Spjd argv += optind; 2588219089Spjd 2589219089Spjd get_interval_count(&argc, argv, &interval, &count); 2590219089Spjd 2591168404Spjd /* 2592168404Spjd * Construct the list of all interesting pools. 2593168404Spjd */ 2594168404Spjd ret = 0; 2595168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2596168404Spjd return (1); 2597168404Spjd 2598168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2599168404Spjd pool_list_free(list); 2600168404Spjd return (1); 2601168404Spjd } 2602168404Spjd 2603168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2604168404Spjd pool_list_free(list); 2605168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2606168404Spjd return (1); 2607168404Spjd } 2608168404Spjd 2609168404Spjd /* 2610168404Spjd * Enter the main iostat loop. 2611168404Spjd */ 2612168404Spjd cb.cb_list = list; 2613168404Spjd cb.cb_verbose = verbose; 2614168404Spjd cb.cb_iteration = 0; 2615168404Spjd cb.cb_namewidth = 0; 2616168404Spjd 2617168404Spjd for (;;) { 2618168404Spjd pool_list_update(list); 2619168404Spjd 2620168404Spjd if ((npools = pool_list_count(list)) == 0) 2621168404Spjd break; 2622168404Spjd 2623168404Spjd /* 2624168404Spjd * Refresh all statistics. This is done as an explicit step 2625168404Spjd * before calculating the maximum name width, so that any 2626168404Spjd * configuration changes are properly accounted for. 2627168404Spjd */ 2628168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2629168404Spjd 2630168404Spjd /* 2631168404Spjd * Iterate over all pools to determine the maximum width 2632168404Spjd * for the pool / device name column across all pools. 2633168404Spjd */ 2634168404Spjd cb.cb_namewidth = 0; 2635168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2636168404Spjd 2637219089Spjd if (timestamp_fmt != NODATE) 2638219089Spjd print_timestamp(timestamp_fmt); 2639219089Spjd 2640168404Spjd /* 2641168404Spjd * If it's the first time, or verbose mode, print the header. 2642168404Spjd */ 2643168404Spjd if (++cb.cb_iteration == 1 || verbose) 2644168404Spjd print_iostat_header(&cb); 2645168404Spjd 2646168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2647168404Spjd 2648168404Spjd /* 2649168404Spjd * If there's more than one pool, and we're not in verbose mode 2650168404Spjd * (which prints a separator for us), then print a separator. 2651168404Spjd */ 2652168404Spjd if (npools > 1 && !verbose) 2653168404Spjd print_iostat_separator(&cb); 2654168404Spjd 2655168404Spjd if (verbose) 2656168404Spjd (void) printf("\n"); 2657168404Spjd 2658168404Spjd /* 2659168404Spjd * Flush the output so that redirection to a file isn't buffered 2660168404Spjd * indefinitely. 2661168404Spjd */ 2662168404Spjd (void) fflush(stdout); 2663168404Spjd 2664168404Spjd if (interval == 0) 2665168404Spjd break; 2666168404Spjd 2667168404Spjd if (count != 0 && --count == 0) 2668168404Spjd break; 2669168404Spjd 2670168404Spjd (void) sleep(interval); 2671168404Spjd } 2672168404Spjd 2673168404Spjd pool_list_free(list); 2674168404Spjd 2675168404Spjd return (ret); 2676168404Spjd} 2677168404Spjd 2678168404Spjdtypedef struct list_cbdata { 2679236155Smm boolean_t cb_verbose; 2680236155Smm int cb_namewidth; 2681168404Spjd boolean_t cb_scripted; 2682185029Spjd zprop_list_t *cb_proplist; 2683168404Spjd} list_cbdata_t; 2684168404Spjd 2685168404Spjd/* 2686168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2687168404Spjd */ 2688185029Spjdstatic void 2689236155Smmprint_header(list_cbdata_t *cb) 2690168404Spjd{ 2691236155Smm zprop_list_t *pl = cb->cb_proplist; 2692236884Smm char headerbuf[ZPOOL_MAXPROPLEN]; 2693185029Spjd const char *header; 2694185029Spjd boolean_t first = B_TRUE; 2695185029Spjd boolean_t right_justify; 2696236155Smm size_t width = 0; 2697168404Spjd 2698185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2699236155Smm width = pl->pl_width; 2700236155Smm if (first && cb->cb_verbose) { 2701236155Smm /* 2702236155Smm * Reset the width to accommodate the verbose listing 2703236155Smm * of devices. 2704236155Smm */ 2705236155Smm width = cb->cb_namewidth; 2706236155Smm } 2707236155Smm 2708185029Spjd if (!first) 2709168404Spjd (void) printf(" "); 2710168404Spjd else 2711185029Spjd first = B_FALSE; 2712168404Spjd 2713236884Smm right_justify = B_FALSE; 2714236884Smm if (pl->pl_prop != ZPROP_INVAL) { 2715236884Smm header = zpool_prop_column_name(pl->pl_prop); 2716236884Smm right_justify = zpool_prop_align_right(pl->pl_prop); 2717236884Smm } else { 2718236884Smm int i; 2719185029Spjd 2720236884Smm for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2721236884Smm headerbuf[i] = toupper(pl->pl_user_prop[i]); 2722236884Smm headerbuf[i] = '\0'; 2723236884Smm header = headerbuf; 2724236884Smm } 2725236884Smm 2726185029Spjd if (pl->pl_next == NULL && !right_justify) 2727185029Spjd (void) printf("%s", header); 2728185029Spjd else if (right_justify) 2729236155Smm (void) printf("%*s", width, header); 2730185029Spjd else 2731236155Smm (void) printf("%-*s", width, header); 2732236155Smm 2733168404Spjd } 2734168404Spjd 2735168404Spjd (void) printf("\n"); 2736168404Spjd} 2737168404Spjd 2738185029Spjd/* 2739185029Spjd * Given a pool and a list of properties, print out all the properties according 2740185029Spjd * to the described layout. 2741185029Spjd */ 2742185029Spjdstatic void 2743236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 2744168404Spjd{ 2745236155Smm zprop_list_t *pl = cb->cb_proplist; 2746185029Spjd boolean_t first = B_TRUE; 2747185029Spjd char property[ZPOOL_MAXPROPLEN]; 2748185029Spjd char *propstr; 2749185029Spjd boolean_t right_justify; 2750236155Smm size_t width; 2751168404Spjd 2752185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2753236155Smm 2754236155Smm width = pl->pl_width; 2755236155Smm if (first && cb->cb_verbose) { 2756236155Smm /* 2757236155Smm * Reset the width to accommodate the verbose listing 2758236155Smm * of devices. 2759236155Smm */ 2760236155Smm width = cb->cb_namewidth; 2761236155Smm } 2762236155Smm 2763185029Spjd if (!first) { 2764236155Smm if (cb->cb_scripted) 2765168404Spjd (void) printf("\t"); 2766168404Spjd else 2767168404Spjd (void) printf(" "); 2768185029Spjd } else { 2769185029Spjd first = B_FALSE; 2770168404Spjd } 2771168404Spjd 2772185029Spjd right_justify = B_FALSE; 2773185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2774236155Smm if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ && 2775236155Smm zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0) 2776236155Smm propstr = "-"; 2777236155Smm else if (zpool_get_prop(zhp, pl->pl_prop, property, 2778185029Spjd sizeof (property), NULL) != 0) 2779185029Spjd propstr = "-"; 2780168404Spjd else 2781185029Spjd propstr = property; 2782168404Spjd 2783185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2784236884Smm } else if ((zpool_prop_feature(pl->pl_user_prop) || 2785236884Smm zpool_prop_unsupported(pl->pl_user_prop)) && 2786236884Smm zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 2787236884Smm sizeof (property)) == 0) { 2788236884Smm propstr = property; 2789185029Spjd } else { 2790185029Spjd propstr = "-"; 2791185029Spjd } 2792168404Spjd 2793168404Spjd 2794185029Spjd /* 2795185029Spjd * If this is being called in scripted mode, or if this is the 2796185029Spjd * last column and it is left-justified, don't include a width 2797185029Spjd * format specifier. 2798185029Spjd */ 2799236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 2800185029Spjd (void) printf("%s", propstr); 2801185029Spjd else if (right_justify) 2802185029Spjd (void) printf("%*s", width, propstr); 2803185029Spjd else 2804185029Spjd (void) printf("%-*s", width, propstr); 2805185029Spjd } 2806168404Spjd 2807185029Spjd (void) printf("\n"); 2808185029Spjd} 2809168404Spjd 2810236155Smmstatic void 2811236155Smmprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted) 2812236155Smm{ 2813236155Smm char propval[64]; 2814236155Smm boolean_t fixed; 2815236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 2816236155Smm 2817236155Smm zfs_nicenum(value, propval, sizeof (propval)); 2818236155Smm 2819236155Smm if (prop == ZPOOL_PROP_EXPANDSZ && value == 0) 2820236155Smm (void) strlcpy(propval, "-", sizeof (propval)); 2821236155Smm 2822236155Smm if (scripted) 2823236155Smm (void) printf("\t%s", propval); 2824236155Smm else 2825236155Smm (void) printf(" %*s", width, propval); 2826236155Smm} 2827236155Smm 2828236155Smmvoid 2829236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 2830236155Smm list_cbdata_t *cb, int depth) 2831236155Smm{ 2832236155Smm nvlist_t **child; 2833236155Smm vdev_stat_t *vs; 2834236155Smm uint_t c, children; 2835236155Smm char *vname; 2836236155Smm boolean_t scripted = cb->cb_scripted; 2837236155Smm 2838236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 2839236155Smm (uint64_t **)&vs, &c) == 0); 2840236155Smm 2841236155Smm if (name != NULL) { 2842236155Smm if (scripted) 2843236155Smm (void) printf("\t%s", name); 2844236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 2845236155Smm (void) printf("%*s%s", depth, "", name); 2846236155Smm else 2847236155Smm (void) printf("%*s%s%*s", depth, "", name, 2848236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2849236155Smm 2850236155Smm /* only toplevel vdevs have capacity stats */ 2851236155Smm if (vs->vs_space == 0) { 2852236155Smm if (scripted) 2853236155Smm (void) printf("\t-\t-\t-"); 2854236155Smm else 2855236155Smm (void) printf(" - - -"); 2856236155Smm } else { 2857236155Smm print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, 2858236155Smm scripted); 2859236155Smm print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc, 2860236155Smm scripted); 2861236155Smm print_one_column(ZPOOL_PROP_FREE, 2862236155Smm vs->vs_space - vs->vs_alloc, scripted); 2863236155Smm } 2864236155Smm print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, 2865236155Smm scripted); 2866236155Smm (void) printf("\n"); 2867236155Smm } 2868236155Smm 2869236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2870236155Smm &child, &children) != 0) 2871236155Smm return; 2872236155Smm 2873236155Smm for (c = 0; c < children; c++) { 2874236155Smm uint64_t ishole = B_FALSE; 2875236155Smm 2876236155Smm if (nvlist_lookup_uint64(child[c], 2877236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 2878236155Smm continue; 2879236155Smm 2880236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 2881236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 2882236155Smm free(vname); 2883236155Smm } 2884236155Smm 2885236155Smm /* 2886236155Smm * Include level 2 ARC devices in iostat output 2887236155Smm */ 2888236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 2889236155Smm &child, &children) != 0) 2890236155Smm return; 2891236155Smm 2892236155Smm if (children > 0) { 2893236155Smm (void) printf("%-*s - - - - - " 2894236155Smm "-\n", cb->cb_namewidth, "cache"); 2895236155Smm for (c = 0; c < children; c++) { 2896236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], 2897236155Smm B_FALSE); 2898236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 2899236155Smm free(vname); 2900236155Smm } 2901236155Smm } 2902236155Smm} 2903236155Smm 2904236155Smm 2905185029Spjd/* 2906185029Spjd * Generic callback function to list a pool. 2907185029Spjd */ 2908185029Spjdint 2909185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 2910185029Spjd{ 2911185029Spjd list_cbdata_t *cbp = data; 2912236155Smm nvlist_t *config; 2913236155Smm nvlist_t *nvroot; 2914168404Spjd 2915236155Smm config = zpool_get_config(zhp, NULL); 2916168404Spjd 2917236155Smm print_pool(zhp, cbp); 2918236155Smm if (!cbp->cb_verbose) 2919236155Smm return (0); 2920168404Spjd 2921236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2922236155Smm &nvroot) == 0); 2923236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 2924236155Smm 2925168404Spjd return (0); 2926168404Spjd} 2927168404Spjd 2928168404Spjd/* 2929219089Spjd * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 2930168404Spjd * 2931185029Spjd * -H Scripted mode. Don't display headers, and separate properties 2932185029Spjd * by a single tab. 2933185029Spjd * -o List of properties to display. Defaults to 2934219089Spjd * "name,size,allocated,free,capacity,health,altroot" 2935219089Spjd * -T Display a timestamp in date(1) or Unix format 2936168404Spjd * 2937168404Spjd * List all pools in the system, whether or not they're healthy. Output space 2938168404Spjd * statistics for each one, as well as health status summary. 2939168404Spjd */ 2940168404Spjdint 2941168404Spjdzpool_do_list(int argc, char **argv) 2942168404Spjd{ 2943168404Spjd int c; 2944168404Spjd int ret; 2945168404Spjd list_cbdata_t cb = { 0 }; 2946185029Spjd static char default_props[] = 2947236155Smm "name,size,allocated,free,capacity,dedupratio," 2948236155Smm "health,altroot"; 2949185029Spjd char *props = default_props; 2950219089Spjd unsigned long interval = 0, count = 0; 2951236155Smm zpool_list_t *list; 2952236155Smm boolean_t first = B_TRUE; 2953168404Spjd 2954168404Spjd /* check options */ 2955236155Smm while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) { 2956168404Spjd switch (c) { 2957168404Spjd case 'H': 2958168404Spjd cb.cb_scripted = B_TRUE; 2959168404Spjd break; 2960168404Spjd case 'o': 2961185029Spjd props = optarg; 2962168404Spjd break; 2963219089Spjd case 'T': 2964219089Spjd get_timestamp_arg(*optarg); 2965219089Spjd break; 2966236155Smm case 'v': 2967236155Smm cb.cb_verbose = B_TRUE; 2968236155Smm break; 2969168404Spjd case ':': 2970168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2971168404Spjd "'%c' option\n"), optopt); 2972168404Spjd usage(B_FALSE); 2973168404Spjd break; 2974168404Spjd case '?': 2975168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2976168404Spjd optopt); 2977168404Spjd usage(B_FALSE); 2978168404Spjd } 2979168404Spjd } 2980168404Spjd 2981168404Spjd argc -= optind; 2982168404Spjd argv += optind; 2983168404Spjd 2984219089Spjd get_interval_count(&argc, argv, &interval, &count); 2985219089Spjd 2986185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 2987185029Spjd usage(B_FALSE); 2988168404Spjd 2989236155Smm if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL) 2990236155Smm return (1); 2991168404Spjd 2992236155Smm if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 2993236155Smm (void) printf(gettext("no pools available\n")); 2994236155Smm zprop_free_list(cb.cb_proplist); 2995236155Smm return (0); 2996236155Smm } 2997236155Smm 2998219089Spjd for (;;) { 2999236155Smm pool_list_update(list); 3000168404Spjd 3001236155Smm if (pool_list_count(list) == 0) 3002236155Smm break; 3003236155Smm 3004236155Smm cb.cb_namewidth = 0; 3005236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3006236155Smm 3007219089Spjd if (timestamp_fmt != NODATE) 3008219089Spjd print_timestamp(timestamp_fmt); 3009168404Spjd 3010236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 3011236155Smm print_header(&cb); 3012236155Smm first = B_FALSE; 3013219089Spjd } 3014236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 3015219089Spjd 3016219089Spjd if (interval == 0) 3017219089Spjd break; 3018219089Spjd 3019219089Spjd if (count != 0 && --count == 0) 3020219089Spjd break; 3021219089Spjd 3022219089Spjd (void) sleep(interval); 3023168404Spjd } 3024168404Spjd 3025219089Spjd zprop_free_list(cb.cb_proplist); 3026168404Spjd return (ret); 3027168404Spjd} 3028168404Spjd 3029168404Spjdstatic nvlist_t * 3030168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name) 3031168404Spjd{ 3032168404Spjd nvlist_t **child; 3033168404Spjd uint_t c, children; 3034168404Spjd nvlist_t *match; 3035168404Spjd char *path; 3036168404Spjd 3037168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 3038168404Spjd &child, &children) != 0) { 3039168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 3040219089Spjd if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 3041219089Spjd name += sizeof(_PATH_DEV) - 1; 3042219089Spjd if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 3043219089Spjd path += sizeof(_PATH_DEV) - 1; 3044168404Spjd if (strcmp(name, path) == 0) 3045168404Spjd return (nv); 3046168404Spjd return (NULL); 3047168404Spjd } 3048168404Spjd 3049168404Spjd for (c = 0; c < children; c++) 3050168404Spjd if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 3051168404Spjd return (match); 3052168404Spjd 3053168404Spjd return (NULL); 3054168404Spjd} 3055168404Spjd 3056168404Spjdstatic int 3057168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 3058168404Spjd{ 3059168404Spjd boolean_t force = B_FALSE; 3060168404Spjd int c; 3061168404Spjd nvlist_t *nvroot; 3062168404Spjd char *poolname, *old_disk, *new_disk; 3063168404Spjd zpool_handle_t *zhp; 3064168404Spjd int ret; 3065168404Spjd 3066168404Spjd /* check options */ 3067168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3068168404Spjd switch (c) { 3069168404Spjd case 'f': 3070168404Spjd force = B_TRUE; 3071168404Spjd break; 3072168404Spjd case '?': 3073168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3074168404Spjd optopt); 3075168404Spjd usage(B_FALSE); 3076168404Spjd } 3077168404Spjd } 3078168404Spjd 3079168404Spjd argc -= optind; 3080168404Spjd argv += optind; 3081168404Spjd 3082168404Spjd /* get pool name and check number of arguments */ 3083168404Spjd if (argc < 1) { 3084168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3085168404Spjd usage(B_FALSE); 3086168404Spjd } 3087168404Spjd 3088168404Spjd poolname = argv[0]; 3089168404Spjd 3090168404Spjd if (argc < 2) { 3091168404Spjd (void) fprintf(stderr, 3092168404Spjd gettext("missing <device> specification\n")); 3093168404Spjd usage(B_FALSE); 3094168404Spjd } 3095168404Spjd 3096168404Spjd old_disk = argv[1]; 3097168404Spjd 3098168404Spjd if (argc < 3) { 3099168404Spjd if (!replacing) { 3100168404Spjd (void) fprintf(stderr, 3101168404Spjd gettext("missing <new_device> specification\n")); 3102168404Spjd usage(B_FALSE); 3103168404Spjd } 3104168404Spjd new_disk = old_disk; 3105168404Spjd argc -= 1; 3106168404Spjd argv += 1; 3107168404Spjd } else { 3108168404Spjd new_disk = argv[2]; 3109168404Spjd argc -= 2; 3110168404Spjd argv += 2; 3111168404Spjd } 3112168404Spjd 3113168404Spjd if (argc > 1) { 3114168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3115168404Spjd usage(B_FALSE); 3116168404Spjd } 3117168404Spjd 3118168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3119168404Spjd return (1); 3120168404Spjd 3121185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3122168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3123168404Spjd poolname); 3124168404Spjd zpool_close(zhp); 3125168404Spjd return (1); 3126168404Spjd } 3127168404Spjd 3128185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3129185029Spjd argc, argv); 3130168404Spjd if (nvroot == NULL) { 3131168404Spjd zpool_close(zhp); 3132168404Spjd return (1); 3133168404Spjd } 3134168404Spjd 3135168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3136168404Spjd 3137168404Spjd nvlist_free(nvroot); 3138168404Spjd zpool_close(zhp); 3139168404Spjd 3140168404Spjd return (ret); 3141168404Spjd} 3142168404Spjd 3143168404Spjd/* 3144168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3145168404Spjd * 3146168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3147168404Spjd * 3148168404Spjd * Replace <device> with <new_device>. 3149168404Spjd */ 3150168404Spjd/* ARGSUSED */ 3151168404Spjdint 3152168404Spjdzpool_do_replace(int argc, char **argv) 3153168404Spjd{ 3154168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3155168404Spjd} 3156168404Spjd 3157168404Spjd/* 3158168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3159168404Spjd * 3160168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3161168404Spjd * 3162168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3163168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3164168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3165168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3166168404Spjd */ 3167168404Spjdint 3168168404Spjdzpool_do_attach(int argc, char **argv) 3169168404Spjd{ 3170168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3171168404Spjd} 3172168404Spjd 3173168404Spjd/* 3174168404Spjd * zpool detach [-f] <pool> <device> 3175168404Spjd * 3176168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3177168404Spjd * (not supported yet) 3178168404Spjd * 3179168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3180168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3181168404Spjd * has the only valid copy of some data. 3182168404Spjd */ 3183168404Spjd/* ARGSUSED */ 3184168404Spjdint 3185168404Spjdzpool_do_detach(int argc, char **argv) 3186168404Spjd{ 3187168404Spjd int c; 3188168404Spjd char *poolname, *path; 3189168404Spjd zpool_handle_t *zhp; 3190168404Spjd int ret; 3191168404Spjd 3192168404Spjd /* check options */ 3193168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3194168404Spjd switch (c) { 3195168404Spjd case 'f': 3196168404Spjd case '?': 3197168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3198168404Spjd optopt); 3199168404Spjd usage(B_FALSE); 3200168404Spjd } 3201168404Spjd } 3202168404Spjd 3203168404Spjd argc -= optind; 3204168404Spjd argv += optind; 3205168404Spjd 3206168404Spjd /* get pool name and check number of arguments */ 3207168404Spjd if (argc < 1) { 3208168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3209168404Spjd usage(B_FALSE); 3210168404Spjd } 3211168404Spjd 3212168404Spjd if (argc < 2) { 3213168404Spjd (void) fprintf(stderr, 3214168404Spjd gettext("missing <device> specification\n")); 3215168404Spjd usage(B_FALSE); 3216168404Spjd } 3217168404Spjd 3218168404Spjd poolname = argv[0]; 3219168404Spjd path = argv[1]; 3220168404Spjd 3221168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3222168404Spjd return (1); 3223168404Spjd 3224168404Spjd ret = zpool_vdev_detach(zhp, path); 3225168404Spjd 3226168404Spjd zpool_close(zhp); 3227168404Spjd 3228168404Spjd return (ret); 3229168404Spjd} 3230168404Spjd 3231168404Spjd/* 3232219089Spjd * zpool split [-n] [-o prop=val] ... 3233219089Spjd * [-o mntopt] ... 3234219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3235219089Spjd * 3236219089Spjd * -n Do not split the pool, but display the resulting layout if 3237219089Spjd * it were to be split. 3238219089Spjd * -o Set property=value, or set mount options. 3239219089Spjd * -R Mount the split-off pool under an alternate root. 3240219089Spjd * 3241219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3242219089Spjd * off may be listed, provided that no more than one device is specified 3243219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3244219089Spjd * state unless -R is specified. 3245219089Spjd * 3246219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3247219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3248219089Spjd * undergoing a resilvering operation. 3249219089Spjd */ 3250219089Spjdint 3251219089Spjdzpool_do_split(int argc, char **argv) 3252219089Spjd{ 3253219089Spjd char *srcpool, *newpool, *propval; 3254219089Spjd char *mntopts = NULL; 3255219089Spjd splitflags_t flags; 3256219089Spjd int c, ret = 0; 3257219089Spjd zpool_handle_t *zhp; 3258219089Spjd nvlist_t *config, *props = NULL; 3259219089Spjd 3260219089Spjd flags.dryrun = B_FALSE; 3261219089Spjd flags.import = B_FALSE; 3262219089Spjd 3263219089Spjd /* check options */ 3264219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3265219089Spjd switch (c) { 3266219089Spjd case 'R': 3267219089Spjd flags.import = B_TRUE; 3268219089Spjd if (add_prop_list( 3269219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3270219089Spjd &props, B_TRUE) != 0) { 3271219089Spjd if (props) 3272219089Spjd nvlist_free(props); 3273219089Spjd usage(B_FALSE); 3274219089Spjd } 3275219089Spjd break; 3276219089Spjd case 'n': 3277219089Spjd flags.dryrun = B_TRUE; 3278219089Spjd break; 3279219089Spjd case 'o': 3280219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3281219089Spjd *propval = '\0'; 3282219089Spjd propval++; 3283219089Spjd if (add_prop_list(optarg, propval, 3284219089Spjd &props, B_TRUE) != 0) { 3285219089Spjd if (props) 3286219089Spjd nvlist_free(props); 3287219089Spjd usage(B_FALSE); 3288219089Spjd } 3289219089Spjd } else { 3290219089Spjd mntopts = optarg; 3291219089Spjd } 3292219089Spjd break; 3293219089Spjd case ':': 3294219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3295219089Spjd "'%c' option\n"), optopt); 3296219089Spjd usage(B_FALSE); 3297219089Spjd break; 3298219089Spjd case '?': 3299219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3300219089Spjd optopt); 3301219089Spjd usage(B_FALSE); 3302219089Spjd break; 3303219089Spjd } 3304219089Spjd } 3305219089Spjd 3306219089Spjd if (!flags.import && mntopts != NULL) { 3307219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3308219089Spjd "valid when importing the pool\n")); 3309219089Spjd usage(B_FALSE); 3310219089Spjd } 3311219089Spjd 3312219089Spjd argc -= optind; 3313219089Spjd argv += optind; 3314219089Spjd 3315219089Spjd if (argc < 1) { 3316219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3317219089Spjd usage(B_FALSE); 3318219089Spjd } 3319219089Spjd if (argc < 2) { 3320219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3321219089Spjd usage(B_FALSE); 3322219089Spjd } 3323219089Spjd 3324219089Spjd srcpool = argv[0]; 3325219089Spjd newpool = argv[1]; 3326219089Spjd 3327219089Spjd argc -= 2; 3328219089Spjd argv += 2; 3329219089Spjd 3330219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3331219089Spjd return (1); 3332219089Spjd 3333219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3334219089Spjd if (config == NULL) { 3335219089Spjd ret = 1; 3336219089Spjd } else { 3337219089Spjd if (flags.dryrun) { 3338219089Spjd (void) printf(gettext("would create '%s' with the " 3339219089Spjd "following layout:\n\n"), newpool); 3340219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3341219089Spjd } 3342219089Spjd nvlist_free(config); 3343219089Spjd } 3344219089Spjd 3345219089Spjd zpool_close(zhp); 3346219089Spjd 3347219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3348219089Spjd return (ret); 3349219089Spjd 3350219089Spjd /* 3351219089Spjd * The split was successful. Now we need to open the new 3352219089Spjd * pool and import it. 3353219089Spjd */ 3354219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3355219089Spjd return (1); 3356219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3357219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3358219089Spjd ret = 1; 3359219089Spjd (void) fprintf(stderr, gettext("Split was succssful, but " 3360219089Spjd "the datasets could not all be mounted\n")); 3361219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3362219089Spjd "different altroot\n"), "zpool import"); 3363219089Spjd } 3364219089Spjd zpool_close(zhp); 3365219089Spjd 3366219089Spjd return (ret); 3367219089Spjd} 3368219089Spjd 3369219089Spjd 3370219089Spjd 3371219089Spjd/* 3372168404Spjd * zpool online <pool> <device> ... 3373168404Spjd */ 3374168404Spjdint 3375168404Spjdzpool_do_online(int argc, char **argv) 3376168404Spjd{ 3377168404Spjd int c, i; 3378168404Spjd char *poolname; 3379168404Spjd zpool_handle_t *zhp; 3380168404Spjd int ret = 0; 3381185029Spjd vdev_state_t newstate; 3382219089Spjd int flags = 0; 3383168404Spjd 3384168404Spjd /* check options */ 3385219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3386168404Spjd switch (c) { 3387219089Spjd case 'e': 3388219089Spjd flags |= ZFS_ONLINE_EXPAND; 3389219089Spjd break; 3390168404Spjd case 't': 3391168404Spjd case '?': 3392168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3393168404Spjd optopt); 3394168404Spjd usage(B_FALSE); 3395168404Spjd } 3396168404Spjd } 3397168404Spjd 3398168404Spjd argc -= optind; 3399168404Spjd argv += optind; 3400168404Spjd 3401168404Spjd /* get pool name and check number of arguments */ 3402168404Spjd if (argc < 1) { 3403168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3404168404Spjd usage(B_FALSE); 3405168404Spjd } 3406168404Spjd if (argc < 2) { 3407168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3408168404Spjd usage(B_FALSE); 3409168404Spjd } 3410168404Spjd 3411168404Spjd poolname = argv[0]; 3412168404Spjd 3413168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3414168404Spjd return (1); 3415168404Spjd 3416185029Spjd for (i = 1; i < argc; i++) { 3417219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3418185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3419185029Spjd (void) printf(gettext("warning: device '%s' " 3420185029Spjd "onlined, but remains in faulted state\n"), 3421185029Spjd argv[i]); 3422185029Spjd if (newstate == VDEV_STATE_FAULTED) 3423185029Spjd (void) printf(gettext("use 'zpool " 3424185029Spjd "clear' to restore a faulted " 3425185029Spjd "device\n")); 3426185029Spjd else 3427185029Spjd (void) printf(gettext("use 'zpool " 3428185029Spjd "replace' to replace devices " 3429185029Spjd "that are no longer present\n")); 3430185029Spjd } 3431185029Spjd } else { 3432168404Spjd ret = 1; 3433185029Spjd } 3434185029Spjd } 3435168404Spjd 3436168404Spjd zpool_close(zhp); 3437168404Spjd 3438168404Spjd return (ret); 3439168404Spjd} 3440168404Spjd 3441168404Spjd/* 3442168404Spjd * zpool offline [-ft] <pool> <device> ... 3443168404Spjd * 3444168404Spjd * -f Force the device into the offline state, even if doing 3445168404Spjd * so would appear to compromise pool availability. 3446168404Spjd * (not supported yet) 3447168404Spjd * 3448168404Spjd * -t Only take the device off-line temporarily. The offline 3449168404Spjd * state will not be persistent across reboots. 3450168404Spjd */ 3451168404Spjd/* ARGSUSED */ 3452168404Spjdint 3453168404Spjdzpool_do_offline(int argc, char **argv) 3454168404Spjd{ 3455168404Spjd int c, i; 3456168404Spjd char *poolname; 3457168404Spjd zpool_handle_t *zhp; 3458168404Spjd int ret = 0; 3459168404Spjd boolean_t istmp = B_FALSE; 3460168404Spjd 3461168404Spjd /* check options */ 3462168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3463168404Spjd switch (c) { 3464168404Spjd case 't': 3465168404Spjd istmp = B_TRUE; 3466168404Spjd break; 3467168404Spjd case 'f': 3468168404Spjd case '?': 3469168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3470168404Spjd optopt); 3471168404Spjd usage(B_FALSE); 3472168404Spjd } 3473168404Spjd } 3474168404Spjd 3475168404Spjd argc -= optind; 3476168404Spjd argv += optind; 3477168404Spjd 3478168404Spjd /* get pool name and check number of arguments */ 3479168404Spjd if (argc < 1) { 3480168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3481168404Spjd usage(B_FALSE); 3482168404Spjd } 3483168404Spjd if (argc < 2) { 3484168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3485168404Spjd usage(B_FALSE); 3486168404Spjd } 3487168404Spjd 3488168404Spjd poolname = argv[0]; 3489168404Spjd 3490168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3491168404Spjd return (1); 3492168404Spjd 3493185029Spjd for (i = 1; i < argc; i++) { 3494185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3495168404Spjd ret = 1; 3496185029Spjd } 3497168404Spjd 3498168404Spjd zpool_close(zhp); 3499168404Spjd 3500168404Spjd return (ret); 3501168404Spjd} 3502168404Spjd 3503168404Spjd/* 3504168404Spjd * zpool clear <pool> [device] 3505168404Spjd * 3506168404Spjd * Clear all errors associated with a pool or a particular device. 3507168404Spjd */ 3508168404Spjdint 3509168404Spjdzpool_do_clear(int argc, char **argv) 3510168404Spjd{ 3511219089Spjd int c; 3512168404Spjd int ret = 0; 3513219089Spjd boolean_t dryrun = B_FALSE; 3514219089Spjd boolean_t do_rewind = B_FALSE; 3515219089Spjd boolean_t xtreme_rewind = B_FALSE; 3516219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3517219089Spjd nvlist_t *policy = NULL; 3518168404Spjd zpool_handle_t *zhp; 3519168404Spjd char *pool, *device; 3520168404Spjd 3521219089Spjd /* check options */ 3522219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3523219089Spjd switch (c) { 3524219089Spjd case 'F': 3525219089Spjd do_rewind = B_TRUE; 3526219089Spjd break; 3527219089Spjd case 'n': 3528219089Spjd dryrun = B_TRUE; 3529219089Spjd break; 3530219089Spjd case 'X': 3531219089Spjd xtreme_rewind = B_TRUE; 3532219089Spjd break; 3533219089Spjd case '?': 3534219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3535219089Spjd optopt); 3536219089Spjd usage(B_FALSE); 3537219089Spjd } 3538219089Spjd } 3539219089Spjd 3540219089Spjd argc -= optind; 3541219089Spjd argv += optind; 3542219089Spjd 3543219089Spjd if (argc < 1) { 3544168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3545168404Spjd usage(B_FALSE); 3546168404Spjd } 3547168404Spjd 3548219089Spjd if (argc > 2) { 3549168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3550168404Spjd usage(B_FALSE); 3551168404Spjd } 3552168404Spjd 3553219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3554219089Spjd (void) fprintf(stderr, 3555219089Spjd gettext("-n or -X only meaningful with -F\n")); 3556219089Spjd usage(B_FALSE); 3557219089Spjd } 3558219089Spjd if (dryrun) 3559219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3560219089Spjd else if (do_rewind) 3561219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3562219089Spjd if (xtreme_rewind) 3563219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3564168404Spjd 3565219089Spjd /* In future, further rewind policy choices can be passed along here */ 3566219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3567219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3568168404Spjd return (1); 3569168404Spjd 3570219089Spjd pool = argv[0]; 3571219089Spjd device = argc == 2 ? argv[1] : NULL; 3572219089Spjd 3573219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3574219089Spjd nvlist_free(policy); 3575219089Spjd return (1); 3576219089Spjd } 3577219089Spjd 3578219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3579168404Spjd ret = 1; 3580168404Spjd 3581168404Spjd zpool_close(zhp); 3582168404Spjd 3583219089Spjd nvlist_free(policy); 3584219089Spjd 3585168404Spjd return (ret); 3586168404Spjd} 3587168404Spjd 3588228103Smm/* 3589228103Smm * zpool reguid <pool> 3590228103Smm */ 3591228103Smmint 3592228103Smmzpool_do_reguid(int argc, char **argv) 3593228103Smm{ 3594228103Smm int c; 3595228103Smm char *poolname; 3596228103Smm zpool_handle_t *zhp; 3597228103Smm int ret = 0; 3598228103Smm 3599228103Smm /* check options */ 3600228103Smm while ((c = getopt(argc, argv, "")) != -1) { 3601228103Smm switch (c) { 3602228103Smm case '?': 3603228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3604228103Smm optopt); 3605228103Smm usage(B_FALSE); 3606228103Smm } 3607228103Smm } 3608228103Smm 3609228103Smm argc -= optind; 3610228103Smm argv += optind; 3611228103Smm 3612228103Smm /* get pool name and check number of arguments */ 3613228103Smm if (argc < 1) { 3614228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 3615228103Smm usage(B_FALSE); 3616228103Smm } 3617228103Smm 3618228103Smm if (argc > 1) { 3619228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 3620228103Smm usage(B_FALSE); 3621228103Smm } 3622228103Smm 3623228103Smm poolname = argv[0]; 3624228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3625228103Smm return (1); 3626228103Smm 3627228103Smm ret = zpool_reguid(zhp); 3628228103Smm 3629228103Smm zpool_close(zhp); 3630228103Smm return (ret); 3631228103Smm} 3632228103Smm 3633228103Smm 3634236155Smm/* 3635236155Smm * zpool reopen <pool> 3636236155Smm * 3637236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 3638236155Smm * 3639236155Smm * NOTE: This command is currently undocumented. If the command is ever 3640236155Smm * exposed then the appropriate usage() messages will need to be made. 3641236155Smm */ 3642236155Smmint 3643236155Smmzpool_do_reopen(int argc, char **argv) 3644236155Smm{ 3645236155Smm int ret = 0; 3646236155Smm zpool_handle_t *zhp; 3647236155Smm char *pool; 3648236155Smm 3649236155Smm argc--; 3650236155Smm argv++; 3651236155Smm 3652236155Smm if (argc != 1) 3653236155Smm return (2); 3654236155Smm 3655236155Smm pool = argv[0]; 3656236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 3657236155Smm return (1); 3658236155Smm 3659236155Smm ret = zpool_reopen(zhp); 3660236155Smm zpool_close(zhp); 3661236155Smm return (ret); 3662236155Smm} 3663236155Smm 3664168404Spjdtypedef struct scrub_cbdata { 3665168404Spjd int cb_type; 3666168404Spjd int cb_argc; 3667168404Spjd char **cb_argv; 3668168404Spjd} scrub_cbdata_t; 3669168404Spjd 3670168404Spjdint 3671168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3672168404Spjd{ 3673168404Spjd scrub_cbdata_t *cb = data; 3674168404Spjd int err; 3675168404Spjd 3676168404Spjd /* 3677168404Spjd * Ignore faulted pools. 3678168404Spjd */ 3679168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3680168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3681168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 3682168404Spjd return (1); 3683168404Spjd } 3684168404Spjd 3685219089Spjd err = zpool_scan(zhp, cb->cb_type); 3686168404Spjd 3687168404Spjd return (err != 0); 3688168404Spjd} 3689168404Spjd 3690168404Spjd/* 3691168404Spjd * zpool scrub [-s] <pool> ... 3692168404Spjd * 3693168404Spjd * -s Stop. Stops any in-progress scrub. 3694168404Spjd */ 3695168404Spjdint 3696168404Spjdzpool_do_scrub(int argc, char **argv) 3697168404Spjd{ 3698168404Spjd int c; 3699168404Spjd scrub_cbdata_t cb; 3700168404Spjd 3701219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 3702168404Spjd 3703168404Spjd /* check options */ 3704168404Spjd while ((c = getopt(argc, argv, "s")) != -1) { 3705168404Spjd switch (c) { 3706168404Spjd case 's': 3707219089Spjd cb.cb_type = POOL_SCAN_NONE; 3708168404Spjd break; 3709168404Spjd case '?': 3710168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3711168404Spjd optopt); 3712168404Spjd usage(B_FALSE); 3713168404Spjd } 3714168404Spjd } 3715168404Spjd 3716168404Spjd cb.cb_argc = argc; 3717168404Spjd cb.cb_argv = argv; 3718168404Spjd argc -= optind; 3719168404Spjd argv += optind; 3720168404Spjd 3721168404Spjd if (argc < 1) { 3722168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3723168404Spjd usage(B_FALSE); 3724168404Spjd } 3725168404Spjd 3726168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3727168404Spjd} 3728168404Spjd 3729168404Spjdtypedef struct status_cbdata { 3730168404Spjd int cb_count; 3731168404Spjd boolean_t cb_allpools; 3732168404Spjd boolean_t cb_verbose; 3733168404Spjd boolean_t cb_explain; 3734168404Spjd boolean_t cb_first; 3735219089Spjd boolean_t cb_dedup_stats; 3736168404Spjd} status_cbdata_t; 3737168404Spjd 3738168404Spjd/* 3739168404Spjd * Print out detailed scrub status. 3740168404Spjd */ 3741168404Spjdvoid 3742219089Spjdprint_scan_status(pool_scan_stat_t *ps) 3743168404Spjd{ 3744219089Spjd time_t start, end; 3745219089Spjd uint64_t elapsed, mins_left, hours_left; 3746219089Spjd uint64_t pass_exam, examined, total; 3747219089Spjd uint_t rate; 3748168404Spjd double fraction_done; 3749219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3750168404Spjd 3751226583Spjd (void) printf(gettext(" scan: ")); 3752168404Spjd 3753219089Spjd /* If there's never been a scan, there's not much to say. */ 3754219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 3755219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 3756168404Spjd (void) printf(gettext("none requested\n")); 3757168404Spjd return; 3758168404Spjd } 3759168404Spjd 3760219089Spjd start = ps->pss_start_time; 3761219089Spjd end = ps->pss_end_time; 3762219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3763168404Spjd 3764219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 3765219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 3766219089Spjd /* 3767219089Spjd * Scan is finished or canceled. 3768219089Spjd */ 3769219089Spjd if (ps->pss_state == DSS_FINISHED) { 3770219089Spjd uint64_t minutes_taken = (end - start) / 60; 3771219089Spjd char *fmt; 3772168404Spjd 3773219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3774219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 3775219089Spjd "%llu errors on %s"); 3776219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3777219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 3778219089Spjd "%llu errors on %s"); 3779219089Spjd } 3780219089Spjd /* LINTED */ 3781219089Spjd (void) printf(fmt, processed_buf, 3782185029Spjd (u_longlong_t)(minutes_taken / 60), 3783185029Spjd (uint_t)(minutes_taken % 60), 3784219089Spjd (u_longlong_t)ps->pss_errors, 3785219089Spjd ctime((time_t *)&end)); 3786168404Spjd return; 3787219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 3788219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3789219089Spjd (void) printf(gettext("scrub canceled on %s"), 3790219089Spjd ctime(&end)); 3791219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3792219089Spjd (void) printf(gettext("resilver canceled on %s"), 3793219089Spjd ctime(&end)); 3794219089Spjd } 3795219089Spjd return; 3796168404Spjd } 3797168404Spjd 3798219089Spjd assert(ps->pss_state == DSS_SCANNING); 3799168404Spjd 3800219089Spjd /* 3801219089Spjd * Scan is in progress. 3802219089Spjd */ 3803219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3804219089Spjd (void) printf(gettext("scrub in progress since %s"), 3805219089Spjd ctime(&start)); 3806219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3807219089Spjd (void) printf(gettext("resilver in progress since %s"), 3808219089Spjd ctime(&start)); 3809219089Spjd } 3810219089Spjd 3811219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 3812219089Spjd total = ps->pss_to_examine; 3813168404Spjd fraction_done = (double)examined / total; 3814168404Spjd 3815219089Spjd /* elapsed time for this pass */ 3816219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 3817219089Spjd elapsed = elapsed ? elapsed : 1; 3818219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 3819219089Spjd rate = pass_exam / elapsed; 3820219089Spjd rate = rate ? rate : 1; 3821219089Spjd mins_left = ((total - examined) / rate) / 60; 3822219089Spjd hours_left = mins_left / 60; 3823219089Spjd 3824219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 3825219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 3826219089Spjd zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 3827219089Spjd 3828219089Spjd /* 3829219089Spjd * do not print estimated time if hours_left is more than 30 days 3830219089Spjd */ 3831226583Spjd (void) printf(gettext(" %s scanned out of %s at %s/s"), 3832219089Spjd examined_buf, total_buf, rate_buf); 3833219089Spjd if (hours_left < (30 * 24)) { 3834219089Spjd (void) printf(gettext(", %lluh%um to go\n"), 3835219089Spjd (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 3836219089Spjd } else { 3837219089Spjd (void) printf(gettext( 3838219089Spjd ", (scan is slow, no estimated time)\n")); 3839219089Spjd } 3840219089Spjd 3841219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 3842226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 3843219089Spjd processed_buf, 100 * fraction_done); 3844219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 3845226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 3846219089Spjd processed_buf, 100 * fraction_done); 3847219089Spjd } 3848168404Spjd} 3849168404Spjd 3850168404Spjdstatic void 3851168404Spjdprint_error_log(zpool_handle_t *zhp) 3852168404Spjd{ 3853185029Spjd nvlist_t *nverrlist = NULL; 3854168404Spjd nvpair_t *elem; 3855168404Spjd char *pathname; 3856168404Spjd size_t len = MAXPATHLEN * 2; 3857168404Spjd 3858168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 3859168404Spjd (void) printf("errors: List of errors unavailable " 3860168404Spjd "(insufficient privileges)\n"); 3861168404Spjd return; 3862168404Spjd } 3863168404Spjd 3864168404Spjd (void) printf("errors: Permanent errors have been " 3865168404Spjd "detected in the following files:\n\n"); 3866168404Spjd 3867168404Spjd pathname = safe_malloc(len); 3868168404Spjd elem = NULL; 3869168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 3870168404Spjd nvlist_t *nv; 3871168404Spjd uint64_t dsobj, obj; 3872168404Spjd 3873168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 3874168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 3875168404Spjd &dsobj) == 0); 3876168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 3877168404Spjd &obj) == 0); 3878168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 3879168404Spjd (void) printf("%7s %s\n", "", pathname); 3880168404Spjd } 3881168404Spjd free(pathname); 3882168404Spjd nvlist_free(nverrlist); 3883168404Spjd} 3884168404Spjd 3885168404Spjdstatic void 3886168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 3887168404Spjd int namewidth) 3888168404Spjd{ 3889168404Spjd uint_t i; 3890168404Spjd char *name; 3891168404Spjd 3892168404Spjd if (nspares == 0) 3893168404Spjd return; 3894168404Spjd 3895168404Spjd (void) printf(gettext("\tspares\n")); 3896168404Spjd 3897168404Spjd for (i = 0; i < nspares; i++) { 3898219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 3899168404Spjd print_status_config(zhp, name, spares[i], 3900209962Smm namewidth, 2, B_TRUE); 3901168404Spjd free(name); 3902168404Spjd } 3903168404Spjd} 3904168404Spjd 3905185029Spjdstatic void 3906185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 3907185029Spjd int namewidth) 3908185029Spjd{ 3909185029Spjd uint_t i; 3910185029Spjd char *name; 3911185029Spjd 3912185029Spjd if (nl2cache == 0) 3913185029Spjd return; 3914185029Spjd 3915185029Spjd (void) printf(gettext("\tcache\n")); 3916185029Spjd 3917185029Spjd for (i = 0; i < nl2cache; i++) { 3918219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 3919185029Spjd print_status_config(zhp, name, l2cache[i], 3920209962Smm namewidth, 2, B_FALSE); 3921185029Spjd free(name); 3922185029Spjd } 3923185029Spjd} 3924185029Spjd 3925219089Spjdstatic void 3926219089Spjdprint_dedup_stats(nvlist_t *config) 3927219089Spjd{ 3928219089Spjd ddt_histogram_t *ddh; 3929219089Spjd ddt_stat_t *dds; 3930219089Spjd ddt_object_t *ddo; 3931219089Spjd uint_t c; 3932219089Spjd 3933219089Spjd /* 3934219089Spjd * If the pool was faulted then we may not have been able to 3935219089Spjd * obtain the config. Otherwise, if have anything in the dedup 3936219089Spjd * table continue processing the stats. 3937219089Spjd */ 3938219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 3939227497Smm (uint64_t **)&ddo, &c) != 0) 3940219089Spjd return; 3941219089Spjd 3942219089Spjd (void) printf("\n"); 3943227497Smm (void) printf(gettext(" dedup: ")); 3944227497Smm if (ddo->ddo_count == 0) { 3945227497Smm (void) printf(gettext("no DDT entries\n")); 3946227497Smm return; 3947227497Smm } 3948227497Smm 3949219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 3950219089Spjd (u_longlong_t)ddo->ddo_count, 3951219089Spjd (u_longlong_t)ddo->ddo_dspace, 3952219089Spjd (u_longlong_t)ddo->ddo_mspace); 3953219089Spjd 3954219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 3955219089Spjd (uint64_t **)&dds, &c) == 0); 3956219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 3957219089Spjd (uint64_t **)&ddh, &c) == 0); 3958219089Spjd zpool_dump_ddt(dds, ddh); 3959219089Spjd} 3960219089Spjd 3961168404Spjd/* 3962168404Spjd * Display a summary of pool status. Displays a summary such as: 3963168404Spjd * 3964168404Spjd * pool: tank 3965168404Spjd * status: DEGRADED 3966168404Spjd * reason: One or more devices ... 3967236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 3968168404Spjd * config: 3969168404Spjd * mirror DEGRADED 3970168404Spjd * c1t0d0 OK 3971168404Spjd * c2t0d0 UNAVAIL 3972168404Spjd * 3973168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 3974168404Spjd * option is specified, then we print out error rate information as well. 3975168404Spjd */ 3976168404Spjdint 3977168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 3978168404Spjd{ 3979168404Spjd status_cbdata_t *cbp = data; 3980168404Spjd nvlist_t *config, *nvroot; 3981168404Spjd char *msgid; 3982168404Spjd int reason; 3983168404Spjd const char *health; 3984168404Spjd uint_t c; 3985168404Spjd vdev_stat_t *vs; 3986168404Spjd 3987168404Spjd config = zpool_get_config(zhp, NULL); 3988168404Spjd reason = zpool_get_status(zhp, &msgid); 3989168404Spjd 3990168404Spjd cbp->cb_count++; 3991168404Spjd 3992168404Spjd /* 3993168404Spjd * If we were given 'zpool status -x', only report those pools with 3994168404Spjd * problems. 3995168404Spjd */ 3996168404Spjd if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 3997168404Spjd if (!cbp->cb_allpools) { 3998168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 3999168404Spjd zpool_get_name(zhp)); 4000168404Spjd if (cbp->cb_first) 4001168404Spjd cbp->cb_first = B_FALSE; 4002168404Spjd } 4003168404Spjd return (0); 4004168404Spjd } 4005168404Spjd 4006168404Spjd if (cbp->cb_first) 4007168404Spjd cbp->cb_first = B_FALSE; 4008168404Spjd else 4009168404Spjd (void) printf("\n"); 4010168404Spjd 4011168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 4012168404Spjd &nvroot) == 0); 4013219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 4014168404Spjd (uint64_t **)&vs, &c) == 0); 4015185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4016168404Spjd 4017168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4018168404Spjd (void) printf(gettext(" state: %s\n"), health); 4019168404Spjd 4020168404Spjd switch (reason) { 4021168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 4022168404Spjd (void) printf(gettext("status: One or more devices could not " 4023168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 4024168404Spjd "continue functioning in a degraded state.\n")); 4025168404Spjd (void) printf(gettext("action: Attach the missing device and " 4026168404Spjd "online it using 'zpool online'.\n")); 4027168404Spjd break; 4028168404Spjd 4029168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 4030168404Spjd (void) printf(gettext("status: One or more devices could not " 4031168404Spjd "be opened. There are insufficient\n\treplicas for the " 4032168404Spjd "pool to continue functioning.\n")); 4033168404Spjd (void) printf(gettext("action: Attach the missing device and " 4034168404Spjd "online it using 'zpool online'.\n")); 4035168404Spjd break; 4036168404Spjd 4037168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 4038168404Spjd (void) printf(gettext("status: One or more devices could not " 4039168404Spjd "be used because the label is missing or\n\tinvalid. " 4040168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 4041168404Spjd "functioning in a degraded state.\n")); 4042168404Spjd (void) printf(gettext("action: Replace the device using " 4043168404Spjd "'zpool replace'.\n")); 4044168404Spjd break; 4045168404Spjd 4046168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4047168404Spjd (void) printf(gettext("status: One or more devices could not " 4048168404Spjd "be used because the label is missing \n\tor invalid. " 4049168404Spjd "There are insufficient replicas for the pool to " 4050168404Spjd "continue\n\tfunctioning.\n")); 4051219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4052219089Spjd zpool_get_name(zhp), reason, config); 4053168404Spjd break; 4054168404Spjd 4055168404Spjd case ZPOOL_STATUS_FAILING_DEV: 4056168404Spjd (void) printf(gettext("status: One or more devices has " 4057168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 4058168404Spjd "made to correct the error. Applications are " 4059168404Spjd "unaffected.\n")); 4060168404Spjd (void) printf(gettext("action: Determine if the device needs " 4061168404Spjd "to be replaced, and clear the errors\n\tusing " 4062168404Spjd "'zpool clear' or replace the device with 'zpool " 4063168404Spjd "replace'.\n")); 4064168404Spjd break; 4065168404Spjd 4066168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 4067168404Spjd (void) printf(gettext("status: One or more devices has " 4068168404Spjd "been taken offline by the administrator.\n\tSufficient " 4069168404Spjd "replicas exist for the pool to continue functioning in " 4070168404Spjd "a\n\tdegraded state.\n")); 4071168404Spjd (void) printf(gettext("action: Online the device using " 4072168404Spjd "'zpool online' or replace the device with\n\t'zpool " 4073168404Spjd "replace'.\n")); 4074168404Spjd break; 4075168404Spjd 4076219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 4077219089Spjd (void) printf(gettext("status: One or more devices has " 4078219089Spjd "been removed by the administrator.\n\tSufficient " 4079219089Spjd "replicas exist for the pool to continue functioning in " 4080219089Spjd "a\n\tdegraded state.\n")); 4081219089Spjd (void) printf(gettext("action: Online the device using " 4082219089Spjd "'zpool online' or replace the device with\n\t'zpool " 4083219089Spjd "replace'.\n")); 4084219089Spjd break; 4085219089Spjd 4086168404Spjd case ZPOOL_STATUS_RESILVERING: 4087168404Spjd (void) printf(gettext("status: One or more devices is " 4088168404Spjd "currently being resilvered. The pool will\n\tcontinue " 4089168404Spjd "to function, possibly in a degraded state.\n")); 4090168404Spjd (void) printf(gettext("action: Wait for the resilver to " 4091168404Spjd "complete.\n")); 4092168404Spjd break; 4093168404Spjd 4094168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 4095168404Spjd (void) printf(gettext("status: One or more devices has " 4096168404Spjd "experienced an error resulting in data\n\tcorruption. " 4097168404Spjd "Applications may be affected.\n")); 4098168404Spjd (void) printf(gettext("action: Restore the file in question " 4099168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 4100168404Spjd "backup.\n")); 4101168404Spjd break; 4102168404Spjd 4103168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4104168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4105168404Spjd "and the pool cannot be opened.\n")); 4106219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4107219089Spjd zpool_get_name(zhp), reason, config); 4108168404Spjd break; 4109168404Spjd 4110168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4111168404Spjd (void) printf(gettext("status: The pool is formatted using an " 4112168404Spjd "older on-disk format. The pool can\n\tstill be used, but " 4113168404Spjd "some features are unavailable.\n")); 4114168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4115168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 4116168404Spjd "be accessible on older software versions.\n")); 4117168404Spjd break; 4118168404Spjd 4119168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 4120168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 4121168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 4122168404Spjd "be accessed on this system.\n")); 4123168404Spjd (void) printf(gettext("action: Access the pool from a system " 4124168404Spjd "running more recent software, or\n\trestore the pool from " 4125168404Spjd "backup.\n")); 4126168404Spjd break; 4127168404Spjd 4128236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 4129236884Smm (void) printf(gettext("status: The pool cannot be accessed on " 4130236884Smm "this system because it uses the\n\tfollowing feature(s) " 4131236884Smm "not supported on this system:\n")); 4132236884Smm zpool_print_unsup_feat(config); 4133236884Smm (void) printf("\n"); 4134236884Smm (void) printf(gettext("action: Access the pool from a system " 4135236884Smm "that supports the required feature(s),\n\tor restore the " 4136236884Smm "pool from backup.\n")); 4137236884Smm break; 4138236884Smm 4139236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4140236884Smm (void) printf(gettext("status: The pool can only be accessed " 4141236884Smm "in read-only mode on this system. It\n\tcannot be " 4142236884Smm "accessed in read-write mode because it uses the " 4143236884Smm "following\n\tfeature(s) not supported on this system:\n")); 4144236884Smm zpool_print_unsup_feat(config); 4145236884Smm (void) printf("\n"); 4146236884Smm (void) printf(gettext("action: The pool cannot be accessed in " 4147236884Smm "read-write mode. Import the pool with\n" 4148236884Smm "\t\"-o readonly=on\", access the pool from a system that " 4149236884Smm "supports the\n\trequired feature(s), or restore the " 4150236884Smm "pool from backup.\n")); 4151236884Smm break; 4152236884Smm 4153185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 4154185029Spjd (void) printf(gettext("status: One or more devices are " 4155185029Spjd "faulted in response to persistent errors.\n\tSufficient " 4156185029Spjd "replicas exist for the pool to continue functioning " 4157185029Spjd "in a\n\tdegraded state.\n")); 4158185029Spjd (void) printf(gettext("action: Replace the faulted device, " 4159185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 4160185029Spjd break; 4161185029Spjd 4162185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 4163185029Spjd (void) printf(gettext("status: One or more devices are " 4164185029Spjd "faulted in response to persistent errors. There are " 4165185029Spjd "insufficient replicas for the pool to\n\tcontinue " 4166185029Spjd "functioning.\n")); 4167185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 4168185029Spjd "from a backup source. Manually marking the device\n" 4169185029Spjd "\trepaired using 'zpool clear' may allow some data " 4170185029Spjd "to be recovered.\n")); 4171185029Spjd break; 4172185029Spjd 4173185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 4174185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 4175185029Spjd (void) printf(gettext("status: One or more devices are " 4176185029Spjd "faulted in response to IO failures.\n")); 4177185029Spjd (void) printf(gettext("action: Make sure the affected devices " 4178185029Spjd "are connected, then run 'zpool clear'.\n")); 4179185029Spjd break; 4180185029Spjd 4181185029Spjd case ZPOOL_STATUS_BAD_LOG: 4182185029Spjd (void) printf(gettext("status: An intent log record " 4183185029Spjd "could not be read.\n" 4184185029Spjd "\tWaiting for adminstrator intervention to fix the " 4185185029Spjd "faulted pool.\n")); 4186185029Spjd (void) printf(gettext("action: Either restore the affected " 4187185029Spjd "device(s) and run 'zpool online',\n" 4188185029Spjd "\tor ignore the intent log records by running " 4189185029Spjd "'zpool clear'.\n")); 4190185029Spjd break; 4191185029Spjd 4192168404Spjd default: 4193168404Spjd /* 4194168404Spjd * The remaining errors can't actually be generated, yet. 4195168404Spjd */ 4196168404Spjd assert(reason == ZPOOL_STATUS_OK); 4197168404Spjd } 4198168404Spjd 4199168404Spjd if (msgid != NULL) 4200236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4201168404Spjd msgid); 4202168404Spjd 4203168404Spjd if (config != NULL) { 4204168404Spjd int namewidth; 4205168404Spjd uint64_t nerr; 4206185029Spjd nvlist_t **spares, **l2cache; 4207185029Spjd uint_t nspares, nl2cache; 4208219089Spjd pool_scan_stat_t *ps = NULL; 4209168404Spjd 4210219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 4211219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 4212219089Spjd print_scan_status(ps); 4213168404Spjd 4214168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 4215168404Spjd if (namewidth < 10) 4216168404Spjd namewidth = 10; 4217168404Spjd 4218168404Spjd (void) printf(gettext("config:\n\n")); 4219168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4220168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4221168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 4222209962Smm namewidth, 0, B_FALSE); 4223209962Smm 4224185029Spjd if (num_logs(nvroot) > 0) 4225213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 4226185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4227185029Spjd &l2cache, &nl2cache) == 0) 4228185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 4229185029Spjd 4230168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 4231168404Spjd &spares, &nspares) == 0) 4232168404Spjd print_spares(zhp, spares, nspares, namewidth); 4233168404Spjd 4234168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4235168404Spjd &nerr) == 0) { 4236168404Spjd nvlist_t *nverrlist = NULL; 4237168404Spjd 4238168404Spjd /* 4239168404Spjd * If the approximate error count is small, get a 4240168404Spjd * precise count by fetching the entire log and 4241168404Spjd * uniquifying the results. 4242168404Spjd */ 4243185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 4244168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 4245168404Spjd nvpair_t *elem; 4246168404Spjd 4247168404Spjd elem = NULL; 4248168404Spjd nerr = 0; 4249168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 4250168404Spjd elem)) != NULL) { 4251168404Spjd nerr++; 4252168404Spjd } 4253168404Spjd } 4254168404Spjd nvlist_free(nverrlist); 4255168404Spjd 4256168404Spjd (void) printf("\n"); 4257168404Spjd 4258168404Spjd if (nerr == 0) 4259168404Spjd (void) printf(gettext("errors: No known data " 4260168404Spjd "errors\n")); 4261168404Spjd else if (!cbp->cb_verbose) 4262168404Spjd (void) printf(gettext("errors: %llu data " 4263168404Spjd "errors, use '-v' for a list\n"), 4264168404Spjd (u_longlong_t)nerr); 4265168404Spjd else 4266168404Spjd print_error_log(zhp); 4267168404Spjd } 4268219089Spjd 4269219089Spjd if (cbp->cb_dedup_stats) 4270219089Spjd print_dedup_stats(config); 4271168404Spjd } else { 4272168404Spjd (void) printf(gettext("config: The configuration cannot be " 4273168404Spjd "determined.\n")); 4274168404Spjd } 4275168404Spjd 4276168404Spjd return (0); 4277168404Spjd} 4278168404Spjd 4279168404Spjd/* 4280219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4281168404Spjd * 4282168404Spjd * -v Display complete error logs 4283168404Spjd * -x Display only pools with potential problems 4284219089Spjd * -D Display dedup status (undocumented) 4285219089Spjd * -T Display a timestamp in date(1) or Unix format 4286168404Spjd * 4287168404Spjd * Describes the health status of all pools or some subset. 4288168404Spjd */ 4289168404Spjdint 4290168404Spjdzpool_do_status(int argc, char **argv) 4291168404Spjd{ 4292168404Spjd int c; 4293168404Spjd int ret; 4294219089Spjd unsigned long interval = 0, count = 0; 4295168404Spjd status_cbdata_t cb = { 0 }; 4296168404Spjd 4297168404Spjd /* check options */ 4298219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4299168404Spjd switch (c) { 4300168404Spjd case 'v': 4301168404Spjd cb.cb_verbose = B_TRUE; 4302168404Spjd break; 4303168404Spjd case 'x': 4304168404Spjd cb.cb_explain = B_TRUE; 4305168404Spjd break; 4306219089Spjd case 'D': 4307219089Spjd cb.cb_dedup_stats = B_TRUE; 4308219089Spjd break; 4309219089Spjd case 'T': 4310219089Spjd get_timestamp_arg(*optarg); 4311219089Spjd break; 4312168404Spjd case '?': 4313168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4314168404Spjd optopt); 4315168404Spjd usage(B_FALSE); 4316168404Spjd } 4317168404Spjd } 4318168404Spjd 4319168404Spjd argc -= optind; 4320168404Spjd argv += optind; 4321168404Spjd 4322219089Spjd get_interval_count(&argc, argv, &interval, &count); 4323168404Spjd 4324168404Spjd if (argc == 0) 4325168404Spjd cb.cb_allpools = B_TRUE; 4326168404Spjd 4327219089Spjd cb.cb_first = B_TRUE; 4328168404Spjd 4329219089Spjd for (;;) { 4330219089Spjd if (timestamp_fmt != NODATE) 4331219089Spjd print_timestamp(timestamp_fmt); 4332168404Spjd 4333219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 4334219089Spjd status_callback, &cb); 4335219089Spjd 4336219089Spjd if (argc == 0 && cb.cb_count == 0) 4337219089Spjd (void) printf(gettext("no pools available\n")); 4338219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 4339219089Spjd (void) printf(gettext("all pools are healthy\n")); 4340219089Spjd 4341219089Spjd if (ret != 0) 4342219089Spjd return (ret); 4343219089Spjd 4344219089Spjd if (interval == 0) 4345219089Spjd break; 4346219089Spjd 4347219089Spjd if (count != 0 && --count == 0) 4348219089Spjd break; 4349219089Spjd 4350219089Spjd (void) sleep(interval); 4351219089Spjd } 4352219089Spjd 4353219089Spjd return (0); 4354168404Spjd} 4355168404Spjd 4356168404Spjdtypedef struct upgrade_cbdata { 4357168404Spjd int cb_all; 4358168404Spjd int cb_first; 4359168404Spjd int cb_newer; 4360212050Spjd char cb_poolname[ZPOOL_MAXNAMELEN]; 4361168404Spjd int cb_argc; 4362185029Spjd uint64_t cb_version; 4363168404Spjd char **cb_argv; 4364168404Spjd} upgrade_cbdata_t; 4365168404Spjd 4366168404Spjdstatic int 4367212050Spjdis_root_pool(zpool_handle_t *zhp) 4368212050Spjd{ 4369212050Spjd static struct statfs sfs; 4370212050Spjd static char *poolname = NULL; 4371212050Spjd static boolean_t stated = B_FALSE; 4372212050Spjd char *slash; 4373212050Spjd 4374212067Spjd if (!stated) { 4375212050Spjd stated = B_TRUE; 4376212050Spjd if (statfs("/", &sfs) == -1) { 4377212050Spjd (void) fprintf(stderr, 4378212050Spjd "Unable to stat root file system: %s.\n", 4379212050Spjd strerror(errno)); 4380212067Spjd return (0); 4381212050Spjd } 4382212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4383212067Spjd return (0); 4384212050Spjd poolname = sfs.f_mntfromname; 4385212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4386212050Spjd *slash = '\0'; 4387212050Spjd } 4388212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4389212050Spjd} 4390212050Spjd 4391212050Spjdstatic int 4392168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4393168404Spjd{ 4394168404Spjd upgrade_cbdata_t *cbp = arg; 4395168404Spjd nvlist_t *config; 4396168404Spjd uint64_t version; 4397168404Spjd int ret = 0; 4398168404Spjd 4399168404Spjd config = zpool_get_config(zhp, NULL); 4400168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4401168404Spjd &version) == 0); 4402168404Spjd 4403236884Smm if (!cbp->cb_newer && SPA_VERSION_IS_SUPPORTED(version) && 4404236884Smm version != SPA_VERSION) { 4405168404Spjd if (!cbp->cb_all) { 4406168404Spjd if (cbp->cb_first) { 4407168404Spjd (void) printf(gettext("The following pools are " 4408168404Spjd "out of date, and can be upgraded. After " 4409168404Spjd "being\nupgraded, these pools will no " 4410168404Spjd "longer be accessible by older software " 4411168404Spjd "versions.\n\n")); 4412168404Spjd (void) printf(gettext("VER POOL\n")); 4413168404Spjd (void) printf(gettext("--- ------------\n")); 4414168404Spjd cbp->cb_first = B_FALSE; 4415168404Spjd } 4416168404Spjd 4417168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4418168404Spjd zpool_get_name(zhp)); 4419168404Spjd } else { 4420168404Spjd cbp->cb_first = B_FALSE; 4421185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 4422168404Spjd if (!ret) { 4423168404Spjd (void) printf(gettext("Successfully upgraded " 4424185029Spjd "'%s'\n\n"), zpool_get_name(zhp)); 4425212050Spjd if (cbp->cb_poolname[0] == '\0' && 4426212050Spjd is_root_pool(zhp)) { 4427212050Spjd (void) strlcpy(cbp->cb_poolname, 4428212050Spjd zpool_get_name(zhp), 4429212050Spjd sizeof(cbp->cb_poolname)); 4430212050Spjd } 4431168404Spjd } 4432168404Spjd } 4433236884Smm } else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) { 4434168404Spjd assert(!cbp->cb_all); 4435168404Spjd 4436168404Spjd if (cbp->cb_first) { 4437168404Spjd (void) printf(gettext("The following pools are " 4438236884Smm "formatted using an unsupported software version " 4439236884Smm "and\ncannot be accessed on the current " 4440236884Smm "system.\n\n")); 4441168404Spjd (void) printf(gettext("VER POOL\n")); 4442168404Spjd (void) printf(gettext("--- ------------\n")); 4443168404Spjd cbp->cb_first = B_FALSE; 4444168404Spjd } 4445168404Spjd 4446168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4447168404Spjd zpool_get_name(zhp)); 4448168404Spjd } 4449168404Spjd 4450168404Spjd zpool_close(zhp); 4451168404Spjd return (ret); 4452168404Spjd} 4453168404Spjd 4454168404Spjd/* ARGSUSED */ 4455168404Spjdstatic int 4456168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 4457168404Spjd{ 4458185029Spjd upgrade_cbdata_t *cbp = data; 4459185029Spjd uint64_t cur_version; 4460168404Spjd int ret; 4461168404Spjd 4462185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 4463185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 4464185029Spjd "Pool 'log' must be renamed using export and import" 4465185029Spjd " to upgrade.\n")); 4466185029Spjd return (1); 4467185029Spjd } 4468168404Spjd 4469185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4470185029Spjd if (cur_version > cbp->cb_version) { 4471168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 4472185029Spjd "using more current version '%llu'.\n"), 4473185029Spjd zpool_get_name(zhp), cur_version); 4474185029Spjd return (0); 4475185029Spjd } 4476185029Spjd if (cur_version == cbp->cb_version) { 4477185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 4478168404Spjd "using the current version.\n"), zpool_get_name(zhp)); 4479168404Spjd return (0); 4480168404Spjd } 4481168404Spjd 4482185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 4483168404Spjd 4484168404Spjd if (!ret) { 4485168404Spjd (void) printf(gettext("Successfully upgraded '%s' " 4486185029Spjd "from version %llu to version %llu\n\n"), 4487185029Spjd zpool_get_name(zhp), (u_longlong_t)cur_version, 4488185029Spjd (u_longlong_t)cbp->cb_version); 4489212050Spjd if (cbp->cb_poolname[0] == '\0' && is_root_pool(zhp)) { 4490212050Spjd (void) strlcpy(cbp->cb_poolname, zpool_get_name(zhp), 4491212050Spjd sizeof(cbp->cb_poolname)); 4492212050Spjd } 4493168404Spjd } 4494168404Spjd 4495168404Spjd return (ret != 0); 4496168404Spjd} 4497168404Spjd 4498168404Spjd/* 4499168404Spjd * zpool upgrade 4500168404Spjd * zpool upgrade -v 4501185029Spjd * zpool upgrade [-V version] <-a | pool ...> 4502168404Spjd * 4503168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 4504168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 4505168404Spjd * upgrade all pools. 4506168404Spjd */ 4507168404Spjdint 4508168404Spjdzpool_do_upgrade(int argc, char **argv) 4509168404Spjd{ 4510168404Spjd int c; 4511168404Spjd upgrade_cbdata_t cb = { 0 }; 4512168404Spjd int ret = 0; 4513168404Spjd boolean_t showversions = B_FALSE; 4514185029Spjd char *end; 4515168404Spjd 4516185029Spjd 4517168404Spjd /* check options */ 4518219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 4519168404Spjd switch (c) { 4520168404Spjd case 'a': 4521168404Spjd cb.cb_all = B_TRUE; 4522168404Spjd break; 4523168404Spjd case 'v': 4524168404Spjd showversions = B_TRUE; 4525168404Spjd break; 4526185029Spjd case 'V': 4527185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 4528236884Smm if (*end != '\0' || 4529236884Smm !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 4530185029Spjd (void) fprintf(stderr, 4531185029Spjd gettext("invalid version '%s'\n"), optarg); 4532185029Spjd usage(B_FALSE); 4533185029Spjd } 4534185029Spjd break; 4535219089Spjd case ':': 4536219089Spjd (void) fprintf(stderr, gettext("missing argument for " 4537219089Spjd "'%c' option\n"), optopt); 4538219089Spjd usage(B_FALSE); 4539219089Spjd break; 4540168404Spjd case '?': 4541168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4542168404Spjd optopt); 4543168404Spjd usage(B_FALSE); 4544168404Spjd } 4545168404Spjd } 4546168404Spjd 4547168404Spjd cb.cb_argc = argc; 4548168404Spjd cb.cb_argv = argv; 4549168404Spjd argc -= optind; 4550168404Spjd argv += optind; 4551168404Spjd 4552185029Spjd if (cb.cb_version == 0) { 4553185029Spjd cb.cb_version = SPA_VERSION; 4554185029Spjd } else if (!cb.cb_all && argc == 0) { 4555185029Spjd (void) fprintf(stderr, gettext("-V option is " 4556185029Spjd "incompatible with other arguments\n")); 4557185029Spjd usage(B_FALSE); 4558185029Spjd } 4559185029Spjd 4560168404Spjd if (showversions) { 4561168404Spjd if (cb.cb_all || argc != 0) { 4562168404Spjd (void) fprintf(stderr, gettext("-v option is " 4563168404Spjd "incompatible with other arguments\n")); 4564168404Spjd usage(B_FALSE); 4565168404Spjd } 4566168404Spjd } else if (cb.cb_all) { 4567168404Spjd if (argc != 0) { 4568185029Spjd (void) fprintf(stderr, gettext("-a option should not " 4569185029Spjd "be used along with a pool name\n")); 4570168404Spjd usage(B_FALSE); 4571168404Spjd } 4572168404Spjd } 4573168404Spjd 4574236884Smm (void) printf(gettext("This system supports ZFS pool feature " 4575236884Smm "flags.\n\n")); 4576168404Spjd cb.cb_first = B_TRUE; 4577168404Spjd if (showversions) { 4578168404Spjd (void) printf(gettext("The following versions are " 4579168404Spjd "supported:\n\n")); 4580168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 4581168404Spjd (void) printf("--- -----------------------------------------" 4582168404Spjd "---------------\n"); 4583168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 4584168404Spjd (void) printf(gettext(" 2 Ditto blocks " 4585168404Spjd "(replicated metadata)\n")); 4586168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 4587168404Spjd "RAID-Z\n")); 4588168404Spjd (void) printf(gettext(" 4 zpool history\n")); 4589168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 4590168404Spjd "algorithm\n")); 4591185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 4592185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 4593185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 4594185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 4595185029Spjd "properties\n")); 4596185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 4597185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 4598185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 4599185029Spjd (void) printf(gettext(" 13 snapused property\n")); 4600209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 4601209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 4602219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 4603219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 4604219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 4605219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 4606219089Spjd (void) printf(gettext(" 20 Compression using zle " 4607219089Spjd "(zero-length encoding)\n")); 4608219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 4609219089Spjd (void) printf(gettext(" 22 Received properties\n")); 4610219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 4611219089Spjd (void) printf(gettext(" 24 System attributes\n")); 4612219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 4613219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 4614219089Spjd "performance\n")); 4615219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 4616219089Spjd "performance\n")); 4617219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 4618219089Spjd (void) printf(gettext("\nFor more information on a particular " 4619219089Spjd "version, including supported releases,\n")); 4620219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 4621168404Spjd } else if (argc == 0) { 4622168404Spjd int notfound; 4623168404Spjd 4624168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4625168404Spjd notfound = cb.cb_first; 4626168404Spjd 4627168404Spjd if (!cb.cb_all && ret == 0) { 4628168404Spjd if (!cb.cb_first) 4629168404Spjd (void) printf("\n"); 4630168404Spjd cb.cb_first = B_TRUE; 4631168404Spjd cb.cb_newer = B_TRUE; 4632168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 4633168404Spjd if (!cb.cb_first) { 4634168404Spjd notfound = B_FALSE; 4635168404Spjd (void) printf("\n"); 4636168404Spjd } 4637168404Spjd } 4638168404Spjd 4639168404Spjd if (ret == 0) { 4640168404Spjd if (notfound) 4641168404Spjd (void) printf(gettext("All pools are formatted " 4642168404Spjd "using this version.\n")); 4643168404Spjd else if (!cb.cb_all) 4644168404Spjd (void) printf(gettext("Use 'zpool upgrade -v' " 4645168404Spjd "for a list of available versions and " 4646168404Spjd "their associated\nfeatures.\n")); 4647168404Spjd } 4648168404Spjd } else { 4649168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, 4650168404Spjd upgrade_one, &cb); 4651168404Spjd } 4652168404Spjd 4653212050Spjd if (cb.cb_poolname[0] != '\0') { 4654212050Spjd (void) printf( 4655212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 4656212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 4657212050Spjd "the following command will do it:\n" 4658212050Spjd "\n" 4659212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 4660212050Spjd cb.cb_poolname); 4661212050Spjd } 4662212050Spjd 4663168404Spjd return (ret); 4664168404Spjd} 4665168404Spjd 4666185029Spjdtypedef struct hist_cbdata { 4667185029Spjd boolean_t first; 4668185029Spjd int longfmt; 4669185029Spjd int internal; 4670185029Spjd} hist_cbdata_t; 4671185029Spjd 4672168404Spjd/* 4673168404Spjd * Print out the command history for a specific pool. 4674168404Spjd */ 4675168404Spjdstatic int 4676168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 4677168404Spjd{ 4678168404Spjd nvlist_t *nvhis; 4679168404Spjd nvlist_t **records; 4680168404Spjd uint_t numrecords; 4681168404Spjd char *cmdstr; 4682185029Spjd char *pathstr; 4683168404Spjd uint64_t dst_time; 4684168404Spjd time_t tsec; 4685168404Spjd struct tm t; 4686168404Spjd char tbuf[30]; 4687168404Spjd int ret, i; 4688185029Spjd uint64_t who; 4689185029Spjd struct passwd *pwd; 4690185029Spjd char *hostname; 4691185029Spjd char *zonename; 4692185029Spjd char internalstr[MAXPATHLEN]; 4693185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 4694185029Spjd uint64_t txg; 4695185029Spjd uint64_t ievent; 4696168404Spjd 4697185029Spjd cb->first = B_FALSE; 4698168404Spjd 4699168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 4700168404Spjd 4701168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 4702168404Spjd return (ret); 4703168404Spjd 4704168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 4705168404Spjd &records, &numrecords) == 0); 4706168404Spjd for (i = 0; i < numrecords; i++) { 4707168404Spjd if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 4708185029Spjd &dst_time) != 0) 4709185029Spjd continue; 4710185029Spjd 4711185029Spjd /* is it an internal event or a standard event? */ 4712185029Spjd if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 4713185029Spjd &cmdstr) != 0) { 4714185029Spjd if (cb->internal == 0) 4715185029Spjd continue; 4716185029Spjd 4717185029Spjd if (nvlist_lookup_uint64(records[i], 4718185029Spjd ZPOOL_HIST_INT_EVENT, &ievent) != 0) 4719185029Spjd continue; 4720185029Spjd verify(nvlist_lookup_uint64(records[i], 4721185029Spjd ZPOOL_HIST_TXG, &txg) == 0); 4722185029Spjd verify(nvlist_lookup_string(records[i], 4723185029Spjd ZPOOL_HIST_INT_STR, &pathstr) == 0); 4724185029Spjd if (ievent >= LOG_END) 4725185029Spjd continue; 4726185029Spjd (void) snprintf(internalstr, 4727185029Spjd sizeof (internalstr), 4728185029Spjd "[internal %s txg:%lld] %s", 4729219089Spjd zfs_history_event_names[ievent], txg, 4730185029Spjd pathstr); 4731185029Spjd cmdstr = internalstr; 4732168404Spjd } 4733185029Spjd tsec = dst_time; 4734185029Spjd (void) localtime_r(&tsec, &t); 4735185029Spjd (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 4736185029Spjd (void) printf("%s %s", tbuf, cmdstr); 4737185029Spjd 4738185029Spjd if (!cb->longfmt) { 4739185029Spjd (void) printf("\n"); 4740185029Spjd continue; 4741185029Spjd } 4742185029Spjd (void) printf(" ["); 4743185029Spjd if (nvlist_lookup_uint64(records[i], 4744185029Spjd ZPOOL_HIST_WHO, &who) == 0) { 4745185029Spjd pwd = getpwuid((uid_t)who); 4746185029Spjd if (pwd) 4747185029Spjd (void) printf("user %s on", 4748185029Spjd pwd->pw_name); 4749185029Spjd else 4750185029Spjd (void) printf("user %d on", 4751185029Spjd (int)who); 4752185029Spjd } else { 4753185029Spjd (void) printf(gettext("no info]\n")); 4754185029Spjd continue; 4755185029Spjd } 4756185029Spjd if (nvlist_lookup_string(records[i], 4757185029Spjd ZPOOL_HIST_HOST, &hostname) == 0) { 4758185029Spjd (void) printf(" %s", hostname); 4759185029Spjd } 4760185029Spjd if (nvlist_lookup_string(records[i], 4761185029Spjd ZPOOL_HIST_ZONE, &zonename) == 0) { 4762185029Spjd (void) printf(":%s", zonename); 4763185029Spjd } 4764185029Spjd 4765185029Spjd (void) printf("]"); 4766185029Spjd (void) printf("\n"); 4767168404Spjd } 4768168404Spjd (void) printf("\n"); 4769168404Spjd nvlist_free(nvhis); 4770168404Spjd 4771168404Spjd return (ret); 4772168404Spjd} 4773168404Spjd 4774168404Spjd/* 4775168404Spjd * zpool history <pool> 4776168404Spjd * 4777168404Spjd * Displays the history of commands that modified pools. 4778168404Spjd */ 4779185029Spjd 4780185029Spjd 4781168404Spjdint 4782168404Spjdzpool_do_history(int argc, char **argv) 4783168404Spjd{ 4784185029Spjd hist_cbdata_t cbdata = { 0 }; 4785168404Spjd int ret; 4786185029Spjd int c; 4787168404Spjd 4788185029Spjd cbdata.first = B_TRUE; 4789185029Spjd /* check options */ 4790185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 4791185029Spjd switch (c) { 4792185029Spjd case 'l': 4793185029Spjd cbdata.longfmt = 1; 4794185029Spjd break; 4795185029Spjd case 'i': 4796185029Spjd cbdata.internal = 1; 4797185029Spjd break; 4798185029Spjd case '?': 4799185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4800185029Spjd optopt); 4801185029Spjd usage(B_FALSE); 4802185029Spjd } 4803185029Spjd } 4804168404Spjd argc -= optind; 4805168404Spjd argv += optind; 4806168404Spjd 4807168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 4808185029Spjd &cbdata); 4809168404Spjd 4810185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 4811168404Spjd (void) printf(gettext("no pools available\n")); 4812168404Spjd return (0); 4813168404Spjd } 4814168404Spjd 4815168404Spjd return (ret); 4816168404Spjd} 4817168404Spjd 4818168404Spjdstatic int 4819168404Spjdget_callback(zpool_handle_t *zhp, void *data) 4820168404Spjd{ 4821185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 4822168404Spjd char value[MAXNAMELEN]; 4823185029Spjd zprop_source_t srctype; 4824185029Spjd zprop_list_t *pl; 4825168404Spjd 4826168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 4827168404Spjd 4828168404Spjd /* 4829185029Spjd * Skip the special fake placeholder. This will also skip 4830185029Spjd * over the name property when 'all' is specified. 4831168404Spjd */ 4832185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 4833168404Spjd pl == cbp->cb_proplist) 4834168404Spjd continue; 4835168404Spjd 4836236884Smm if (pl->pl_prop == ZPROP_INVAL && 4837236884Smm (zpool_prop_feature(pl->pl_user_prop) || 4838236884Smm zpool_prop_unsupported(pl->pl_user_prop))) { 4839236884Smm srctype = ZPROP_SRC_LOCAL; 4840168404Spjd 4841236884Smm if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 4842236884Smm value, sizeof (value)) == 0) { 4843236884Smm zprop_print_one_property(zpool_get_name(zhp), 4844236884Smm cbp, pl->pl_user_prop, value, srctype, 4845236884Smm NULL, NULL); 4846236884Smm } 4847236884Smm } else { 4848236884Smm if (zpool_get_prop(zhp, pl->pl_prop, value, 4849236884Smm sizeof (value), &srctype) != 0) 4850236884Smm continue; 4851236884Smm 4852236884Smm zprop_print_one_property(zpool_get_name(zhp), cbp, 4853236884Smm zpool_prop_to_name(pl->pl_prop), value, srctype, 4854236884Smm NULL, NULL); 4855236884Smm } 4856168404Spjd } 4857168404Spjd return (0); 4858168404Spjd} 4859168404Spjd 4860168404Spjdint 4861168404Spjdzpool_do_get(int argc, char **argv) 4862168404Spjd{ 4863185029Spjd zprop_get_cbdata_t cb = { 0 }; 4864185029Spjd zprop_list_t fake_name = { 0 }; 4865168404Spjd int ret; 4866168404Spjd 4867236884Smm if (argc < 2) { 4868236884Smm (void) fprintf(stderr, gettext("missing property " 4869236884Smm "argument\n")); 4870168404Spjd usage(B_FALSE); 4871236884Smm } 4872168404Spjd 4873168404Spjd cb.cb_first = B_TRUE; 4874185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 4875168404Spjd cb.cb_columns[0] = GET_COL_NAME; 4876168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 4877168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 4878168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 4879185029Spjd cb.cb_type = ZFS_TYPE_POOL; 4880168404Spjd 4881236884Smm if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 4882185029Spjd ZFS_TYPE_POOL) != 0) 4883168404Spjd usage(B_FALSE); 4884168404Spjd 4885168404Spjd if (cb.cb_proplist != NULL) { 4886185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 4887168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 4888168404Spjd fake_name.pl_next = cb.cb_proplist; 4889168404Spjd cb.cb_proplist = &fake_name; 4890168404Spjd } 4891168404Spjd 4892168404Spjd ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 4893168404Spjd get_callback, &cb); 4894168404Spjd 4895168404Spjd if (cb.cb_proplist == &fake_name) 4896185029Spjd zprop_free_list(fake_name.pl_next); 4897168404Spjd else 4898185029Spjd zprop_free_list(cb.cb_proplist); 4899168404Spjd 4900168404Spjd return (ret); 4901168404Spjd} 4902168404Spjd 4903168404Spjdtypedef struct set_cbdata { 4904168404Spjd char *cb_propname; 4905168404Spjd char *cb_value; 4906168404Spjd boolean_t cb_any_successful; 4907168404Spjd} set_cbdata_t; 4908168404Spjd 4909168404Spjdint 4910168404Spjdset_callback(zpool_handle_t *zhp, void *data) 4911168404Spjd{ 4912168404Spjd int error; 4913168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 4914168404Spjd 4915168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 4916168404Spjd 4917168404Spjd if (!error) 4918168404Spjd cb->cb_any_successful = B_TRUE; 4919168404Spjd 4920168404Spjd return (error); 4921168404Spjd} 4922168404Spjd 4923168404Spjdint 4924168404Spjdzpool_do_set(int argc, char **argv) 4925168404Spjd{ 4926168404Spjd set_cbdata_t cb = { 0 }; 4927168404Spjd int error; 4928168404Spjd 4929168404Spjd if (argc > 1 && argv[1][0] == '-') { 4930168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4931168404Spjd argv[1][1]); 4932168404Spjd usage(B_FALSE); 4933168404Spjd } 4934168404Spjd 4935168404Spjd if (argc < 2) { 4936168404Spjd (void) fprintf(stderr, gettext("missing property=value " 4937168404Spjd "argument\n")); 4938168404Spjd usage(B_FALSE); 4939168404Spjd } 4940168404Spjd 4941168404Spjd if (argc < 3) { 4942168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 4943168404Spjd usage(B_FALSE); 4944168404Spjd } 4945168404Spjd 4946168404Spjd if (argc > 3) { 4947168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 4948168404Spjd usage(B_FALSE); 4949168404Spjd } 4950168404Spjd 4951168404Spjd cb.cb_propname = argv[1]; 4952168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 4953168404Spjd if (cb.cb_value == NULL) { 4954168404Spjd (void) fprintf(stderr, gettext("missing value in " 4955168404Spjd "property=value argument\n")); 4956168404Spjd usage(B_FALSE); 4957168404Spjd } 4958168404Spjd 4959168404Spjd *(cb.cb_value) = '\0'; 4960168404Spjd cb.cb_value++; 4961168404Spjd 4962168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 4963168404Spjd set_callback, &cb); 4964168404Spjd 4965168404Spjd return (error); 4966168404Spjd} 4967168404Spjd 4968168404Spjdstatic int 4969168404Spjdfind_command_idx(char *command, int *idx) 4970168404Spjd{ 4971168404Spjd int i; 4972168404Spjd 4973168404Spjd for (i = 0; i < NCOMMAND; i++) { 4974168404Spjd if (command_table[i].name == NULL) 4975168404Spjd continue; 4976168404Spjd 4977168404Spjd if (strcmp(command, command_table[i].name) == 0) { 4978168404Spjd *idx = i; 4979168404Spjd return (0); 4980168404Spjd } 4981168404Spjd } 4982168404Spjd return (1); 4983168404Spjd} 4984168404Spjd 4985168404Spjdint 4986168404Spjdmain(int argc, char **argv) 4987168404Spjd{ 4988168404Spjd int ret; 4989168404Spjd int i; 4990168404Spjd char *cmdname; 4991168404Spjd 4992168404Spjd (void) setlocale(LC_ALL, ""); 4993168404Spjd (void) textdomain(TEXT_DOMAIN); 4994168404Spjd 4995168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 4996168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 4997168404Spjd "initialize ZFS library\n")); 4998168404Spjd return (1); 4999168404Spjd } 5000168404Spjd 5001168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 5002168404Spjd 5003168404Spjd opterr = 0; 5004168404Spjd 5005168404Spjd /* 5006168404Spjd * Make sure the user has specified some command. 5007168404Spjd */ 5008168404Spjd if (argc < 2) { 5009168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 5010168404Spjd usage(B_FALSE); 5011168404Spjd } 5012168404Spjd 5013168404Spjd cmdname = argv[1]; 5014168404Spjd 5015168404Spjd /* 5016168404Spjd * Special case '-?' 5017168404Spjd */ 5018168404Spjd if (strcmp(cmdname, "-?") == 0) 5019168404Spjd usage(B_TRUE); 5020168404Spjd 5021185029Spjd zpool_set_history_str("zpool", argc, argv, history_str); 5022185029Spjd verify(zpool_stage_history(g_zfs, history_str) == 0); 5023185029Spjd 5024168404Spjd /* 5025168404Spjd * Run the appropriate command. 5026168404Spjd */ 5027168404Spjd if (find_command_idx(cmdname, &i) == 0) { 5028168404Spjd current_command = &command_table[i]; 5029168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 5030185029Spjd } else if (strchr(cmdname, '=')) { 5031185029Spjd verify(find_command_idx("set", &i) == 0); 5032185029Spjd current_command = &command_table[i]; 5033185029Spjd ret = command_table[i].func(argc, argv); 5034185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 5035185029Spjd /* 5036185029Spjd * 'freeze' is a vile debugging abomination, so we treat 5037185029Spjd * it as such. 5038185029Spjd */ 5039168404Spjd char buf[16384]; 5040168404Spjd int fd = open(ZFS_DEV, O_RDWR); 5041168404Spjd (void) strcpy((void *)buf, argv[2]); 5042168404Spjd return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 5043185029Spjd } else { 5044168404Spjd (void) fprintf(stderr, gettext("unrecognized " 5045168404Spjd "command '%s'\n"), cmdname); 5046168404Spjd usage(B_FALSE); 5047168404Spjd } 5048168404Spjd 5049168404Spjd libzfs_fini(g_zfs); 5050168404Spjd 5051168404Spjd /* 5052168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 5053168404Spjd * for the purposes of running ::findleaks. 5054168404Spjd */ 5055168404Spjd if (getenv("ZFS_ABORT") != NULL) { 5056168404Spjd (void) printf("dumping core by request\n"); 5057168404Spjd abort(); 5058168404Spjd } 5059168404Spjd 5060168404Spjd return (ret); 5061168404Spjd} 5062