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