1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <assert.h> 30 #include <ctype.h> 31 #include <dirent.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <libgen.h> 35 #include <libintl.h> 36 #include <libuutil.h> 37 #include <locale.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <strings.h> 42 #include <unistd.h> 43 #include <priv.h> 44 #include <sys/fs/zfs.h> 45 46 #include <sys/stat.h> 47 48 #include <libzfs.h> 49 50 #include "zpool_util.h" 51 52 static int zpool_do_create(int, char **); 53 static int zpool_do_destroy(int, char **); 54 55 static int zpool_do_add(int, char **); 56 static int zpool_do_remove(int, char **); 57 58 static int zpool_do_list(int, char **); 59 static int zpool_do_iostat(int, char **); 60 static int zpool_do_status(int, char **); 61 62 static int zpool_do_online(int, char **); 63 static int zpool_do_offline(int, char **); 64 static int zpool_do_clear(int, char **); 65 66 static int zpool_do_attach(int, char **); 67 static int zpool_do_detach(int, char **); 68 static int zpool_do_replace(int, char **); 69 70 static int zpool_do_scrub(int, char **); 71 72 static int zpool_do_import(int, char **); 73 static int zpool_do_export(int, char **); 74 75 static int zpool_do_upgrade(int, char **); 76 77 static int zpool_do_history(int, char **); 78 79 static int zpool_do_get(int, char **); 80 static int zpool_do_set(int, char **); 81 82 /* 83 * These libumem hooks provide a reasonable set of defaults for the allocator's 84 * debugging facilities. 85 */ 86 const char * 87 _umem_debug_init(void) 88 { 89 return ("default,verbose"); /* $UMEM_DEBUG setting */ 90 } 91 92 const char * 93 _umem_logging_init(void) 94 { 95 return ("fail,contents"); /* $UMEM_LOGGING setting */ 96 } 97 98 typedef enum { 99 HELP_ADD, 100 HELP_ATTACH, 101 HELP_CLEAR, 102 HELP_CREATE, 103 HELP_DESTROY, 104 HELP_DETACH, 105 HELP_EXPORT, 106 HELP_HISTORY, 107 HELP_IMPORT, 108 HELP_IOSTAT, 109 HELP_LIST, 110 HELP_OFFLINE, 111 HELP_ONLINE, 112 HELP_REPLACE, 113 HELP_REMOVE, 114 HELP_SCRUB, 115 HELP_STATUS, 116 HELP_UPGRADE, 117 HELP_GET, 118 HELP_SET 119 } zpool_help_t; 120 121 122 typedef struct zpool_command { 123 const char *name; 124 int (*func)(int, char **); 125 zpool_help_t usage; 126 } zpool_command_t; 127 128 /* 129 * Master command table. Each ZFS command has a name, associated function, and 130 * usage message. The usage messages need to be internationalized, so we have 131 * to have a function to return the usage message based on a command index. 132 * 133 * These commands are organized according to how they are displayed in the usage 134 * message. An empty command (one with a NULL name) indicates an empty line in 135 * the generic usage message. 136 */ 137 static zpool_command_t command_table[] = { 138 { "create", zpool_do_create, HELP_CREATE }, 139 { "destroy", zpool_do_destroy, HELP_DESTROY }, 140 { NULL }, 141 { "add", zpool_do_add, HELP_ADD }, 142 { "remove", zpool_do_remove, HELP_REMOVE }, 143 { NULL }, 144 { "list", zpool_do_list, HELP_LIST }, 145 { "iostat", zpool_do_iostat, HELP_IOSTAT }, 146 { "status", zpool_do_status, HELP_STATUS }, 147 { NULL }, 148 { "online", zpool_do_online, HELP_ONLINE }, 149 { "offline", zpool_do_offline, HELP_OFFLINE }, 150 { "clear", zpool_do_clear, HELP_CLEAR }, 151 { NULL }, 152 { "attach", zpool_do_attach, HELP_ATTACH }, 153 { "detach", zpool_do_detach, HELP_DETACH }, 154 { "replace", zpool_do_replace, HELP_REPLACE }, 155 { NULL }, 156 { "scrub", zpool_do_scrub, HELP_SCRUB }, 157 { NULL }, 158 { "import", zpool_do_import, HELP_IMPORT }, 159 { "export", zpool_do_export, HELP_EXPORT }, 160 { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 161 { NULL }, 162 { "history", zpool_do_history, HELP_HISTORY }, 163 { "get", zpool_do_get, HELP_GET }, 164 { "set", zpool_do_set, HELP_SET }, 165 }; 166 167 #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 168 169 zpool_command_t *current_command; 170 171 static const char * 172 get_usage(zpool_help_t idx) { 173 switch (idx) { 174 case HELP_ADD: 175 return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 176 case HELP_ATTACH: 177 return (gettext("\tattach [-f] <pool> <device> " 178 "<new_device>\n")); 179 case HELP_CLEAR: 180 return (gettext("\tclear <pool> [device]\n")); 181 case HELP_CREATE: 182 return (gettext("\tcreate [-fn] [-R root] [-m mountpoint] " 183 "<pool> <vdev> ...\n")); 184 case HELP_DESTROY: 185 return (gettext("\tdestroy [-f] <pool>\n")); 186 case HELP_DETACH: 187 return (gettext("\tdetach <pool> <device>\n")); 188 case HELP_EXPORT: 189 return (gettext("\texport [-f] <pool> ...\n")); 190 case HELP_HISTORY: 191 return (gettext("\thistory [<pool>]\n")); 192 case HELP_IMPORT: 193 return (gettext("\timport [-d dir] [-D]\n" 194 "\timport [-d dir] [-D] [-f] [-o opts] [-R root] -a\n" 195 "\timport [-d dir] [-D] [-f] [-o opts] [-R root ]" 196 " <pool | id> [newpool]\n")); 197 case HELP_IOSTAT: 198 return (gettext("\tiostat [-v] [pool] ... [interval " 199 "[count]]\n")); 200 case HELP_LIST: 201 return (gettext("\tlist [-H] [-o field[,field]*] " 202 "[pool] ...\n")); 203 case HELP_OFFLINE: 204 return (gettext("\toffline [-t] <pool> <device> ...\n")); 205 case HELP_ONLINE: 206 return (gettext("\tonline <pool> <device> ...\n")); 207 case HELP_REPLACE: 208 return (gettext("\treplace [-f] <pool> <device> " 209 "[new_device]\n")); 210 case HELP_REMOVE: 211 return (gettext("\tremove <pool> <device>\n")); 212 case HELP_SCRUB: 213 return (gettext("\tscrub [-s] <pool> ...\n")); 214 case HELP_STATUS: 215 return (gettext("\tstatus [-vx] [pool] ...\n")); 216 case HELP_UPGRADE: 217 return (gettext("\tupgrade\n" 218 "\tupgrade -v\n" 219 "\tupgrade <-a | pool>\n")); 220 case HELP_GET: 221 return (gettext("\tget <all | property[,property]...> " 222 "<pool> ...\n")); 223 case HELP_SET: 224 return (gettext("\tset <property=value> <pool> \n")); 225 } 226 227 abort(); 228 /* NOTREACHED */ 229 } 230 231 /* 232 * Fields available for 'zpool list'. 233 */ 234 typedef enum { 235 ZPOOL_FIELD_NAME, 236 ZPOOL_FIELD_SIZE, 237 ZPOOL_FIELD_USED, 238 ZPOOL_FIELD_AVAILABLE, 239 ZPOOL_FIELD_CAPACITY, 240 ZPOOL_FIELD_HEALTH, 241 ZPOOL_FIELD_ROOT 242 } zpool_field_t; 243 244 #define MAX_FIELDS 10 245 246 typedef struct column_def { 247 const char *cd_title; 248 size_t cd_width; 249 enum { 250 left_justify, 251 right_justify 252 } cd_justify; 253 } column_def_t; 254 255 static column_def_t column_table[] = { 256 { "NAME", 20, left_justify }, 257 { "SIZE", 6, right_justify }, 258 { "USED", 6, right_justify }, 259 { "AVAIL", 6, right_justify }, 260 { "CAP", 5, right_justify }, 261 { "HEALTH", 9, left_justify }, 262 { "ALTROOT", 15, left_justify } 263 }; 264 265 static char *column_subopts[] = { 266 "name", 267 "size", 268 "used", 269 "available", 270 "capacity", 271 "health", 272 "root", 273 NULL 274 }; 275 276 /* 277 * Callback routine that will print out a pool property value. 278 */ 279 static zpool_prop_t 280 print_prop_cb(zpool_prop_t prop, void *cb) 281 { 282 FILE *fp = cb; 283 284 (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 285 286 if (zpool_prop_values(prop) == NULL) 287 (void) fprintf(fp, "-\n"); 288 else 289 (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 290 291 return (ZFS_PROP_CONT); 292 } 293 294 /* 295 * Display usage message. If we're inside a command, display only the usage for 296 * that command. Otherwise, iterate over the entire command table and display 297 * a complete usage message. 298 */ 299 void 300 usage(boolean_t requested) 301 { 302 int i; 303 FILE *fp = requested ? stdout : stderr; 304 305 if (current_command == NULL) { 306 int i; 307 308 (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 309 (void) fprintf(fp, 310 gettext("where 'command' is one of the following:\n\n")); 311 312 for (i = 0; i < NCOMMAND; i++) { 313 if (command_table[i].name == NULL) 314 (void) fprintf(fp, "\n"); 315 else 316 (void) fprintf(fp, "%s", 317 get_usage(command_table[i].usage)); 318 } 319 } else { 320 (void) fprintf(fp, gettext("usage:\n")); 321 (void) fprintf(fp, "%s", get_usage(current_command->usage)); 322 323 if (strcmp(current_command->name, "list") == 0) { 324 (void) fprintf(fp, gettext("\nwhere 'field' is one " 325 "of the following:\n\n")); 326 327 for (i = 0; column_subopts[i] != NULL; i++) 328 (void) fprintf(fp, "\t%s\n", column_subopts[i]); 329 } 330 } 331 332 if (current_command != NULL && 333 ((strcmp(current_command->name, "set") == 0) || 334 (strcmp(current_command->name, "get") == 0))) { 335 336 (void) fprintf(fp, 337 gettext("\nthe following properties are supported:\n")); 338 339 (void) fprintf(fp, "\n\t%-13s %s\n\n", 340 "PROPERTY", "VALUES"); 341 342 /* Iterate over all properties */ 343 (void) zpool_prop_iter(print_prop_cb, fp, B_FALSE); 344 } 345 346 /* 347 * See comments at end of main(). 348 */ 349 if (getenv("ZFS_ABORT") != NULL) { 350 (void) printf("dumping core by request\n"); 351 abort(); 352 } 353 354 exit(requested ? 0 : 2); 355 } 356 357 const char * 358 state_to_health(int vs_state) 359 { 360 switch (vs_state) { 361 case VDEV_STATE_CLOSED: 362 case VDEV_STATE_CANT_OPEN: 363 case VDEV_STATE_OFFLINE: 364 return (dgettext(TEXT_DOMAIN, "FAULTED")); 365 case VDEV_STATE_DEGRADED: 366 return (dgettext(TEXT_DOMAIN, "DEGRADED")); 367 case VDEV_STATE_HEALTHY: 368 return (dgettext(TEXT_DOMAIN, "ONLINE")); 369 } 370 371 return (dgettext(TEXT_DOMAIN, "UNKNOWN")); 372 } 373 374 const char * 375 state_to_name(vdev_stat_t *vs) 376 { 377 switch (vs->vs_state) { 378 case VDEV_STATE_CLOSED: 379 case VDEV_STATE_CANT_OPEN: 380 if (vs->vs_aux == VDEV_AUX_CORRUPT_DATA) 381 return (gettext("FAULTED")); 382 else 383 return (gettext("UNAVAIL")); 384 case VDEV_STATE_OFFLINE: 385 return (gettext("OFFLINE")); 386 case VDEV_STATE_REMOVED: 387 return (gettext("REMOVED")); 388 case VDEV_STATE_FAULTED: 389 return (gettext("FAULTED")); 390 case VDEV_STATE_DEGRADED: 391 return (gettext("DEGRADED")); 392 case VDEV_STATE_HEALTHY: 393 return (gettext("ONLINE")); 394 } 395 396 return (gettext("UNKNOWN")); 397 } 398 399 void 400 print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent) 401 { 402 nvlist_t **child; 403 uint_t c, children; 404 char *vname; 405 406 if (name != NULL) 407 (void) printf("\t%*s%s\n", indent, "", name); 408 409 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 410 &child, &children) != 0) 411 return; 412 413 for (c = 0; c < children; c++) { 414 vname = zpool_vdev_name(g_zfs, zhp, child[c]); 415 print_vdev_tree(zhp, vname, child[c], indent + 2); 416 free(vname); 417 } 418 } 419 420 /* 421 * zpool add [-fn] <pool> <vdev> ... 422 * 423 * -f Force addition of devices, even if they appear in use 424 * -n Do not add the devices, but display the resulting layout if 425 * they were to be added. 426 * 427 * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 428 * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 429 * libzfs. 430 */ 431 int 432 zpool_do_add(int argc, char **argv) 433 { 434 boolean_t force = B_FALSE; 435 boolean_t dryrun = B_FALSE; 436 int c; 437 nvlist_t *nvroot; 438 char *poolname; 439 int ret; 440 zpool_handle_t *zhp; 441 nvlist_t *config; 442 443 /* check options */ 444 while ((c = getopt(argc, argv, "fn")) != -1) { 445 switch (c) { 446 case 'f': 447 force = B_TRUE; 448 break; 449 case 'n': 450 dryrun = B_TRUE; 451 break; 452 case '?': 453 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 454 optopt); 455 usage(B_FALSE); 456 } 457 } 458 459 argc -= optind; 460 argv += optind; 461 462 /* get pool name and check number of arguments */ 463 if (argc < 1) { 464 (void) fprintf(stderr, gettext("missing pool name argument\n")); 465 usage(B_FALSE); 466 } 467 if (argc < 2) { 468 (void) fprintf(stderr, gettext("missing vdev specification\n")); 469 usage(B_FALSE); 470 } 471 472 poolname = argv[0]; 473 474 argc--; 475 argv++; 476 477 if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 478 return (1); 479 480 if ((config = zpool_get_config(zhp, NULL)) == NULL) { 481 (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 482 poolname); 483 zpool_close(zhp); 484 return (1); 485 } 486 487 /* pass off to get_vdev_spec for processing */ 488 nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv); 489 if (nvroot == NULL) { 490 zpool_close(zhp); 491 return (1); 492 } 493 494 if (dryrun) { 495 nvlist_t *poolnvroot; 496 497 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 498 &poolnvroot) == 0); 499 500 (void) printf(gettext("would update '%s' to the following " 501 "configuration:\n"), zpool_get_name(zhp)); 502 503 print_vdev_tree(zhp, poolname, poolnvroot, 0); 504 print_vdev_tree(zhp, NULL, nvroot, 0); 505 506 ret = 0; 507 } else { 508 ret = (zpool_add(zhp, nvroot) != 0); 509 if (!ret) { 510 zpool_log_history(g_zfs, argc + 1 + optind, 511 argv - 1 - optind, poolname, B_TRUE, B_FALSE); 512 } 513 } 514 515 nvlist_free(nvroot); 516 zpool_close(zhp); 517 518 return (ret); 519 } 520 521 /* 522 * zpool remove <pool> <vdev> 523 * 524 * Removes the given vdev from the pool. Currently, this only supports removing 525 * spares from the pool. Eventually, we'll want to support removing leaf vdevs 526 * (as an alias for 'detach') as well as toplevel vdevs. 527 */ 528 int 529 zpool_do_remove(int argc, char **argv) 530 { 531 char *poolname; 532 int ret; 533 zpool_handle_t *zhp; 534 535 argc--; 536 argv++; 537 538 /* get pool name and check number of arguments */ 539 if (argc < 1) { 540 (void) fprintf(stderr, gettext("missing pool name argument\n")); 541 usage(B_FALSE); 542 } 543 if (argc < 2) { 544 (void) fprintf(stderr, gettext("missing device\n")); 545 usage(B_FALSE); 546 } 547 548 poolname = argv[0]; 549 550 if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 551 return (1); 552 553 ret = (zpool_vdev_remove(zhp, argv[1]) != 0); 554 if (!ret) { 555 zpool_log_history(g_zfs, ++argc, --argv, poolname, B_TRUE, 556 B_FALSE); 557 } 558 559 return (ret); 560 } 561 562 /* 563 * zpool create [-fn] [-R root] [-m mountpoint] <pool> <dev> ... 564 * 565 * -f Force creation, even if devices appear in use 566 * -n Do not create the pool, but display the resulting layout if it 567 * were to be created. 568 * -R Create a pool under an alternate root 569 * -m Set default mountpoint for the root dataset. By default it's 570 * '/<pool>' 571 * 572 * Creates the named pool according to the given vdev specification. The 573 * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 574 * we get the nvlist back from get_vdev_spec(), we either print out the contents 575 * (if '-n' was specified), or pass it to libzfs to do the creation. 576 */ 577 int 578 zpool_do_create(int argc, char **argv) 579 { 580 boolean_t force = B_FALSE; 581 boolean_t dryrun = B_FALSE; 582 int c; 583 nvlist_t *nvroot; 584 char *poolname; 585 int ret; 586 char *altroot = NULL; 587 char *mountpoint = NULL; 588 nvlist_t **child; 589 uint_t children; 590 591 /* check options */ 592 while ((c = getopt(argc, argv, ":fnR:m:")) != -1) { 593 switch (c) { 594 case 'f': 595 force = B_TRUE; 596 break; 597 case 'n': 598 dryrun = B_TRUE; 599 break; 600 case 'R': 601 altroot = optarg; 602 break; 603 case 'm': 604 mountpoint = optarg; 605 break; 606 case ':': 607 (void) fprintf(stderr, gettext("missing argument for " 608 "'%c' option\n"), optopt); 609 usage(B_FALSE); 610 break; 611 case '?': 612 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 613 optopt); 614 usage(B_FALSE); 615 } 616 } 617 618 argc -= optind; 619 argv += optind; 620 621 /* get pool name and check number of arguments */ 622 if (argc < 1) { 623 (void) fprintf(stderr, gettext("missing pool name argument\n")); 624 usage(B_FALSE); 625 } 626 if (argc < 2) { 627 (void) fprintf(stderr, gettext("missing vdev specification\n")); 628 usage(B_FALSE); 629 } 630 631 poolname = argv[0]; 632 633 /* 634 * As a special case, check for use of '/' in the name, and direct the 635 * user to use 'zfs create' instead. 636 */ 637 if (strchr(poolname, '/') != NULL) { 638 (void) fprintf(stderr, gettext("cannot create '%s': invalid " 639 "character '/' in pool name\n"), poolname); 640 (void) fprintf(stderr, gettext("use 'zfs create' to " 641 "create a dataset\n")); 642 return (1); 643 } 644 645 /* pass off to get_vdev_spec for bulk processing */ 646 nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1, 647 argv + 1); 648 if (nvroot == NULL) 649 return (1); 650 651 /* make_root_vdev() allows 0 toplevel children if there are spares */ 652 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 653 &child, &children) == 0); 654 if (children == 0) { 655 (void) fprintf(stderr, gettext("invalid vdev " 656 "specification: at least one toplevel vdev must be " 657 "specified\n")); 658 return (1); 659 } 660 661 662 if (altroot != NULL && altroot[0] != '/') { 663 (void) fprintf(stderr, gettext("invalid alternate root '%s': " 664 "must be an absolute path\n"), altroot); 665 nvlist_free(nvroot); 666 return (1); 667 } 668 669 /* 670 * Check the validity of the mountpoint and direct the user to use the 671 * '-m' mountpoint option if it looks like its in use. 672 */ 673 if (mountpoint == NULL || 674 (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 675 strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 676 char buf[MAXPATHLEN]; 677 struct stat64 statbuf; 678 679 if (mountpoint && mountpoint[0] != '/') { 680 (void) fprintf(stderr, gettext("invalid mountpoint " 681 "'%s': must be an absolute path, 'legacy', or " 682 "'none'\n"), mountpoint); 683 nvlist_free(nvroot); 684 return (1); 685 } 686 687 if (mountpoint == NULL) { 688 if (altroot != NULL) 689 (void) snprintf(buf, sizeof (buf), "%s/%s", 690 altroot, poolname); 691 else 692 (void) snprintf(buf, sizeof (buf), "/%s", 693 poolname); 694 } else { 695 if (altroot != NULL) 696 (void) snprintf(buf, sizeof (buf), "%s%s", 697 altroot, mountpoint); 698 else 699 (void) snprintf(buf, sizeof (buf), "%s", 700 mountpoint); 701 } 702 703 if (stat64(buf, &statbuf) == 0 && 704 statbuf.st_nlink != 2) { 705 if (mountpoint == NULL) 706 (void) fprintf(stderr, gettext("default " 707 "mountpoint '%s' exists and is not " 708 "empty\n"), buf); 709 else 710 (void) fprintf(stderr, gettext("mountpoint " 711 "'%s' exists and is not empty\n"), buf); 712 (void) fprintf(stderr, gettext("use '-m' " 713 "option to provide a different default\n")); 714 nvlist_free(nvroot); 715 return (1); 716 } 717 } 718 719 720 if (dryrun) { 721 /* 722 * For a dry run invocation, print out a basic message and run 723 * through all the vdevs in the list and print out in an 724 * appropriate hierarchy. 725 */ 726 (void) printf(gettext("would create '%s' with the " 727 "following layout:\n\n"), poolname); 728 729 print_vdev_tree(NULL, poolname, nvroot, 0); 730 731 ret = 0; 732 } else { 733 ret = 1; 734 /* 735 * Hand off to libzfs. 736 */ 737 if (zpool_create(g_zfs, poolname, nvroot, altroot) == 0) { 738 zfs_handle_t *pool = zfs_open(g_zfs, poolname, 739 ZFS_TYPE_FILESYSTEM); 740 if (pool != NULL) { 741 if (mountpoint != NULL) 742 verify(zfs_prop_set(pool, 743 zfs_prop_to_name( 744 ZFS_PROP_MOUNTPOINT), 745 mountpoint) == 0); 746 if (zfs_mount(pool, NULL, 0) == 0) 747 ret = zfs_share_nfs(pool); 748 zfs_close(pool); 749 } 750 zpool_log_history(g_zfs, argc + optind, argv - optind, 751 poolname, B_TRUE, B_TRUE); 752 } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 753 (void) fprintf(stderr, gettext("pool name may have " 754 "been omitted\n")); 755 } 756 } 757 758 nvlist_free(nvroot); 759 760 return (ret); 761 } 762 763 /* 764 * zpool destroy <pool> 765 * 766 * -f Forcefully unmount any datasets 767 * 768 * Destroy the given pool. Automatically unmounts any datasets in the pool. 769 */ 770 int 771 zpool_do_destroy(int argc, char **argv) 772 { 773 boolean_t force = B_FALSE; 774 int c; 775 char *pool; 776 zpool_handle_t *zhp; 777 int ret; 778 779 /* check options */ 780 while ((c = getopt(argc, argv, "f")) != -1) { 781 switch (c) { 782 case 'f': 783 force = B_TRUE; 784 break; 785 case '?': 786 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 787 optopt); 788 usage(B_FALSE); 789 } 790 } 791 792 argc -= optind; 793 argv += optind; 794 795 /* check arguments */ 796 if (argc < 1) { 797 (void) fprintf(stderr, gettext("missing pool argument\n")); 798 usage(B_FALSE); 799 } 800 if (argc > 1) { 801 (void) fprintf(stderr, gettext("too many arguments\n")); 802 usage(B_FALSE); 803 } 804 805 pool = argv[0]; 806 807 if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 808 /* 809 * As a special case, check for use of '/' in the name, and 810 * direct the user to use 'zfs destroy' instead. 811 */ 812 if (strchr(pool, '/') != NULL) 813 (void) fprintf(stderr, gettext("use 'zfs destroy' to " 814 "destroy a dataset\n")); 815 return (1); 816 } 817 818 if (zpool_disable_datasets(zhp, force) != 0) { 819 (void) fprintf(stderr, gettext("could not destroy '%s': " 820 "could not unmount datasets\n"), zpool_get_name(zhp)); 821 return (1); 822 } 823 824 zpool_log_history(g_zfs, argc + optind, argv - optind, pool, B_TRUE, 825 B_FALSE); 826 827 ret = (zpool_destroy(zhp) != 0); 828 829 zpool_close(zhp); 830 831 return (ret); 832 } 833 834 /* 835 * zpool export [-f] <pool> ... 836 * 837 * -f Forcefully unmount datasets 838 * 839 * Export the given pools. By default, the command will attempt to cleanly 840 * unmount any active datasets within the pool. If the '-f' flag is specified, 841 * then the datasets will be forcefully unmounted. 842 */ 843 int 844 zpool_do_export(int argc, char **argv) 845 { 846 boolean_t force = B_FALSE; 847 int c; 848 zpool_handle_t *zhp; 849 int ret; 850 int i; 851 852 /* check options */ 853 while ((c = getopt(argc, argv, "f")) != -1) { 854 switch (c) { 855 case 'f': 856 force = B_TRUE; 857 break; 858 case '?': 859 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 860 optopt); 861 usage(B_FALSE); 862 } 863 } 864 865 argc -= optind; 866 argv += optind; 867 868 /* check arguments */ 869 if (argc < 1) { 870 (void) fprintf(stderr, gettext("missing pool argument\n")); 871 usage(B_FALSE); 872 } 873 874 ret = 0; 875 for (i = 0; i < argc; i++) { 876 if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 877 ret = 1; 878 continue; 879 } 880 881 if (zpool_disable_datasets(zhp, force) != 0) { 882 ret = 1; 883 zpool_close(zhp); 884 continue; 885 } 886 887 zpool_log_history(g_zfs, argc + optind, argv - optind, argv[i], 888 B_TRUE, B_FALSE); 889 890 if (zpool_export(zhp) != 0) 891 ret = 1; 892 893 zpool_close(zhp); 894 } 895 896 return (ret); 897 } 898 899 /* 900 * Given a vdev configuration, determine the maximum width needed for the device 901 * name column. 902 */ 903 static int 904 max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 905 { 906 char *name = zpool_vdev_name(g_zfs, zhp, nv); 907 nvlist_t **child; 908 uint_t c, children; 909 int ret; 910 911 if (strlen(name) + depth > max) 912 max = strlen(name) + depth; 913 914 free(name); 915 916 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 917 &child, &children) == 0) { 918 for (c = 0; c < children; c++) 919 if ((ret = max_width(zhp, child[c], depth + 2, 920 max)) > max) 921 max = ret; 922 } 923 924 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 925 &child, &children) == 0) { 926 for (c = 0; c < children; c++) 927 if ((ret = max_width(zhp, child[c], depth + 2, 928 max)) > max) 929 max = ret; 930 } 931 932 933 return (max); 934 } 935 936 937 /* 938 * Print the configuration of an exported pool. Iterate over all vdevs in the 939 * pool, printing out the name and status for each one. 940 */ 941 void 942 print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 943 { 944 nvlist_t **child; 945 uint_t c, children; 946 vdev_stat_t *vs; 947 char *type, *vname; 948 949 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 950 if (strcmp(type, VDEV_TYPE_MISSING) == 0) 951 return; 952 953 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 954 (uint64_t **)&vs, &c) == 0); 955 956 (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 957 (void) printf(" %s", state_to_name(vs)); 958 959 if (vs->vs_aux != 0) { 960 (void) printf(" "); 961 962 switch (vs->vs_aux) { 963 case VDEV_AUX_OPEN_FAILED: 964 (void) printf(gettext("cannot open")); 965 break; 966 967 case VDEV_AUX_BAD_GUID_SUM: 968 (void) printf(gettext("missing device")); 969 break; 970 971 case VDEV_AUX_NO_REPLICAS: 972 (void) printf(gettext("insufficient replicas")); 973 break; 974 975 case VDEV_AUX_VERSION_NEWER: 976 (void) printf(gettext("newer version")); 977 break; 978 979 case VDEV_AUX_ERR_EXCEEDED: 980 (void) printf(gettext("too many errors")); 981 break; 982 983 default: 984 (void) printf(gettext("corrupted data")); 985 break; 986 } 987 } 988 (void) printf("\n"); 989 990 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 991 &child, &children) != 0) 992 return; 993 994 for (c = 0; c < children; c++) { 995 vname = zpool_vdev_name(g_zfs, NULL, child[c]); 996 print_import_config(vname, child[c], 997 namewidth, depth + 2); 998 free(vname); 999 } 1000 1001 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1002 &child, &children) != 0) 1003 return; 1004 1005 (void) printf(gettext("\tspares\n")); 1006 for (c = 0; c < children; c++) { 1007 vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1008 (void) printf("\t %s\n", vname); 1009 free(vname); 1010 } 1011 } 1012 1013 /* 1014 * Display the status for the given pool. 1015 */ 1016 static void 1017 show_import(nvlist_t *config) 1018 { 1019 uint64_t pool_state; 1020 vdev_stat_t *vs; 1021 char *name; 1022 uint64_t guid; 1023 char *msgid; 1024 nvlist_t *nvroot; 1025 int reason; 1026 const char *health; 1027 uint_t vsc; 1028 int namewidth; 1029 1030 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1031 &name) == 0); 1032 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1033 &guid) == 0); 1034 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1035 &pool_state) == 0); 1036 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1037 &nvroot) == 0); 1038 1039 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1040 (uint64_t **)&vs, &vsc) == 0); 1041 health = state_to_health(vs->vs_state); 1042 1043 reason = zpool_import_status(config, &msgid); 1044 1045 (void) printf(gettext(" pool: %s\n"), name); 1046 (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1047 (void) printf(gettext(" state: %s"), health); 1048 if (pool_state == POOL_STATE_DESTROYED) 1049 (void) printf(gettext(" (DESTROYED)")); 1050 (void) printf("\n"); 1051 1052 switch (reason) { 1053 case ZPOOL_STATUS_MISSING_DEV_R: 1054 case ZPOOL_STATUS_MISSING_DEV_NR: 1055 case ZPOOL_STATUS_BAD_GUID_SUM: 1056 (void) printf(gettext("status: One or more devices are missing " 1057 "from the system.\n")); 1058 break; 1059 1060 case ZPOOL_STATUS_CORRUPT_LABEL_R: 1061 case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1062 (void) printf(gettext("status: One or more devices contains " 1063 "corrupted data.\n")); 1064 break; 1065 1066 case ZPOOL_STATUS_CORRUPT_DATA: 1067 (void) printf(gettext("status: The pool data is corrupted.\n")); 1068 break; 1069 1070 case ZPOOL_STATUS_OFFLINE_DEV: 1071 (void) printf(gettext("status: One or more devices " 1072 "are offlined.\n")); 1073 break; 1074 1075 case ZPOOL_STATUS_CORRUPT_POOL: 1076 (void) printf(gettext("status: The pool metadata is " 1077 "corrupted.\n")); 1078 break; 1079 1080 case ZPOOL_STATUS_VERSION_OLDER: 1081 (void) printf(gettext("status: The pool is formatted using an " 1082 "older on-disk version.\n")); 1083 break; 1084 1085 case ZPOOL_STATUS_VERSION_NEWER: 1086 (void) printf(gettext("status: The pool is formatted using an " 1087 "incompatible version.\n")); 1088 break; 1089 case ZPOOL_STATUS_HOSTID_MISMATCH: 1090 (void) printf(gettext("status: The pool was last accessed by " 1091 "another system.\n")); 1092 break; 1093 case ZPOOL_STATUS_FAULTED_DEV_R: 1094 case ZPOOL_STATUS_FAULTED_DEV_NR: 1095 (void) printf(gettext("status: One or more devices are " 1096 "faulted.\n")); 1097 break; 1098 1099 default: 1100 /* 1101 * No other status can be seen when importing pools. 1102 */ 1103 assert(reason == ZPOOL_STATUS_OK); 1104 } 1105 1106 /* 1107 * Print out an action according to the overall state of the pool. 1108 */ 1109 if (vs->vs_state == VDEV_STATE_HEALTHY) { 1110 if (reason == ZPOOL_STATUS_VERSION_OLDER) 1111 (void) printf(gettext("action: The pool can be " 1112 "imported using its name or numeric identifier, " 1113 "though\n\tsome features will not be available " 1114 "without an explicit 'zpool upgrade'.\n")); 1115 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 1116 (void) printf(gettext("action: The pool can be " 1117 "imported using its name or numeric " 1118 "identifier and\n\tthe '-f' flag.\n")); 1119 else 1120 (void) printf(gettext("action: The pool can be " 1121 "imported using its name or numeric " 1122 "identifier.\n")); 1123 } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1124 (void) printf(gettext("action: The pool can be imported " 1125 "despite missing or damaged devices. The\n\tfault " 1126 "tolerance of the pool may be compromised if imported.\n")); 1127 } else { 1128 switch (reason) { 1129 case ZPOOL_STATUS_VERSION_NEWER: 1130 (void) printf(gettext("action: The pool cannot be " 1131 "imported. Access the pool on a system running " 1132 "newer\n\tsoftware, or recreate the pool from " 1133 "backup.\n")); 1134 break; 1135 case ZPOOL_STATUS_MISSING_DEV_R: 1136 case ZPOOL_STATUS_MISSING_DEV_NR: 1137 case ZPOOL_STATUS_BAD_GUID_SUM: 1138 (void) printf(gettext("action: The pool cannot be " 1139 "imported. Attach the missing\n\tdevices and try " 1140 "again.\n")); 1141 break; 1142 default: 1143 (void) printf(gettext("action: The pool cannot be " 1144 "imported due to damaged devices or data.\n")); 1145 } 1146 } 1147 1148 /* 1149 * If the state is "closed" or "can't open", and the aux state 1150 * is "corrupt data": 1151 */ 1152 if (((vs->vs_state == VDEV_STATE_CLOSED) || 1153 (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1154 (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1155 if (pool_state == POOL_STATE_DESTROYED) 1156 (void) printf(gettext("\tThe pool was destroyed, " 1157 "but can be imported using the '-Df' flags.\n")); 1158 else if (pool_state != POOL_STATE_EXPORTED) 1159 (void) printf(gettext("\tThe pool may be active on " 1160 "on another system, but can be imported using\n\t" 1161 "the '-f' flag.\n")); 1162 } 1163 1164 if (msgid != NULL) 1165 (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1166 msgid); 1167 1168 (void) printf(gettext("config:\n\n")); 1169 1170 namewidth = max_width(NULL, nvroot, 0, 0); 1171 if (namewidth < 10) 1172 namewidth = 10; 1173 print_import_config(name, nvroot, namewidth, 0); 1174 1175 if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1176 (void) printf(gettext("\n\tAdditional devices are known to " 1177 "be part of this pool, though their\n\texact " 1178 "configuration cannot be determined.\n")); 1179 } 1180 } 1181 1182 /* 1183 * Perform the import for the given configuration. This passes the heavy 1184 * lifting off to zpool_import(), and then mounts the datasets contained within 1185 * the pool. 1186 */ 1187 static int 1188 do_import(nvlist_t *config, const char *newname, const char *mntopts, 1189 const char *altroot, int force, int argc, char **argv) 1190 { 1191 zpool_handle_t *zhp; 1192 char *name; 1193 uint64_t state; 1194 uint64_t version; 1195 1196 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1197 &name) == 0); 1198 1199 verify(nvlist_lookup_uint64(config, 1200 ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1201 verify(nvlist_lookup_uint64(config, 1202 ZPOOL_CONFIG_VERSION, &version) == 0); 1203 if (version > ZFS_VERSION) { 1204 (void) fprintf(stderr, gettext("cannot import '%s': pool " 1205 "is formatted using a newer ZFS version\n"), name); 1206 return (1); 1207 } else if (state != POOL_STATE_EXPORTED && !force) { 1208 uint64_t hostid; 1209 1210 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1211 &hostid) == 0) { 1212 if ((unsigned long)hostid != gethostid()) { 1213 char *hostname; 1214 uint64_t timestamp; 1215 time_t t; 1216 1217 verify(nvlist_lookup_string(config, 1218 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1219 verify(nvlist_lookup_uint64(config, 1220 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1221 t = timestamp; 1222 (void) fprintf(stderr, gettext("cannot import " 1223 "'%s': pool may be in use from other " 1224 "system, it was last accessed by %s " 1225 "(hostid: 0x%lx) on %s"), name, hostname, 1226 (unsigned long)hostid, 1227 asctime(localtime(&t))); 1228 (void) fprintf(stderr, gettext("use '-f' to " 1229 "import anyway\n")); 1230 return (1); 1231 } 1232 } else { 1233 (void) fprintf(stderr, gettext("cannot import '%s': " 1234 "pool may be in use from other system\n"), name); 1235 (void) fprintf(stderr, gettext("use '-f' to import " 1236 "anyway\n")); 1237 return (1); 1238 } 1239 } 1240 1241 if (zpool_import(g_zfs, config, newname, altroot) != 0) 1242 return (1); 1243 1244 if (newname != NULL) 1245 name = (char *)newname; 1246 1247 zpool_log_history(g_zfs, argc, argv, name, B_TRUE, B_FALSE); 1248 1249 verify((zhp = zpool_open(g_zfs, name)) != NULL); 1250 1251 if (zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1252 zpool_close(zhp); 1253 return (1); 1254 } 1255 1256 zpool_close(zhp); 1257 return (0); 1258 } 1259 1260 /* 1261 * zpool import [-d dir] [-D] 1262 * import [-R root] [-D] [-d dir] [-f] -a 1263 * import [-R root] [-D] [-d dir] [-f] <pool | id> [newpool] 1264 * 1265 * -d Scan in a specific directory, other than /dev/dsk. More than 1266 * one directory can be specified using multiple '-d' options. 1267 * 1268 * -D Scan for previously destroyed pools or import all or only 1269 * specified destroyed pools. 1270 * 1271 * -R Temporarily import the pool, with all mountpoints relative to 1272 * the given root. The pool will remain exported when the machine 1273 * is rebooted. 1274 * 1275 * -f Force import, even if it appears that the pool is active. 1276 * 1277 * -a Import all pools found. 1278 * 1279 * The import command scans for pools to import, and import pools based on pool 1280 * name and GUID. The pool can also be renamed as part of the import process. 1281 */ 1282 int 1283 zpool_do_import(int argc, char **argv) 1284 { 1285 char **searchdirs = NULL; 1286 int nsearch = 0; 1287 int c; 1288 int err; 1289 nvlist_t *pools; 1290 boolean_t do_all = B_FALSE; 1291 boolean_t do_destroyed = B_FALSE; 1292 char *altroot = NULL; 1293 char *mntopts = NULL; 1294 boolean_t do_force = B_FALSE; 1295 nvpair_t *elem; 1296 nvlist_t *config; 1297 uint64_t searchguid; 1298 char *searchname; 1299 nvlist_t *found_config; 1300 boolean_t first; 1301 uint64_t pool_state; 1302 1303 /* check options */ 1304 while ((c = getopt(argc, argv, ":Dfd:R:ao:")) != -1) { 1305 switch (c) { 1306 case 'a': 1307 do_all = B_TRUE; 1308 break; 1309 case 'd': 1310 if (searchdirs == NULL) { 1311 searchdirs = safe_malloc(sizeof (char *)); 1312 } else { 1313 char **tmp = safe_malloc((nsearch + 1) * 1314 sizeof (char *)); 1315 bcopy(searchdirs, tmp, nsearch * 1316 sizeof (char *)); 1317 free(searchdirs); 1318 searchdirs = tmp; 1319 } 1320 searchdirs[nsearch++] = optarg; 1321 break; 1322 case 'D': 1323 do_destroyed = B_TRUE; 1324 break; 1325 case 'f': 1326 do_force = B_TRUE; 1327 break; 1328 case 'o': 1329 mntopts = optarg; 1330 break; 1331 case 'R': 1332 altroot = optarg; 1333 break; 1334 case ':': 1335 (void) fprintf(stderr, gettext("missing argument for " 1336 "'%c' option\n"), optopt); 1337 usage(B_FALSE); 1338 break; 1339 case '?': 1340 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1341 optopt); 1342 usage(B_FALSE); 1343 } 1344 } 1345 1346 argc -= optind; 1347 argv += optind; 1348 1349 if (searchdirs == NULL) { 1350 searchdirs = safe_malloc(sizeof (char *)); 1351 searchdirs[0] = "/dev/dsk"; 1352 nsearch = 1; 1353 } 1354 1355 /* check argument count */ 1356 if (do_all) { 1357 if (argc != 0) { 1358 (void) fprintf(stderr, gettext("too many arguments\n")); 1359 usage(B_FALSE); 1360 } 1361 } else { 1362 if (argc > 2) { 1363 (void) fprintf(stderr, gettext("too many arguments\n")); 1364 usage(B_FALSE); 1365 } 1366 1367 /* 1368 * Check for the SYS_CONFIG privilege. We do this explicitly 1369 * here because otherwise any attempt to discover pools will 1370 * silently fail. 1371 */ 1372 if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1373 (void) fprintf(stderr, gettext("cannot " 1374 "discover pools: permission denied\n")); 1375 free(searchdirs); 1376 return (1); 1377 } 1378 } 1379 1380 if ((pools = zpool_find_import(g_zfs, nsearch, searchdirs)) == NULL) { 1381 free(searchdirs); 1382 return (1); 1383 } 1384 1385 /* 1386 * We now have a list of all available pools in the given directories. 1387 * Depending on the arguments given, we do one of the following: 1388 * 1389 * <none> Iterate through all pools and display information about 1390 * each one. 1391 * 1392 * -a Iterate through all pools and try to import each one. 1393 * 1394 * <id> Find the pool that corresponds to the given GUID/pool 1395 * name and import that one. 1396 * 1397 * -D Above options applies only to destroyed pools. 1398 */ 1399 if (argc != 0) { 1400 char *endptr; 1401 1402 errno = 0; 1403 searchguid = strtoull(argv[0], &endptr, 10); 1404 if (errno != 0 || *endptr != '\0') 1405 searchname = argv[0]; 1406 else 1407 searchname = NULL; 1408 found_config = NULL; 1409 } 1410 1411 err = 0; 1412 elem = NULL; 1413 first = B_TRUE; 1414 while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1415 1416 verify(nvpair_value_nvlist(elem, &config) == 0); 1417 1418 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1419 &pool_state) == 0); 1420 if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 1421 continue; 1422 if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 1423 continue; 1424 1425 if (argc == 0) { 1426 if (first) 1427 first = B_FALSE; 1428 else if (!do_all) 1429 (void) printf("\n"); 1430 1431 if (do_all) 1432 err |= do_import(config, NULL, mntopts, 1433 altroot, do_force, argc + optind, 1434 argv - optind); 1435 else 1436 show_import(config); 1437 } else if (searchname != NULL) { 1438 char *name; 1439 1440 /* 1441 * We are searching for a pool based on name. 1442 */ 1443 verify(nvlist_lookup_string(config, 1444 ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1445 1446 if (strcmp(name, searchname) == 0) { 1447 if (found_config != NULL) { 1448 (void) fprintf(stderr, gettext( 1449 "cannot import '%s': more than " 1450 "one matching pool\n"), searchname); 1451 (void) fprintf(stderr, gettext( 1452 "import by numeric ID instead\n")); 1453 err = B_TRUE; 1454 } 1455 found_config = config; 1456 } 1457 } else { 1458 uint64_t guid; 1459 1460 /* 1461 * Search for a pool by guid. 1462 */ 1463 verify(nvlist_lookup_uint64(config, 1464 ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1465 1466 if (guid == searchguid) 1467 found_config = config; 1468 } 1469 } 1470 1471 /* 1472 * If we were searching for a specific pool, verify that we found a 1473 * pool, and then do the import. 1474 */ 1475 if (argc != 0 && err == 0) { 1476 if (found_config == NULL) { 1477 (void) fprintf(stderr, gettext("cannot import '%s': " 1478 "no such pool available\n"), argv[0]); 1479 err = B_TRUE; 1480 } else { 1481 err |= do_import(found_config, argc == 1 ? NULL : 1482 argv[1], mntopts, altroot, do_force, argc + optind, 1483 argv - optind); 1484 } 1485 } 1486 1487 /* 1488 * If we were just looking for pools, report an error if none were 1489 * found. 1490 */ 1491 if (argc == 0 && first) 1492 (void) fprintf(stderr, 1493 gettext("no pools available to import\n")); 1494 1495 nvlist_free(pools); 1496 free(searchdirs); 1497 1498 return (err ? 1 : 0); 1499 } 1500 1501 typedef struct iostat_cbdata { 1502 zpool_list_t *cb_list; 1503 int cb_verbose; 1504 int cb_iteration; 1505 int cb_namewidth; 1506 } iostat_cbdata_t; 1507 1508 static void 1509 print_iostat_separator(iostat_cbdata_t *cb) 1510 { 1511 int i = 0; 1512 1513 for (i = 0; i < cb->cb_namewidth; i++) 1514 (void) printf("-"); 1515 (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1516 } 1517 1518 static void 1519 print_iostat_header(iostat_cbdata_t *cb) 1520 { 1521 (void) printf("%*s capacity operations bandwidth\n", 1522 cb->cb_namewidth, ""); 1523 (void) printf("%-*s used avail read write read write\n", 1524 cb->cb_namewidth, "pool"); 1525 print_iostat_separator(cb); 1526 } 1527 1528 /* 1529 * Display a single statistic. 1530 */ 1531 void 1532 print_one_stat(uint64_t value) 1533 { 1534 char buf[64]; 1535 1536 zfs_nicenum(value, buf, sizeof (buf)); 1537 (void) printf(" %5s", buf); 1538 } 1539 1540 /* 1541 * Print out all the statistics for the given vdev. This can either be the 1542 * toplevel configuration, or called recursively. If 'name' is NULL, then this 1543 * is a verbose output, and we don't want to display the toplevel pool stats. 1544 */ 1545 void 1546 print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1547 nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1548 { 1549 nvlist_t **oldchild, **newchild; 1550 uint_t c, children; 1551 vdev_stat_t *oldvs, *newvs; 1552 vdev_stat_t zerovs = { 0 }; 1553 uint64_t tdelta; 1554 double scale; 1555 char *vname; 1556 1557 if (oldnv != NULL) { 1558 verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1559 (uint64_t **)&oldvs, &c) == 0); 1560 } else { 1561 oldvs = &zerovs; 1562 } 1563 1564 verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1565 (uint64_t **)&newvs, &c) == 0); 1566 1567 if (strlen(name) + depth > cb->cb_namewidth) 1568 (void) printf("%*s%s", depth, "", name); 1569 else 1570 (void) printf("%*s%s%*s", depth, "", name, 1571 (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1572 1573 tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1574 1575 if (tdelta == 0) 1576 scale = 1.0; 1577 else 1578 scale = (double)NANOSEC / tdelta; 1579 1580 /* only toplevel vdevs have capacity stats */ 1581 if (newvs->vs_space == 0) { 1582 (void) printf(" - -"); 1583 } else { 1584 print_one_stat(newvs->vs_alloc); 1585 print_one_stat(newvs->vs_space - newvs->vs_alloc); 1586 } 1587 1588 print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1589 oldvs->vs_ops[ZIO_TYPE_READ]))); 1590 1591 print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1592 oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1593 1594 print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1595 oldvs->vs_bytes[ZIO_TYPE_READ]))); 1596 1597 print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1598 oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1599 1600 (void) printf("\n"); 1601 1602 if (!cb->cb_verbose) 1603 return; 1604 1605 if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1606 &newchild, &children) != 0) 1607 return; 1608 1609 if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1610 &oldchild, &c) != 0) 1611 return; 1612 1613 for (c = 0; c < children; c++) { 1614 vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1615 print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1616 newchild[c], cb, depth + 2); 1617 free(vname); 1618 } 1619 } 1620 1621 static int 1622 refresh_iostat(zpool_handle_t *zhp, void *data) 1623 { 1624 iostat_cbdata_t *cb = data; 1625 boolean_t missing; 1626 1627 /* 1628 * If the pool has disappeared, remove it from the list and continue. 1629 */ 1630 if (zpool_refresh_stats(zhp, &missing) != 0) 1631 return (-1); 1632 1633 if (missing) 1634 pool_list_remove(cb->cb_list, zhp); 1635 1636 return (0); 1637 } 1638 1639 /* 1640 * Callback to print out the iostats for the given pool. 1641 */ 1642 int 1643 print_iostat(zpool_handle_t *zhp, void *data) 1644 { 1645 iostat_cbdata_t *cb = data; 1646 nvlist_t *oldconfig, *newconfig; 1647 nvlist_t *oldnvroot, *newnvroot; 1648 1649 newconfig = zpool_get_config(zhp, &oldconfig); 1650 1651 if (cb->cb_iteration == 1) 1652 oldconfig = NULL; 1653 1654 verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1655 &newnvroot) == 0); 1656 1657 if (oldconfig == NULL) 1658 oldnvroot = NULL; 1659 else 1660 verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 1661 &oldnvroot) == 0); 1662 1663 /* 1664 * Print out the statistics for the pool. 1665 */ 1666 print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1667 1668 if (cb->cb_verbose) 1669 print_iostat_separator(cb); 1670 1671 return (0); 1672 } 1673 1674 int 1675 get_namewidth(zpool_handle_t *zhp, void *data) 1676 { 1677 iostat_cbdata_t *cb = data; 1678 nvlist_t *config, *nvroot; 1679 1680 if ((config = zpool_get_config(zhp, NULL)) != NULL) { 1681 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1682 &nvroot) == 0); 1683 if (!cb->cb_verbose) 1684 cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1685 else 1686 cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 1687 } 1688 1689 /* 1690 * The width must fall into the range [10,38]. The upper limit is the 1691 * maximum we can have and still fit in 80 columns. 1692 */ 1693 if (cb->cb_namewidth < 10) 1694 cb->cb_namewidth = 10; 1695 if (cb->cb_namewidth > 38) 1696 cb->cb_namewidth = 38; 1697 1698 return (0); 1699 } 1700 1701 /* 1702 * zpool iostat [-v] [pool] ... [interval [count]] 1703 * 1704 * -v Display statistics for individual vdevs 1705 * 1706 * This command can be tricky because we want to be able to deal with pool 1707 * creation/destruction as well as vdev configuration changes. The bulk of this 1708 * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1709 * on pool_list_update() to detect the addition of new pools. Configuration 1710 * changes are all handled within libzfs. 1711 */ 1712 int 1713 zpool_do_iostat(int argc, char **argv) 1714 { 1715 int c; 1716 int ret; 1717 int npools; 1718 unsigned long interval = 0, count = 0; 1719 zpool_list_t *list; 1720 boolean_t verbose = B_FALSE; 1721 iostat_cbdata_t cb; 1722 1723 /* check options */ 1724 while ((c = getopt(argc, argv, "v")) != -1) { 1725 switch (c) { 1726 case 'v': 1727 verbose = B_TRUE; 1728 break; 1729 case '?': 1730 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1731 optopt); 1732 usage(B_FALSE); 1733 } 1734 } 1735 1736 argc -= optind; 1737 argv += optind; 1738 1739 /* 1740 * Determine if the last argument is an integer or a pool name 1741 */ 1742 if (argc > 0 && isdigit(argv[argc - 1][0])) { 1743 char *end; 1744 1745 errno = 0; 1746 interval = strtoul(argv[argc - 1], &end, 10); 1747 1748 if (*end == '\0' && errno == 0) { 1749 if (interval == 0) { 1750 (void) fprintf(stderr, gettext("interval " 1751 "cannot be zero\n")); 1752 usage(B_FALSE); 1753 } 1754 1755 /* 1756 * Ignore the last parameter 1757 */ 1758 argc--; 1759 } else { 1760 /* 1761 * If this is not a valid number, just plow on. The 1762 * user will get a more informative error message later 1763 * on. 1764 */ 1765 interval = 0; 1766 } 1767 } 1768 1769 /* 1770 * If the last argument is also an integer, then we have both a count 1771 * and an integer. 1772 */ 1773 if (argc > 0 && isdigit(argv[argc - 1][0])) { 1774 char *end; 1775 1776 errno = 0; 1777 count = interval; 1778 interval = strtoul(argv[argc - 1], &end, 10); 1779 1780 if (*end == '\0' && errno == 0) { 1781 if (interval == 0) { 1782 (void) fprintf(stderr, gettext("interval " 1783 "cannot be zero\n")); 1784 usage(B_FALSE); 1785 } 1786 1787 /* 1788 * Ignore the last parameter 1789 */ 1790 argc--; 1791 } else { 1792 interval = 0; 1793 } 1794 } 1795 1796 /* 1797 * Construct the list of all interesting pools. 1798 */ 1799 ret = 0; 1800 if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 1801 return (1); 1802 1803 if (pool_list_count(list) == 0 && argc != 0) { 1804 pool_list_free(list); 1805 return (1); 1806 } 1807 1808 if (pool_list_count(list) == 0 && interval == 0) { 1809 pool_list_free(list); 1810 (void) fprintf(stderr, gettext("no pools available\n")); 1811 return (1); 1812 } 1813 1814 /* 1815 * Enter the main iostat loop. 1816 */ 1817 cb.cb_list = list; 1818 cb.cb_verbose = verbose; 1819 cb.cb_iteration = 0; 1820 cb.cb_namewidth = 0; 1821 1822 for (;;) { 1823 pool_list_update(list); 1824 1825 if ((npools = pool_list_count(list)) == 0) 1826 break; 1827 1828 /* 1829 * Refresh all statistics. This is done as an explicit step 1830 * before calculating the maximum name width, so that any 1831 * configuration changes are properly accounted for. 1832 */ 1833 (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 1834 1835 /* 1836 * Iterate over all pools to determine the maximum width 1837 * for the pool / device name column across all pools. 1838 */ 1839 cb.cb_namewidth = 0; 1840 (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 1841 1842 /* 1843 * If it's the first time, or verbose mode, print the header. 1844 */ 1845 if (++cb.cb_iteration == 1 || verbose) 1846 print_iostat_header(&cb); 1847 1848 (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 1849 1850 /* 1851 * If there's more than one pool, and we're not in verbose mode 1852 * (which prints a separator for us), then print a separator. 1853 */ 1854 if (npools > 1 && !verbose) 1855 print_iostat_separator(&cb); 1856 1857 if (verbose) 1858 (void) printf("\n"); 1859 1860 /* 1861 * Flush the output so that redirection to a file isn't buffered 1862 * indefinitely. 1863 */ 1864 (void) fflush(stdout); 1865 1866 if (interval == 0) 1867 break; 1868 1869 if (count != 0 && --count == 0) 1870 break; 1871 1872 (void) sleep(interval); 1873 } 1874 1875 pool_list_free(list); 1876 1877 return (ret); 1878 } 1879 1880 typedef struct list_cbdata { 1881 boolean_t cb_scripted; 1882 boolean_t cb_first; 1883 int cb_fields[MAX_FIELDS]; 1884 int cb_fieldcount; 1885 } list_cbdata_t; 1886 1887 /* 1888 * Given a list of columns to display, output appropriate headers for each one. 1889 */ 1890 void 1891 print_header(int *fields, size_t count) 1892 { 1893 int i; 1894 column_def_t *col; 1895 const char *fmt; 1896 1897 for (i = 0; i < count; i++) { 1898 col = &column_table[fields[i]]; 1899 if (i != 0) 1900 (void) printf(" "); 1901 if (col->cd_justify == left_justify) 1902 fmt = "%-*s"; 1903 else 1904 fmt = "%*s"; 1905 1906 (void) printf(fmt, i == count - 1 ? strlen(col->cd_title) : 1907 col->cd_width, col->cd_title); 1908 } 1909 1910 (void) printf("\n"); 1911 } 1912 1913 int 1914 list_callback(zpool_handle_t *zhp, void *data) 1915 { 1916 list_cbdata_t *cbp = data; 1917 nvlist_t *config; 1918 int i; 1919 char buf[ZPOOL_MAXNAMELEN]; 1920 uint64_t total; 1921 uint64_t used; 1922 const char *fmt; 1923 column_def_t *col; 1924 1925 if (cbp->cb_first) { 1926 if (!cbp->cb_scripted) 1927 print_header(cbp->cb_fields, cbp->cb_fieldcount); 1928 cbp->cb_first = B_FALSE; 1929 } 1930 1931 if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 1932 config = NULL; 1933 } else { 1934 config = zpool_get_config(zhp, NULL); 1935 total = zpool_get_space_total(zhp); 1936 used = zpool_get_space_used(zhp); 1937 } 1938 1939 for (i = 0; i < cbp->cb_fieldcount; i++) { 1940 if (i != 0) { 1941 if (cbp->cb_scripted) 1942 (void) printf("\t"); 1943 else 1944 (void) printf(" "); 1945 } 1946 1947 col = &column_table[cbp->cb_fields[i]]; 1948 1949 switch (cbp->cb_fields[i]) { 1950 case ZPOOL_FIELD_NAME: 1951 (void) strlcpy(buf, zpool_get_name(zhp), sizeof (buf)); 1952 break; 1953 1954 case ZPOOL_FIELD_SIZE: 1955 if (config == NULL) 1956 (void) strlcpy(buf, "-", sizeof (buf)); 1957 else 1958 zfs_nicenum(total, buf, sizeof (buf)); 1959 break; 1960 1961 case ZPOOL_FIELD_USED: 1962 if (config == NULL) 1963 (void) strlcpy(buf, "-", sizeof (buf)); 1964 else 1965 zfs_nicenum(used, buf, sizeof (buf)); 1966 break; 1967 1968 case ZPOOL_FIELD_AVAILABLE: 1969 if (config == NULL) 1970 (void) strlcpy(buf, "-", sizeof (buf)); 1971 else 1972 zfs_nicenum(total - used, buf, sizeof (buf)); 1973 break; 1974 1975 case ZPOOL_FIELD_CAPACITY: 1976 if (config == NULL) { 1977 (void) strlcpy(buf, "-", sizeof (buf)); 1978 } else { 1979 uint64_t capacity = (total == 0 ? 0 : 1980 (used * 100 / total)); 1981 (void) snprintf(buf, sizeof (buf), "%llu%%", 1982 (u_longlong_t)capacity); 1983 } 1984 break; 1985 1986 case ZPOOL_FIELD_HEALTH: 1987 if (config == NULL) { 1988 (void) strlcpy(buf, "FAULTED", sizeof (buf)); 1989 } else { 1990 nvlist_t *nvroot; 1991 vdev_stat_t *vs; 1992 uint_t vsc; 1993 1994 verify(nvlist_lookup_nvlist(config, 1995 ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 1996 verify(nvlist_lookup_uint64_array(nvroot, 1997 ZPOOL_CONFIG_STATS, (uint64_t **)&vs, 1998 &vsc) == 0); 1999 (void) strlcpy(buf, state_to_name(vs), 2000 sizeof (buf)); 2001 } 2002 break; 2003 2004 case ZPOOL_FIELD_ROOT: 2005 if (config == NULL) 2006 (void) strlcpy(buf, "-", sizeof (buf)); 2007 else if (zpool_get_root(zhp, buf, sizeof (buf)) != 0) 2008 (void) strlcpy(buf, "-", sizeof (buf)); 2009 break; 2010 } 2011 2012 if (cbp->cb_scripted) 2013 (void) printf("%s", buf); 2014 else { 2015 if (col->cd_justify == left_justify) 2016 fmt = "%-*s"; 2017 else 2018 fmt = "%*s"; 2019 2020 (void) printf(fmt, i == cbp->cb_fieldcount - 1 ? 2021 strlen(buf) : col->cd_width, buf); 2022 } 2023 } 2024 2025 (void) printf("\n"); 2026 2027 return (0); 2028 } 2029 2030 /* 2031 * zpool list [-H] [-o field[,field]*] [pool] ... 2032 * 2033 * -H Scripted mode. Don't display headers, and separate fields by 2034 * a single tab. 2035 * -o List of fields to display. Defaults to all fields, or 2036 * "name,size,used,available,capacity,health,root" 2037 * 2038 * List all pools in the system, whether or not they're healthy. Output space 2039 * statistics for each one, as well as health status summary. 2040 */ 2041 int 2042 zpool_do_list(int argc, char **argv) 2043 { 2044 int c; 2045 int ret; 2046 list_cbdata_t cb = { 0 }; 2047 static char default_fields[] = 2048 "name,size,used,available,capacity,health,root"; 2049 char *fields = default_fields; 2050 char *value; 2051 2052 /* check options */ 2053 while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2054 switch (c) { 2055 case 'H': 2056 cb.cb_scripted = B_TRUE; 2057 break; 2058 case 'o': 2059 fields = optarg; 2060 break; 2061 case ':': 2062 (void) fprintf(stderr, gettext("missing argument for " 2063 "'%c' option\n"), optopt); 2064 usage(B_FALSE); 2065 break; 2066 case '?': 2067 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2068 optopt); 2069 usage(B_FALSE); 2070 } 2071 } 2072 2073 argc -= optind; 2074 argv += optind; 2075 2076 while (*fields != '\0') { 2077 if (cb.cb_fieldcount == MAX_FIELDS) { 2078 (void) fprintf(stderr, gettext("too many " 2079 "properties given to -o option\n")); 2080 usage(B_FALSE); 2081 } 2082 2083 if ((cb.cb_fields[cb.cb_fieldcount] = getsubopt(&fields, 2084 column_subopts, &value)) == -1) { 2085 (void) fprintf(stderr, gettext("invalid property " 2086 "'%s'\n"), value); 2087 usage(B_FALSE); 2088 } 2089 2090 cb.cb_fieldcount++; 2091 } 2092 2093 2094 cb.cb_first = B_TRUE; 2095 2096 ret = for_each_pool(argc, argv, B_TRUE, NULL, list_callback, &cb); 2097 2098 if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2099 (void) printf(gettext("no pools available\n")); 2100 return (0); 2101 } 2102 2103 return (ret); 2104 } 2105 2106 static nvlist_t * 2107 zpool_get_vdev_by_name(nvlist_t *nv, char *name) 2108 { 2109 nvlist_t **child; 2110 uint_t c, children; 2111 nvlist_t *match; 2112 char *path; 2113 2114 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2115 &child, &children) != 0) { 2116 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2117 if (strncmp(name, "/dev/dsk/", 9) == 0) 2118 name += 9; 2119 if (strncmp(path, "/dev/dsk/", 9) == 0) 2120 path += 9; 2121 if (strcmp(name, path) == 0) 2122 return (nv); 2123 return (NULL); 2124 } 2125 2126 for (c = 0; c < children; c++) 2127 if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2128 return (match); 2129 2130 return (NULL); 2131 } 2132 2133 static int 2134 zpool_do_attach_or_replace(int argc, char **argv, int replacing) 2135 { 2136 boolean_t force = B_FALSE; 2137 int c; 2138 nvlist_t *nvroot; 2139 char *poolname, *old_disk, *new_disk; 2140 zpool_handle_t *zhp; 2141 int ret; 2142 int log_argc; 2143 char **log_argv; 2144 2145 /* check options */ 2146 while ((c = getopt(argc, argv, "f")) != -1) { 2147 switch (c) { 2148 case 'f': 2149 force = B_TRUE; 2150 break; 2151 case '?': 2152 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2153 optopt); 2154 usage(B_FALSE); 2155 } 2156 } 2157 2158 log_argc = argc; 2159 log_argv = argv; 2160 argc -= optind; 2161 argv += optind; 2162 2163 /* get pool name and check number of arguments */ 2164 if (argc < 1) { 2165 (void) fprintf(stderr, gettext("missing pool name argument\n")); 2166 usage(B_FALSE); 2167 } 2168 2169 poolname = argv[0]; 2170 2171 if (argc < 2) { 2172 (void) fprintf(stderr, 2173 gettext("missing <device> specification\n")); 2174 usage(B_FALSE); 2175 } 2176 2177 old_disk = argv[1]; 2178 2179 if (argc < 3) { 2180 if (!replacing) { 2181 (void) fprintf(stderr, 2182 gettext("missing <new_device> specification\n")); 2183 usage(B_FALSE); 2184 } 2185 new_disk = old_disk; 2186 argc -= 1; 2187 argv += 1; 2188 } else { 2189 new_disk = argv[2]; 2190 argc -= 2; 2191 argv += 2; 2192 } 2193 2194 if (argc > 1) { 2195 (void) fprintf(stderr, gettext("too many arguments\n")); 2196 usage(B_FALSE); 2197 } 2198 2199 if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2200 return (1); 2201 2202 if (zpool_get_config(zhp, NULL) == NULL) { 2203 (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2204 poolname); 2205 zpool_close(zhp); 2206 return (1); 2207 } 2208 2209 nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv); 2210 if (nvroot == NULL) { 2211 zpool_close(zhp); 2212 return (1); 2213 } 2214 2215 ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 2216 2217 if (!ret) { 2218 zpool_log_history(g_zfs, log_argc, log_argv, poolname, B_TRUE, 2219 B_FALSE); 2220 } 2221 2222 nvlist_free(nvroot); 2223 zpool_close(zhp); 2224 2225 return (ret); 2226 } 2227 2228 /* 2229 * zpool replace [-f] <pool> <device> <new_device> 2230 * 2231 * -f Force attach, even if <new_device> appears to be in use. 2232 * 2233 * Replace <device> with <new_device>. 2234 */ 2235 /* ARGSUSED */ 2236 int 2237 zpool_do_replace(int argc, char **argv) 2238 { 2239 return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2240 } 2241 2242 /* 2243 * zpool attach [-f] <pool> <device> <new_device> 2244 * 2245 * -f Force attach, even if <new_device> appears to be in use. 2246 * 2247 * Attach <new_device> to the mirror containing <device>. If <device> is not 2248 * part of a mirror, then <device> will be transformed into a mirror of 2249 * <device> and <new_device>. In either case, <new_device> will begin life 2250 * with a DTL of [0, now], and will immediately begin to resilver itself. 2251 */ 2252 int 2253 zpool_do_attach(int argc, char **argv) 2254 { 2255 return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2256 } 2257 2258 /* 2259 * zpool detach [-f] <pool> <device> 2260 * 2261 * -f Force detach of <device>, even if DTLs argue against it 2262 * (not supported yet) 2263 * 2264 * Detach a device from a mirror. The operation will be refused if <device> 2265 * is the last device in the mirror, or if the DTLs indicate that this device 2266 * has the only valid copy of some data. 2267 */ 2268 /* ARGSUSED */ 2269 int 2270 zpool_do_detach(int argc, char **argv) 2271 { 2272 int c; 2273 char *poolname, *path; 2274 zpool_handle_t *zhp; 2275 int ret; 2276 2277 /* check options */ 2278 while ((c = getopt(argc, argv, "f")) != -1) { 2279 switch (c) { 2280 case 'f': 2281 case '?': 2282 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2283 optopt); 2284 usage(B_FALSE); 2285 } 2286 } 2287 2288 argc -= optind; 2289 argv += optind; 2290 2291 /* get pool name and check number of arguments */ 2292 if (argc < 1) { 2293 (void) fprintf(stderr, gettext("missing pool name argument\n")); 2294 usage(B_FALSE); 2295 } 2296 2297 if (argc < 2) { 2298 (void) fprintf(stderr, 2299 gettext("missing <device> specification\n")); 2300 usage(B_FALSE); 2301 } 2302 2303 poolname = argv[0]; 2304 path = argv[1]; 2305 2306 if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2307 return (1); 2308 2309 ret = zpool_vdev_detach(zhp, path); 2310 2311 if (!ret) { 2312 zpool_log_history(g_zfs, argc + optind, argv - optind, poolname, 2313 B_TRUE, B_FALSE); 2314 } 2315 zpool_close(zhp); 2316 2317 return (ret); 2318 } 2319 2320 /* 2321 * zpool online <pool> <device> ... 2322 */ 2323 int 2324 zpool_do_online(int argc, char **argv) 2325 { 2326 int c, i; 2327 char *poolname; 2328 zpool_handle_t *zhp; 2329 int ret = 0; 2330 vdev_state_t newstate; 2331 2332 /* check options */ 2333 while ((c = getopt(argc, argv, "t")) != -1) { 2334 switch (c) { 2335 case 't': 2336 case '?': 2337 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2338 optopt); 2339 usage(B_FALSE); 2340 } 2341 } 2342 2343 argc -= optind; 2344 argv += optind; 2345 2346 /* get pool name and check number of arguments */ 2347 if (argc < 1) { 2348 (void) fprintf(stderr, gettext("missing pool name\n")); 2349 usage(B_FALSE); 2350 } 2351 if (argc < 2) { 2352 (void) fprintf(stderr, gettext("missing device name\n")); 2353 usage(B_FALSE); 2354 } 2355 2356 poolname = argv[0]; 2357 2358 if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2359 return (1); 2360 2361 for (i = 1; i < argc; i++) { 2362 if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) { 2363 if (newstate != VDEV_STATE_HEALTHY) { 2364 (void) printf(gettext("warning: device '%s' " 2365 "onlined, but remains in faulted state\n"), 2366 argv[i]); 2367 if (newstate == VDEV_STATE_FAULTED) 2368 (void) printf(gettext("use 'zpool " 2369 "clear' to restore a faulted " 2370 "device\n")); 2371 else 2372 (void) printf(gettext("use 'zpool " 2373 "replace' to replace devices " 2374 "that are no longer present\n")); 2375 } 2376 } else { 2377 ret = 1; 2378 } 2379 } 2380 2381 if (!ret) { 2382 zpool_log_history(g_zfs, argc + optind, argv - optind, poolname, 2383 B_TRUE, B_FALSE); 2384 } 2385 zpool_close(zhp); 2386 2387 return (ret); 2388 } 2389 2390 /* 2391 * zpool offline [-ft] <pool> <device> ... 2392 * 2393 * -f Force the device into the offline state, even if doing 2394 * so would appear to compromise pool availability. 2395 * (not supported yet) 2396 * 2397 * -t Only take the device off-line temporarily. The offline 2398 * state will not be persistent across reboots. 2399 */ 2400 /* ARGSUSED */ 2401 int 2402 zpool_do_offline(int argc, char **argv) 2403 { 2404 int c, i; 2405 char *poolname; 2406 zpool_handle_t *zhp; 2407 int ret = 0; 2408 boolean_t istmp = B_FALSE; 2409 2410 /* check options */ 2411 while ((c = getopt(argc, argv, "ft")) != -1) { 2412 switch (c) { 2413 case 't': 2414 istmp = B_TRUE; 2415 break; 2416 case 'f': 2417 case '?': 2418 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2419 optopt); 2420 usage(B_FALSE); 2421 } 2422 } 2423 2424 argc -= optind; 2425 argv += optind; 2426 2427 /* get pool name and check number of arguments */ 2428 if (argc < 1) { 2429 (void) fprintf(stderr, gettext("missing pool name\n")); 2430 usage(B_FALSE); 2431 } 2432 if (argc < 2) { 2433 (void) fprintf(stderr, gettext("missing device name\n")); 2434 usage(B_FALSE); 2435 } 2436 2437 poolname = argv[0]; 2438 2439 if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2440 return (1); 2441 2442 for (i = 1; i < argc; i++) { 2443 if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2444 ret = 1; 2445 } 2446 2447 if (!ret) { 2448 zpool_log_history(g_zfs, argc + optind, argv - optind, poolname, 2449 B_TRUE, B_FALSE); 2450 } 2451 zpool_close(zhp); 2452 2453 return (ret); 2454 } 2455 2456 /* 2457 * zpool clear <pool> [device] 2458 * 2459 * Clear all errors associated with a pool or a particular device. 2460 */ 2461 int 2462 zpool_do_clear(int argc, char **argv) 2463 { 2464 int ret = 0; 2465 zpool_handle_t *zhp; 2466 char *pool, *device; 2467 2468 if (argc < 2) { 2469 (void) fprintf(stderr, gettext("missing pool name\n")); 2470 usage(B_FALSE); 2471 } 2472 2473 if (argc > 3) { 2474 (void) fprintf(stderr, gettext("too many arguments\n")); 2475 usage(B_FALSE); 2476 } 2477 2478 pool = argv[1]; 2479 device = argc == 3 ? argv[2] : NULL; 2480 2481 if ((zhp = zpool_open(g_zfs, pool)) == NULL) 2482 return (1); 2483 2484 if (zpool_clear(zhp, device) != 0) 2485 ret = 1; 2486 2487 if (!ret) 2488 zpool_log_history(g_zfs, argc, argv, pool, B_TRUE, B_FALSE); 2489 zpool_close(zhp); 2490 2491 return (ret); 2492 } 2493 2494 typedef struct scrub_cbdata { 2495 int cb_type; 2496 int cb_argc; 2497 char **cb_argv; 2498 } scrub_cbdata_t; 2499 2500 int 2501 scrub_callback(zpool_handle_t *zhp, void *data) 2502 { 2503 scrub_cbdata_t *cb = data; 2504 int err; 2505 2506 /* 2507 * Ignore faulted pools. 2508 */ 2509 if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2510 (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2511 "currently unavailable\n"), zpool_get_name(zhp)); 2512 return (1); 2513 } 2514 2515 err = zpool_scrub(zhp, cb->cb_type); 2516 2517 if (!err) { 2518 zpool_log_history(g_zfs, cb->cb_argc, cb->cb_argv, 2519 zpool_get_name(zhp), B_TRUE, B_FALSE); 2520 } 2521 2522 return (err != 0); 2523 } 2524 2525 /* 2526 * zpool scrub [-s] <pool> ... 2527 * 2528 * -s Stop. Stops any in-progress scrub. 2529 */ 2530 int 2531 zpool_do_scrub(int argc, char **argv) 2532 { 2533 int c; 2534 scrub_cbdata_t cb; 2535 2536 cb.cb_type = POOL_SCRUB_EVERYTHING; 2537 2538 /* check options */ 2539 while ((c = getopt(argc, argv, "s")) != -1) { 2540 switch (c) { 2541 case 's': 2542 cb.cb_type = POOL_SCRUB_NONE; 2543 break; 2544 case '?': 2545 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2546 optopt); 2547 usage(B_FALSE); 2548 } 2549 } 2550 2551 cb.cb_argc = argc; 2552 cb.cb_argv = argv; 2553 argc -= optind; 2554 argv += optind; 2555 2556 if (argc < 1) { 2557 (void) fprintf(stderr, gettext("missing pool name argument\n")); 2558 usage(B_FALSE); 2559 } 2560 2561 return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2562 } 2563 2564 typedef struct status_cbdata { 2565 int cb_count; 2566 boolean_t cb_allpools; 2567 boolean_t cb_verbose; 2568 boolean_t cb_explain; 2569 boolean_t cb_first; 2570 } status_cbdata_t; 2571 2572 /* 2573 * Print out detailed scrub status. 2574 */ 2575 void 2576 print_scrub_status(nvlist_t *nvroot) 2577 { 2578 vdev_stat_t *vs; 2579 uint_t vsc; 2580 time_t start, end, now; 2581 double fraction_done; 2582 uint64_t examined, total, minutes_left; 2583 char *scrub_type; 2584 2585 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2586 (uint64_t **)&vs, &vsc) == 0); 2587 2588 /* 2589 * If there's never been a scrub, there's not much to say. 2590 */ 2591 if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2592 (void) printf(gettext("none requested\n")); 2593 return; 2594 } 2595 2596 scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2597 "resilver" : "scrub"; 2598 2599 start = vs->vs_scrub_start; 2600 end = vs->vs_scrub_end; 2601 now = time(NULL); 2602 examined = vs->vs_scrub_examined; 2603 total = vs->vs_alloc; 2604 2605 if (end != 0) { 2606 (void) printf(gettext("%s %s with %llu errors on %s"), 2607 scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 2608 (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2609 return; 2610 } 2611 2612 if (examined == 0) 2613 examined = 1; 2614 if (examined > total) 2615 total = examined; 2616 2617 fraction_done = (double)examined / total; 2618 minutes_left = (uint64_t)((now - start) * 2619 (1 - fraction_done) / fraction_done / 60); 2620 2621 (void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"), 2622 scrub_type, 100 * fraction_done, 2623 (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2624 } 2625 2626 typedef struct spare_cbdata { 2627 uint64_t cb_guid; 2628 zpool_handle_t *cb_zhp; 2629 } spare_cbdata_t; 2630 2631 static boolean_t 2632 find_vdev(nvlist_t *nv, uint64_t search) 2633 { 2634 uint64_t guid; 2635 nvlist_t **child; 2636 uint_t c, children; 2637 2638 if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 2639 search == guid) 2640 return (B_TRUE); 2641 2642 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2643 &child, &children) == 0) { 2644 for (c = 0; c < children; c++) 2645 if (find_vdev(child[c], search)) 2646 return (B_TRUE); 2647 } 2648 2649 return (B_FALSE); 2650 } 2651 2652 static int 2653 find_spare(zpool_handle_t *zhp, void *data) 2654 { 2655 spare_cbdata_t *cbp = data; 2656 nvlist_t *config, *nvroot; 2657 2658 config = zpool_get_config(zhp, NULL); 2659 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2660 &nvroot) == 0); 2661 2662 if (find_vdev(nvroot, cbp->cb_guid)) { 2663 cbp->cb_zhp = zhp; 2664 return (1); 2665 } 2666 2667 zpool_close(zhp); 2668 return (0); 2669 } 2670 2671 /* 2672 * Print out configuration state as requested by status_callback. 2673 */ 2674 void 2675 print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 2676 int namewidth, int depth, boolean_t isspare) 2677 { 2678 nvlist_t **child; 2679 uint_t c, children; 2680 vdev_stat_t *vs; 2681 char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 2682 char *vname; 2683 uint64_t notpresent; 2684 spare_cbdata_t cb; 2685 const char *state; 2686 2687 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2688 (uint64_t **)&vs, &c) == 0); 2689 2690 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2691 &child, &children) != 0) 2692 children = 0; 2693 2694 state = state_to_name(vs); 2695 if (isspare) { 2696 /* 2697 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 2698 * online drives. 2699 */ 2700 if (vs->vs_aux == VDEV_AUX_SPARED) 2701 state = "INUSE"; 2702 else if (vs->vs_state == VDEV_STATE_HEALTHY) 2703 state = "AVAIL"; 2704 } 2705 2706 (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 2707 name, state); 2708 2709 if (!isspare) { 2710 zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 2711 zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 2712 zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 2713 (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 2714 } 2715 2716 if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2717 ¬present) == 0) { 2718 char *path; 2719 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2720 (void) printf(" was %s", path); 2721 } else if (vs->vs_aux != 0) { 2722 (void) printf(" "); 2723 2724 switch (vs->vs_aux) { 2725 case VDEV_AUX_OPEN_FAILED: 2726 (void) printf(gettext("cannot open")); 2727 break; 2728 2729 case VDEV_AUX_BAD_GUID_SUM: 2730 (void) printf(gettext("missing device")); 2731 break; 2732 2733 case VDEV_AUX_NO_REPLICAS: 2734 (void) printf(gettext("insufficient replicas")); 2735 break; 2736 2737 case VDEV_AUX_VERSION_NEWER: 2738 (void) printf(gettext("newer version")); 2739 break; 2740 2741 case VDEV_AUX_SPARED: 2742 verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 2743 &cb.cb_guid) == 0); 2744 if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 2745 if (strcmp(zpool_get_name(cb.cb_zhp), 2746 zpool_get_name(zhp)) == 0) 2747 (void) printf(gettext("currently in " 2748 "use")); 2749 else 2750 (void) printf(gettext("in use by " 2751 "pool '%s'"), 2752 zpool_get_name(cb.cb_zhp)); 2753 zpool_close(cb.cb_zhp); 2754 } else { 2755 (void) printf(gettext("currently in use")); 2756 } 2757 break; 2758 2759 case VDEV_AUX_ERR_EXCEEDED: 2760 (void) printf(gettext("too many errors")); 2761 break; 2762 2763 default: 2764 (void) printf(gettext("corrupted data")); 2765 break; 2766 } 2767 } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2768 /* 2769 * Report bytes resilvered/repaired on leaf devices. 2770 */ 2771 zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2772 (void) printf(gettext(" %s %s"), repaired, 2773 (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2774 "resilvered" : "repaired"); 2775 } 2776 2777 (void) printf("\n"); 2778 2779 for (c = 0; c < children; c++) { 2780 vname = zpool_vdev_name(g_zfs, zhp, child[c]); 2781 print_status_config(zhp, vname, child[c], 2782 namewidth, depth + 2, isspare); 2783 free(vname); 2784 } 2785 } 2786 2787 static void 2788 print_error_log(zpool_handle_t *zhp) 2789 { 2790 nvlist_t *nverrlist; 2791 nvpair_t *elem; 2792 char *pathname; 2793 size_t len = MAXPATHLEN * 2; 2794 2795 if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2796 (void) printf("errors: List of errors unavailable " 2797 "(insufficient privileges)\n"); 2798 return; 2799 } 2800 2801 (void) printf("errors: Permanent errors have been " 2802 "detected in the following files:\n\n"); 2803 2804 pathname = safe_malloc(len); 2805 elem = NULL; 2806 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 2807 nvlist_t *nv; 2808 uint64_t dsobj, obj; 2809 2810 verify(nvpair_value_nvlist(elem, &nv) == 0); 2811 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 2812 &dsobj) == 0); 2813 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 2814 &obj) == 0); 2815 zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 2816 (void) printf("%7s %s\n", "", pathname); 2817 } 2818 free(pathname); 2819 nvlist_free(nverrlist); 2820 } 2821 2822 static void 2823 print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 2824 int namewidth) 2825 { 2826 uint_t i; 2827 char *name; 2828 2829 if (nspares == 0) 2830 return; 2831 2832 (void) printf(gettext("\tspares\n")); 2833 2834 for (i = 0; i < nspares; i++) { 2835 name = zpool_vdev_name(g_zfs, zhp, spares[i]); 2836 print_status_config(zhp, name, spares[i], 2837 namewidth, 2, B_TRUE); 2838 free(name); 2839 } 2840 } 2841 2842 /* 2843 * Display a summary of pool status. Displays a summary such as: 2844 * 2845 * pool: tank 2846 * status: DEGRADED 2847 * reason: One or more devices ... 2848 * see: http://www.sun.com/msg/ZFS-xxxx-01 2849 * config: 2850 * mirror DEGRADED 2851 * c1t0d0 OK 2852 * c2t0d0 UNAVAIL 2853 * 2854 * When given the '-v' option, we print out the complete config. If the '-e' 2855 * option is specified, then we print out error rate information as well. 2856 */ 2857 int 2858 status_callback(zpool_handle_t *zhp, void *data) 2859 { 2860 status_cbdata_t *cbp = data; 2861 nvlist_t *config, *nvroot; 2862 char *msgid; 2863 int reason; 2864 const char *health; 2865 uint_t c; 2866 vdev_stat_t *vs; 2867 2868 config = zpool_get_config(zhp, NULL); 2869 reason = zpool_get_status(zhp, &msgid); 2870 2871 cbp->cb_count++; 2872 2873 /* 2874 * If we were given 'zpool status -x', only report those pools with 2875 * problems. 2876 */ 2877 if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 2878 if (!cbp->cb_allpools) { 2879 (void) printf(gettext("pool '%s' is healthy\n"), 2880 zpool_get_name(zhp)); 2881 if (cbp->cb_first) 2882 cbp->cb_first = B_FALSE; 2883 } 2884 return (0); 2885 } 2886 2887 if (cbp->cb_first) 2888 cbp->cb_first = B_FALSE; 2889 else 2890 (void) printf("\n"); 2891 2892 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2893 &nvroot) == 0); 2894 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2895 (uint64_t **)&vs, &c) == 0); 2896 health = state_to_name(vs); 2897 2898 (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 2899 (void) printf(gettext(" state: %s\n"), health); 2900 2901 switch (reason) { 2902 case ZPOOL_STATUS_MISSING_DEV_R: 2903 (void) printf(gettext("status: One or more devices could not " 2904 "be opened. Sufficient replicas exist for\n\tthe pool to " 2905 "continue functioning in a degraded state.\n")); 2906 (void) printf(gettext("action: Attach the missing device and " 2907 "online it using 'zpool online'.\n")); 2908 break; 2909 2910 case ZPOOL_STATUS_MISSING_DEV_NR: 2911 (void) printf(gettext("status: One or more devices could not " 2912 "be opened. There are insufficient\n\treplicas for the " 2913 "pool to continue functioning.\n")); 2914 (void) printf(gettext("action: Attach the missing device and " 2915 "online it using 'zpool online'.\n")); 2916 break; 2917 2918 case ZPOOL_STATUS_CORRUPT_LABEL_R: 2919 (void) printf(gettext("status: One or more devices could not " 2920 "be used because the label is missing or\n\tinvalid. " 2921 "Sufficient replicas exist for the pool to continue\n\t" 2922 "functioning in a degraded state.\n")); 2923 (void) printf(gettext("action: Replace the device using " 2924 "'zpool replace'.\n")); 2925 break; 2926 2927 case ZPOOL_STATUS_CORRUPT_LABEL_NR: 2928 (void) printf(gettext("status: One or more devices could not " 2929 "be used because the label is missing \n\tor invalid. " 2930 "There are insufficient replicas for the pool to " 2931 "continue\n\tfunctioning.\n")); 2932 (void) printf(gettext("action: Destroy and re-create the pool " 2933 "from a backup source.\n")); 2934 break; 2935 2936 case ZPOOL_STATUS_FAILING_DEV: 2937 (void) printf(gettext("status: One or more devices has " 2938 "experienced an unrecoverable error. An\n\tattempt was " 2939 "made to correct the error. Applications are " 2940 "unaffected.\n")); 2941 (void) printf(gettext("action: Determine if the device needs " 2942 "to be replaced, and clear the errors\n\tusing " 2943 "'zpool clear' or replace the device with 'zpool " 2944 "replace'.\n")); 2945 break; 2946 2947 case ZPOOL_STATUS_OFFLINE_DEV: 2948 (void) printf(gettext("status: One or more devices has " 2949 "been taken offline by the administrator.\n\tSufficient " 2950 "replicas exist for the pool to continue functioning in " 2951 "a\n\tdegraded state.\n")); 2952 (void) printf(gettext("action: Online the device using " 2953 "'zpool online' or replace the device with\n\t'zpool " 2954 "replace'.\n")); 2955 break; 2956 2957 case ZPOOL_STATUS_RESILVERING: 2958 (void) printf(gettext("status: One or more devices is " 2959 "currently being resilvered. The pool will\n\tcontinue " 2960 "to function, possibly in a degraded state.\n")); 2961 (void) printf(gettext("action: Wait for the resilver to " 2962 "complete.\n")); 2963 break; 2964 2965 case ZPOOL_STATUS_CORRUPT_DATA: 2966 (void) printf(gettext("status: One or more devices has " 2967 "experienced an error resulting in data\n\tcorruption. " 2968 "Applications may be affected.\n")); 2969 (void) printf(gettext("action: Restore the file in question " 2970 "if possible. Otherwise restore the\n\tentire pool from " 2971 "backup.\n")); 2972 break; 2973 2974 case ZPOOL_STATUS_CORRUPT_POOL: 2975 (void) printf(gettext("status: The pool metadata is corrupted " 2976 "and the pool cannot be opened.\n")); 2977 (void) printf(gettext("action: Destroy and re-create the pool " 2978 "from a backup source.\n")); 2979 break; 2980 2981 case ZPOOL_STATUS_VERSION_OLDER: 2982 (void) printf(gettext("status: The pool is formatted using an " 2983 "older on-disk format. The pool can\n\tstill be used, but " 2984 "some features are unavailable.\n")); 2985 (void) printf(gettext("action: Upgrade the pool using 'zpool " 2986 "upgrade'. Once this is done, the\n\tpool will no longer " 2987 "be accessible on older software versions.\n")); 2988 break; 2989 2990 case ZPOOL_STATUS_VERSION_NEWER: 2991 (void) printf(gettext("status: The pool has been upgraded to a " 2992 "newer, incompatible on-disk version.\n\tThe pool cannot " 2993 "be accessed on this system.\n")); 2994 (void) printf(gettext("action: Access the pool from a system " 2995 "running more recent software, or\n\trestore the pool from " 2996 "backup.\n")); 2997 break; 2998 2999 case ZPOOL_STATUS_FAULTED_DEV_R: 3000 (void) printf(gettext("status: One or more devices are " 3001 "faulted in response to persistent errors.\n\tSufficient " 3002 "replicas exist for the pool to continue functioning " 3003 "in a\n\tdegraded state.\n")); 3004 (void) printf(gettext("action: Replace the faulted device, " 3005 "or use 'zpool clear' to mark the device\n\trepaired.\n")); 3006 break; 3007 3008 case ZPOOL_STATUS_FAULTED_DEV_NR: 3009 (void) printf(gettext("status: One or more devices are " 3010 "faulted in response to persistent errors. There are " 3011 "insufficient replicas for the pool to\n\tcontinue " 3012 "functioning.\n")); 3013 (void) printf(gettext("action: Destroy and re-create the pool " 3014 "from a backup source. Manually marking the device\n" 3015 "\trepaired using 'zpool clear' may allow some data " 3016 "to be recovered.\n")); 3017 break; 3018 3019 default: 3020 /* 3021 * The remaining errors can't actually be generated, yet. 3022 */ 3023 assert(reason == ZPOOL_STATUS_OK); 3024 } 3025 3026 if (msgid != NULL) 3027 (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3028 msgid); 3029 3030 if (config != NULL) { 3031 int namewidth; 3032 uint64_t nerr; 3033 nvlist_t **spares; 3034 uint_t nspares; 3035 3036 3037 (void) printf(gettext(" scrub: ")); 3038 print_scrub_status(nvroot); 3039 3040 namewidth = max_width(zhp, nvroot, 0, 0); 3041 if (namewidth < 10) 3042 namewidth = 10; 3043 3044 (void) printf(gettext("config:\n\n")); 3045 (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3046 "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3047 print_status_config(zhp, zpool_get_name(zhp), nvroot, 3048 namewidth, 0, B_FALSE); 3049 3050 if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 3051 &spares, &nspares) == 0) 3052 print_spares(zhp, spares, nspares, namewidth); 3053 3054 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3055 &nerr) == 0) { 3056 nvlist_t *nverrlist = NULL; 3057 3058 /* 3059 * If the approximate error count is small, get a 3060 * precise count by fetching the entire log and 3061 * uniquifying the results. 3062 */ 3063 if (nerr < 100 && !cbp->cb_verbose && 3064 zpool_get_errlog(zhp, &nverrlist) == 0) { 3065 nvpair_t *elem; 3066 3067 elem = NULL; 3068 nerr = 0; 3069 while ((elem = nvlist_next_nvpair(nverrlist, 3070 elem)) != NULL) { 3071 nerr++; 3072 } 3073 } 3074 nvlist_free(nverrlist); 3075 3076 (void) printf("\n"); 3077 3078 if (nerr == 0) 3079 (void) printf(gettext("errors: No known data " 3080 "errors\n")); 3081 else if (!cbp->cb_verbose) 3082 (void) printf(gettext("errors: %llu data " 3083 "errors, use '-v' for a list\n"), 3084 (u_longlong_t)nerr); 3085 else 3086 print_error_log(zhp); 3087 } 3088 } else { 3089 (void) printf(gettext("config: The configuration cannot be " 3090 "determined.\n")); 3091 } 3092 3093 return (0); 3094 } 3095 3096 /* 3097 * zpool status [-vx] [pool] ... 3098 * 3099 * -v Display complete error logs 3100 * -x Display only pools with potential problems 3101 * 3102 * Describes the health status of all pools or some subset. 3103 */ 3104 int 3105 zpool_do_status(int argc, char **argv) 3106 { 3107 int c; 3108 int ret; 3109 status_cbdata_t cb = { 0 }; 3110 3111 /* check options */ 3112 while ((c = getopt(argc, argv, "vx")) != -1) { 3113 switch (c) { 3114 case 'v': 3115 cb.cb_verbose = B_TRUE; 3116 break; 3117 case 'x': 3118 cb.cb_explain = B_TRUE; 3119 break; 3120 case '?': 3121 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3122 optopt); 3123 usage(B_FALSE); 3124 } 3125 } 3126 3127 argc -= optind; 3128 argv += optind; 3129 3130 cb.cb_first = B_TRUE; 3131 3132 if (argc == 0) 3133 cb.cb_allpools = B_TRUE; 3134 3135 ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3136 3137 if (argc == 0 && cb.cb_count == 0) 3138 (void) printf(gettext("no pools available\n")); 3139 else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3140 (void) printf(gettext("all pools are healthy\n")); 3141 3142 return (ret); 3143 } 3144 3145 typedef struct upgrade_cbdata { 3146 int cb_all; 3147 int cb_first; 3148 int cb_newer; 3149 int cb_argc; 3150 char **cb_argv; 3151 } upgrade_cbdata_t; 3152 3153 static int 3154 upgrade_cb(zpool_handle_t *zhp, void *arg) 3155 { 3156 upgrade_cbdata_t *cbp = arg; 3157 nvlist_t *config; 3158 uint64_t version; 3159 int ret = 0; 3160 3161 config = zpool_get_config(zhp, NULL); 3162 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3163 &version) == 0); 3164 3165 if (!cbp->cb_newer && version < ZFS_VERSION) { 3166 if (!cbp->cb_all) { 3167 if (cbp->cb_first) { 3168 (void) printf(gettext("The following pools are " 3169 "out of date, and can be upgraded. After " 3170 "being\nupgraded, these pools will no " 3171 "longer be accessible by older software " 3172 "versions.\n\n")); 3173 (void) printf(gettext("VER POOL\n")); 3174 (void) printf(gettext("--- ------------\n")); 3175 cbp->cb_first = B_FALSE; 3176 } 3177 3178 (void) printf("%2llu %s\n", (u_longlong_t)version, 3179 zpool_get_name(zhp)); 3180 } else { 3181 cbp->cb_first = B_FALSE; 3182 ret = zpool_upgrade(zhp); 3183 if (!ret) { 3184 zpool_log_history(g_zfs, cbp->cb_argc, 3185 cbp->cb_argv, zpool_get_name(zhp), B_TRUE, 3186 B_FALSE); 3187 (void) printf(gettext("Successfully upgraded " 3188 "'%s'\n"), zpool_get_name(zhp)); 3189 } 3190 } 3191 } else if (cbp->cb_newer && version > ZFS_VERSION) { 3192 assert(!cbp->cb_all); 3193 3194 if (cbp->cb_first) { 3195 (void) printf(gettext("The following pools are " 3196 "formatted using a newer software version and\n" 3197 "cannot be accessed on the current system.\n\n")); 3198 (void) printf(gettext("VER POOL\n")); 3199 (void) printf(gettext("--- ------------\n")); 3200 cbp->cb_first = B_FALSE; 3201 } 3202 3203 (void) printf("%2llu %s\n", (u_longlong_t)version, 3204 zpool_get_name(zhp)); 3205 } 3206 3207 zpool_close(zhp); 3208 return (ret); 3209 } 3210 3211 /* ARGSUSED */ 3212 static int 3213 upgrade_one(zpool_handle_t *zhp, void *data) 3214 { 3215 nvlist_t *config; 3216 uint64_t version; 3217 int ret; 3218 upgrade_cbdata_t *cbp = data; 3219 3220 config = zpool_get_config(zhp, NULL); 3221 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3222 &version) == 0); 3223 3224 if (version == ZFS_VERSION) { 3225 (void) printf(gettext("Pool '%s' is already formatted " 3226 "using the current version.\n"), zpool_get_name(zhp)); 3227 return (0); 3228 } 3229 3230 ret = zpool_upgrade(zhp); 3231 3232 if (!ret) { 3233 zpool_log_history(g_zfs, cbp->cb_argc, cbp->cb_argv, 3234 zpool_get_name(zhp), B_TRUE, B_FALSE); 3235 (void) printf(gettext("Successfully upgraded '%s' " 3236 "from version %llu to version %llu\n"), zpool_get_name(zhp), 3237 (u_longlong_t)version, (u_longlong_t)ZFS_VERSION); 3238 } 3239 3240 return (ret != 0); 3241 } 3242 3243 /* 3244 * zpool upgrade 3245 * zpool upgrade -v 3246 * zpool upgrade <-a | pool> 3247 * 3248 * With no arguments, display downrev'd ZFS pool available for upgrade. 3249 * Individual pools can be upgraded by specifying the pool, and '-a' will 3250 * upgrade all pools. 3251 */ 3252 int 3253 zpool_do_upgrade(int argc, char **argv) 3254 { 3255 int c; 3256 upgrade_cbdata_t cb = { 0 }; 3257 int ret = 0; 3258 boolean_t showversions = B_FALSE; 3259 3260 /* check options */ 3261 while ((c = getopt(argc, argv, "av")) != -1) { 3262 switch (c) { 3263 case 'a': 3264 cb.cb_all = B_TRUE; 3265 break; 3266 case 'v': 3267 showversions = B_TRUE; 3268 break; 3269 case '?': 3270 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3271 optopt); 3272 usage(B_FALSE); 3273 } 3274 } 3275 3276 cb.cb_argc = argc; 3277 cb.cb_argv = argv; 3278 argc -= optind; 3279 argv += optind; 3280 3281 if (showversions) { 3282 if (cb.cb_all || argc != 0) { 3283 (void) fprintf(stderr, gettext("-v option is " 3284 "incompatible with other arguments\n")); 3285 usage(B_FALSE); 3286 } 3287 } else if (cb.cb_all) { 3288 if (argc != 0) { 3289 (void) fprintf(stderr, gettext("-a option is " 3290 "incompatible with other arguments\n")); 3291 usage(B_FALSE); 3292 } 3293 } 3294 3295 (void) printf(gettext("This system is currently running ZFS version " 3296 "%llu.\n\n"), ZFS_VERSION); 3297 cb.cb_first = B_TRUE; 3298 if (showversions) { 3299 (void) printf(gettext("The following versions are " 3300 "supported:\n\n")); 3301 (void) printf(gettext("VER DESCRIPTION\n")); 3302 (void) printf("--- -----------------------------------------" 3303 "---------------\n"); 3304 (void) printf(gettext(" 1 Initial ZFS version\n")); 3305 (void) printf(gettext(" 2 Ditto blocks " 3306 "(replicated metadata)\n")); 3307 (void) printf(gettext(" 3 Hot spares and double parity " 3308 "RAID-Z\n")); 3309 (void) printf(gettext(" 4 zpool history\n")); 3310 (void) printf(gettext(" 5 Compression using the gzip " 3311 "algorithm\n")); 3312 (void) printf(gettext(" 6 pool properties ")); 3313 (void) printf(gettext("\nFor more information on a particular " 3314 "version, including supported releases, see:\n\n")); 3315 (void) printf("http://www.opensolaris.org/os/community/zfs/" 3316 "version/N\n\n"); 3317 (void) printf(gettext("Where 'N' is the version number.\n")); 3318 } else if (argc == 0) { 3319 int notfound; 3320 3321 ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3322 notfound = cb.cb_first; 3323 3324 if (!cb.cb_all && ret == 0) { 3325 if (!cb.cb_first) 3326 (void) printf("\n"); 3327 cb.cb_first = B_TRUE; 3328 cb.cb_newer = B_TRUE; 3329 ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3330 if (!cb.cb_first) { 3331 notfound = B_FALSE; 3332 (void) printf("\n"); 3333 } 3334 } 3335 3336 if (ret == 0) { 3337 if (notfound) 3338 (void) printf(gettext("All pools are formatted " 3339 "using this version.\n")); 3340 else if (!cb.cb_all) 3341 (void) printf(gettext("Use 'zpool upgrade -v' " 3342 "for a list of available versions and " 3343 "their associated\nfeatures.\n")); 3344 } 3345 } else { 3346 ret = for_each_pool(argc, argv, B_FALSE, NULL, 3347 upgrade_one, &cb); 3348 } 3349 3350 return (ret); 3351 } 3352 3353 /* 3354 * Print out the command history for a specific pool. 3355 */ 3356 static int 3357 get_history_one(zpool_handle_t *zhp, void *data) 3358 { 3359 nvlist_t *nvhis; 3360 nvlist_t **records; 3361 uint_t numrecords; 3362 char *cmdstr; 3363 uint64_t dst_time; 3364 time_t tsec; 3365 struct tm t; 3366 char tbuf[30]; 3367 int ret, i; 3368 3369 *(boolean_t *)data = B_FALSE; 3370 3371 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 3372 3373 if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 3374 return (ret); 3375 3376 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 3377 &records, &numrecords) == 0); 3378 for (i = 0; i < numrecords; i++) { 3379 if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3380 &dst_time) == 0) { 3381 verify(nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3382 &cmdstr) == 0); 3383 tsec = dst_time; 3384 (void) localtime_r(&tsec, &t); 3385 (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3386 (void) printf("%s %s\n", tbuf, cmdstr); 3387 } 3388 } 3389 (void) printf("\n"); 3390 nvlist_free(nvhis); 3391 3392 return (ret); 3393 } 3394 3395 /* 3396 * zpool history <pool> 3397 * 3398 * Displays the history of commands that modified pools. 3399 */ 3400 int 3401 zpool_do_history(int argc, char **argv) 3402 { 3403 boolean_t first = B_TRUE; 3404 int ret; 3405 3406 argc -= optind; 3407 argv += optind; 3408 3409 ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3410 &first); 3411 3412 if (argc == 0 && first == B_TRUE) { 3413 (void) printf(gettext("no pools available\n")); 3414 return (0); 3415 } 3416 3417 return (ret); 3418 } 3419 3420 static int 3421 get_callback(zpool_handle_t *zhp, void *data) 3422 { 3423 libzfs_get_cbdata_t *cbp = (libzfs_get_cbdata_t *)data; 3424 char value[MAXNAMELEN]; 3425 zfs_source_t srctype; 3426 zpool_proplist_t *pl; 3427 3428 for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3429 3430 /* 3431 * Skip the special fake placeholder. 3432 */ 3433 if (pl->pl_prop == ZFS_PROP_NAME && 3434 pl == cbp->cb_proplist) 3435 continue; 3436 3437 if (zpool_get_prop(zhp, pl->pl_prop, 3438 value, sizeof (value), &srctype) != 0) 3439 continue; 3440 3441 libzfs_print_one_property(zpool_get_name(zhp), cbp, 3442 zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3443 } 3444 return (0); 3445 } 3446 3447 int 3448 zpool_do_get(int argc, char **argv) 3449 { 3450 libzfs_get_cbdata_t cb = { 0 }; 3451 zpool_proplist_t fake_name = { 0 }; 3452 int ret; 3453 3454 if (argc < 3) 3455 usage(B_FALSE); 3456 3457 cb.cb_first = B_TRUE; 3458 cb.cb_sources = ZFS_SRC_ALL; 3459 cb.cb_columns[0] = GET_COL_NAME; 3460 cb.cb_columns[1] = GET_COL_PROPERTY; 3461 cb.cb_columns[2] = GET_COL_VALUE; 3462 cb.cb_columns[3] = GET_COL_SOURCE; 3463 3464 if (zpool_get_proplist(g_zfs, argv[1], &cb.cb_proplist) != 0) 3465 usage(B_FALSE); 3466 3467 if (cb.cb_proplist != NULL) { 3468 fake_name.pl_prop = ZFS_PROP_NAME; 3469 fake_name.pl_width = strlen(gettext("NAME")); 3470 fake_name.pl_next = cb.cb_proplist; 3471 cb.cb_proplist = &fake_name; 3472 } 3473 3474 ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3475 get_callback, &cb); 3476 3477 if (cb.cb_proplist == &fake_name) 3478 zfs_free_proplist(fake_name.pl_next); 3479 else 3480 zfs_free_proplist(cb.cb_proplist); 3481 3482 return (ret); 3483 } 3484 3485 typedef struct set_cbdata { 3486 char *cb_propname; 3487 char *cb_value; 3488 boolean_t cb_any_successful; 3489 } set_cbdata_t; 3490 3491 int 3492 set_callback(zpool_handle_t *zhp, void *data) 3493 { 3494 int error; 3495 set_cbdata_t *cb = (set_cbdata_t *)data; 3496 3497 error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3498 3499 if (!error) 3500 cb->cb_any_successful = B_TRUE; 3501 3502 return (error); 3503 } 3504 3505 int 3506 zpool_do_set(int argc, char **argv) 3507 { 3508 set_cbdata_t cb = { 0 }; 3509 int error; 3510 3511 if (argc > 1 && argv[1][0] == '-') { 3512 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3513 argv[1][1]); 3514 usage(B_FALSE); 3515 } 3516 3517 if (argc < 2) { 3518 (void) fprintf(stderr, gettext("missing property=value " 3519 "argument\n")); 3520 usage(B_FALSE); 3521 } 3522 3523 if (argc < 3) { 3524 (void) fprintf(stderr, gettext("missing pool name\n")); 3525 usage(B_FALSE); 3526 } 3527 3528 if (argc > 3) { 3529 (void) fprintf(stderr, gettext("too many pool names\n")); 3530 usage(B_FALSE); 3531 } 3532 3533 cb.cb_propname = argv[1]; 3534 cb.cb_value = strchr(cb.cb_propname, '='); 3535 if (cb.cb_value == NULL) { 3536 (void) fprintf(stderr, gettext("missing value in " 3537 "property=value argument\n")); 3538 usage(B_FALSE); 3539 } 3540 3541 *(cb.cb_value) = '\0'; 3542 cb.cb_value++; 3543 3544 error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3545 set_callback, &cb); 3546 3547 if (cb.cb_any_successful) { 3548 *(cb.cb_value - 1) = '='; 3549 zpool_log_history(g_zfs, argc, argv, argv[2], B_FALSE, B_FALSE); 3550 } 3551 3552 return (error); 3553 } 3554 3555 static int 3556 find_command_idx(char *command, int *idx) 3557 { 3558 int i; 3559 3560 for (i = 0; i < NCOMMAND; i++) { 3561 if (command_table[i].name == NULL) 3562 continue; 3563 3564 if (strcmp(command, command_table[i].name) == 0) { 3565 *idx = i; 3566 return (0); 3567 } 3568 } 3569 return (1); 3570 } 3571 3572 int 3573 main(int argc, char **argv) 3574 { 3575 int ret; 3576 int i; 3577 char *cmdname; 3578 int found = 0; 3579 3580 (void) setlocale(LC_ALL, ""); 3581 (void) textdomain(TEXT_DOMAIN); 3582 3583 if ((g_zfs = libzfs_init()) == NULL) { 3584 (void) fprintf(stderr, gettext("internal error: failed to " 3585 "initialize ZFS library\n")); 3586 return (1); 3587 } 3588 3589 libzfs_print_on_error(g_zfs, B_TRUE); 3590 3591 opterr = 0; 3592 3593 /* 3594 * Make sure the user has specified some command. 3595 */ 3596 if (argc < 2) { 3597 (void) fprintf(stderr, gettext("missing command\n")); 3598 usage(B_FALSE); 3599 } 3600 3601 cmdname = argv[1]; 3602 3603 /* 3604 * Special case '-?' 3605 */ 3606 if (strcmp(cmdname, "-?") == 0) 3607 usage(B_TRUE); 3608 3609 /* 3610 * Run the appropriate command. 3611 */ 3612 if (find_command_idx(cmdname, &i) == 0) { 3613 current_command = &command_table[i]; 3614 ret = command_table[i].func(argc - 1, argv + 1); 3615 found++; 3616 } 3617 3618 /* 3619 * 'freeze' is a vile debugging abomination, so we treat it as such. 3620 */ 3621 if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 3622 char buf[16384]; 3623 int fd = open(ZFS_DEV, O_RDWR); 3624 (void) strcpy((void *)buf, argv[2]); 3625 return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 3626 } 3627 3628 if (!found) { 3629 (void) fprintf(stderr, gettext("unrecognized " 3630 "command '%s'\n"), cmdname); 3631 usage(B_FALSE); 3632 } 3633 3634 libzfs_fini(g_zfs); 3635 3636 /* 3637 * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3638 * for the purposes of running ::findleaks. 3639 */ 3640 if (getenv("ZFS_ABORT") != NULL) { 3641 (void) printf("dumping core by request\n"); 3642 abort(); 3643 } 3644 3645 return (ret); 3646 } 3647