1*fa9e4066Sahrens /* 2*fa9e4066Sahrens * CDDL HEADER START 3*fa9e4066Sahrens * 4*fa9e4066Sahrens * The contents of this file are subject to the terms of the 5*fa9e4066Sahrens * Common Development and Distribution License, Version 1.0 only 6*fa9e4066Sahrens * (the "License"). You may not use this file except in compliance 7*fa9e4066Sahrens * with the License. 8*fa9e4066Sahrens * 9*fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 11*fa9e4066Sahrens * See the License for the specific language governing permissions 12*fa9e4066Sahrens * and limitations under the License. 13*fa9e4066Sahrens * 14*fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15*fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 17*fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18*fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19*fa9e4066Sahrens * 20*fa9e4066Sahrens * CDDL HEADER END 21*fa9e4066Sahrens */ 22*fa9e4066Sahrens /* 23*fa9e4066Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*fa9e4066Sahrens * Use is subject to license terms. 25*fa9e4066Sahrens */ 26*fa9e4066Sahrens 27*fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28*fa9e4066Sahrens 29*fa9e4066Sahrens #include <assert.h> 30*fa9e4066Sahrens #include <ctype.h> 31*fa9e4066Sahrens #include <dirent.h> 32*fa9e4066Sahrens #include <errno.h> 33*fa9e4066Sahrens #include <fcntl.h> 34*fa9e4066Sahrens #include <libgen.h> 35*fa9e4066Sahrens #include <libintl.h> 36*fa9e4066Sahrens #include <libuutil.h> 37*fa9e4066Sahrens #include <locale.h> 38*fa9e4066Sahrens #include <stdio.h> 39*fa9e4066Sahrens #include <stdlib.h> 40*fa9e4066Sahrens #include <string.h> 41*fa9e4066Sahrens #include <strings.h> 42*fa9e4066Sahrens #include <unistd.h> 43*fa9e4066Sahrens #include <priv.h> 44*fa9e4066Sahrens 45*fa9e4066Sahrens #include <sys/stat.h> 46*fa9e4066Sahrens 47*fa9e4066Sahrens #include <libzfs.h> 48*fa9e4066Sahrens 49*fa9e4066Sahrens #include "zpool_util.h" 50*fa9e4066Sahrens 51*fa9e4066Sahrens static int zpool_do_create(int, char **); 52*fa9e4066Sahrens static int zpool_do_destroy(int, char **); 53*fa9e4066Sahrens 54*fa9e4066Sahrens static int zpool_do_add(int, char **); 55*fa9e4066Sahrens 56*fa9e4066Sahrens static int zpool_do_list(int, char **); 57*fa9e4066Sahrens static int zpool_do_iostat(int, char **); 58*fa9e4066Sahrens static int zpool_do_status(int, char **); 59*fa9e4066Sahrens 60*fa9e4066Sahrens static int zpool_do_online(int, char **); 61*fa9e4066Sahrens static int zpool_do_offline(int, char **); 62*fa9e4066Sahrens 63*fa9e4066Sahrens static int zpool_do_attach(int, char **); 64*fa9e4066Sahrens static int zpool_do_detach(int, char **); 65*fa9e4066Sahrens static int zpool_do_replace(int, char **); 66*fa9e4066Sahrens 67*fa9e4066Sahrens static int zpool_do_scrub(int, char **); 68*fa9e4066Sahrens 69*fa9e4066Sahrens static int zpool_do_import(int, char **); 70*fa9e4066Sahrens static int zpool_do_export(int, char **); 71*fa9e4066Sahrens 72*fa9e4066Sahrens /* 73*fa9e4066Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 74*fa9e4066Sahrens * debugging facilities. 75*fa9e4066Sahrens */ 76*fa9e4066Sahrens const char * 77*fa9e4066Sahrens _umem_debug_init() 78*fa9e4066Sahrens { 79*fa9e4066Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 80*fa9e4066Sahrens } 81*fa9e4066Sahrens 82*fa9e4066Sahrens const char * 83*fa9e4066Sahrens _umem_logging_init(void) 84*fa9e4066Sahrens { 85*fa9e4066Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 86*fa9e4066Sahrens } 87*fa9e4066Sahrens 88*fa9e4066Sahrens typedef struct zpool_command { 89*fa9e4066Sahrens const char *name; 90*fa9e4066Sahrens int (*func)(int, char **); 91*fa9e4066Sahrens const char *usage; 92*fa9e4066Sahrens } zpool_command_t; 93*fa9e4066Sahrens 94*fa9e4066Sahrens /* 95*fa9e4066Sahrens * Master command table. Each ZFS command has a name, associated function, and 96*fa9e4066Sahrens * usage message. These commands are organized according to how they are 97*fa9e4066Sahrens * displayed in the usage message. An empty command (one with a NULL name) 98*fa9e4066Sahrens * indicates an empty line in the generic usage message. 99*fa9e4066Sahrens */ 100*fa9e4066Sahrens static zpool_command_t command_table[] = { 101*fa9e4066Sahrens { "create", zpool_do_create, 102*fa9e4066Sahrens "\tcreate [-fn] [-R root] [-m mountpoint] <pool> <vdev> ...\n" }, 103*fa9e4066Sahrens { "destroy", zpool_do_destroy, 104*fa9e4066Sahrens "\tdestroy [-f] <pool>\n" }, 105*fa9e4066Sahrens 106*fa9e4066Sahrens 107*fa9e4066Sahrens { NULL }, 108*fa9e4066Sahrens 109*fa9e4066Sahrens { "add", zpool_do_add, 110*fa9e4066Sahrens "\tadd [-fn] <pool> <vdev> ...\n" }, 111*fa9e4066Sahrens 112*fa9e4066Sahrens { NULL }, 113*fa9e4066Sahrens 114*fa9e4066Sahrens { "list", zpool_do_list, 115*fa9e4066Sahrens "\tlist [-H] [-o field[,field]*] [pool] ...\n" }, 116*fa9e4066Sahrens { "iostat", zpool_do_iostat, 117*fa9e4066Sahrens "\tiostat [-v] [pool] ... [interval [count]]\n" }, 118*fa9e4066Sahrens { "status", zpool_do_status, 119*fa9e4066Sahrens "\tstatus [-vx] [pool] ...\n" }, 120*fa9e4066Sahrens 121*fa9e4066Sahrens { NULL }, 122*fa9e4066Sahrens 123*fa9e4066Sahrens { "online", zpool_do_online, 124*fa9e4066Sahrens "\tonline <pool> <device>\n" }, 125*fa9e4066Sahrens { "offline", zpool_do_offline, 126*fa9e4066Sahrens "\toffline <pool> <device>\n" }, 127*fa9e4066Sahrens 128*fa9e4066Sahrens { NULL }, 129*fa9e4066Sahrens 130*fa9e4066Sahrens { "attach", zpool_do_attach, 131*fa9e4066Sahrens "\tattach [-f] <pool> <device> <new_device>\n" }, 132*fa9e4066Sahrens { "detach", zpool_do_detach, 133*fa9e4066Sahrens "\tdetach <pool> <device>\n" }, 134*fa9e4066Sahrens { "replace", zpool_do_replace, 135*fa9e4066Sahrens "\treplace [-f] <pool> <device> [new_device]\n" }, 136*fa9e4066Sahrens 137*fa9e4066Sahrens { NULL }, 138*fa9e4066Sahrens 139*fa9e4066Sahrens { "scrub", zpool_do_scrub, 140*fa9e4066Sahrens "\tscrub [-s] <pool> ...\n" }, 141*fa9e4066Sahrens 142*fa9e4066Sahrens { NULL }, 143*fa9e4066Sahrens 144*fa9e4066Sahrens { "import", zpool_do_import, 145*fa9e4066Sahrens "\timport [-d dir]\n" 146*fa9e4066Sahrens "\timport [-d dir] [-f] [-o opts] [-R root] -a\n" 147*fa9e4066Sahrens "\timport [-d dir] [-f] [-o opts] [-R root ]<pool | id> " 148*fa9e4066Sahrens "[newpool]\n" }, 149*fa9e4066Sahrens { "export", zpool_do_export, 150*fa9e4066Sahrens "\texport [-f] <pool> ...\n" }, 151*fa9e4066Sahrens 152*fa9e4066Sahrens { NULL } 153*fa9e4066Sahrens }; 154*fa9e4066Sahrens 155*fa9e4066Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 156*fa9e4066Sahrens 157*fa9e4066Sahrens zpool_command_t *current_command; 158*fa9e4066Sahrens 159*fa9e4066Sahrens /* 160*fa9e4066Sahrens * Fields available for 'zpool list'. 161*fa9e4066Sahrens */ 162*fa9e4066Sahrens typedef enum { 163*fa9e4066Sahrens ZPOOL_FIELD_NAME, 164*fa9e4066Sahrens ZPOOL_FIELD_SIZE, 165*fa9e4066Sahrens ZPOOL_FIELD_USED, 166*fa9e4066Sahrens ZPOOL_FIELD_AVAILABLE, 167*fa9e4066Sahrens ZPOOL_FIELD_CAPACITY, 168*fa9e4066Sahrens ZPOOL_FIELD_HEALTH, 169*fa9e4066Sahrens ZPOOL_FIELD_ROOT 170*fa9e4066Sahrens } zpool_field_t; 171*fa9e4066Sahrens 172*fa9e4066Sahrens #define MAX_FIELDS 10 173*fa9e4066Sahrens 174*fa9e4066Sahrens typedef struct column_def { 175*fa9e4066Sahrens const char *cd_title; 176*fa9e4066Sahrens size_t cd_width; 177*fa9e4066Sahrens enum { 178*fa9e4066Sahrens left_justify, 179*fa9e4066Sahrens right_justify 180*fa9e4066Sahrens } cd_justify; 181*fa9e4066Sahrens } column_def_t; 182*fa9e4066Sahrens 183*fa9e4066Sahrens static column_def_t column_table[] = { 184*fa9e4066Sahrens { "NAME", 20, left_justify }, 185*fa9e4066Sahrens { "SIZE", 6, right_justify }, 186*fa9e4066Sahrens { "USED", 6, right_justify }, 187*fa9e4066Sahrens { "AVAIL", 6, right_justify }, 188*fa9e4066Sahrens { "CAP", 5, right_justify }, 189*fa9e4066Sahrens { "HEALTH", 9, left_justify }, 190*fa9e4066Sahrens { "ALTROOT", 15, left_justify } 191*fa9e4066Sahrens }; 192*fa9e4066Sahrens 193*fa9e4066Sahrens static char *column_subopts[] = { 194*fa9e4066Sahrens "name", 195*fa9e4066Sahrens "size", 196*fa9e4066Sahrens "used", 197*fa9e4066Sahrens "available", 198*fa9e4066Sahrens "capacity", 199*fa9e4066Sahrens "health", 200*fa9e4066Sahrens "root", 201*fa9e4066Sahrens NULL 202*fa9e4066Sahrens }; 203*fa9e4066Sahrens 204*fa9e4066Sahrens /* 205*fa9e4066Sahrens * Display usage message. If we're inside a command, display only the usage for 206*fa9e4066Sahrens * that command. Otherwise, iterate over the entire command table and display 207*fa9e4066Sahrens * a complete usage message. 208*fa9e4066Sahrens */ 209*fa9e4066Sahrens void 210*fa9e4066Sahrens usage(int requested) 211*fa9e4066Sahrens { 212*fa9e4066Sahrens int i; 213*fa9e4066Sahrens FILE *fp = requested ? stdout : stderr; 214*fa9e4066Sahrens 215*fa9e4066Sahrens if (current_command == NULL) { 216*fa9e4066Sahrens int i; 217*fa9e4066Sahrens 218*fa9e4066Sahrens (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 219*fa9e4066Sahrens (void) fprintf(fp, 220*fa9e4066Sahrens gettext("where 'command' is one of the following:\n\n")); 221*fa9e4066Sahrens 222*fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 223*fa9e4066Sahrens if (command_table[i].name == NULL) 224*fa9e4066Sahrens (void) fprintf(fp, "\n"); 225*fa9e4066Sahrens else 226*fa9e4066Sahrens (void) fprintf(fp, "%s", 227*fa9e4066Sahrens command_table[i].usage); 228*fa9e4066Sahrens } 229*fa9e4066Sahrens } else { 230*fa9e4066Sahrens (void) fprintf(fp, gettext("usage:\n")); 231*fa9e4066Sahrens (void) fprintf(fp, current_command->usage); 232*fa9e4066Sahrens 233*fa9e4066Sahrens if (strcmp(current_command->name, "list") == 0) { 234*fa9e4066Sahrens (void) fprintf(fp, gettext("\nwhere 'field' is one " 235*fa9e4066Sahrens "of the following:\n\n")); 236*fa9e4066Sahrens 237*fa9e4066Sahrens for (i = 0; column_subopts[i] != NULL; i++) 238*fa9e4066Sahrens (void) fprintf(fp, "\t%s\n", column_subopts[i]); 239*fa9e4066Sahrens } 240*fa9e4066Sahrens } 241*fa9e4066Sahrens 242*fa9e4066Sahrens exit(requested ? 0 : 2); 243*fa9e4066Sahrens } 244*fa9e4066Sahrens 245*fa9e4066Sahrens const char * 246*fa9e4066Sahrens state_to_name(int state) 247*fa9e4066Sahrens { 248*fa9e4066Sahrens switch (state) { 249*fa9e4066Sahrens case VDEV_STATE_CLOSED: 250*fa9e4066Sahrens case VDEV_STATE_CANT_OPEN: 251*fa9e4066Sahrens return (gettext("FAULTED")); 252*fa9e4066Sahrens case VDEV_STATE_OFFLINE: 253*fa9e4066Sahrens return (gettext("OFFLINE")); 254*fa9e4066Sahrens case VDEV_STATE_DEGRADED: 255*fa9e4066Sahrens return (gettext("DEGRADED")); 256*fa9e4066Sahrens case VDEV_STATE_HEALTHY: 257*fa9e4066Sahrens return (gettext("ONLINE")); 258*fa9e4066Sahrens } 259*fa9e4066Sahrens 260*fa9e4066Sahrens return (gettext("UNKNOWN")); 261*fa9e4066Sahrens } 262*fa9e4066Sahrens 263*fa9e4066Sahrens void 264*fa9e4066Sahrens print_vdev_tree(const char *name, nvlist_t *nv, int indent) 265*fa9e4066Sahrens { 266*fa9e4066Sahrens nvlist_t **child; 267*fa9e4066Sahrens uint_t c, children; 268*fa9e4066Sahrens 269*fa9e4066Sahrens if (name != NULL) 270*fa9e4066Sahrens (void) printf("\t%*s%s\n", indent, "", name); 271*fa9e4066Sahrens 272*fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 273*fa9e4066Sahrens &child, &children) != 0) 274*fa9e4066Sahrens return; 275*fa9e4066Sahrens 276*fa9e4066Sahrens for (c = 0; c < children; c++) 277*fa9e4066Sahrens print_vdev_tree(vdev_get_name(child[c]), child[c], indent + 2); 278*fa9e4066Sahrens } 279*fa9e4066Sahrens 280*fa9e4066Sahrens /* 281*fa9e4066Sahrens * zpool add [-fn] <pool> <vdev> ... 282*fa9e4066Sahrens * 283*fa9e4066Sahrens * -f Force addition of devices, even if they appear in use 284*fa9e4066Sahrens * -n Do not add the devices, but display the resulting layout if 285*fa9e4066Sahrens * they were to be added. 286*fa9e4066Sahrens * 287*fa9e4066Sahrens * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 288*fa9e4066Sahrens * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 289*fa9e4066Sahrens * libzfs. 290*fa9e4066Sahrens */ 291*fa9e4066Sahrens int 292*fa9e4066Sahrens zpool_do_add(int argc, char **argv) 293*fa9e4066Sahrens { 294*fa9e4066Sahrens int force = FALSE; 295*fa9e4066Sahrens int dryrun = FALSE; 296*fa9e4066Sahrens int c; 297*fa9e4066Sahrens nvlist_t *nvroot; 298*fa9e4066Sahrens char *poolname; 299*fa9e4066Sahrens int ret; 300*fa9e4066Sahrens zpool_handle_t *zhp; 301*fa9e4066Sahrens nvlist_t *config; 302*fa9e4066Sahrens 303*fa9e4066Sahrens /* check options */ 304*fa9e4066Sahrens while ((c = getopt(argc, argv, "fn")) != -1) { 305*fa9e4066Sahrens switch (c) { 306*fa9e4066Sahrens case 'f': 307*fa9e4066Sahrens force = TRUE; 308*fa9e4066Sahrens break; 309*fa9e4066Sahrens case 'n': 310*fa9e4066Sahrens dryrun = TRUE; 311*fa9e4066Sahrens break; 312*fa9e4066Sahrens case '?': 313*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 314*fa9e4066Sahrens optopt); 315*fa9e4066Sahrens usage(FALSE); 316*fa9e4066Sahrens } 317*fa9e4066Sahrens } 318*fa9e4066Sahrens 319*fa9e4066Sahrens argc -= optind; 320*fa9e4066Sahrens argv += optind; 321*fa9e4066Sahrens 322*fa9e4066Sahrens /* get pool name and check number of arguments */ 323*fa9e4066Sahrens if (argc < 1) { 324*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 325*fa9e4066Sahrens usage(FALSE); 326*fa9e4066Sahrens } 327*fa9e4066Sahrens if (argc < 2) { 328*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 329*fa9e4066Sahrens usage(FALSE); 330*fa9e4066Sahrens } 331*fa9e4066Sahrens 332*fa9e4066Sahrens poolname = argv[0]; 333*fa9e4066Sahrens 334*fa9e4066Sahrens argc--; 335*fa9e4066Sahrens argv++; 336*fa9e4066Sahrens 337*fa9e4066Sahrens if ((zhp = zpool_open(poolname)) == NULL) 338*fa9e4066Sahrens return (1); 339*fa9e4066Sahrens 340*fa9e4066Sahrens if ((config = zpool_get_config(zhp)) == NULL) { 341*fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 342*fa9e4066Sahrens poolname); 343*fa9e4066Sahrens zpool_close(zhp); 344*fa9e4066Sahrens return (1); 345*fa9e4066Sahrens } 346*fa9e4066Sahrens 347*fa9e4066Sahrens /* pass off to get_vdev_spec for processing */ 348*fa9e4066Sahrens nvroot = make_root_vdev(config, force, !force, argc, argv); 349*fa9e4066Sahrens if (nvroot == NULL) { 350*fa9e4066Sahrens zpool_close(zhp); 351*fa9e4066Sahrens return (1); 352*fa9e4066Sahrens } 353*fa9e4066Sahrens 354*fa9e4066Sahrens if (dryrun) { 355*fa9e4066Sahrens nvlist_t *poolnvroot; 356*fa9e4066Sahrens 357*fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 358*fa9e4066Sahrens &poolnvroot) == 0); 359*fa9e4066Sahrens 360*fa9e4066Sahrens (void) printf(gettext("would update '%s' to the following " 361*fa9e4066Sahrens "configuration:\n"), zpool_get_name(zhp)); 362*fa9e4066Sahrens 363*fa9e4066Sahrens print_vdev_tree(poolname, poolnvroot, 0); 364*fa9e4066Sahrens print_vdev_tree(NULL, nvroot, 0); 365*fa9e4066Sahrens 366*fa9e4066Sahrens ret = 0; 367*fa9e4066Sahrens } else { 368*fa9e4066Sahrens ret = (zpool_add(zhp, nvroot) != 0); 369*fa9e4066Sahrens } 370*fa9e4066Sahrens 371*fa9e4066Sahrens return (ret); 372*fa9e4066Sahrens } 373*fa9e4066Sahrens 374*fa9e4066Sahrens /* 375*fa9e4066Sahrens * zpool create [-fn] [-R root] [-m mountpoint] <pool> <dev> ... 376*fa9e4066Sahrens * 377*fa9e4066Sahrens * -f Force creation, even if devices appear in use 378*fa9e4066Sahrens * -n Do not create the pool, but display the resulting layout if it 379*fa9e4066Sahrens * were to be created. 380*fa9e4066Sahrens * -R Create a pool under an alternate root 381*fa9e4066Sahrens * -m Set default mountpoint for the root dataset. By default it's 382*fa9e4066Sahrens * '/<pool>' 383*fa9e4066Sahrens * 384*fa9e4066Sahrens * Creates the the named pool according to the given vdev specification. The 385*fa9e4066Sahrens * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 386*fa9e4066Sahrens * we get the nvlist back from get_vdev_spec(), we either print out the contents 387*fa9e4066Sahrens * (if '-n' was specified), or pass it to libzfs to do the creation. 388*fa9e4066Sahrens */ 389*fa9e4066Sahrens int 390*fa9e4066Sahrens zpool_do_create(int argc, char **argv) 391*fa9e4066Sahrens { 392*fa9e4066Sahrens int force = FALSE; 393*fa9e4066Sahrens int dryrun = FALSE; 394*fa9e4066Sahrens int c; 395*fa9e4066Sahrens nvlist_t *nvroot; 396*fa9e4066Sahrens char *poolname; 397*fa9e4066Sahrens int ret; 398*fa9e4066Sahrens char *altroot = NULL; 399*fa9e4066Sahrens char *mountpoint = NULL; 400*fa9e4066Sahrens 401*fa9e4066Sahrens /* check options */ 402*fa9e4066Sahrens while ((c = getopt(argc, argv, ":fnR:m:")) != -1) { 403*fa9e4066Sahrens switch (c) { 404*fa9e4066Sahrens case 'f': 405*fa9e4066Sahrens force = TRUE; 406*fa9e4066Sahrens break; 407*fa9e4066Sahrens case 'n': 408*fa9e4066Sahrens dryrun = TRUE; 409*fa9e4066Sahrens break; 410*fa9e4066Sahrens case 'R': 411*fa9e4066Sahrens altroot = optarg; 412*fa9e4066Sahrens break; 413*fa9e4066Sahrens case 'm': 414*fa9e4066Sahrens mountpoint = optarg; 415*fa9e4066Sahrens break; 416*fa9e4066Sahrens case ':': 417*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 418*fa9e4066Sahrens "'%c' option\n"), optopt); 419*fa9e4066Sahrens usage(FALSE); 420*fa9e4066Sahrens break; 421*fa9e4066Sahrens case '?': 422*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 423*fa9e4066Sahrens optopt); 424*fa9e4066Sahrens usage(FALSE); 425*fa9e4066Sahrens } 426*fa9e4066Sahrens } 427*fa9e4066Sahrens 428*fa9e4066Sahrens argc -= optind; 429*fa9e4066Sahrens argv += optind; 430*fa9e4066Sahrens 431*fa9e4066Sahrens /* get pool name and check number of arguments */ 432*fa9e4066Sahrens if (argc < 1) { 433*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 434*fa9e4066Sahrens usage(FALSE); 435*fa9e4066Sahrens } 436*fa9e4066Sahrens if (argc < 2) { 437*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing vdev specification\n")); 438*fa9e4066Sahrens usage(FALSE); 439*fa9e4066Sahrens } 440*fa9e4066Sahrens 441*fa9e4066Sahrens poolname = argv[0]; 442*fa9e4066Sahrens 443*fa9e4066Sahrens /* 444*fa9e4066Sahrens * As a special case, check for use of '/' in the name, and direct the 445*fa9e4066Sahrens * user to use 'zfs create' instead. 446*fa9e4066Sahrens */ 447*fa9e4066Sahrens if (strchr(poolname, '/') != NULL) { 448*fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot create '%s': invalid " 449*fa9e4066Sahrens "character '/' in pool name\n"), poolname); 450*fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs create' to " 451*fa9e4066Sahrens "create a dataset\n")); 452*fa9e4066Sahrens return (1); 453*fa9e4066Sahrens } 454*fa9e4066Sahrens 455*fa9e4066Sahrens /* pass off to get_vdev_spec for bulk processing */ 456*fa9e4066Sahrens nvroot = make_root_vdev(NULL, force, !force, argc - 1, argv + 1); 457*fa9e4066Sahrens if (nvroot == NULL) 458*fa9e4066Sahrens return (1); 459*fa9e4066Sahrens 460*fa9e4066Sahrens if (altroot != NULL && altroot[0] != '/') { 461*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid alternate root '%s': " 462*fa9e4066Sahrens "must be an absolute path\n")); 463*fa9e4066Sahrens return (1); 464*fa9e4066Sahrens } 465*fa9e4066Sahrens 466*fa9e4066Sahrens /* 467*fa9e4066Sahrens * Check the validity of the mountpoint and direct the user to use the 468*fa9e4066Sahrens * '-m' mountpoint option if it looks like its in use. 469*fa9e4066Sahrens */ 470*fa9e4066Sahrens if (mountpoint == NULL || 471*fa9e4066Sahrens (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 472*fa9e4066Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 473*fa9e4066Sahrens char buf[MAXPATHLEN]; 474*fa9e4066Sahrens struct stat64 statbuf; 475*fa9e4066Sahrens 476*fa9e4066Sahrens if (mountpoint && mountpoint[0] != '/') { 477*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid mountpoint " 478*fa9e4066Sahrens "'%s': must be an absolute path, 'legacy', or " 479*fa9e4066Sahrens "'none'\n"), mountpoint); 480*fa9e4066Sahrens return (1); 481*fa9e4066Sahrens } 482*fa9e4066Sahrens 483*fa9e4066Sahrens if (mountpoint == NULL) { 484*fa9e4066Sahrens if (altroot != NULL) 485*fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s/%s", 486*fa9e4066Sahrens altroot, poolname); 487*fa9e4066Sahrens else 488*fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "/%s", 489*fa9e4066Sahrens poolname); 490*fa9e4066Sahrens } else { 491*fa9e4066Sahrens if (altroot != NULL) 492*fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s%s", 493*fa9e4066Sahrens altroot, mountpoint); 494*fa9e4066Sahrens else 495*fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%s", 496*fa9e4066Sahrens mountpoint); 497*fa9e4066Sahrens } 498*fa9e4066Sahrens 499*fa9e4066Sahrens if (stat64(buf, &statbuf) == 0 && 500*fa9e4066Sahrens statbuf.st_nlink != 2) { 501*fa9e4066Sahrens if (mountpoint == NULL) 502*fa9e4066Sahrens (void) fprintf(stderr, gettext("default " 503*fa9e4066Sahrens "mountpoint '%s' exists and is not " 504*fa9e4066Sahrens "empty\n"), buf); 505*fa9e4066Sahrens else 506*fa9e4066Sahrens (void) fprintf(stderr, gettext("mountpoint " 507*fa9e4066Sahrens "'%s' exists and is not empty\n"), buf); 508*fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-m' " 509*fa9e4066Sahrens "option to provide a different default\n")); 510*fa9e4066Sahrens return (1); 511*fa9e4066Sahrens } 512*fa9e4066Sahrens } 513*fa9e4066Sahrens 514*fa9e4066Sahrens 515*fa9e4066Sahrens if (dryrun) { 516*fa9e4066Sahrens /* 517*fa9e4066Sahrens * For a dry run invocation, print out a basic message and run 518*fa9e4066Sahrens * through all the vdevs in the list and print out in an 519*fa9e4066Sahrens * appropriate hierarchy. 520*fa9e4066Sahrens * 521*fa9e4066Sahrens * XXZFS find out of we can create the pool? 522*fa9e4066Sahrens */ 523*fa9e4066Sahrens (void) printf(gettext("would create '%s' with the " 524*fa9e4066Sahrens "following layout:\n\n"), poolname); 525*fa9e4066Sahrens 526*fa9e4066Sahrens print_vdev_tree(poolname, nvroot, 0); 527*fa9e4066Sahrens 528*fa9e4066Sahrens ret = 0; 529*fa9e4066Sahrens } else { 530*fa9e4066Sahrens ret = 1; 531*fa9e4066Sahrens /* 532*fa9e4066Sahrens * Hand off to libzfs. 533*fa9e4066Sahrens */ 534*fa9e4066Sahrens if (zpool_create(poolname, nvroot, altroot) == 0) { 535*fa9e4066Sahrens zfs_handle_t *pool = zfs_open(poolname, 536*fa9e4066Sahrens ZFS_TYPE_FILESYSTEM); 537*fa9e4066Sahrens if (pool != NULL) { 538*fa9e4066Sahrens if (mountpoint != NULL) 539*fa9e4066Sahrens verify(zfs_prop_set(pool, 540*fa9e4066Sahrens ZFS_PROP_MOUNTPOINT, 541*fa9e4066Sahrens mountpoint) == 0); 542*fa9e4066Sahrens if (zfs_mount(pool, NULL, 0) == 0) 543*fa9e4066Sahrens ret = zfs_share(pool); 544*fa9e4066Sahrens zfs_close(pool); 545*fa9e4066Sahrens } 546*fa9e4066Sahrens } 547*fa9e4066Sahrens 548*fa9e4066Sahrens } 549*fa9e4066Sahrens 550*fa9e4066Sahrens nvlist_free(nvroot); 551*fa9e4066Sahrens 552*fa9e4066Sahrens return (ret); 553*fa9e4066Sahrens } 554*fa9e4066Sahrens 555*fa9e4066Sahrens /* 556*fa9e4066Sahrens * zpool destroy <pool> 557*fa9e4066Sahrens * 558*fa9e4066Sahrens * -f Forcefully unmount any datasets 559*fa9e4066Sahrens * 560*fa9e4066Sahrens * Destroy the given pool. Automatically unmounts any datasets in the pool. 561*fa9e4066Sahrens */ 562*fa9e4066Sahrens int 563*fa9e4066Sahrens zpool_do_destroy(int argc, char **argv) 564*fa9e4066Sahrens { 565*fa9e4066Sahrens int force = FALSE; 566*fa9e4066Sahrens int c; 567*fa9e4066Sahrens char *pool; 568*fa9e4066Sahrens zpool_handle_t *zhp; 569*fa9e4066Sahrens int ret; 570*fa9e4066Sahrens 571*fa9e4066Sahrens /* check options */ 572*fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 573*fa9e4066Sahrens switch (c) { 574*fa9e4066Sahrens case 'f': 575*fa9e4066Sahrens force = TRUE; 576*fa9e4066Sahrens break; 577*fa9e4066Sahrens case '?': 578*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 579*fa9e4066Sahrens optopt); 580*fa9e4066Sahrens usage(FALSE); 581*fa9e4066Sahrens } 582*fa9e4066Sahrens } 583*fa9e4066Sahrens 584*fa9e4066Sahrens argc -= optind; 585*fa9e4066Sahrens argv += optind; 586*fa9e4066Sahrens 587*fa9e4066Sahrens /* check arguments */ 588*fa9e4066Sahrens if (argc < 1) { 589*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 590*fa9e4066Sahrens usage(FALSE); 591*fa9e4066Sahrens } 592*fa9e4066Sahrens if (argc > 1) { 593*fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 594*fa9e4066Sahrens usage(FALSE); 595*fa9e4066Sahrens } 596*fa9e4066Sahrens 597*fa9e4066Sahrens pool = argv[0]; 598*fa9e4066Sahrens 599*fa9e4066Sahrens if ((zhp = zpool_open_canfail(pool)) == NULL) { 600*fa9e4066Sahrens /* 601*fa9e4066Sahrens * As a special case, check for use of '/' in the name, and 602*fa9e4066Sahrens * direct the user to use 'zfs destroy' instead. 603*fa9e4066Sahrens */ 604*fa9e4066Sahrens if (strchr(pool, '/') != NULL) 605*fa9e4066Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy' to " 606*fa9e4066Sahrens "destroy a dataset\n")); 607*fa9e4066Sahrens return (1); 608*fa9e4066Sahrens } 609*fa9e4066Sahrens 610*fa9e4066Sahrens if (unmount_datasets(zhp, force) != 0) { 611*fa9e4066Sahrens (void) fprintf(stderr, gettext("could not destroy '%s': " 612*fa9e4066Sahrens "could not unmount datasets\n"), zpool_get_name(zhp)); 613*fa9e4066Sahrens return (1); 614*fa9e4066Sahrens } 615*fa9e4066Sahrens 616*fa9e4066Sahrens ret = (zpool_destroy(zhp) != 0); 617*fa9e4066Sahrens 618*fa9e4066Sahrens zpool_close(zhp); 619*fa9e4066Sahrens 620*fa9e4066Sahrens return (ret); 621*fa9e4066Sahrens } 622*fa9e4066Sahrens 623*fa9e4066Sahrens /* 624*fa9e4066Sahrens * zpool export [-f] <pool> ... 625*fa9e4066Sahrens * 626*fa9e4066Sahrens * -f Forcefully unmount datasets 627*fa9e4066Sahrens * 628*fa9e4066Sahrens * Export the the given pools. By default, the command will attempt to cleanly 629*fa9e4066Sahrens * unmount any active datasets within the pool. If the '-f' flag is specified, 630*fa9e4066Sahrens * then the datasets will be forcefully unmounted. 631*fa9e4066Sahrens */ 632*fa9e4066Sahrens int 633*fa9e4066Sahrens zpool_do_export(int argc, char **argv) 634*fa9e4066Sahrens { 635*fa9e4066Sahrens int force = FALSE; 636*fa9e4066Sahrens int c; 637*fa9e4066Sahrens zpool_handle_t *zhp; 638*fa9e4066Sahrens int ret; 639*fa9e4066Sahrens int i; 640*fa9e4066Sahrens 641*fa9e4066Sahrens /* check options */ 642*fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 643*fa9e4066Sahrens switch (c) { 644*fa9e4066Sahrens case 'f': 645*fa9e4066Sahrens force = TRUE; 646*fa9e4066Sahrens break; 647*fa9e4066Sahrens case '?': 648*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 649*fa9e4066Sahrens optopt); 650*fa9e4066Sahrens usage(FALSE); 651*fa9e4066Sahrens } 652*fa9e4066Sahrens } 653*fa9e4066Sahrens 654*fa9e4066Sahrens argc -= optind; 655*fa9e4066Sahrens argv += optind; 656*fa9e4066Sahrens 657*fa9e4066Sahrens /* check arguments */ 658*fa9e4066Sahrens if (argc < 1) { 659*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool argument\n")); 660*fa9e4066Sahrens usage(FALSE); 661*fa9e4066Sahrens } 662*fa9e4066Sahrens 663*fa9e4066Sahrens ret = 0; 664*fa9e4066Sahrens for (i = 0; i < argc; i++) { 665*fa9e4066Sahrens if ((zhp = zpool_open_canfail(argv[i])) == NULL) { 666*fa9e4066Sahrens ret = 1; 667*fa9e4066Sahrens continue; 668*fa9e4066Sahrens } 669*fa9e4066Sahrens 670*fa9e4066Sahrens if (unmount_datasets(zhp, force) != 0) { 671*fa9e4066Sahrens ret = 1; 672*fa9e4066Sahrens zpool_close(zhp); 673*fa9e4066Sahrens continue; 674*fa9e4066Sahrens } 675*fa9e4066Sahrens 676*fa9e4066Sahrens if (zpool_export(zhp) != 0) 677*fa9e4066Sahrens ret = 1; 678*fa9e4066Sahrens 679*fa9e4066Sahrens zpool_close(zhp); 680*fa9e4066Sahrens } 681*fa9e4066Sahrens 682*fa9e4066Sahrens return (ret); 683*fa9e4066Sahrens } 684*fa9e4066Sahrens 685*fa9e4066Sahrens /* 686*fa9e4066Sahrens * Given a vdev configuration, determine the maximum width needed for the device 687*fa9e4066Sahrens * name column. 688*fa9e4066Sahrens */ 689*fa9e4066Sahrens static int 690*fa9e4066Sahrens max_width(nvlist_t *nv, int depth, int max) 691*fa9e4066Sahrens { 692*fa9e4066Sahrens const char *name = vdev_get_name(nv); 693*fa9e4066Sahrens nvlist_t **child; 694*fa9e4066Sahrens uint_t c, children; 695*fa9e4066Sahrens int ret; 696*fa9e4066Sahrens 697*fa9e4066Sahrens if (strlen(name) + depth > max) 698*fa9e4066Sahrens max = strlen(name) + depth; 699*fa9e4066Sahrens 700*fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 701*fa9e4066Sahrens &child, &children) != 0) 702*fa9e4066Sahrens return (max); 703*fa9e4066Sahrens 704*fa9e4066Sahrens for (c = 0; c < children; c++) 705*fa9e4066Sahrens if ((ret = max_width(child[c], depth + 2, max)) > max) 706*fa9e4066Sahrens max = ret; 707*fa9e4066Sahrens 708*fa9e4066Sahrens return (max); 709*fa9e4066Sahrens } 710*fa9e4066Sahrens 711*fa9e4066Sahrens 712*fa9e4066Sahrens /* 713*fa9e4066Sahrens * Print the configuration of an exported pool. Iterate over all vdevs in the 714*fa9e4066Sahrens * pool, printing out the name and status for each one. 715*fa9e4066Sahrens */ 716*fa9e4066Sahrens void 717*fa9e4066Sahrens print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 718*fa9e4066Sahrens { 719*fa9e4066Sahrens nvlist_t **child; 720*fa9e4066Sahrens uint_t c, children; 721*fa9e4066Sahrens vdev_stat_t *vs; 722*fa9e4066Sahrens char *type; 723*fa9e4066Sahrens 724*fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 725*fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_MISSING) == 0) 726*fa9e4066Sahrens return; 727*fa9e4066Sahrens 728*fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 729*fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 730*fa9e4066Sahrens 731*fa9e4066Sahrens (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 732*fa9e4066Sahrens 733*fa9e4066Sahrens if (vs->vs_aux != 0) { 734*fa9e4066Sahrens (void) printf(" %-8s ", state_to_name(vs->vs_state)); 735*fa9e4066Sahrens 736*fa9e4066Sahrens switch (vs->vs_aux) { 737*fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 738*fa9e4066Sahrens (void) printf(gettext("cannot open")); 739*fa9e4066Sahrens break; 740*fa9e4066Sahrens 741*fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 742*fa9e4066Sahrens (void) printf(gettext("missing device")); 743*fa9e4066Sahrens break; 744*fa9e4066Sahrens 745*fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 746*fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 747*fa9e4066Sahrens break; 748*fa9e4066Sahrens 749*fa9e4066Sahrens default: 750*fa9e4066Sahrens (void) printf(gettext("corrupted data")); 751*fa9e4066Sahrens break; 752*fa9e4066Sahrens } 753*fa9e4066Sahrens } else { 754*fa9e4066Sahrens (void) printf(" %s", state_to_name(vs->vs_state)); 755*fa9e4066Sahrens } 756*fa9e4066Sahrens (void) printf("\n"); 757*fa9e4066Sahrens 758*fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 759*fa9e4066Sahrens &child, &children) != 0) 760*fa9e4066Sahrens return; 761*fa9e4066Sahrens 762*fa9e4066Sahrens for (c = 0; c < children; c++) 763*fa9e4066Sahrens print_import_config(vdev_get_name(child[c]), child[c], 764*fa9e4066Sahrens namewidth, depth + 2); 765*fa9e4066Sahrens } 766*fa9e4066Sahrens 767*fa9e4066Sahrens /* 768*fa9e4066Sahrens * Display the status for the given pool. 769*fa9e4066Sahrens */ 770*fa9e4066Sahrens static void 771*fa9e4066Sahrens show_import(nvlist_t *config) 772*fa9e4066Sahrens { 773*fa9e4066Sahrens uint64_t pool_state; 774*fa9e4066Sahrens vdev_stat_t *vs; 775*fa9e4066Sahrens char *name; 776*fa9e4066Sahrens uint64_t guid; 777*fa9e4066Sahrens char *msgid; 778*fa9e4066Sahrens nvlist_t *nvroot; 779*fa9e4066Sahrens int reason; 780*fa9e4066Sahrens char *health; 781*fa9e4066Sahrens uint_t vsc; 782*fa9e4066Sahrens int namewidth; 783*fa9e4066Sahrens 784*fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 785*fa9e4066Sahrens &name) == 0); 786*fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 787*fa9e4066Sahrens &guid) == 0); 788*fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 789*fa9e4066Sahrens &pool_state) == 0); 790*fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_HEALTH, 791*fa9e4066Sahrens &health) == 0); 792*fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 793*fa9e4066Sahrens &nvroot) == 0); 794*fa9e4066Sahrens 795*fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 796*fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 797*fa9e4066Sahrens 798*fa9e4066Sahrens reason = zpool_import_status(config, &msgid); 799*fa9e4066Sahrens 800*fa9e4066Sahrens (void) printf(" pool: %s\n", name); 801*fa9e4066Sahrens (void) printf(" id: %llu\n", guid); 802*fa9e4066Sahrens (void) printf(" state: %s\n", health); 803*fa9e4066Sahrens 804*fa9e4066Sahrens switch (reason) { 805*fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 806*fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 807*fa9e4066Sahrens case ZPOOL_STATUS_BAD_GUID_SUM: 808*fa9e4066Sahrens (void) printf(gettext("status: One or more devices are missing " 809*fa9e4066Sahrens "from the system.\n")); 810*fa9e4066Sahrens break; 811*fa9e4066Sahrens 812*fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 813*fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 814*fa9e4066Sahrens (void) printf(gettext("status: One or more devices contains " 815*fa9e4066Sahrens "corrupted data.\n")); 816*fa9e4066Sahrens break; 817*fa9e4066Sahrens 818*fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_DATA: 819*fa9e4066Sahrens (void) printf(gettext("status: The pool data is corrupted.\n")); 820*fa9e4066Sahrens break; 821*fa9e4066Sahrens 822*fa9e4066Sahrens default: 823*fa9e4066Sahrens /* 824*fa9e4066Sahrens * No other status can be seen when importing pools. 825*fa9e4066Sahrens */ 826*fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 827*fa9e4066Sahrens } 828*fa9e4066Sahrens 829*fa9e4066Sahrens /* 830*fa9e4066Sahrens * Print out an action according to the overall state of the pool. 831*fa9e4066Sahrens */ 832*fa9e4066Sahrens if (strcmp(health, gettext("ONLINE")) == 0) { 833*fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported" 834*fa9e4066Sahrens " using its name or numeric identifier.")); 835*fa9e4066Sahrens if (pool_state != POOL_STATE_EXPORTED) 836*fa9e4066Sahrens (void) printf(gettext(" The\n\tpool may be active on " 837*fa9e4066Sahrens "on another system, but can be imported using\n\t" 838*fa9e4066Sahrens "the '-f' flag.\n")); 839*fa9e4066Sahrens else 840*fa9e4066Sahrens (void) printf("\n"); 841*fa9e4066Sahrens } else if (strcmp(health, gettext("DEGRADED")) == 0) { 842*fa9e4066Sahrens (void) printf(gettext("action: The pool can be imported " 843*fa9e4066Sahrens "despite missing or damaged devices. The\n\tfault " 844*fa9e4066Sahrens "tolerance of the pool may be compromised if imported.")); 845*fa9e4066Sahrens if (pool_state != POOL_STATE_EXPORTED) 846*fa9e4066Sahrens (void) printf(gettext(" The\n\tpool may be active on " 847*fa9e4066Sahrens "on another system, but can be imported using\n\t" 848*fa9e4066Sahrens "the '-f' flag.\n")); 849*fa9e4066Sahrens else 850*fa9e4066Sahrens (void) printf("\n"); 851*fa9e4066Sahrens } else { 852*fa9e4066Sahrens if (reason == ZPOOL_STATUS_MISSING_DEV_R || 853*fa9e4066Sahrens reason == ZPOOL_STATUS_MISSING_DEV_NR || 854*fa9e4066Sahrens reason == ZPOOL_STATUS_BAD_GUID_SUM) 855*fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 856*fa9e4066Sahrens "imported. Attach the missing\n\tdevices and try " 857*fa9e4066Sahrens "again.\n")); 858*fa9e4066Sahrens else 859*fa9e4066Sahrens (void) printf(gettext("action: The pool cannot be " 860*fa9e4066Sahrens "imported due to damaged devices or data.\n")); 861*fa9e4066Sahrens } 862*fa9e4066Sahrens 863*fa9e4066Sahrens if (msgid != NULL) 864*fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 865*fa9e4066Sahrens msgid); 866*fa9e4066Sahrens 867*fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 868*fa9e4066Sahrens 869*fa9e4066Sahrens namewidth = max_width(nvroot, 0, 0); 870*fa9e4066Sahrens if (namewidth < 10) 871*fa9e4066Sahrens namewidth = 10; 872*fa9e4066Sahrens print_import_config(name, nvroot, namewidth, 0); 873*fa9e4066Sahrens 874*fa9e4066Sahrens if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 875*fa9e4066Sahrens (void) printf("\n\tAdditional devices are known to " 876*fa9e4066Sahrens "be part of this pool, though their\n\texact " 877*fa9e4066Sahrens "configuration cannot be determined.\n"); 878*fa9e4066Sahrens } 879*fa9e4066Sahrens } 880*fa9e4066Sahrens 881*fa9e4066Sahrens /* 882*fa9e4066Sahrens * Perform the import for the given configuration. This passes the heavy 883*fa9e4066Sahrens * lifting off to zpool_import(), and then mounts the datasets contained within 884*fa9e4066Sahrens * the pool. 885*fa9e4066Sahrens */ 886*fa9e4066Sahrens static int 887*fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts, 888*fa9e4066Sahrens const char *altroot, int force) 889*fa9e4066Sahrens { 890*fa9e4066Sahrens zpool_handle_t *zhp; 891*fa9e4066Sahrens char *name; 892*fa9e4066Sahrens uint64_t state; 893*fa9e4066Sahrens 894*fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 895*fa9e4066Sahrens &name) == 0); 896*fa9e4066Sahrens 897*fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 898*fa9e4066Sahrens ZPOOL_CONFIG_POOL_STATE, &state) == 0); 899*fa9e4066Sahrens if (state != POOL_STATE_EXPORTED && !force) { 900*fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': pool " 901*fa9e4066Sahrens "may be in use from other system\n"), name); 902*fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-f' to import anyway\n")); 903*fa9e4066Sahrens return (1); 904*fa9e4066Sahrens } 905*fa9e4066Sahrens 906*fa9e4066Sahrens if (zpool_import(config, newname, altroot) != 0) 907*fa9e4066Sahrens return (1); 908*fa9e4066Sahrens 909*fa9e4066Sahrens if (newname != NULL) 910*fa9e4066Sahrens name = (char *)newname; 911*fa9e4066Sahrens 912*fa9e4066Sahrens verify((zhp = zpool_open(name)) != NULL); 913*fa9e4066Sahrens 914*fa9e4066Sahrens if (mount_datasets(zhp, mntopts) != 0) { 915*fa9e4066Sahrens zpool_close(zhp); 916*fa9e4066Sahrens return (1); 917*fa9e4066Sahrens } 918*fa9e4066Sahrens 919*fa9e4066Sahrens zpool_close(zhp); 920*fa9e4066Sahrens return (0); 921*fa9e4066Sahrens } 922*fa9e4066Sahrens 923*fa9e4066Sahrens /* 924*fa9e4066Sahrens * zpool import [-d dir] 925*fa9e4066Sahrens * import [-R root] [-d dir] [-f] -a 926*fa9e4066Sahrens * import [-R root] [-d dir] [-f] <pool | id> [newpool] 927*fa9e4066Sahrens * 928*fa9e4066Sahrens * -d Scan in a specific directory, other than /dev/dsk. More than 929*fa9e4066Sahrens * one directory can be specified using multiple '-d' options. 930*fa9e4066Sahrens * 931*fa9e4066Sahrens * -R Temporarily import the pool, with all mountpoints relative to 932*fa9e4066Sahrens * the given root. The pool will remain exported when the machine 933*fa9e4066Sahrens * is rebooted. 934*fa9e4066Sahrens * 935*fa9e4066Sahrens * -f Force import, even if it appears that the pool is active. 936*fa9e4066Sahrens * 937*fa9e4066Sahrens * -a Import all pools found. 938*fa9e4066Sahrens * 939*fa9e4066Sahrens * The import command scans for pools to import, and import pools based on pool 940*fa9e4066Sahrens * name and GUID. The pool can also be renamed as part of the import process. 941*fa9e4066Sahrens */ 942*fa9e4066Sahrens int 943*fa9e4066Sahrens zpool_do_import(int argc, char **argv) 944*fa9e4066Sahrens { 945*fa9e4066Sahrens char **searchdirs = NULL; 946*fa9e4066Sahrens int nsearch = 0; 947*fa9e4066Sahrens int c; 948*fa9e4066Sahrens int err; 949*fa9e4066Sahrens nvlist_t *pools; 950*fa9e4066Sahrens int do_all = FALSE; 951*fa9e4066Sahrens char *altroot = NULL; 952*fa9e4066Sahrens char *mntopts = NULL; 953*fa9e4066Sahrens int do_force = FALSE; 954*fa9e4066Sahrens nvpair_t *elem; 955*fa9e4066Sahrens nvlist_t *config; 956*fa9e4066Sahrens uint64_t searchguid; 957*fa9e4066Sahrens char *searchname; 958*fa9e4066Sahrens nvlist_t *found_config; 959*fa9e4066Sahrens int first; 960*fa9e4066Sahrens 961*fa9e4066Sahrens /* check options */ 962*fa9e4066Sahrens while ((c = getopt(argc, argv, ":fd:R:ao:")) != -1) { 963*fa9e4066Sahrens switch (c) { 964*fa9e4066Sahrens case 'a': 965*fa9e4066Sahrens do_all = TRUE; 966*fa9e4066Sahrens break; 967*fa9e4066Sahrens case 'd': 968*fa9e4066Sahrens if (searchdirs == NULL) { 969*fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 970*fa9e4066Sahrens } else { 971*fa9e4066Sahrens char **tmp = safe_malloc((nsearch + 1) * 972*fa9e4066Sahrens sizeof (char *)); 973*fa9e4066Sahrens bcopy(searchdirs, tmp, nsearch * 974*fa9e4066Sahrens sizeof (char *)); 975*fa9e4066Sahrens free(searchdirs); 976*fa9e4066Sahrens searchdirs = tmp; 977*fa9e4066Sahrens } 978*fa9e4066Sahrens searchdirs[nsearch++] = optarg; 979*fa9e4066Sahrens break; 980*fa9e4066Sahrens case 'f': 981*fa9e4066Sahrens do_force = TRUE; 982*fa9e4066Sahrens break; 983*fa9e4066Sahrens case 'o': 984*fa9e4066Sahrens mntopts = optarg; 985*fa9e4066Sahrens break; 986*fa9e4066Sahrens case 'R': 987*fa9e4066Sahrens altroot = optarg; 988*fa9e4066Sahrens break; 989*fa9e4066Sahrens case ':': 990*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 991*fa9e4066Sahrens "'%c' option\n"), optopt); 992*fa9e4066Sahrens usage(FALSE); 993*fa9e4066Sahrens break; 994*fa9e4066Sahrens case '?': 995*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 996*fa9e4066Sahrens optopt); 997*fa9e4066Sahrens usage(FALSE); 998*fa9e4066Sahrens } 999*fa9e4066Sahrens } 1000*fa9e4066Sahrens 1001*fa9e4066Sahrens argc -= optind; 1002*fa9e4066Sahrens argv += optind; 1003*fa9e4066Sahrens 1004*fa9e4066Sahrens if (searchdirs == NULL) { 1005*fa9e4066Sahrens searchdirs = safe_malloc(sizeof (char *)); 1006*fa9e4066Sahrens searchdirs[0] = "/dev/dsk"; 1007*fa9e4066Sahrens nsearch = 1; 1008*fa9e4066Sahrens } 1009*fa9e4066Sahrens 1010*fa9e4066Sahrens /* check argument count */ 1011*fa9e4066Sahrens if (do_all) { 1012*fa9e4066Sahrens if (argc != 0) { 1013*fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 1014*fa9e4066Sahrens usage(FALSE); 1015*fa9e4066Sahrens } 1016*fa9e4066Sahrens } else { 1017*fa9e4066Sahrens if (argc > 2) { 1018*fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 1019*fa9e4066Sahrens usage(FALSE); 1020*fa9e4066Sahrens } 1021*fa9e4066Sahrens 1022*fa9e4066Sahrens /* 1023*fa9e4066Sahrens * Check for the SYS_CONFIG privilege. We do this explicitly 1024*fa9e4066Sahrens * here because otherwise any attempt to discover pools will 1025*fa9e4066Sahrens * silently fail. 1026*fa9e4066Sahrens */ 1027*fa9e4066Sahrens if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1028*fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot " 1029*fa9e4066Sahrens "discover pools: permission denied\n")); 1030*fa9e4066Sahrens return (1); 1031*fa9e4066Sahrens } 1032*fa9e4066Sahrens } 1033*fa9e4066Sahrens 1034*fa9e4066Sahrens if ((pools = zpool_find_import(nsearch, searchdirs)) == NULL) 1035*fa9e4066Sahrens return (1); 1036*fa9e4066Sahrens 1037*fa9e4066Sahrens /* 1038*fa9e4066Sahrens * We now have a list of all available pools in the given directories. 1039*fa9e4066Sahrens * Depending on the arguments given, we do one of the following: 1040*fa9e4066Sahrens * 1041*fa9e4066Sahrens * <none> Iterate through all pools and display information about 1042*fa9e4066Sahrens * each one. 1043*fa9e4066Sahrens * 1044*fa9e4066Sahrens * -a Iterate through all pools and try to import each one. 1045*fa9e4066Sahrens * 1046*fa9e4066Sahrens * <id> Find the pool that corresponds to the given GUID/pool 1047*fa9e4066Sahrens * name and import that one. 1048*fa9e4066Sahrens */ 1049*fa9e4066Sahrens if (argc != 0) { 1050*fa9e4066Sahrens char *endptr; 1051*fa9e4066Sahrens 1052*fa9e4066Sahrens errno = 0; 1053*fa9e4066Sahrens searchguid = strtoull(argv[0], &endptr, 10); 1054*fa9e4066Sahrens if (errno != 0 || *endptr != '\0') 1055*fa9e4066Sahrens searchname = argv[0]; 1056*fa9e4066Sahrens else 1057*fa9e4066Sahrens searchname = NULL; 1058*fa9e4066Sahrens found_config = NULL; 1059*fa9e4066Sahrens } 1060*fa9e4066Sahrens 1061*fa9e4066Sahrens err = 0; 1062*fa9e4066Sahrens elem = NULL; 1063*fa9e4066Sahrens first = TRUE; 1064*fa9e4066Sahrens while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1065*fa9e4066Sahrens 1066*fa9e4066Sahrens verify(nvpair_value_nvlist(elem, &config) == 0); 1067*fa9e4066Sahrens 1068*fa9e4066Sahrens if (argc == 0) { 1069*fa9e4066Sahrens if (first) 1070*fa9e4066Sahrens first = FALSE; 1071*fa9e4066Sahrens else 1072*fa9e4066Sahrens (void) printf("\n"); 1073*fa9e4066Sahrens 1074*fa9e4066Sahrens if (do_all) 1075*fa9e4066Sahrens err |= do_import(config, NULL, mntopts, 1076*fa9e4066Sahrens altroot, do_force); 1077*fa9e4066Sahrens else 1078*fa9e4066Sahrens show_import(config); 1079*fa9e4066Sahrens } else if (searchname != NULL) { 1080*fa9e4066Sahrens char *name; 1081*fa9e4066Sahrens 1082*fa9e4066Sahrens /* 1083*fa9e4066Sahrens * We are searching for a pool based on name. 1084*fa9e4066Sahrens */ 1085*fa9e4066Sahrens verify(nvlist_lookup_string(config, 1086*fa9e4066Sahrens ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1087*fa9e4066Sahrens 1088*fa9e4066Sahrens if (strcmp(name, searchname) == 0) { 1089*fa9e4066Sahrens if (found_config != NULL) { 1090*fa9e4066Sahrens (void) fprintf(stderr, gettext( 1091*fa9e4066Sahrens "cannot import '%s': more than " 1092*fa9e4066Sahrens "one matching pool\n"), searchname); 1093*fa9e4066Sahrens (void) fprintf(stderr, gettext( 1094*fa9e4066Sahrens "import by numeric ID instead\n")); 1095*fa9e4066Sahrens err = TRUE; 1096*fa9e4066Sahrens } 1097*fa9e4066Sahrens found_config = config; 1098*fa9e4066Sahrens } 1099*fa9e4066Sahrens } else { 1100*fa9e4066Sahrens uint64_t guid; 1101*fa9e4066Sahrens 1102*fa9e4066Sahrens /* 1103*fa9e4066Sahrens * Search for a pool by guid. 1104*fa9e4066Sahrens */ 1105*fa9e4066Sahrens verify(nvlist_lookup_uint64(config, 1106*fa9e4066Sahrens ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1107*fa9e4066Sahrens 1108*fa9e4066Sahrens if (guid == searchguid) 1109*fa9e4066Sahrens found_config = config; 1110*fa9e4066Sahrens } 1111*fa9e4066Sahrens } 1112*fa9e4066Sahrens 1113*fa9e4066Sahrens /* 1114*fa9e4066Sahrens * If we were searching for a specific pool, verify that we found a 1115*fa9e4066Sahrens * pool, and then do the import. 1116*fa9e4066Sahrens */ 1117*fa9e4066Sahrens if (argc != 0 && err == 0) { 1118*fa9e4066Sahrens if (found_config == NULL) { 1119*fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot import '%s': " 1120*fa9e4066Sahrens "no such pool available\n"), argv[0]); 1121*fa9e4066Sahrens err = TRUE; 1122*fa9e4066Sahrens } else { 1123*fa9e4066Sahrens err |= do_import(found_config, argc == 1 ? NULL : 1124*fa9e4066Sahrens argv[1], mntopts, altroot, do_force); 1125*fa9e4066Sahrens } 1126*fa9e4066Sahrens } 1127*fa9e4066Sahrens 1128*fa9e4066Sahrens /* 1129*fa9e4066Sahrens * If we were just looking for pools, report an error if none were 1130*fa9e4066Sahrens * found. 1131*fa9e4066Sahrens */ 1132*fa9e4066Sahrens if (argc == 0 && first) 1133*fa9e4066Sahrens (void) fprintf(stderr, 1134*fa9e4066Sahrens gettext("no pools available to import\n")); 1135*fa9e4066Sahrens 1136*fa9e4066Sahrens nvlist_free(pools); 1137*fa9e4066Sahrens 1138*fa9e4066Sahrens return (err ? 1 : 0); 1139*fa9e4066Sahrens } 1140*fa9e4066Sahrens 1141*fa9e4066Sahrens typedef struct iostat_cbdata { 1142*fa9e4066Sahrens zpool_list_t *cb_list; 1143*fa9e4066Sahrens int cb_verbose; 1144*fa9e4066Sahrens int cb_iteration; 1145*fa9e4066Sahrens int cb_namewidth; 1146*fa9e4066Sahrens } iostat_cbdata_t; 1147*fa9e4066Sahrens 1148*fa9e4066Sahrens static void 1149*fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb) 1150*fa9e4066Sahrens { 1151*fa9e4066Sahrens int i = 0; 1152*fa9e4066Sahrens 1153*fa9e4066Sahrens for (i = 0; i < cb->cb_namewidth; i++) 1154*fa9e4066Sahrens (void) printf("-"); 1155*fa9e4066Sahrens (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1156*fa9e4066Sahrens } 1157*fa9e4066Sahrens 1158*fa9e4066Sahrens static void 1159*fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb) 1160*fa9e4066Sahrens { 1161*fa9e4066Sahrens (void) printf("%*s capacity operations bandwidth\n", 1162*fa9e4066Sahrens cb->cb_namewidth, ""); 1163*fa9e4066Sahrens (void) printf("%-*s used avail read write read write\n", 1164*fa9e4066Sahrens cb->cb_namewidth, "pool"); 1165*fa9e4066Sahrens print_iostat_separator(cb); 1166*fa9e4066Sahrens } 1167*fa9e4066Sahrens 1168*fa9e4066Sahrens /* 1169*fa9e4066Sahrens * Display a single statistic. 1170*fa9e4066Sahrens */ 1171*fa9e4066Sahrens void 1172*fa9e4066Sahrens print_one_stat(uint64_t value) 1173*fa9e4066Sahrens { 1174*fa9e4066Sahrens char buf[64]; 1175*fa9e4066Sahrens 1176*fa9e4066Sahrens zfs_nicenum(value, buf, sizeof (buf)); 1177*fa9e4066Sahrens (void) printf(" %5s", buf); 1178*fa9e4066Sahrens } 1179*fa9e4066Sahrens 1180*fa9e4066Sahrens /* 1181*fa9e4066Sahrens * Print out all the statistics for the given vdev. This can either be the 1182*fa9e4066Sahrens * toplevel configuration, or called recursively. If 'name' is NULL, then this 1183*fa9e4066Sahrens * is a verbose output, and we don't want to display the toplevel pool stats. 1184*fa9e4066Sahrens */ 1185*fa9e4066Sahrens void 1186*fa9e4066Sahrens print_vdev_stats(const char *name, nvlist_t *oldnv, nvlist_t *newnv, 1187*fa9e4066Sahrens iostat_cbdata_t *cb, int depth) 1188*fa9e4066Sahrens { 1189*fa9e4066Sahrens nvlist_t **oldchild, **newchild; 1190*fa9e4066Sahrens uint_t c, children; 1191*fa9e4066Sahrens vdev_stat_t *oldvs, *newvs; 1192*fa9e4066Sahrens vdev_stat_t zerovs = { 0 }; 1193*fa9e4066Sahrens uint64_t tdelta; 1194*fa9e4066Sahrens double scale; 1195*fa9e4066Sahrens 1196*fa9e4066Sahrens if (oldnv != NULL) { 1197*fa9e4066Sahrens verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1198*fa9e4066Sahrens (uint64_t **)&oldvs, &c) == 0); 1199*fa9e4066Sahrens } else { 1200*fa9e4066Sahrens oldvs = &zerovs; 1201*fa9e4066Sahrens } 1202*fa9e4066Sahrens 1203*fa9e4066Sahrens verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1204*fa9e4066Sahrens (uint64_t **)&newvs, &c) == 0); 1205*fa9e4066Sahrens 1206*fa9e4066Sahrens if (strlen(name) + depth > cb->cb_namewidth) 1207*fa9e4066Sahrens (void) printf("%*s%s", depth, "", name); 1208*fa9e4066Sahrens else 1209*fa9e4066Sahrens (void) printf("%*s%s%*s", depth, "", name, 1210*fa9e4066Sahrens (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1211*fa9e4066Sahrens 1212*fa9e4066Sahrens tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1213*fa9e4066Sahrens 1214*fa9e4066Sahrens if (tdelta == 0) 1215*fa9e4066Sahrens scale = 1.0; 1216*fa9e4066Sahrens else 1217*fa9e4066Sahrens scale = (double)NANOSEC / tdelta; 1218*fa9e4066Sahrens 1219*fa9e4066Sahrens /* only toplevel vdevs have capacity stats */ 1220*fa9e4066Sahrens if (newvs->vs_space == 0) { 1221*fa9e4066Sahrens (void) printf(" - -"); 1222*fa9e4066Sahrens } else { 1223*fa9e4066Sahrens print_one_stat(newvs->vs_alloc); 1224*fa9e4066Sahrens print_one_stat(newvs->vs_space - newvs->vs_alloc); 1225*fa9e4066Sahrens } 1226*fa9e4066Sahrens 1227*fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1228*fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_READ]))); 1229*fa9e4066Sahrens 1230*fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1231*fa9e4066Sahrens oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1232*fa9e4066Sahrens 1233*fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1234*fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_READ]))); 1235*fa9e4066Sahrens 1236*fa9e4066Sahrens print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1237*fa9e4066Sahrens oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1238*fa9e4066Sahrens 1239*fa9e4066Sahrens (void) printf("\n"); 1240*fa9e4066Sahrens 1241*fa9e4066Sahrens if (!cb->cb_verbose) 1242*fa9e4066Sahrens return; 1243*fa9e4066Sahrens 1244*fa9e4066Sahrens if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1245*fa9e4066Sahrens &newchild, &children) != 0) 1246*fa9e4066Sahrens return; 1247*fa9e4066Sahrens 1248*fa9e4066Sahrens if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1249*fa9e4066Sahrens &oldchild, &c) != 0) 1250*fa9e4066Sahrens return; 1251*fa9e4066Sahrens 1252*fa9e4066Sahrens for (c = 0; c < children; c++) 1253*fa9e4066Sahrens print_vdev_stats(vdev_get_name(newchild[c]), 1254*fa9e4066Sahrens oldnv ? oldchild[c] : NULL, newchild[c], cb, depth + 2); 1255*fa9e4066Sahrens } 1256*fa9e4066Sahrens 1257*fa9e4066Sahrens /* 1258*fa9e4066Sahrens * Callback to print out the iostats for the given pool. 1259*fa9e4066Sahrens */ 1260*fa9e4066Sahrens int 1261*fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data) 1262*fa9e4066Sahrens { 1263*fa9e4066Sahrens iostat_cbdata_t *cb = data; 1264*fa9e4066Sahrens nvlist_t *oldconfig, *newconfig; 1265*fa9e4066Sahrens nvlist_t *oldnvroot, *newnvroot; 1266*fa9e4066Sahrens uint64_t oldtxg, newtxg; 1267*fa9e4066Sahrens 1268*fa9e4066Sahrens if (zpool_refresh_stats(zhp, &oldconfig, &newconfig) != 0) { 1269*fa9e4066Sahrens /* 1270*fa9e4066Sahrens * This pool has disappeared, so remove it 1271*fa9e4066Sahrens * from the list and continue. 1272*fa9e4066Sahrens */ 1273*fa9e4066Sahrens pool_list_remove(cb->cb_list, zhp); 1274*fa9e4066Sahrens return (0); 1275*fa9e4066Sahrens } 1276*fa9e4066Sahrens 1277*fa9e4066Sahrens if (cb->cb_iteration == 1) { 1278*fa9e4066Sahrens if (oldconfig != NULL) 1279*fa9e4066Sahrens nvlist_free(oldconfig); 1280*fa9e4066Sahrens oldconfig = NULL; 1281*fa9e4066Sahrens } 1282*fa9e4066Sahrens 1283*fa9e4066Sahrens verify(nvlist_lookup_uint64(newconfig, ZPOOL_CONFIG_POOL_TXG, 1284*fa9e4066Sahrens &newtxg) == 0); 1285*fa9e4066Sahrens verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1286*fa9e4066Sahrens &newnvroot) == 0); 1287*fa9e4066Sahrens 1288*fa9e4066Sahrens if (oldconfig == NULL || 1289*fa9e4066Sahrens nvlist_lookup_uint64(oldconfig, ZPOOL_CONFIG_POOL_TXG, &oldtxg) || 1290*fa9e4066Sahrens oldtxg != newtxg || 1291*fa9e4066Sahrens nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, &oldnvroot)) 1292*fa9e4066Sahrens oldnvroot = NULL; 1293*fa9e4066Sahrens 1294*fa9e4066Sahrens /* 1295*fa9e4066Sahrens * Print out the statistics for the pool. 1296*fa9e4066Sahrens */ 1297*fa9e4066Sahrens print_vdev_stats(zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1298*fa9e4066Sahrens 1299*fa9e4066Sahrens if (cb->cb_verbose) 1300*fa9e4066Sahrens print_iostat_separator(cb); 1301*fa9e4066Sahrens 1302*fa9e4066Sahrens if (oldconfig != NULL) 1303*fa9e4066Sahrens nvlist_free(oldconfig); 1304*fa9e4066Sahrens 1305*fa9e4066Sahrens return (0); 1306*fa9e4066Sahrens } 1307*fa9e4066Sahrens 1308*fa9e4066Sahrens int 1309*fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data) 1310*fa9e4066Sahrens { 1311*fa9e4066Sahrens iostat_cbdata_t *cb = data; 1312*fa9e4066Sahrens nvlist_t *config, *nvroot; 1313*fa9e4066Sahrens 1314*fa9e4066Sahrens if ((config = zpool_get_config(zhp)) != NULL) { 1315*fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1316*fa9e4066Sahrens &nvroot) == 0); 1317*fa9e4066Sahrens if (!cb->cb_verbose) 1318*fa9e4066Sahrens cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1319*fa9e4066Sahrens else 1320*fa9e4066Sahrens cb->cb_namewidth = max_width(nvroot, 0, 0); 1321*fa9e4066Sahrens } 1322*fa9e4066Sahrens 1323*fa9e4066Sahrens /* 1324*fa9e4066Sahrens * The width must fall into the range [10,38]. The upper limit is the 1325*fa9e4066Sahrens * maximum we can have and still fit in 80 columns. 1326*fa9e4066Sahrens */ 1327*fa9e4066Sahrens if (cb->cb_namewidth < 10) 1328*fa9e4066Sahrens cb->cb_namewidth = 10; 1329*fa9e4066Sahrens if (cb->cb_namewidth > 38) 1330*fa9e4066Sahrens cb->cb_namewidth = 38; 1331*fa9e4066Sahrens 1332*fa9e4066Sahrens return (0); 1333*fa9e4066Sahrens } 1334*fa9e4066Sahrens 1335*fa9e4066Sahrens /* 1336*fa9e4066Sahrens * zpool iostat [-v] [pool] ... [interval [count]] 1337*fa9e4066Sahrens * 1338*fa9e4066Sahrens * -v Display statistics for individual vdevs 1339*fa9e4066Sahrens * 1340*fa9e4066Sahrens * This command can be tricky because we want to be able to deal with pool 1341*fa9e4066Sahrens * creation/destruction as well as vdev configuration changes. The bulk of this 1342*fa9e4066Sahrens * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1343*fa9e4066Sahrens * on pool_list_update() to detect the addition of new pools. Configuration 1344*fa9e4066Sahrens * changes are all handled within libzfs. 1345*fa9e4066Sahrens */ 1346*fa9e4066Sahrens int 1347*fa9e4066Sahrens zpool_do_iostat(int argc, char **argv) 1348*fa9e4066Sahrens { 1349*fa9e4066Sahrens int c; 1350*fa9e4066Sahrens int ret; 1351*fa9e4066Sahrens int npools; 1352*fa9e4066Sahrens unsigned long interval = 0, count = 0; 1353*fa9e4066Sahrens zpool_list_t *list; 1354*fa9e4066Sahrens int verbose = FALSE; 1355*fa9e4066Sahrens iostat_cbdata_t cb; 1356*fa9e4066Sahrens 1357*fa9e4066Sahrens /* check options */ 1358*fa9e4066Sahrens while ((c = getopt(argc, argv, "v")) != -1) { 1359*fa9e4066Sahrens switch (c) { 1360*fa9e4066Sahrens case 'v': 1361*fa9e4066Sahrens verbose = TRUE; 1362*fa9e4066Sahrens break; 1363*fa9e4066Sahrens case '?': 1364*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1365*fa9e4066Sahrens optopt); 1366*fa9e4066Sahrens usage(FALSE); 1367*fa9e4066Sahrens } 1368*fa9e4066Sahrens } 1369*fa9e4066Sahrens 1370*fa9e4066Sahrens argc -= optind; 1371*fa9e4066Sahrens argv += optind; 1372*fa9e4066Sahrens 1373*fa9e4066Sahrens /* 1374*fa9e4066Sahrens * Determine if the last argument is an integer or a pool name 1375*fa9e4066Sahrens */ 1376*fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1377*fa9e4066Sahrens char *end; 1378*fa9e4066Sahrens 1379*fa9e4066Sahrens errno = 0; 1380*fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1381*fa9e4066Sahrens 1382*fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1383*fa9e4066Sahrens if (interval == 0) { 1384*fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1385*fa9e4066Sahrens "cannot be zero\n")); 1386*fa9e4066Sahrens usage(FALSE); 1387*fa9e4066Sahrens } 1388*fa9e4066Sahrens 1389*fa9e4066Sahrens /* 1390*fa9e4066Sahrens * Ignore the last parameter 1391*fa9e4066Sahrens */ 1392*fa9e4066Sahrens argc--; 1393*fa9e4066Sahrens } else { 1394*fa9e4066Sahrens /* 1395*fa9e4066Sahrens * If this is not a valid number, just plow on. The 1396*fa9e4066Sahrens * user will get a more informative error message later 1397*fa9e4066Sahrens * on. 1398*fa9e4066Sahrens */ 1399*fa9e4066Sahrens interval = 0; 1400*fa9e4066Sahrens } 1401*fa9e4066Sahrens } 1402*fa9e4066Sahrens 1403*fa9e4066Sahrens /* 1404*fa9e4066Sahrens * If the last argument is also an integer, then we have both a count 1405*fa9e4066Sahrens * and an integer. 1406*fa9e4066Sahrens */ 1407*fa9e4066Sahrens if (argc > 0 && isdigit(argv[argc - 1][0])) { 1408*fa9e4066Sahrens char *end; 1409*fa9e4066Sahrens 1410*fa9e4066Sahrens errno = 0; 1411*fa9e4066Sahrens count = interval; 1412*fa9e4066Sahrens interval = strtoul(argv[argc - 1], &end, 10); 1413*fa9e4066Sahrens 1414*fa9e4066Sahrens if (*end == '\0' && errno == 0) { 1415*fa9e4066Sahrens if (interval == 0) { 1416*fa9e4066Sahrens (void) fprintf(stderr, gettext("interval " 1417*fa9e4066Sahrens "cannot be zero\n")); 1418*fa9e4066Sahrens usage(FALSE); 1419*fa9e4066Sahrens } 1420*fa9e4066Sahrens 1421*fa9e4066Sahrens /* 1422*fa9e4066Sahrens * Ignore the last parameter 1423*fa9e4066Sahrens */ 1424*fa9e4066Sahrens argc--; 1425*fa9e4066Sahrens } else { 1426*fa9e4066Sahrens interval = 0; 1427*fa9e4066Sahrens } 1428*fa9e4066Sahrens } 1429*fa9e4066Sahrens 1430*fa9e4066Sahrens /* 1431*fa9e4066Sahrens * Construct the list of all interesting pools. 1432*fa9e4066Sahrens */ 1433*fa9e4066Sahrens ret = 0; 1434*fa9e4066Sahrens if ((list = pool_list_get(argc, argv, &ret)) == NULL) 1435*fa9e4066Sahrens return (1); 1436*fa9e4066Sahrens 1437*fa9e4066Sahrens if (pool_list_count(list) == 0 && argc != 0) 1438*fa9e4066Sahrens return (1); 1439*fa9e4066Sahrens 1440*fa9e4066Sahrens if (pool_list_count(list) == 0 && interval == 0) { 1441*fa9e4066Sahrens (void) fprintf(stderr, gettext("no pools available\n")); 1442*fa9e4066Sahrens return (1); 1443*fa9e4066Sahrens } 1444*fa9e4066Sahrens 1445*fa9e4066Sahrens /* 1446*fa9e4066Sahrens * Enter the main iostat loop. 1447*fa9e4066Sahrens */ 1448*fa9e4066Sahrens cb.cb_list = list; 1449*fa9e4066Sahrens cb.cb_verbose = verbose; 1450*fa9e4066Sahrens cb.cb_iteration = 0; 1451*fa9e4066Sahrens cb.cb_namewidth = 0; 1452*fa9e4066Sahrens 1453*fa9e4066Sahrens for (;;) { 1454*fa9e4066Sahrens pool_list_update(list); 1455*fa9e4066Sahrens 1456*fa9e4066Sahrens if ((npools = pool_list_count(list)) == 0) 1457*fa9e4066Sahrens break; 1458*fa9e4066Sahrens 1459*fa9e4066Sahrens /* 1460*fa9e4066Sahrens * Iterate over all pools to determine the maximum width 1461*fa9e4066Sahrens * for the pool / device name column across all pools. 1462*fa9e4066Sahrens */ 1463*fa9e4066Sahrens cb.cb_namewidth = 0; 1464*fa9e4066Sahrens (void) pool_list_iter(list, FALSE, get_namewidth, &cb); 1465*fa9e4066Sahrens 1466*fa9e4066Sahrens /* 1467*fa9e4066Sahrens * If it's the first time, or verbose mode, print the header. 1468*fa9e4066Sahrens */ 1469*fa9e4066Sahrens if (++cb.cb_iteration == 1 || verbose) 1470*fa9e4066Sahrens print_iostat_header(&cb); 1471*fa9e4066Sahrens 1472*fa9e4066Sahrens (void) pool_list_iter(list, FALSE, print_iostat, &cb); 1473*fa9e4066Sahrens 1474*fa9e4066Sahrens /* 1475*fa9e4066Sahrens * If there's more than one pool, and we're not in verbose mode 1476*fa9e4066Sahrens * (which prints a separator for us), then print a separator. 1477*fa9e4066Sahrens */ 1478*fa9e4066Sahrens if (npools > 1 && !verbose) 1479*fa9e4066Sahrens print_iostat_separator(&cb); 1480*fa9e4066Sahrens 1481*fa9e4066Sahrens if (verbose) 1482*fa9e4066Sahrens (void) printf("\n"); 1483*fa9e4066Sahrens 1484*fa9e4066Sahrens if (interval == 0) 1485*fa9e4066Sahrens break; 1486*fa9e4066Sahrens 1487*fa9e4066Sahrens if (count != 0 && --count == 0) 1488*fa9e4066Sahrens break; 1489*fa9e4066Sahrens 1490*fa9e4066Sahrens (void) sleep(interval); 1491*fa9e4066Sahrens } 1492*fa9e4066Sahrens 1493*fa9e4066Sahrens pool_list_free(list); 1494*fa9e4066Sahrens 1495*fa9e4066Sahrens return (ret); 1496*fa9e4066Sahrens } 1497*fa9e4066Sahrens 1498*fa9e4066Sahrens typedef struct list_cbdata { 1499*fa9e4066Sahrens int cb_scripted; 1500*fa9e4066Sahrens int cb_first; 1501*fa9e4066Sahrens int cb_fields[MAX_FIELDS]; 1502*fa9e4066Sahrens int cb_fieldcount; 1503*fa9e4066Sahrens } list_cbdata_t; 1504*fa9e4066Sahrens 1505*fa9e4066Sahrens /* 1506*fa9e4066Sahrens * Given a list of columns to display, output appropriate headers for each one. 1507*fa9e4066Sahrens */ 1508*fa9e4066Sahrens void 1509*fa9e4066Sahrens print_header(int *fields, size_t count) 1510*fa9e4066Sahrens { 1511*fa9e4066Sahrens int i; 1512*fa9e4066Sahrens column_def_t *col; 1513*fa9e4066Sahrens const char *fmt; 1514*fa9e4066Sahrens 1515*fa9e4066Sahrens for (i = 0; i < count; i++) { 1516*fa9e4066Sahrens col = &column_table[fields[i]]; 1517*fa9e4066Sahrens if (i != 0) 1518*fa9e4066Sahrens (void) printf(" "); 1519*fa9e4066Sahrens if (col->cd_justify == left_justify) 1520*fa9e4066Sahrens fmt = "%-*s"; 1521*fa9e4066Sahrens else 1522*fa9e4066Sahrens fmt = "%*s"; 1523*fa9e4066Sahrens 1524*fa9e4066Sahrens (void) printf(fmt, i == count - 1 ? strlen(col->cd_title) : 1525*fa9e4066Sahrens col->cd_width, col->cd_title); 1526*fa9e4066Sahrens } 1527*fa9e4066Sahrens 1528*fa9e4066Sahrens (void) printf("\n"); 1529*fa9e4066Sahrens } 1530*fa9e4066Sahrens 1531*fa9e4066Sahrens int 1532*fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data) 1533*fa9e4066Sahrens { 1534*fa9e4066Sahrens list_cbdata_t *cbp = data; 1535*fa9e4066Sahrens nvlist_t *config; 1536*fa9e4066Sahrens int i; 1537*fa9e4066Sahrens char buf[ZPOOL_MAXNAMELEN]; 1538*fa9e4066Sahrens uint64_t total; 1539*fa9e4066Sahrens uint64_t used; 1540*fa9e4066Sahrens const char *fmt; 1541*fa9e4066Sahrens column_def_t *col; 1542*fa9e4066Sahrens 1543*fa9e4066Sahrens if (cbp->cb_first) { 1544*fa9e4066Sahrens if (!cbp->cb_scripted) 1545*fa9e4066Sahrens print_header(cbp->cb_fields, cbp->cb_fieldcount); 1546*fa9e4066Sahrens cbp->cb_first = FALSE; 1547*fa9e4066Sahrens } 1548*fa9e4066Sahrens 1549*fa9e4066Sahrens if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 1550*fa9e4066Sahrens config = NULL; 1551*fa9e4066Sahrens } else { 1552*fa9e4066Sahrens config = zpool_get_config(zhp); 1553*fa9e4066Sahrens total = zpool_get_space_total(zhp); 1554*fa9e4066Sahrens used = zpool_get_space_used(zhp); 1555*fa9e4066Sahrens } 1556*fa9e4066Sahrens 1557*fa9e4066Sahrens for (i = 0; i < cbp->cb_fieldcount; i++) { 1558*fa9e4066Sahrens if (i != 0) { 1559*fa9e4066Sahrens if (cbp->cb_scripted) 1560*fa9e4066Sahrens (void) printf("\t"); 1561*fa9e4066Sahrens else 1562*fa9e4066Sahrens (void) printf(" "); 1563*fa9e4066Sahrens } 1564*fa9e4066Sahrens 1565*fa9e4066Sahrens col = &column_table[cbp->cb_fields[i]]; 1566*fa9e4066Sahrens 1567*fa9e4066Sahrens switch (cbp->cb_fields[i]) { 1568*fa9e4066Sahrens case ZPOOL_FIELD_NAME: 1569*fa9e4066Sahrens (void) strlcpy(buf, zpool_get_name(zhp), sizeof (buf)); 1570*fa9e4066Sahrens break; 1571*fa9e4066Sahrens 1572*fa9e4066Sahrens case ZPOOL_FIELD_SIZE: 1573*fa9e4066Sahrens if (config == NULL) 1574*fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 1575*fa9e4066Sahrens else 1576*fa9e4066Sahrens zfs_nicenum(total, buf, sizeof (buf)); 1577*fa9e4066Sahrens break; 1578*fa9e4066Sahrens 1579*fa9e4066Sahrens case ZPOOL_FIELD_USED: 1580*fa9e4066Sahrens if (config == NULL) 1581*fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 1582*fa9e4066Sahrens else 1583*fa9e4066Sahrens zfs_nicenum(used, buf, sizeof (buf)); 1584*fa9e4066Sahrens break; 1585*fa9e4066Sahrens 1586*fa9e4066Sahrens case ZPOOL_FIELD_AVAILABLE: 1587*fa9e4066Sahrens if (config == NULL) 1588*fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 1589*fa9e4066Sahrens else 1590*fa9e4066Sahrens zfs_nicenum(total - used, buf, sizeof (buf)); 1591*fa9e4066Sahrens break; 1592*fa9e4066Sahrens 1593*fa9e4066Sahrens case ZPOOL_FIELD_CAPACITY: 1594*fa9e4066Sahrens if (config == NULL) { 1595*fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 1596*fa9e4066Sahrens } else { 1597*fa9e4066Sahrens uint64_t capacity = (total == 0 ? 0 : 1598*fa9e4066Sahrens (used * 100 / total)); 1599*fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%llu%%", 1600*fa9e4066Sahrens capacity); 1601*fa9e4066Sahrens } 1602*fa9e4066Sahrens break; 1603*fa9e4066Sahrens 1604*fa9e4066Sahrens case ZPOOL_FIELD_HEALTH: 1605*fa9e4066Sahrens if (config == NULL) { 1606*fa9e4066Sahrens (void) strlcpy(buf, "FAULTED", sizeof (buf)); 1607*fa9e4066Sahrens } else { 1608*fa9e4066Sahrens nvlist_t *nvroot; 1609*fa9e4066Sahrens vdev_stat_t *vs; 1610*fa9e4066Sahrens uint_t vsc; 1611*fa9e4066Sahrens 1612*fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, 1613*fa9e4066Sahrens ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 1614*fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, 1615*fa9e4066Sahrens ZPOOL_CONFIG_STATS, (uint64_t **)&vs, 1616*fa9e4066Sahrens &vsc) == 0); 1617*fa9e4066Sahrens (void) strlcpy(buf, state_to_name(vs->vs_state), 1618*fa9e4066Sahrens sizeof (buf)); 1619*fa9e4066Sahrens } 1620*fa9e4066Sahrens break; 1621*fa9e4066Sahrens 1622*fa9e4066Sahrens case ZPOOL_FIELD_ROOT: 1623*fa9e4066Sahrens if (config == NULL) 1624*fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 1625*fa9e4066Sahrens else if (zpool_get_root(zhp, buf, sizeof (buf)) != 0) 1626*fa9e4066Sahrens (void) strlcpy(buf, "-", sizeof (buf)); 1627*fa9e4066Sahrens break; 1628*fa9e4066Sahrens } 1629*fa9e4066Sahrens 1630*fa9e4066Sahrens if (cbp->cb_scripted) 1631*fa9e4066Sahrens (void) printf("%s", buf); 1632*fa9e4066Sahrens else { 1633*fa9e4066Sahrens if (col->cd_justify == left_justify) 1634*fa9e4066Sahrens fmt = "%-*s"; 1635*fa9e4066Sahrens else 1636*fa9e4066Sahrens fmt = "%*s"; 1637*fa9e4066Sahrens 1638*fa9e4066Sahrens (void) printf(fmt, i == cbp->cb_fieldcount - 1 ? 1639*fa9e4066Sahrens strlen(buf) : col->cd_width, buf); 1640*fa9e4066Sahrens } 1641*fa9e4066Sahrens } 1642*fa9e4066Sahrens 1643*fa9e4066Sahrens (void) printf("\n"); 1644*fa9e4066Sahrens 1645*fa9e4066Sahrens return (0); 1646*fa9e4066Sahrens } 1647*fa9e4066Sahrens 1648*fa9e4066Sahrens /* 1649*fa9e4066Sahrens * zpool list [-H] [-o field[,field]*] [pool] ... 1650*fa9e4066Sahrens * 1651*fa9e4066Sahrens * -H Scripted mode. Don't display headers, and separate fields by 1652*fa9e4066Sahrens * a single tab. 1653*fa9e4066Sahrens * -o List of fields to display. Defaults to all fields, or 1654*fa9e4066Sahrens * "name,size,used,available,capacity,health,root" 1655*fa9e4066Sahrens * 1656*fa9e4066Sahrens * List all pools in the system, whether or not they're healthy. Output space 1657*fa9e4066Sahrens * statistics for each one, as well as health status summary. 1658*fa9e4066Sahrens */ 1659*fa9e4066Sahrens int 1660*fa9e4066Sahrens zpool_do_list(int argc, char **argv) 1661*fa9e4066Sahrens { 1662*fa9e4066Sahrens int c; 1663*fa9e4066Sahrens int ret; 1664*fa9e4066Sahrens list_cbdata_t cb = { 0 }; 1665*fa9e4066Sahrens static char default_fields[] = 1666*fa9e4066Sahrens "name,size,used,available,capacity,health,root"; 1667*fa9e4066Sahrens char *fields = default_fields; 1668*fa9e4066Sahrens char *value; 1669*fa9e4066Sahrens 1670*fa9e4066Sahrens /* check options */ 1671*fa9e4066Sahrens while ((c = getopt(argc, argv, ":Ho:")) != -1) { 1672*fa9e4066Sahrens switch (c) { 1673*fa9e4066Sahrens case 'H': 1674*fa9e4066Sahrens cb.cb_scripted = TRUE; 1675*fa9e4066Sahrens break; 1676*fa9e4066Sahrens case 'o': 1677*fa9e4066Sahrens fields = optarg; 1678*fa9e4066Sahrens break; 1679*fa9e4066Sahrens case ':': 1680*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing argument for " 1681*fa9e4066Sahrens "'%c' option\n"), optopt); 1682*fa9e4066Sahrens usage(FALSE); 1683*fa9e4066Sahrens break; 1684*fa9e4066Sahrens case '?': 1685*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1686*fa9e4066Sahrens optopt); 1687*fa9e4066Sahrens usage(FALSE); 1688*fa9e4066Sahrens } 1689*fa9e4066Sahrens } 1690*fa9e4066Sahrens 1691*fa9e4066Sahrens argc -= optind; 1692*fa9e4066Sahrens argv += optind; 1693*fa9e4066Sahrens 1694*fa9e4066Sahrens while (*fields != '\0') { 1695*fa9e4066Sahrens if (cb.cb_fieldcount == MAX_FIELDS) { 1696*fa9e4066Sahrens (void) fprintf(stderr, gettext("too many " 1697*fa9e4066Sahrens "properties given to -o option\n")); 1698*fa9e4066Sahrens usage(FALSE); 1699*fa9e4066Sahrens } 1700*fa9e4066Sahrens 1701*fa9e4066Sahrens if ((cb.cb_fields[cb.cb_fieldcount] = getsubopt(&fields, 1702*fa9e4066Sahrens column_subopts, &value)) == -1) { 1703*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid property " 1704*fa9e4066Sahrens "'%s'\n"), value); 1705*fa9e4066Sahrens usage(FALSE); 1706*fa9e4066Sahrens } 1707*fa9e4066Sahrens 1708*fa9e4066Sahrens cb.cb_fieldcount++; 1709*fa9e4066Sahrens } 1710*fa9e4066Sahrens 1711*fa9e4066Sahrens 1712*fa9e4066Sahrens cb.cb_first = TRUE; 1713*fa9e4066Sahrens 1714*fa9e4066Sahrens ret = for_each_pool(argc, argv, TRUE, list_callback, &cb); 1715*fa9e4066Sahrens 1716*fa9e4066Sahrens if (argc == 0 && cb.cb_first) { 1717*fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 1718*fa9e4066Sahrens return (0); 1719*fa9e4066Sahrens } 1720*fa9e4066Sahrens 1721*fa9e4066Sahrens return (ret); 1722*fa9e4066Sahrens } 1723*fa9e4066Sahrens 1724*fa9e4066Sahrens static nvlist_t * 1725*fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name) 1726*fa9e4066Sahrens { 1727*fa9e4066Sahrens nvlist_t **child; 1728*fa9e4066Sahrens uint_t c, children; 1729*fa9e4066Sahrens nvlist_t *match; 1730*fa9e4066Sahrens char *path; 1731*fa9e4066Sahrens 1732*fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1733*fa9e4066Sahrens &child, &children) != 0) { 1734*fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 1735*fa9e4066Sahrens if (strncmp(name, "/dev/dsk/", 9) == 0) 1736*fa9e4066Sahrens name += 9; 1737*fa9e4066Sahrens if (strncmp(path, "/dev/dsk/", 9) == 0) 1738*fa9e4066Sahrens path += 9; 1739*fa9e4066Sahrens if (strcmp(name, path) == 0) 1740*fa9e4066Sahrens return (nv); 1741*fa9e4066Sahrens return (NULL); 1742*fa9e4066Sahrens } 1743*fa9e4066Sahrens 1744*fa9e4066Sahrens for (c = 0; c < children; c++) 1745*fa9e4066Sahrens if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 1746*fa9e4066Sahrens return (match); 1747*fa9e4066Sahrens 1748*fa9e4066Sahrens return (NULL); 1749*fa9e4066Sahrens } 1750*fa9e4066Sahrens 1751*fa9e4066Sahrens static int 1752*fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing) 1753*fa9e4066Sahrens { 1754*fa9e4066Sahrens int force = FALSE; 1755*fa9e4066Sahrens int c; 1756*fa9e4066Sahrens nvlist_t *nvroot; 1757*fa9e4066Sahrens char *poolname, *old_disk, *new_disk; 1758*fa9e4066Sahrens zpool_handle_t *zhp; 1759*fa9e4066Sahrens nvlist_t *config; 1760*fa9e4066Sahrens 1761*fa9e4066Sahrens /* check options */ 1762*fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 1763*fa9e4066Sahrens switch (c) { 1764*fa9e4066Sahrens case 'f': 1765*fa9e4066Sahrens force = TRUE; 1766*fa9e4066Sahrens break; 1767*fa9e4066Sahrens case '?': 1768*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1769*fa9e4066Sahrens optopt); 1770*fa9e4066Sahrens usage(FALSE); 1771*fa9e4066Sahrens } 1772*fa9e4066Sahrens } 1773*fa9e4066Sahrens 1774*fa9e4066Sahrens argc -= optind; 1775*fa9e4066Sahrens argv += optind; 1776*fa9e4066Sahrens 1777*fa9e4066Sahrens /* get pool name and check number of arguments */ 1778*fa9e4066Sahrens if (argc < 1) { 1779*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 1780*fa9e4066Sahrens usage(FALSE); 1781*fa9e4066Sahrens } 1782*fa9e4066Sahrens 1783*fa9e4066Sahrens poolname = argv[0]; 1784*fa9e4066Sahrens 1785*fa9e4066Sahrens if (argc < 2) { 1786*fa9e4066Sahrens (void) fprintf(stderr, 1787*fa9e4066Sahrens gettext("missing <device> specification\n")); 1788*fa9e4066Sahrens usage(FALSE); 1789*fa9e4066Sahrens } 1790*fa9e4066Sahrens 1791*fa9e4066Sahrens old_disk = argv[1]; 1792*fa9e4066Sahrens 1793*fa9e4066Sahrens if (argc < 3) { 1794*fa9e4066Sahrens if (!replacing) { 1795*fa9e4066Sahrens (void) fprintf(stderr, 1796*fa9e4066Sahrens gettext("missing <new_device> specification\n")); 1797*fa9e4066Sahrens usage(FALSE); 1798*fa9e4066Sahrens } 1799*fa9e4066Sahrens new_disk = old_disk; 1800*fa9e4066Sahrens argc -= 1; 1801*fa9e4066Sahrens argv += 1; 1802*fa9e4066Sahrens } else { 1803*fa9e4066Sahrens new_disk = argv[2]; 1804*fa9e4066Sahrens argc -= 2; 1805*fa9e4066Sahrens argv += 2; 1806*fa9e4066Sahrens } 1807*fa9e4066Sahrens 1808*fa9e4066Sahrens if (argc > 1) { 1809*fa9e4066Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 1810*fa9e4066Sahrens usage(FALSE); 1811*fa9e4066Sahrens } 1812*fa9e4066Sahrens 1813*fa9e4066Sahrens if ((zhp = zpool_open(poolname)) == NULL) 1814*fa9e4066Sahrens return (1); 1815*fa9e4066Sahrens 1816*fa9e4066Sahrens if ((config = zpool_get_config(zhp)) == NULL) { 1817*fa9e4066Sahrens (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 1818*fa9e4066Sahrens poolname); 1819*fa9e4066Sahrens zpool_close(zhp); 1820*fa9e4066Sahrens return (1); 1821*fa9e4066Sahrens } 1822*fa9e4066Sahrens 1823*fa9e4066Sahrens nvroot = make_root_vdev(config, force, B_FALSE, argc, argv); 1824*fa9e4066Sahrens if (nvroot == NULL) { 1825*fa9e4066Sahrens zpool_close(zhp); 1826*fa9e4066Sahrens return (1); 1827*fa9e4066Sahrens } 1828*fa9e4066Sahrens 1829*fa9e4066Sahrens return (zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing)); 1830*fa9e4066Sahrens } 1831*fa9e4066Sahrens 1832*fa9e4066Sahrens /* 1833*fa9e4066Sahrens * zpool replace [-f] <pool> <device> <new_device> 1834*fa9e4066Sahrens * 1835*fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 1836*fa9e4066Sahrens * 1837*fa9e4066Sahrens * Replace <device> with <new_device>. 1838*fa9e4066Sahrens */ 1839*fa9e4066Sahrens /* ARGSUSED */ 1840*fa9e4066Sahrens int 1841*fa9e4066Sahrens zpool_do_replace(int argc, char **argv) 1842*fa9e4066Sahrens { 1843*fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 1844*fa9e4066Sahrens } 1845*fa9e4066Sahrens 1846*fa9e4066Sahrens /* 1847*fa9e4066Sahrens * zpool attach [-f] <pool> <device> <new_device> 1848*fa9e4066Sahrens * 1849*fa9e4066Sahrens * -f Force attach, even if <new_device> appears to be in use. 1850*fa9e4066Sahrens * 1851*fa9e4066Sahrens * Attach <new_device> to the mirror containing <device>. If <device> is not 1852*fa9e4066Sahrens * part of a mirror, then <device> will be transformed into a mirror of 1853*fa9e4066Sahrens * <device> and <new_device>. In either case, <new_device> will begin life 1854*fa9e4066Sahrens * with a DTL of [0, now], and will immediately begin to resilver itself. 1855*fa9e4066Sahrens */ 1856*fa9e4066Sahrens int 1857*fa9e4066Sahrens zpool_do_attach(int argc, char **argv) 1858*fa9e4066Sahrens { 1859*fa9e4066Sahrens return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 1860*fa9e4066Sahrens } 1861*fa9e4066Sahrens 1862*fa9e4066Sahrens /* 1863*fa9e4066Sahrens * zpool detach [-f] <pool> <device> 1864*fa9e4066Sahrens * 1865*fa9e4066Sahrens * -f Force detach of <device>, even if DTLs argue against it 1866*fa9e4066Sahrens * (not supported yet) 1867*fa9e4066Sahrens * 1868*fa9e4066Sahrens * Detach a device from a mirror. The operation will be refused if <device> 1869*fa9e4066Sahrens * is the last device in the mirror, or if the DTLs indicate that this device 1870*fa9e4066Sahrens * has the only valid copy of some data. 1871*fa9e4066Sahrens */ 1872*fa9e4066Sahrens /* ARGSUSED */ 1873*fa9e4066Sahrens int 1874*fa9e4066Sahrens zpool_do_detach(int argc, char **argv) 1875*fa9e4066Sahrens { 1876*fa9e4066Sahrens int c; 1877*fa9e4066Sahrens char *poolname, *path; 1878*fa9e4066Sahrens zpool_handle_t *zhp; 1879*fa9e4066Sahrens 1880*fa9e4066Sahrens /* check options */ 1881*fa9e4066Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 1882*fa9e4066Sahrens switch (c) { 1883*fa9e4066Sahrens case 'f': 1884*fa9e4066Sahrens case '?': 1885*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1886*fa9e4066Sahrens optopt); 1887*fa9e4066Sahrens usage(FALSE); 1888*fa9e4066Sahrens } 1889*fa9e4066Sahrens } 1890*fa9e4066Sahrens 1891*fa9e4066Sahrens argc -= optind; 1892*fa9e4066Sahrens argv += optind; 1893*fa9e4066Sahrens 1894*fa9e4066Sahrens /* get pool name and check number of arguments */ 1895*fa9e4066Sahrens if (argc < 1) { 1896*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 1897*fa9e4066Sahrens usage(FALSE); 1898*fa9e4066Sahrens } 1899*fa9e4066Sahrens 1900*fa9e4066Sahrens if (argc < 2) { 1901*fa9e4066Sahrens (void) fprintf(stderr, 1902*fa9e4066Sahrens gettext("missing <device> specification\n")); 1903*fa9e4066Sahrens usage(FALSE); 1904*fa9e4066Sahrens } 1905*fa9e4066Sahrens 1906*fa9e4066Sahrens poolname = argv[0]; 1907*fa9e4066Sahrens path = argv[1]; 1908*fa9e4066Sahrens 1909*fa9e4066Sahrens if ((zhp = zpool_open(poolname)) == NULL) 1910*fa9e4066Sahrens return (1); 1911*fa9e4066Sahrens 1912*fa9e4066Sahrens return (zpool_vdev_detach(zhp, path)); 1913*fa9e4066Sahrens } 1914*fa9e4066Sahrens 1915*fa9e4066Sahrens /* 1916*fa9e4066Sahrens * zpool online [-t] <pool> <device> 1917*fa9e4066Sahrens * 1918*fa9e4066Sahrens * -t Only bring the device on-line temporarily. The online 1919*fa9e4066Sahrens * state will not be persistent across reboots. 1920*fa9e4066Sahrens */ 1921*fa9e4066Sahrens /* ARGSUSED */ 1922*fa9e4066Sahrens int 1923*fa9e4066Sahrens zpool_do_online(int argc, char **argv) 1924*fa9e4066Sahrens { 1925*fa9e4066Sahrens int c, i; 1926*fa9e4066Sahrens char *poolname; 1927*fa9e4066Sahrens zpool_handle_t *zhp; 1928*fa9e4066Sahrens int ret = 0; 1929*fa9e4066Sahrens 1930*fa9e4066Sahrens /* check options */ 1931*fa9e4066Sahrens while ((c = getopt(argc, argv, "t")) != -1) { 1932*fa9e4066Sahrens switch (c) { 1933*fa9e4066Sahrens case 't': 1934*fa9e4066Sahrens case '?': 1935*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1936*fa9e4066Sahrens optopt); 1937*fa9e4066Sahrens usage(FALSE); 1938*fa9e4066Sahrens } 1939*fa9e4066Sahrens } 1940*fa9e4066Sahrens 1941*fa9e4066Sahrens argc -= optind; 1942*fa9e4066Sahrens argv += optind; 1943*fa9e4066Sahrens 1944*fa9e4066Sahrens /* get pool name and check number of arguments */ 1945*fa9e4066Sahrens if (argc < 1) { 1946*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 1947*fa9e4066Sahrens usage(FALSE); 1948*fa9e4066Sahrens } 1949*fa9e4066Sahrens if (argc < 2) { 1950*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 1951*fa9e4066Sahrens usage(FALSE); 1952*fa9e4066Sahrens } 1953*fa9e4066Sahrens 1954*fa9e4066Sahrens poolname = argv[0]; 1955*fa9e4066Sahrens 1956*fa9e4066Sahrens if ((zhp = zpool_open(poolname)) == NULL) 1957*fa9e4066Sahrens return (1); 1958*fa9e4066Sahrens 1959*fa9e4066Sahrens for (i = 1; i < argc; i++) 1960*fa9e4066Sahrens if (zpool_vdev_online(zhp, argv[i]) == 0) 1961*fa9e4066Sahrens (void) printf(gettext("Bringing device %s online\n"), 1962*fa9e4066Sahrens argv[i]); 1963*fa9e4066Sahrens else 1964*fa9e4066Sahrens ret = 1; 1965*fa9e4066Sahrens 1966*fa9e4066Sahrens return (ret); 1967*fa9e4066Sahrens } 1968*fa9e4066Sahrens 1969*fa9e4066Sahrens /* 1970*fa9e4066Sahrens * zpool offline [-ft] <pool> <device> 1971*fa9e4066Sahrens * 1972*fa9e4066Sahrens * -f Force the device into the offline state, even if doing 1973*fa9e4066Sahrens * so would appear to compromise pool availability. 1974*fa9e4066Sahrens * (not supported yet) 1975*fa9e4066Sahrens * 1976*fa9e4066Sahrens * -t Only take the device off-line temporarily. The offline 1977*fa9e4066Sahrens * state will not be persistent across reboots. 1978*fa9e4066Sahrens * (not supported yet) 1979*fa9e4066Sahrens */ 1980*fa9e4066Sahrens /* ARGSUSED */ 1981*fa9e4066Sahrens int 1982*fa9e4066Sahrens zpool_do_offline(int argc, char **argv) 1983*fa9e4066Sahrens { 1984*fa9e4066Sahrens int c, i; 1985*fa9e4066Sahrens char *poolname; 1986*fa9e4066Sahrens zpool_handle_t *zhp; 1987*fa9e4066Sahrens int ret = 0; 1988*fa9e4066Sahrens 1989*fa9e4066Sahrens /* check options */ 1990*fa9e4066Sahrens while ((c = getopt(argc, argv, "ft")) != -1) { 1991*fa9e4066Sahrens switch (c) { 1992*fa9e4066Sahrens case 'f': 1993*fa9e4066Sahrens case 't': 1994*fa9e4066Sahrens case '?': 1995*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1996*fa9e4066Sahrens optopt); 1997*fa9e4066Sahrens usage(FALSE); 1998*fa9e4066Sahrens } 1999*fa9e4066Sahrens } 2000*fa9e4066Sahrens 2001*fa9e4066Sahrens argc -= optind; 2002*fa9e4066Sahrens argv += optind; 2003*fa9e4066Sahrens 2004*fa9e4066Sahrens /* get pool name and check number of arguments */ 2005*fa9e4066Sahrens if (argc < 1) { 2006*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name\n")); 2007*fa9e4066Sahrens usage(FALSE); 2008*fa9e4066Sahrens } 2009*fa9e4066Sahrens if (argc < 2) { 2010*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing device name\n")); 2011*fa9e4066Sahrens usage(FALSE); 2012*fa9e4066Sahrens } 2013*fa9e4066Sahrens 2014*fa9e4066Sahrens poolname = argv[0]; 2015*fa9e4066Sahrens 2016*fa9e4066Sahrens if ((zhp = zpool_open(poolname)) == NULL) 2017*fa9e4066Sahrens return (1); 2018*fa9e4066Sahrens 2019*fa9e4066Sahrens for (i = 1; i < argc; i++) 2020*fa9e4066Sahrens if (zpool_vdev_offline(zhp, argv[i]) == 0) 2021*fa9e4066Sahrens (void) printf(gettext("Bringing device %s offline\n"), 2022*fa9e4066Sahrens argv[i]); 2023*fa9e4066Sahrens else 2024*fa9e4066Sahrens ret = 1; 2025*fa9e4066Sahrens 2026*fa9e4066Sahrens return (ret); 2027*fa9e4066Sahrens } 2028*fa9e4066Sahrens 2029*fa9e4066Sahrens typedef struct scrub_cbdata { 2030*fa9e4066Sahrens int cb_type; 2031*fa9e4066Sahrens } scrub_cbdata_t; 2032*fa9e4066Sahrens 2033*fa9e4066Sahrens int 2034*fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data) 2035*fa9e4066Sahrens { 2036*fa9e4066Sahrens scrub_cbdata_t *cb = data; 2037*fa9e4066Sahrens 2038*fa9e4066Sahrens return (zpool_scrub(zhp, cb->cb_type) != 0); 2039*fa9e4066Sahrens } 2040*fa9e4066Sahrens 2041*fa9e4066Sahrens /* 2042*fa9e4066Sahrens * zpool scrub [-s] <pool> ... 2043*fa9e4066Sahrens * 2044*fa9e4066Sahrens * -s Stop. Stops any in-progress scrub. 2045*fa9e4066Sahrens */ 2046*fa9e4066Sahrens int 2047*fa9e4066Sahrens zpool_do_scrub(int argc, char **argv) 2048*fa9e4066Sahrens { 2049*fa9e4066Sahrens int c; 2050*fa9e4066Sahrens scrub_cbdata_t cb; 2051*fa9e4066Sahrens 2052*fa9e4066Sahrens cb.cb_type = POOL_SCRUB_EVERYTHING; 2053*fa9e4066Sahrens 2054*fa9e4066Sahrens /* check options */ 2055*fa9e4066Sahrens while ((c = getopt(argc, argv, "s")) != -1) { 2056*fa9e4066Sahrens switch (c) { 2057*fa9e4066Sahrens case 's': 2058*fa9e4066Sahrens cb.cb_type = POOL_SCRUB_NONE; 2059*fa9e4066Sahrens break; 2060*fa9e4066Sahrens case '?': 2061*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2062*fa9e4066Sahrens optopt); 2063*fa9e4066Sahrens usage(FALSE); 2064*fa9e4066Sahrens } 2065*fa9e4066Sahrens } 2066*fa9e4066Sahrens 2067*fa9e4066Sahrens argc -= optind; 2068*fa9e4066Sahrens argv += optind; 2069*fa9e4066Sahrens 2070*fa9e4066Sahrens if (argc < 1) { 2071*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing pool name argument\n")); 2072*fa9e4066Sahrens usage(FALSE); 2073*fa9e4066Sahrens } 2074*fa9e4066Sahrens 2075*fa9e4066Sahrens return (for_each_pool(argc, argv, TRUE, scrub_callback, &cb)); 2076*fa9e4066Sahrens } 2077*fa9e4066Sahrens 2078*fa9e4066Sahrens typedef struct status_cbdata { 2079*fa9e4066Sahrens int cb_verbose; 2080*fa9e4066Sahrens int cb_explain; 2081*fa9e4066Sahrens int cb_count; 2082*fa9e4066Sahrens int cb_first; 2083*fa9e4066Sahrens } status_cbdata_t; 2084*fa9e4066Sahrens 2085*fa9e4066Sahrens /* 2086*fa9e4066Sahrens * Print out detailed scrub status. 2087*fa9e4066Sahrens */ 2088*fa9e4066Sahrens void 2089*fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot) 2090*fa9e4066Sahrens { 2091*fa9e4066Sahrens vdev_stat_t *vs; 2092*fa9e4066Sahrens uint_t vsc; 2093*fa9e4066Sahrens time_t start, end, now; 2094*fa9e4066Sahrens double fraction_done; 2095*fa9e4066Sahrens uint64_t examined, total, minutes_left; 2096*fa9e4066Sahrens char *scrub_type; 2097*fa9e4066Sahrens 2098*fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2099*fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 2100*fa9e4066Sahrens 2101*fa9e4066Sahrens /* 2102*fa9e4066Sahrens * If there's never been a scrub, there's not much to say. 2103*fa9e4066Sahrens */ 2104*fa9e4066Sahrens if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2105*fa9e4066Sahrens (void) printf(gettext("none requested\n")); 2106*fa9e4066Sahrens return; 2107*fa9e4066Sahrens } 2108*fa9e4066Sahrens 2109*fa9e4066Sahrens scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2110*fa9e4066Sahrens "resilver" : "scrub"; 2111*fa9e4066Sahrens 2112*fa9e4066Sahrens start = vs->vs_scrub_start; 2113*fa9e4066Sahrens end = vs->vs_scrub_end; 2114*fa9e4066Sahrens now = time(NULL); 2115*fa9e4066Sahrens examined = vs->vs_scrub_examined; 2116*fa9e4066Sahrens total = vs->vs_alloc; 2117*fa9e4066Sahrens 2118*fa9e4066Sahrens if (end != 0) { 2119*fa9e4066Sahrens (void) printf(gettext("%s %s with %llu errors on %s"), 2120*fa9e4066Sahrens scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 2121*fa9e4066Sahrens (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2122*fa9e4066Sahrens return; 2123*fa9e4066Sahrens } 2124*fa9e4066Sahrens 2125*fa9e4066Sahrens if (examined == 0) 2126*fa9e4066Sahrens examined = 1; 2127*fa9e4066Sahrens if (examined > total) 2128*fa9e4066Sahrens total = examined; 2129*fa9e4066Sahrens 2130*fa9e4066Sahrens fraction_done = (double)examined / total; 2131*fa9e4066Sahrens minutes_left = (uint64_t)((now - start) * 2132*fa9e4066Sahrens (1 - fraction_done) / fraction_done / 60); 2133*fa9e4066Sahrens 2134*fa9e4066Sahrens (void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"), 2135*fa9e4066Sahrens scrub_type, 100 * fraction_done, 2136*fa9e4066Sahrens (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2137*fa9e4066Sahrens } 2138*fa9e4066Sahrens 2139*fa9e4066Sahrens /* 2140*fa9e4066Sahrens * Print out configuration state as requested by status_callback. 2141*fa9e4066Sahrens */ 2142*fa9e4066Sahrens void 2143*fa9e4066Sahrens print_status_config(const char *name, nvlist_t *nv, int namewidth, int depth) 2144*fa9e4066Sahrens { 2145*fa9e4066Sahrens nvlist_t **child; 2146*fa9e4066Sahrens uint_t c, children; 2147*fa9e4066Sahrens vdev_stat_t *vs; 2148*fa9e4066Sahrens char rbuf[6], wbuf[6], cbuf[6], repaired[6]; 2149*fa9e4066Sahrens 2150*fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2151*fa9e4066Sahrens (uint64_t **)&vs, &c) == 0); 2152*fa9e4066Sahrens 2153*fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2154*fa9e4066Sahrens &child, &children) != 0) 2155*fa9e4066Sahrens children = 0; 2156*fa9e4066Sahrens 2157*fa9e4066Sahrens (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 2158*fa9e4066Sahrens name, state_to_name(vs->vs_state)); 2159*fa9e4066Sahrens 2160*fa9e4066Sahrens zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 2161*fa9e4066Sahrens zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 2162*fa9e4066Sahrens zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 2163*fa9e4066Sahrens (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 2164*fa9e4066Sahrens 2165*fa9e4066Sahrens if (vs->vs_aux != 0) { 2166*fa9e4066Sahrens (void) printf(" "); 2167*fa9e4066Sahrens 2168*fa9e4066Sahrens switch (vs->vs_aux) { 2169*fa9e4066Sahrens case VDEV_AUX_OPEN_FAILED: 2170*fa9e4066Sahrens (void) printf(gettext("cannot open")); 2171*fa9e4066Sahrens break; 2172*fa9e4066Sahrens 2173*fa9e4066Sahrens case VDEV_AUX_BAD_GUID_SUM: 2174*fa9e4066Sahrens (void) printf(gettext("missing device")); 2175*fa9e4066Sahrens break; 2176*fa9e4066Sahrens 2177*fa9e4066Sahrens case VDEV_AUX_NO_REPLICAS: 2178*fa9e4066Sahrens (void) printf(gettext("insufficient replicas")); 2179*fa9e4066Sahrens break; 2180*fa9e4066Sahrens 2181*fa9e4066Sahrens default: 2182*fa9e4066Sahrens (void) printf(gettext("corrupted data")); 2183*fa9e4066Sahrens break; 2184*fa9e4066Sahrens } 2185*fa9e4066Sahrens } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2186*fa9e4066Sahrens /* 2187*fa9e4066Sahrens * Report bytes resilvered/repaired on leaf devices. 2188*fa9e4066Sahrens */ 2189*fa9e4066Sahrens zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2190*fa9e4066Sahrens (void) printf(gettext(" %s %s"), repaired, 2191*fa9e4066Sahrens (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2192*fa9e4066Sahrens "resilvered" : "repaired"); 2193*fa9e4066Sahrens } 2194*fa9e4066Sahrens 2195*fa9e4066Sahrens (void) printf("\n"); 2196*fa9e4066Sahrens 2197*fa9e4066Sahrens for (c = 0; c < children; c++) 2198*fa9e4066Sahrens print_status_config(vdev_get_name(child[c]), child[c], 2199*fa9e4066Sahrens namewidth, depth + 2); 2200*fa9e4066Sahrens } 2201*fa9e4066Sahrens 2202*fa9e4066Sahrens /* 2203*fa9e4066Sahrens * Display a summary of pool status. Displays a summary such as: 2204*fa9e4066Sahrens * 2205*fa9e4066Sahrens * pool: tank 2206*fa9e4066Sahrens * status: DEGRADED 2207*fa9e4066Sahrens * reason: One or more devices ... 2208*fa9e4066Sahrens * see: http://www.sun.com/msg/ZFS-xxxx-01 2209*fa9e4066Sahrens * config: 2210*fa9e4066Sahrens * mirror DEGRADED 2211*fa9e4066Sahrens * c1t0d0 OK 2212*fa9e4066Sahrens * c2t0d0 FAULTED 2213*fa9e4066Sahrens * 2214*fa9e4066Sahrens * When given the '-v' option, we print out the complete config. If the '-e' 2215*fa9e4066Sahrens * option is specified, then we print out error rate information as well. 2216*fa9e4066Sahrens */ 2217*fa9e4066Sahrens int 2218*fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data) 2219*fa9e4066Sahrens { 2220*fa9e4066Sahrens status_cbdata_t *cbp = data; 2221*fa9e4066Sahrens nvlist_t *config, *nvroot; 2222*fa9e4066Sahrens char *msgid; 2223*fa9e4066Sahrens int reason; 2224*fa9e4066Sahrens char *health; 2225*fa9e4066Sahrens 2226*fa9e4066Sahrens config = zpool_get_config(zhp); 2227*fa9e4066Sahrens reason = zpool_get_status(zhp, &msgid); 2228*fa9e4066Sahrens 2229*fa9e4066Sahrens cbp->cb_count++; 2230*fa9e4066Sahrens 2231*fa9e4066Sahrens /* 2232*fa9e4066Sahrens * If we were given 'zpool status -x', only report those pools with 2233*fa9e4066Sahrens * problems. 2234*fa9e4066Sahrens */ 2235*fa9e4066Sahrens if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) 2236*fa9e4066Sahrens return (0); 2237*fa9e4066Sahrens 2238*fa9e4066Sahrens if (cbp->cb_first) 2239*fa9e4066Sahrens cbp->cb_first = FALSE; 2240*fa9e4066Sahrens else 2241*fa9e4066Sahrens (void) printf("\n"); 2242*fa9e4066Sahrens 2243*fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_HEALTH, 2244*fa9e4066Sahrens &health) == 0); 2245*fa9e4066Sahrens 2246*fa9e4066Sahrens (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 2247*fa9e4066Sahrens (void) printf(gettext(" state: %s\n"), health); 2248*fa9e4066Sahrens 2249*fa9e4066Sahrens switch (reason) { 2250*fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_R: 2251*fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2252*fa9e4066Sahrens "be opened. Sufficient replicas exist for\n\tthe pool to " 2253*fa9e4066Sahrens "continue functioning in a degraded state.\n")); 2254*fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2255*fa9e4066Sahrens "online it using 'zpool online'.\n")); 2256*fa9e4066Sahrens break; 2257*fa9e4066Sahrens 2258*fa9e4066Sahrens case ZPOOL_STATUS_MISSING_DEV_NR: 2259*fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2260*fa9e4066Sahrens "be opened. There are insufficient\n\treplicas for the " 2261*fa9e4066Sahrens "pool to continue functioning.\n")); 2262*fa9e4066Sahrens (void) printf(gettext("action: Attach the missing device and " 2263*fa9e4066Sahrens "online it using 'zpool online'.\n")); 2264*fa9e4066Sahrens break; 2265*fa9e4066Sahrens 2266*fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_R: 2267*fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2268*fa9e4066Sahrens "be used because the label is missing or\n\tinvalid. " 2269*fa9e4066Sahrens "Sufficient replicas exist for the pool to continue\n\t" 2270*fa9e4066Sahrens "functioning in a degraded state.\n")); 2271*fa9e4066Sahrens (void) printf(gettext("action: Replace the device using " 2272*fa9e4066Sahrens "'zpool replace'.\n")); 2273*fa9e4066Sahrens break; 2274*fa9e4066Sahrens 2275*fa9e4066Sahrens case ZPOOL_STATUS_CORRUPT_LABEL_NR: 2276*fa9e4066Sahrens (void) printf(gettext("status: One or more devices could not " 2277*fa9e4066Sahrens "be used because the the label is missing \n\tor invalid. " 2278*fa9e4066Sahrens "There are insufficient replicas for the pool to " 2279*fa9e4066Sahrens "continue\n\tfunctioning.\n")); 2280*fa9e4066Sahrens (void) printf(gettext("action: Destroy and re-create the pool " 2281*fa9e4066Sahrens "from a backup source.\n")); 2282*fa9e4066Sahrens break; 2283*fa9e4066Sahrens 2284*fa9e4066Sahrens case ZPOOL_STATUS_FAILING_DEV: 2285*fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2286*fa9e4066Sahrens "experienced an unrecoverable error. An\n\tattempt was " 2287*fa9e4066Sahrens "made to correct the error. Applications are " 2288*fa9e4066Sahrens "unaffected.\n")); 2289*fa9e4066Sahrens (void) printf(gettext("action: Determine if the device needs " 2290*fa9e4066Sahrens "to be replaced, and clear the errors\n\tusing " 2291*fa9e4066Sahrens "'zpool online' or replace the device with 'zpool " 2292*fa9e4066Sahrens "replace'.\n")); 2293*fa9e4066Sahrens break; 2294*fa9e4066Sahrens 2295*fa9e4066Sahrens case ZPOOL_STATUS_OFFLINE_DEV: 2296*fa9e4066Sahrens (void) printf(gettext("status: One or more devices has " 2297*fa9e4066Sahrens "been taken offline by the adminstrator.\n\tSufficient " 2298*fa9e4066Sahrens "replicas exist for the pool to continue functioning in " 2299*fa9e4066Sahrens "a\n\tdegraded state.\n")); 2300*fa9e4066Sahrens (void) printf(gettext("action: Online the device using " 2301*fa9e4066Sahrens "'zpool online' or replace the device with\n\t'zpool " 2302*fa9e4066Sahrens "replace'.\n")); 2303*fa9e4066Sahrens break; 2304*fa9e4066Sahrens 2305*fa9e4066Sahrens case ZPOOL_STATUS_RESILVERING: 2306*fa9e4066Sahrens (void) printf(gettext("status: One or more devices is " 2307*fa9e4066Sahrens "currently being resilvered. The pool will\n\tcontinue " 2308*fa9e4066Sahrens "to function, possibly in a degraded state.\n")); 2309*fa9e4066Sahrens (void) printf(gettext("action: Wait for the resilver to " 2310*fa9e4066Sahrens "complete.\n")); 2311*fa9e4066Sahrens break; 2312*fa9e4066Sahrens 2313*fa9e4066Sahrens default: 2314*fa9e4066Sahrens /* 2315*fa9e4066Sahrens * The remaining errors can't actually be generated, yet. 2316*fa9e4066Sahrens */ 2317*fa9e4066Sahrens assert(reason == ZPOOL_STATUS_OK); 2318*fa9e4066Sahrens } 2319*fa9e4066Sahrens 2320*fa9e4066Sahrens if (msgid != NULL) 2321*fa9e4066Sahrens (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 2322*fa9e4066Sahrens msgid); 2323*fa9e4066Sahrens 2324*fa9e4066Sahrens if (config != NULL) { 2325*fa9e4066Sahrens int namewidth; 2326*fa9e4066Sahrens 2327*fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2328*fa9e4066Sahrens &nvroot) == 0); 2329*fa9e4066Sahrens 2330*fa9e4066Sahrens (void) printf(gettext(" scrub: ")); 2331*fa9e4066Sahrens print_scrub_status(nvroot); 2332*fa9e4066Sahrens 2333*fa9e4066Sahrens namewidth = max_width(nvroot, 0, 0); 2334*fa9e4066Sahrens if (namewidth < 10) 2335*fa9e4066Sahrens namewidth = 10; 2336*fa9e4066Sahrens 2337*fa9e4066Sahrens (void) printf(gettext("config:\n\n")); 2338*fa9e4066Sahrens (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 2339*fa9e4066Sahrens "NAME", "STATE", "READ", "WRITE", "CKSUM"); 2340*fa9e4066Sahrens print_status_config(zpool_get_name(zhp), nvroot, namewidth, 0); 2341*fa9e4066Sahrens } else { 2342*fa9e4066Sahrens (void) printf(gettext("config: The configuration cannot be " 2343*fa9e4066Sahrens "determined.\n")); 2344*fa9e4066Sahrens } 2345*fa9e4066Sahrens 2346*fa9e4066Sahrens return (0); 2347*fa9e4066Sahrens } 2348*fa9e4066Sahrens 2349*fa9e4066Sahrens /* 2350*fa9e4066Sahrens * zpool status [-vx] [pool] ... 2351*fa9e4066Sahrens * 2352*fa9e4066Sahrens * -v Display complete error logs 2353*fa9e4066Sahrens * -x Display only pools with potential problems 2354*fa9e4066Sahrens * 2355*fa9e4066Sahrens * Describes the health status of all pools or some subset. 2356*fa9e4066Sahrens */ 2357*fa9e4066Sahrens int 2358*fa9e4066Sahrens zpool_do_status(int argc, char **argv) 2359*fa9e4066Sahrens { 2360*fa9e4066Sahrens int c; 2361*fa9e4066Sahrens int ret; 2362*fa9e4066Sahrens status_cbdata_t cb = { 0 }; 2363*fa9e4066Sahrens 2364*fa9e4066Sahrens /* check options */ 2365*fa9e4066Sahrens while ((c = getopt(argc, argv, "vx")) != -1) { 2366*fa9e4066Sahrens switch (c) { 2367*fa9e4066Sahrens case 'v': 2368*fa9e4066Sahrens cb.cb_verbose = TRUE; 2369*fa9e4066Sahrens break; 2370*fa9e4066Sahrens case 'x': 2371*fa9e4066Sahrens cb.cb_explain = TRUE; 2372*fa9e4066Sahrens break; 2373*fa9e4066Sahrens case '?': 2374*fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2375*fa9e4066Sahrens optopt); 2376*fa9e4066Sahrens usage(FALSE); 2377*fa9e4066Sahrens } 2378*fa9e4066Sahrens } 2379*fa9e4066Sahrens 2380*fa9e4066Sahrens argc -= optind; 2381*fa9e4066Sahrens argv += optind; 2382*fa9e4066Sahrens 2383*fa9e4066Sahrens cb.cb_first = TRUE; 2384*fa9e4066Sahrens 2385*fa9e4066Sahrens ret = for_each_pool(argc, argv, TRUE, status_callback, &cb); 2386*fa9e4066Sahrens 2387*fa9e4066Sahrens if (argc == 0 && cb.cb_count == 0) 2388*fa9e4066Sahrens (void) printf(gettext("no pools available\n")); 2389*fa9e4066Sahrens else if (cb.cb_explain && cb.cb_first) { 2390*fa9e4066Sahrens if (argc == 0) { 2391*fa9e4066Sahrens (void) printf(gettext("all pools are healthy\n")); 2392*fa9e4066Sahrens } else { 2393*fa9e4066Sahrens int i; 2394*fa9e4066Sahrens for (i = 0; i < argc; i++) 2395*fa9e4066Sahrens (void) printf(gettext("pool '%s' is healthy\n"), 2396*fa9e4066Sahrens argv[i]); 2397*fa9e4066Sahrens } 2398*fa9e4066Sahrens } 2399*fa9e4066Sahrens 2400*fa9e4066Sahrens return (ret); 2401*fa9e4066Sahrens } 2402*fa9e4066Sahrens 2403*fa9e4066Sahrens int 2404*fa9e4066Sahrens main(int argc, char **argv) 2405*fa9e4066Sahrens { 2406*fa9e4066Sahrens int ret; 2407*fa9e4066Sahrens int i; 2408*fa9e4066Sahrens char *cmdname; 2409*fa9e4066Sahrens 2410*fa9e4066Sahrens (void) setlocale(LC_ALL, ""); 2411*fa9e4066Sahrens (void) textdomain(TEXT_DOMAIN); 2412*fa9e4066Sahrens 2413*fa9e4066Sahrens opterr = 0; 2414*fa9e4066Sahrens 2415*fa9e4066Sahrens /* 2416*fa9e4066Sahrens * Make sure the user has specified some command. 2417*fa9e4066Sahrens */ 2418*fa9e4066Sahrens if (argc < 2) { 2419*fa9e4066Sahrens (void) fprintf(stderr, gettext("missing command\n")); 2420*fa9e4066Sahrens usage(FALSE); 2421*fa9e4066Sahrens } 2422*fa9e4066Sahrens 2423*fa9e4066Sahrens cmdname = argv[1]; 2424*fa9e4066Sahrens 2425*fa9e4066Sahrens /* 2426*fa9e4066Sahrens * Special case '-?' 2427*fa9e4066Sahrens */ 2428*fa9e4066Sahrens if (strcmp(cmdname, "-?") == 0) 2429*fa9e4066Sahrens usage(TRUE); 2430*fa9e4066Sahrens 2431*fa9e4066Sahrens /* 2432*fa9e4066Sahrens * Run the appropriate command. 2433*fa9e4066Sahrens */ 2434*fa9e4066Sahrens for (i = 0; i < NCOMMAND; i++) { 2435*fa9e4066Sahrens if (command_table[i].name == NULL) 2436*fa9e4066Sahrens continue; 2437*fa9e4066Sahrens 2438*fa9e4066Sahrens if (strcmp(cmdname, command_table[i].name) == 0) { 2439*fa9e4066Sahrens current_command = &command_table[i]; 2440*fa9e4066Sahrens ret = command_table[i].func(argc - 1, argv + 1); 2441*fa9e4066Sahrens break; 2442*fa9e4066Sahrens } 2443*fa9e4066Sahrens } 2444*fa9e4066Sahrens 2445*fa9e4066Sahrens /* 2446*fa9e4066Sahrens * 'freeze' is a vile debugging abomination, so we treat it as such. 2447*fa9e4066Sahrens */ 2448*fa9e4066Sahrens if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 2449*fa9e4066Sahrens char buf[8192]; 2450*fa9e4066Sahrens int fd = open("/dev/zpoolctl", O_RDWR); 2451*fa9e4066Sahrens (void) strcpy((void *)buf, argv[2]); 2452*fa9e4066Sahrens return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 2453*fa9e4066Sahrens } 2454*fa9e4066Sahrens 2455*fa9e4066Sahrens if (i == NCOMMAND) { 2456*fa9e4066Sahrens (void) fprintf(stderr, gettext("unrecognized " 2457*fa9e4066Sahrens "command '%s'\n"), cmdname); 2458*fa9e4066Sahrens usage(FALSE); 2459*fa9e4066Sahrens } 2460*fa9e4066Sahrens 2461*fa9e4066Sahrens /* 2462*fa9e4066Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 2463*fa9e4066Sahrens * for the purposes of running ::findleaks. 2464*fa9e4066Sahrens */ 2465*fa9e4066Sahrens if (getenv("ZFS_ABORT") != NULL) { 2466*fa9e4066Sahrens (void) printf("dumping core by request\n"); 2467*fa9e4066Sahrens abort(); 2468*fa9e4066Sahrens } 2469*fa9e4066Sahrens 2470*fa9e4066Sahrens return (ret); 2471*fa9e4066Sahrens } 2472