zpool_main.c revision 185029
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23185029Spjd * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24168404Spjd * Use is subject to license terms. 25168404Spjd */ 26168404Spjd 27168404Spjd#include <solaris.h> 28168404Spjd#include <assert.h> 29168404Spjd#include <ctype.h> 30168404Spjd#include <dirent.h> 31168404Spjd#include <errno.h> 32168404Spjd#include <fcntl.h> 33168404Spjd#include <libgen.h> 34168404Spjd#include <libintl.h> 35168404Spjd#include <libuutil.h> 36168404Spjd#include <locale.h> 37168404Spjd#include <stdio.h> 38168404Spjd#include <stdlib.h> 39168404Spjd#include <string.h> 40168404Spjd#include <strings.h> 41168404Spjd#include <unistd.h> 42168404Spjd#include <priv.h> 43185029Spjd#include <pwd.h> 44185029Spjd#include <zone.h> 45168404Spjd#include <sys/time.h> 46168404Spjd#include <sys/fs/zfs.h> 47168404Spjd 48168404Spjd#include <sys/stat.h> 49168404Spjd 50168404Spjd#include <libzfs.h> 51168404Spjd 52168404Spjd#include "zpool_util.h" 53185029Spjd#include "zfs_comutil.h" 54168404Spjd 55168404Spjdstatic int zpool_do_create(int, char **); 56168404Spjdstatic int zpool_do_destroy(int, char **); 57168404Spjd 58168404Spjdstatic int zpool_do_add(int, char **); 59168404Spjdstatic int zpool_do_remove(int, char **); 60168404Spjd 61168404Spjdstatic int zpool_do_list(int, char **); 62168404Spjdstatic int zpool_do_iostat(int, char **); 63168404Spjdstatic int zpool_do_status(int, char **); 64168404Spjd 65168404Spjdstatic int zpool_do_online(int, char **); 66168404Spjdstatic int zpool_do_offline(int, char **); 67168404Spjdstatic int zpool_do_clear(int, char **); 68168404Spjd 69168404Spjdstatic int zpool_do_attach(int, char **); 70168404Spjdstatic int zpool_do_detach(int, char **); 71168404Spjdstatic int zpool_do_replace(int, char **); 72168404Spjd 73168404Spjdstatic int zpool_do_scrub(int, char **); 74168404Spjd 75168404Spjdstatic int zpool_do_import(int, char **); 76168404Spjdstatic int zpool_do_export(int, char **); 77168404Spjd 78168404Spjdstatic int zpool_do_upgrade(int, char **); 79168404Spjd 80168404Spjdstatic int zpool_do_history(int, char **); 81168404Spjd 82168404Spjdstatic int zpool_do_get(int, char **); 83168404Spjdstatic int zpool_do_set(int, char **); 84168404Spjd 85168404Spjd/* 86168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 87168404Spjd * debugging facilities. 88168404Spjd */ 89185029Spjd 90185029Spjd#ifdef DEBUG 91168404Spjdconst char * 92168404Spjd_umem_debug_init(void) 93168404Spjd{ 94168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 95168404Spjd} 96168404Spjd 97168404Spjdconst char * 98168404Spjd_umem_logging_init(void) 99168404Spjd{ 100168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 101168404Spjd} 102185029Spjd#endif 103168404Spjd 104168404Spjdtypedef enum { 105168404Spjd HELP_ADD, 106168404Spjd HELP_ATTACH, 107168404Spjd HELP_CLEAR, 108168404Spjd HELP_CREATE, 109168404Spjd HELP_DESTROY, 110168404Spjd HELP_DETACH, 111168404Spjd HELP_EXPORT, 112168404Spjd HELP_HISTORY, 113168404Spjd HELP_IMPORT, 114168404Spjd HELP_IOSTAT, 115168404Spjd HELP_LIST, 116168404Spjd HELP_OFFLINE, 117168404Spjd HELP_ONLINE, 118168404Spjd HELP_REPLACE, 119168404Spjd HELP_REMOVE, 120168404Spjd HELP_SCRUB, 121168404Spjd HELP_STATUS, 122168404Spjd HELP_UPGRADE, 123168404Spjd HELP_GET, 124168404Spjd HELP_SET 125168404Spjd} zpool_help_t; 126168404Spjd 127168404Spjd 128168404Spjdtypedef struct zpool_command { 129168404Spjd const char *name; 130168404Spjd int (*func)(int, char **); 131168404Spjd zpool_help_t usage; 132168404Spjd} zpool_command_t; 133168404Spjd 134168404Spjd/* 135168404Spjd * Master command table. Each ZFS command has a name, associated function, and 136168404Spjd * usage message. The usage messages need to be internationalized, so we have 137168404Spjd * to have a function to return the usage message based on a command index. 138168404Spjd * 139168404Spjd * These commands are organized according to how they are displayed in the usage 140168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 141168404Spjd * the generic usage message. 142168404Spjd */ 143168404Spjdstatic zpool_command_t command_table[] = { 144168404Spjd { "create", zpool_do_create, HELP_CREATE }, 145168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 146168404Spjd { NULL }, 147168404Spjd { "add", zpool_do_add, HELP_ADD }, 148168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 149168404Spjd { NULL }, 150168404Spjd { "list", zpool_do_list, HELP_LIST }, 151168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 152168404Spjd { "status", zpool_do_status, HELP_STATUS }, 153168404Spjd { NULL }, 154168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 155168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 156168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 157168404Spjd { NULL }, 158168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 159168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 160168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 161168404Spjd { NULL }, 162168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 163168404Spjd { NULL }, 164168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 165168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 166168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 167168404Spjd { NULL }, 168168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 169168404Spjd { "get", zpool_do_get, HELP_GET }, 170168404Spjd { "set", zpool_do_set, HELP_SET }, 171168404Spjd}; 172168404Spjd 173168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 174168404Spjd 175168404Spjdzpool_command_t *current_command; 176185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 177168404Spjd 178168404Spjdstatic const char * 179168404Spjdget_usage(zpool_help_t idx) { 180168404Spjd switch (idx) { 181168404Spjd case HELP_ADD: 182168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 183168404Spjd case HELP_ATTACH: 184168404Spjd return (gettext("\tattach [-f] <pool> <device> " 185185029Spjd "<new-device>\n")); 186168404Spjd case HELP_CLEAR: 187168404Spjd return (gettext("\tclear <pool> [device]\n")); 188168404Spjd case HELP_CREATE: 189185029Spjd return (gettext("\tcreate [-fn] [-o property=value] ... \n" 190185029Spjd "\t [-O file-system-property=value] ... \n" 191185029Spjd "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 192168404Spjd case HELP_DESTROY: 193168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 194168404Spjd case HELP_DETACH: 195168404Spjd return (gettext("\tdetach <pool> <device>\n")); 196168404Spjd case HELP_EXPORT: 197168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 198168404Spjd case HELP_HISTORY: 199185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 200168404Spjd case HELP_IMPORT: 201168404Spjd return (gettext("\timport [-d dir] [-D]\n" 202185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 203185029Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n" 204185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 205185029Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-R root] " 206185029Spjd "<pool | id> [newpool]\n")); 207168404Spjd case HELP_IOSTAT: 208168404Spjd return (gettext("\tiostat [-v] [pool] ... [interval " 209168404Spjd "[count]]\n")); 210168404Spjd case HELP_LIST: 211185029Spjd return (gettext("\tlist [-H] [-o property[,...]] " 212168404Spjd "[pool] ...\n")); 213168404Spjd case HELP_OFFLINE: 214168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 215168404Spjd case HELP_ONLINE: 216168404Spjd return (gettext("\tonline <pool> <device> ...\n")); 217168404Spjd case HELP_REPLACE: 218168404Spjd return (gettext("\treplace [-f] <pool> <device> " 219185029Spjd "[new-device]\n")); 220168404Spjd case HELP_REMOVE: 221185029Spjd return (gettext("\tremove <pool> <device> ...\n")); 222168404Spjd case HELP_SCRUB: 223168404Spjd return (gettext("\tscrub [-s] <pool> ...\n")); 224168404Spjd case HELP_STATUS: 225168404Spjd return (gettext("\tstatus [-vx] [pool] ...\n")); 226168404Spjd case HELP_UPGRADE: 227168404Spjd return (gettext("\tupgrade\n" 228168404Spjd "\tupgrade -v\n" 229185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 230168404Spjd case HELP_GET: 231185029Spjd return (gettext("\tget <\"all\" | property[,...]> " 232168404Spjd "<pool> ...\n")); 233168404Spjd case HELP_SET: 234168404Spjd return (gettext("\tset <property=value> <pool> \n")); 235168404Spjd } 236168404Spjd 237168404Spjd abort(); 238168404Spjd /* NOTREACHED */ 239168404Spjd} 240168404Spjd 241168404Spjd 242168404Spjd/* 243168404Spjd * Callback routine that will print out a pool property value. 244168404Spjd */ 245185029Spjdstatic int 246185029Spjdprint_prop_cb(int prop, void *cb) 247168404Spjd{ 248168404Spjd FILE *fp = cb; 249168404Spjd 250168404Spjd (void) fprintf(fp, "\t%-13s ", zpool_prop_to_name(prop)); 251168404Spjd 252185029Spjd if (zpool_prop_readonly(prop)) 253185029Spjd (void) fprintf(fp, " NO "); 254185029Spjd else 255185029Spjd (void) fprintf(fp, " YES "); 256185029Spjd 257168404Spjd if (zpool_prop_values(prop) == NULL) 258168404Spjd (void) fprintf(fp, "-\n"); 259168404Spjd else 260168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 261168404Spjd 262185029Spjd return (ZPROP_CONT); 263168404Spjd} 264168404Spjd 265168404Spjd/* 266168404Spjd * Display usage message. If we're inside a command, display only the usage for 267168404Spjd * that command. Otherwise, iterate over the entire command table and display 268168404Spjd * a complete usage message. 269168404Spjd */ 270168404Spjdvoid 271168404Spjdusage(boolean_t requested) 272168404Spjd{ 273168404Spjd FILE *fp = requested ? stdout : stderr; 274168404Spjd 275168404Spjd if (current_command == NULL) { 276168404Spjd int i; 277168404Spjd 278168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 279168404Spjd (void) fprintf(fp, 280168404Spjd gettext("where 'command' is one of the following:\n\n")); 281168404Spjd 282168404Spjd for (i = 0; i < NCOMMAND; i++) { 283168404Spjd if (command_table[i].name == NULL) 284168404Spjd (void) fprintf(fp, "\n"); 285168404Spjd else 286168404Spjd (void) fprintf(fp, "%s", 287168404Spjd get_usage(command_table[i].usage)); 288168404Spjd } 289168404Spjd } else { 290168404Spjd (void) fprintf(fp, gettext("usage:\n")); 291168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 292168404Spjd } 293168404Spjd 294168404Spjd if (current_command != NULL && 295168404Spjd ((strcmp(current_command->name, "set") == 0) || 296185029Spjd (strcmp(current_command->name, "get") == 0) || 297185029Spjd (strcmp(current_command->name, "list") == 0))) { 298168404Spjd 299168404Spjd (void) fprintf(fp, 300168404Spjd gettext("\nthe following properties are supported:\n")); 301168404Spjd 302185029Spjd (void) fprintf(fp, "\n\t%-13s %s %s\n\n", 303185029Spjd "PROPERTY", "EDIT", "VALUES"); 304168404Spjd 305168404Spjd /* Iterate over all properties */ 306185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 307185029Spjd ZFS_TYPE_POOL); 308168404Spjd } 309168404Spjd 310168404Spjd /* 311168404Spjd * See comments at end of main(). 312168404Spjd */ 313168404Spjd if (getenv("ZFS_ABORT") != NULL) { 314168404Spjd (void) printf("dumping core by request\n"); 315168404Spjd abort(); 316168404Spjd } 317168404Spjd 318168404Spjd exit(requested ? 0 : 2); 319168404Spjd} 320168404Spjd 321168404Spjdvoid 322185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 323185029Spjd boolean_t print_logs) 324168404Spjd{ 325168404Spjd nvlist_t **child; 326168404Spjd uint_t c, children; 327168404Spjd char *vname; 328168404Spjd 329168404Spjd if (name != NULL) 330168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 331168404Spjd 332168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 333168404Spjd &child, &children) != 0) 334168404Spjd return; 335168404Spjd 336168404Spjd for (c = 0; c < children; c++) { 337185029Spjd uint64_t is_log = B_FALSE; 338185029Spjd 339185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 340185029Spjd &is_log); 341185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 342185029Spjd continue; 343185029Spjd 344168404Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c]); 345185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 346185029Spjd B_FALSE); 347168404Spjd free(vname); 348168404Spjd } 349168404Spjd} 350168404Spjd 351168404Spjd/* 352185029Spjd * Add a property pair (name, string-value) into a property nvlist. 353185029Spjd */ 354185029Spjdstatic int 355185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 356185029Spjd boolean_t poolprop) 357185029Spjd{ 358185029Spjd zpool_prop_t prop = ZPROP_INVAL; 359185029Spjd zfs_prop_t fprop; 360185029Spjd nvlist_t *proplist; 361185029Spjd const char *normnm; 362185029Spjd char *strval; 363185029Spjd 364185029Spjd if (*props == NULL && 365185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 366185029Spjd (void) fprintf(stderr, 367185029Spjd gettext("internal error: out of memory\n")); 368185029Spjd return (1); 369185029Spjd } 370185029Spjd 371185029Spjd proplist = *props; 372185029Spjd 373185029Spjd if (poolprop) { 374185029Spjd if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 375185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 376185029Spjd "not a valid pool property\n"), propname); 377185029Spjd return (2); 378185029Spjd } 379185029Spjd normnm = zpool_prop_to_name(prop); 380185029Spjd } else { 381185029Spjd if ((fprop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 382185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 383185029Spjd "not a valid file system property\n"), propname); 384185029Spjd return (2); 385185029Spjd } 386185029Spjd normnm = zfs_prop_to_name(fprop); 387185029Spjd } 388185029Spjd 389185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 390185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 391185029Spjd (void) fprintf(stderr, gettext("property '%s' " 392185029Spjd "specified multiple times\n"), propname); 393185029Spjd return (2); 394185029Spjd } 395185029Spjd 396185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 397185029Spjd (void) fprintf(stderr, gettext("internal " 398185029Spjd "error: out of memory\n")); 399185029Spjd return (1); 400185029Spjd } 401185029Spjd 402185029Spjd return (0); 403185029Spjd} 404185029Spjd 405185029Spjd/* 406168404Spjd * zpool add [-fn] <pool> <vdev> ... 407168404Spjd * 408168404Spjd * -f Force addition of devices, even if they appear in use 409168404Spjd * -n Do not add the devices, but display the resulting layout if 410168404Spjd * they were to be added. 411168404Spjd * 412168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 413168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 414168404Spjd * libzfs. 415168404Spjd */ 416168404Spjdint 417168404Spjdzpool_do_add(int argc, char **argv) 418168404Spjd{ 419168404Spjd boolean_t force = B_FALSE; 420168404Spjd boolean_t dryrun = B_FALSE; 421168404Spjd int c; 422168404Spjd nvlist_t *nvroot; 423168404Spjd char *poolname; 424168404Spjd int ret; 425168404Spjd zpool_handle_t *zhp; 426168404Spjd nvlist_t *config; 427168404Spjd 428168404Spjd /* check options */ 429168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 430168404Spjd switch (c) { 431168404Spjd case 'f': 432168404Spjd force = B_TRUE; 433168404Spjd break; 434168404Spjd case 'n': 435168404Spjd dryrun = B_TRUE; 436168404Spjd break; 437168404Spjd case '?': 438168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 439168404Spjd optopt); 440168404Spjd usage(B_FALSE); 441168404Spjd } 442168404Spjd } 443168404Spjd 444168404Spjd argc -= optind; 445168404Spjd argv += optind; 446168404Spjd 447168404Spjd /* get pool name and check number of arguments */ 448168404Spjd if (argc < 1) { 449168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 450168404Spjd usage(B_FALSE); 451168404Spjd } 452168404Spjd if (argc < 2) { 453168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 454168404Spjd usage(B_FALSE); 455168404Spjd } 456168404Spjd 457168404Spjd poolname = argv[0]; 458168404Spjd 459168404Spjd argc--; 460168404Spjd argv++; 461168404Spjd 462168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 463168404Spjd return (1); 464168404Spjd 465168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 466168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 467168404Spjd poolname); 468168404Spjd zpool_close(zhp); 469168404Spjd return (1); 470168404Spjd } 471168404Spjd 472168404Spjd /* pass off to get_vdev_spec for processing */ 473185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 474185029Spjd argc, argv); 475168404Spjd if (nvroot == NULL) { 476168404Spjd zpool_close(zhp); 477168404Spjd return (1); 478168404Spjd } 479168404Spjd 480168404Spjd if (dryrun) { 481168404Spjd nvlist_t *poolnvroot; 482168404Spjd 483168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 484168404Spjd &poolnvroot) == 0); 485168404Spjd 486168404Spjd (void) printf(gettext("would update '%s' to the following " 487168404Spjd "configuration:\n"), zpool_get_name(zhp)); 488168404Spjd 489185029Spjd /* print original main pool and new tree */ 490185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 491185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 492168404Spjd 493185029Spjd /* Do the same for the logs */ 494185029Spjd if (num_logs(poolnvroot) > 0) { 495185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 496185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 497185029Spjd } else if (num_logs(nvroot) > 0) { 498185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 499185029Spjd } 500185029Spjd 501168404Spjd ret = 0; 502168404Spjd } else { 503168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 504168404Spjd } 505168404Spjd 506168404Spjd nvlist_free(nvroot); 507168404Spjd zpool_close(zhp); 508168404Spjd 509168404Spjd return (ret); 510168404Spjd} 511168404Spjd 512168404Spjd/* 513185029Spjd * zpool remove <pool> <vdev> ... 514168404Spjd * 515168404Spjd * Removes the given vdev from the pool. Currently, this only supports removing 516185029Spjd * spares and cache devices from the pool. Eventually, we'll want to support 517185029Spjd * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs. 518168404Spjd */ 519168404Spjdint 520168404Spjdzpool_do_remove(int argc, char **argv) 521168404Spjd{ 522168404Spjd char *poolname; 523185029Spjd int i, ret = 0; 524168404Spjd zpool_handle_t *zhp; 525168404Spjd 526168404Spjd argc--; 527168404Spjd argv++; 528168404Spjd 529168404Spjd /* get pool name and check number of arguments */ 530168404Spjd if (argc < 1) { 531168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 532168404Spjd usage(B_FALSE); 533168404Spjd } 534168404Spjd if (argc < 2) { 535168404Spjd (void) fprintf(stderr, gettext("missing device\n")); 536168404Spjd usage(B_FALSE); 537168404Spjd } 538168404Spjd 539168404Spjd poolname = argv[0]; 540168404Spjd 541168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 542168404Spjd return (1); 543168404Spjd 544185029Spjd for (i = 1; i < argc; i++) { 545185029Spjd if (zpool_vdev_remove(zhp, argv[i]) != 0) 546185029Spjd ret = 1; 547168404Spjd } 548168404Spjd 549168404Spjd return (ret); 550168404Spjd} 551168404Spjd 552168404Spjd/* 553185029Spjd * zpool create [-fn] [-o property=value] ... 554185029Spjd * [-O file-system-property=value] ... 555185029Spjd * [-R root] [-m mountpoint] <pool> <dev> ... 556168404Spjd * 557168404Spjd * -f Force creation, even if devices appear in use 558168404Spjd * -n Do not create the pool, but display the resulting layout if it 559168404Spjd * were to be created. 560168404Spjd * -R Create a pool under an alternate root 561168404Spjd * -m Set default mountpoint for the root dataset. By default it's 562168404Spjd * '/<pool>' 563185029Spjd * -o Set property=value. 564185029Spjd * -O Set fsproperty=value in the pool's root file system 565168404Spjd * 566168404Spjd * Creates the named pool according to the given vdev specification. The 567168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 568168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 569168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 570168404Spjd */ 571168404Spjdint 572168404Spjdzpool_do_create(int argc, char **argv) 573168404Spjd{ 574168404Spjd boolean_t force = B_FALSE; 575168404Spjd boolean_t dryrun = B_FALSE; 576168404Spjd int c; 577185029Spjd nvlist_t *nvroot = NULL; 578168404Spjd char *poolname; 579185029Spjd int ret = 1; 580168404Spjd char *altroot = NULL; 581168404Spjd char *mountpoint = NULL; 582185029Spjd nvlist_t *fsprops = NULL; 583185029Spjd nvlist_t *props = NULL; 584185029Spjd char *propval; 585168404Spjd 586168404Spjd /* check options */ 587185029Spjd while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) { 588168404Spjd switch (c) { 589168404Spjd case 'f': 590168404Spjd force = B_TRUE; 591168404Spjd break; 592168404Spjd case 'n': 593168404Spjd dryrun = B_TRUE; 594168404Spjd break; 595168404Spjd case 'R': 596168404Spjd altroot = optarg; 597185029Spjd if (add_prop_list(zpool_prop_to_name( 598185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 599185029Spjd goto errout; 600185029Spjd if (nvlist_lookup_string(props, 601185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 602185029Spjd &propval) == 0) 603185029Spjd break; 604185029Spjd if (add_prop_list(zpool_prop_to_name( 605185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 606185029Spjd goto errout; 607168404Spjd break; 608168404Spjd case 'm': 609168404Spjd mountpoint = optarg; 610168404Spjd break; 611185029Spjd case 'o': 612185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 613185029Spjd (void) fprintf(stderr, gettext("missing " 614185029Spjd "'=' for -o option\n")); 615185029Spjd goto errout; 616185029Spjd } 617185029Spjd *propval = '\0'; 618185029Spjd propval++; 619185029Spjd 620185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 621185029Spjd goto errout; 622185029Spjd break; 623185029Spjd case 'O': 624185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 625185029Spjd (void) fprintf(stderr, gettext("missing " 626185029Spjd "'=' for -O option\n")); 627185029Spjd goto errout; 628185029Spjd } 629185029Spjd *propval = '\0'; 630185029Spjd propval++; 631185029Spjd 632185029Spjd if (add_prop_list(optarg, propval, &fsprops, B_FALSE)) 633185029Spjd goto errout; 634185029Spjd break; 635168404Spjd case ':': 636168404Spjd (void) fprintf(stderr, gettext("missing argument for " 637168404Spjd "'%c' option\n"), optopt); 638185029Spjd goto badusage; 639168404Spjd case '?': 640168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 641168404Spjd optopt); 642185029Spjd goto badusage; 643168404Spjd } 644168404Spjd } 645168404Spjd 646168404Spjd argc -= optind; 647168404Spjd argv += optind; 648168404Spjd 649168404Spjd /* get pool name and check number of arguments */ 650168404Spjd if (argc < 1) { 651168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 652185029Spjd goto badusage; 653168404Spjd } 654168404Spjd if (argc < 2) { 655168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 656185029Spjd goto badusage; 657168404Spjd } 658168404Spjd 659168404Spjd poolname = argv[0]; 660168404Spjd 661168404Spjd /* 662168404Spjd * As a special case, check for use of '/' in the name, and direct the 663168404Spjd * user to use 'zfs create' instead. 664168404Spjd */ 665168404Spjd if (strchr(poolname, '/') != NULL) { 666168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 667168404Spjd "character '/' in pool name\n"), poolname); 668168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 669168404Spjd "create a dataset\n")); 670185029Spjd goto errout; 671168404Spjd } 672168404Spjd 673168404Spjd /* pass off to get_vdev_spec for bulk processing */ 674185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 675185029Spjd argc - 1, argv + 1); 676168404Spjd if (nvroot == NULL) 677185029Spjd goto errout; 678168404Spjd 679168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 680185029Spjd if (!zfs_allocatable_devs(nvroot)) { 681168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 682168404Spjd "specification: at least one toplevel vdev must be " 683168404Spjd "specified\n")); 684185029Spjd goto errout; 685168404Spjd } 686168404Spjd 687168404Spjd 688168404Spjd if (altroot != NULL && altroot[0] != '/') { 689168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 690168404Spjd "must be an absolute path\n"), altroot); 691185029Spjd goto errout; 692168404Spjd } 693168404Spjd 694168404Spjd /* 695168404Spjd * Check the validity of the mountpoint and direct the user to use the 696168404Spjd * '-m' mountpoint option if it looks like its in use. 697168404Spjd */ 698168404Spjd if (mountpoint == NULL || 699168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 700168404Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) { 701168404Spjd char buf[MAXPATHLEN]; 702185029Spjd DIR *dirp; 703168404Spjd 704168404Spjd if (mountpoint && mountpoint[0] != '/') { 705168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 706168404Spjd "'%s': must be an absolute path, 'legacy', or " 707168404Spjd "'none'\n"), mountpoint); 708185029Spjd goto errout; 709168404Spjd } 710168404Spjd 711168404Spjd if (mountpoint == NULL) { 712168404Spjd if (altroot != NULL) 713168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 714168404Spjd altroot, poolname); 715168404Spjd else 716168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 717168404Spjd poolname); 718168404Spjd } else { 719168404Spjd if (altroot != NULL) 720168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 721168404Spjd altroot, mountpoint); 722168404Spjd else 723168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 724168404Spjd mountpoint); 725168404Spjd } 726168404Spjd 727185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 728185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 729185029Spjd "%s\n"), buf, strerror(errno)); 730185029Spjd (void) fprintf(stderr, gettext("use '-m' " 731185029Spjd "option to provide a different default\n")); 732185029Spjd goto errout; 733185029Spjd } else if (dirp) { 734185029Spjd int count = 0; 735185029Spjd 736185029Spjd while (count < 3 && readdir(dirp) != NULL) 737185029Spjd count++; 738185029Spjd (void) closedir(dirp); 739185029Spjd 740185029Spjd if (count > 2) { 741168404Spjd (void) fprintf(stderr, gettext("mountpoint " 742168404Spjd "'%s' exists and is not empty\n"), buf); 743185029Spjd (void) fprintf(stderr, gettext("use '-m' " 744185029Spjd "option to provide a " 745185029Spjd "different default\n")); 746185029Spjd goto errout; 747185029Spjd } 748168404Spjd } 749168404Spjd } 750168404Spjd 751168404Spjd if (dryrun) { 752168404Spjd /* 753168404Spjd * For a dry run invocation, print out a basic message and run 754168404Spjd * through all the vdevs in the list and print out in an 755168404Spjd * appropriate hierarchy. 756168404Spjd */ 757168404Spjd (void) printf(gettext("would create '%s' with the " 758168404Spjd "following layout:\n\n"), poolname); 759168404Spjd 760185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 761185029Spjd if (num_logs(nvroot) > 0) 762185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 763168404Spjd 764168404Spjd ret = 0; 765168404Spjd } else { 766168404Spjd /* 767168404Spjd * Hand off to libzfs. 768168404Spjd */ 769185029Spjd if (zpool_create(g_zfs, poolname, 770185029Spjd nvroot, props, fsprops) == 0) { 771168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 772168404Spjd ZFS_TYPE_FILESYSTEM); 773168404Spjd if (pool != NULL) { 774168404Spjd if (mountpoint != NULL) 775168404Spjd verify(zfs_prop_set(pool, 776168404Spjd zfs_prop_to_name( 777168404Spjd ZFS_PROP_MOUNTPOINT), 778168404Spjd mountpoint) == 0); 779168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 780185029Spjd ret = zfs_shareall(pool); 781168404Spjd zfs_close(pool); 782168404Spjd } 783168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 784168404Spjd (void) fprintf(stderr, gettext("pool name may have " 785168404Spjd "been omitted\n")); 786168404Spjd } 787168404Spjd } 788168404Spjd 789185029Spjderrout: 790168404Spjd nvlist_free(nvroot); 791185029Spjd nvlist_free(fsprops); 792185029Spjd nvlist_free(props); 793168404Spjd return (ret); 794185029Spjdbadusage: 795185029Spjd nvlist_free(fsprops); 796185029Spjd nvlist_free(props); 797185029Spjd usage(B_FALSE); 798185029Spjd return (2); 799168404Spjd} 800168404Spjd 801168404Spjd/* 802168404Spjd * zpool destroy <pool> 803168404Spjd * 804168404Spjd * -f Forcefully unmount any datasets 805168404Spjd * 806168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 807168404Spjd */ 808168404Spjdint 809168404Spjdzpool_do_destroy(int argc, char **argv) 810168404Spjd{ 811168404Spjd boolean_t force = B_FALSE; 812168404Spjd int c; 813168404Spjd char *pool; 814168404Spjd zpool_handle_t *zhp; 815168404Spjd int ret; 816168404Spjd 817168404Spjd /* check options */ 818168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 819168404Spjd switch (c) { 820168404Spjd case 'f': 821168404Spjd force = B_TRUE; 822168404Spjd break; 823168404Spjd case '?': 824168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 825168404Spjd optopt); 826168404Spjd usage(B_FALSE); 827168404Spjd } 828168404Spjd } 829168404Spjd 830168404Spjd argc -= optind; 831168404Spjd argv += optind; 832168404Spjd 833168404Spjd /* check arguments */ 834168404Spjd if (argc < 1) { 835168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 836168404Spjd usage(B_FALSE); 837168404Spjd } 838168404Spjd if (argc > 1) { 839168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 840168404Spjd usage(B_FALSE); 841168404Spjd } 842168404Spjd 843168404Spjd pool = argv[0]; 844168404Spjd 845168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 846168404Spjd /* 847168404Spjd * As a special case, check for use of '/' in the name, and 848168404Spjd * direct the user to use 'zfs destroy' instead. 849168404Spjd */ 850168404Spjd if (strchr(pool, '/') != NULL) 851168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 852168404Spjd "destroy a dataset\n")); 853168404Spjd return (1); 854168404Spjd } 855168404Spjd 856168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 857168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 858168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 859168404Spjd return (1); 860168404Spjd } 861168404Spjd 862168404Spjd ret = (zpool_destroy(zhp) != 0); 863168404Spjd 864168404Spjd zpool_close(zhp); 865168404Spjd 866168404Spjd return (ret); 867168404Spjd} 868168404Spjd 869168404Spjd/* 870168404Spjd * zpool export [-f] <pool> ... 871168404Spjd * 872168404Spjd * -f Forcefully unmount datasets 873168404Spjd * 874168404Spjd * Export the given pools. By default, the command will attempt to cleanly 875168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 876168404Spjd * then the datasets will be forcefully unmounted. 877168404Spjd */ 878168404Spjdint 879168404Spjdzpool_do_export(int argc, char **argv) 880168404Spjd{ 881168404Spjd boolean_t force = B_FALSE; 882168404Spjd int c; 883168404Spjd zpool_handle_t *zhp; 884168404Spjd int ret; 885168404Spjd int i; 886168404Spjd 887168404Spjd /* check options */ 888168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 889168404Spjd switch (c) { 890168404Spjd case 'f': 891168404Spjd force = B_TRUE; 892168404Spjd break; 893168404Spjd case '?': 894168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 895168404Spjd optopt); 896168404Spjd usage(B_FALSE); 897168404Spjd } 898168404Spjd } 899168404Spjd 900168404Spjd argc -= optind; 901168404Spjd argv += optind; 902168404Spjd 903168404Spjd /* check arguments */ 904168404Spjd if (argc < 1) { 905168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 906168404Spjd usage(B_FALSE); 907168404Spjd } 908168404Spjd 909168404Spjd ret = 0; 910168404Spjd for (i = 0; i < argc; i++) { 911168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 912168404Spjd ret = 1; 913168404Spjd continue; 914168404Spjd } 915168404Spjd 916168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 917168404Spjd ret = 1; 918168404Spjd zpool_close(zhp); 919168404Spjd continue; 920168404Spjd } 921168404Spjd 922185029Spjd if (zpool_export(zhp, force) != 0) 923168404Spjd ret = 1; 924168404Spjd 925168404Spjd zpool_close(zhp); 926168404Spjd } 927168404Spjd 928168404Spjd return (ret); 929168404Spjd} 930168404Spjd 931168404Spjd/* 932168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 933168404Spjd * name column. 934168404Spjd */ 935168404Spjdstatic int 936168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 937168404Spjd{ 938168404Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv); 939168404Spjd nvlist_t **child; 940168404Spjd uint_t c, children; 941168404Spjd int ret; 942168404Spjd 943168404Spjd if (strlen(name) + depth > max) 944168404Spjd max = strlen(name) + depth; 945168404Spjd 946168404Spjd free(name); 947168404Spjd 948168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 949168404Spjd &child, &children) == 0) { 950168404Spjd for (c = 0; c < children; c++) 951168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 952168404Spjd max)) > max) 953168404Spjd max = ret; 954168404Spjd } 955168404Spjd 956185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 957185029Spjd &child, &children) == 0) { 958185029Spjd for (c = 0; c < children; c++) 959185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 960185029Spjd max)) > max) 961185029Spjd max = ret; 962185029Spjd } 963185029Spjd 964168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 965168404Spjd &child, &children) == 0) { 966168404Spjd for (c = 0; c < children; c++) 967168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 968168404Spjd max)) > max) 969168404Spjd max = ret; 970168404Spjd } 971168404Spjd 972168404Spjd 973168404Spjd return (max); 974168404Spjd} 975168404Spjd 976168404Spjd 977168404Spjd/* 978168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 979168404Spjd * pool, printing out the name and status for each one. 980168404Spjd */ 981168404Spjdvoid 982185029Spjdprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth, 983185029Spjd boolean_t print_logs) 984168404Spjd{ 985168404Spjd nvlist_t **child; 986168404Spjd uint_t c, children; 987168404Spjd vdev_stat_t *vs; 988168404Spjd char *type, *vname; 989168404Spjd 990168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 991168404Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0) 992168404Spjd return; 993168404Spjd 994168404Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 995168404Spjd (uint64_t **)&vs, &c) == 0); 996168404Spjd 997168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 998185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 999168404Spjd 1000168404Spjd if (vs->vs_aux != 0) { 1001185029Spjd (void) printf(" "); 1002168404Spjd 1003168404Spjd switch (vs->vs_aux) { 1004168404Spjd case VDEV_AUX_OPEN_FAILED: 1005168404Spjd (void) printf(gettext("cannot open")); 1006168404Spjd break; 1007168404Spjd 1008168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1009168404Spjd (void) printf(gettext("missing device")); 1010168404Spjd break; 1011168404Spjd 1012168404Spjd case VDEV_AUX_NO_REPLICAS: 1013168404Spjd (void) printf(gettext("insufficient replicas")); 1014168404Spjd break; 1015168404Spjd 1016168404Spjd case VDEV_AUX_VERSION_NEWER: 1017168404Spjd (void) printf(gettext("newer version")); 1018168404Spjd break; 1019168404Spjd 1020185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1021185029Spjd (void) printf(gettext("too many errors")); 1022185029Spjd break; 1023185029Spjd 1024168404Spjd default: 1025168404Spjd (void) printf(gettext("corrupted data")); 1026168404Spjd break; 1027168404Spjd } 1028168404Spjd } 1029168404Spjd (void) printf("\n"); 1030168404Spjd 1031168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1032168404Spjd &child, &children) != 0) 1033168404Spjd return; 1034168404Spjd 1035168404Spjd for (c = 0; c < children; c++) { 1036185029Spjd uint64_t is_log = B_FALSE; 1037185029Spjd 1038185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1039185029Spjd &is_log); 1040185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 1041185029Spjd continue; 1042185029Spjd 1043168404Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1044168404Spjd print_import_config(vname, child[c], 1045185029Spjd namewidth, depth + 2, B_FALSE); 1046168404Spjd free(vname); 1047168404Spjd } 1048168404Spjd 1049185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1050185029Spjd &child, &children) == 0) { 1051185029Spjd (void) printf(gettext("\tcache\n")); 1052185029Spjd for (c = 0; c < children; c++) { 1053185029Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1054185029Spjd (void) printf("\t %s\n", vname); 1055185029Spjd free(vname); 1056185029Spjd } 1057185029Spjd } 1058185029Spjd 1059168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1060185029Spjd &child, &children) == 0) { 1061185029Spjd (void) printf(gettext("\tspares\n")); 1062185029Spjd for (c = 0; c < children; c++) { 1063185029Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c]); 1064185029Spjd (void) printf("\t %s\n", vname); 1065185029Spjd free(vname); 1066185029Spjd } 1067168404Spjd } 1068168404Spjd} 1069168404Spjd 1070168404Spjd/* 1071168404Spjd * Display the status for the given pool. 1072168404Spjd */ 1073168404Spjdstatic void 1074168404Spjdshow_import(nvlist_t *config) 1075168404Spjd{ 1076168404Spjd uint64_t pool_state; 1077168404Spjd vdev_stat_t *vs; 1078168404Spjd char *name; 1079168404Spjd uint64_t guid; 1080168404Spjd char *msgid; 1081168404Spjd nvlist_t *nvroot; 1082168404Spjd int reason; 1083168404Spjd const char *health; 1084168404Spjd uint_t vsc; 1085168404Spjd int namewidth; 1086168404Spjd 1087168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1088168404Spjd &name) == 0); 1089168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1090168404Spjd &guid) == 0); 1091168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1092168404Spjd &pool_state) == 0); 1093168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1094168404Spjd &nvroot) == 0); 1095168404Spjd 1096168404Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 1097168404Spjd (uint64_t **)&vs, &vsc) == 0); 1098185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1099168404Spjd 1100168404Spjd reason = zpool_import_status(config, &msgid); 1101168404Spjd 1102168404Spjd (void) printf(gettext(" pool: %s\n"), name); 1103168404Spjd (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1104168404Spjd (void) printf(gettext(" state: %s"), health); 1105168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1106168404Spjd (void) printf(gettext(" (DESTROYED)")); 1107168404Spjd (void) printf("\n"); 1108168404Spjd 1109168404Spjd switch (reason) { 1110168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1111168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1112168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1113168404Spjd (void) printf(gettext("status: One or more devices are missing " 1114168404Spjd "from the system.\n")); 1115168404Spjd break; 1116168404Spjd 1117168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1118168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1119168404Spjd (void) printf(gettext("status: One or more devices contains " 1120168404Spjd "corrupted data.\n")); 1121168404Spjd break; 1122168404Spjd 1123168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1124168404Spjd (void) printf(gettext("status: The pool data is corrupted.\n")); 1125168404Spjd break; 1126168404Spjd 1127168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1128168404Spjd (void) printf(gettext("status: One or more devices " 1129168404Spjd "are offlined.\n")); 1130168404Spjd break; 1131168404Spjd 1132168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1133168404Spjd (void) printf(gettext("status: The pool metadata is " 1134168404Spjd "corrupted.\n")); 1135168404Spjd break; 1136168404Spjd 1137168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1138168404Spjd (void) printf(gettext("status: The pool is formatted using an " 1139168404Spjd "older on-disk version.\n")); 1140168404Spjd break; 1141168404Spjd 1142168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1143168404Spjd (void) printf(gettext("status: The pool is formatted using an " 1144168404Spjd "incompatible version.\n")); 1145168404Spjd break; 1146168404Spjd 1147168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1148168498Spjd (void) printf(gettext("status: The pool was last accessed by " 1149168498Spjd "another system.\n")); 1150168498Spjd break; 1151185029Spjd 1152185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1153185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1154185029Spjd (void) printf(gettext("status: One or more devices are " 1155185029Spjd "faulted.\n")); 1156185029Spjd break; 1157185029Spjd 1158185029Spjd case ZPOOL_STATUS_BAD_LOG: 1159185029Spjd (void) printf(gettext("status: An intent log record cannot be " 1160185029Spjd "read.\n")); 1161185029Spjd break; 1162185029Spjd 1163168404Spjd default: 1164168404Spjd /* 1165168404Spjd * No other status can be seen when importing pools. 1166168404Spjd */ 1167168404Spjd assert(reason == ZPOOL_STATUS_OK); 1168168404Spjd } 1169168404Spjd 1170168404Spjd /* 1171168404Spjd * Print out an action according to the overall state of the pool. 1172168404Spjd */ 1173168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1174168404Spjd if (reason == ZPOOL_STATUS_VERSION_OLDER) 1175168404Spjd (void) printf(gettext("action: The pool can be " 1176168404Spjd "imported using its name or numeric identifier, " 1177168404Spjd "though\n\tsome features will not be available " 1178168404Spjd "without an explicit 'zpool upgrade'.\n")); 1179168498Spjd else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) 1180168498Spjd (void) printf(gettext("action: The pool can be " 1181168498Spjd "imported using its name or numeric " 1182168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1183168404Spjd else 1184168404Spjd (void) printf(gettext("action: The pool can be " 1185168404Spjd "imported using its name or numeric " 1186168404Spjd "identifier.\n")); 1187168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1188168404Spjd (void) printf(gettext("action: The pool can be imported " 1189168404Spjd "despite missing or damaged devices. The\n\tfault " 1190168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1191168404Spjd } else { 1192168404Spjd switch (reason) { 1193168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1194168404Spjd (void) printf(gettext("action: The pool cannot be " 1195168404Spjd "imported. Access the pool on a system running " 1196168404Spjd "newer\n\tsoftware, or recreate the pool from " 1197168404Spjd "backup.\n")); 1198168404Spjd break; 1199168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1200168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1201168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1202168404Spjd (void) printf(gettext("action: The pool cannot be " 1203168404Spjd "imported. Attach the missing\n\tdevices and try " 1204168404Spjd "again.\n")); 1205168404Spjd break; 1206168404Spjd default: 1207168404Spjd (void) printf(gettext("action: The pool cannot be " 1208168404Spjd "imported due to damaged devices or data.\n")); 1209168404Spjd } 1210168404Spjd } 1211168404Spjd 1212168404Spjd /* 1213168404Spjd * If the state is "closed" or "can't open", and the aux state 1214168404Spjd * is "corrupt data": 1215168404Spjd */ 1216168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1217168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1218168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1219168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1220168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1221168404Spjd "but can be imported using the '-Df' flags.\n")); 1222168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1223168404Spjd (void) printf(gettext("\tThe pool may be active on " 1224185029Spjd "another system, but can be imported using\n\t" 1225168404Spjd "the '-f' flag.\n")); 1226168404Spjd } 1227168404Spjd 1228168404Spjd if (msgid != NULL) 1229168404Spjd (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 1230168404Spjd msgid); 1231168404Spjd 1232168404Spjd (void) printf(gettext("config:\n\n")); 1233168404Spjd 1234168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1235168404Spjd if (namewidth < 10) 1236168404Spjd namewidth = 10; 1237168404Spjd 1238185029Spjd print_import_config(name, nvroot, namewidth, 0, B_FALSE); 1239185029Spjd if (num_logs(nvroot) > 0) { 1240185029Spjd (void) printf(gettext("\tlogs\n")); 1241185029Spjd print_import_config(name, nvroot, namewidth, 0, B_TRUE); 1242185029Spjd } 1243185029Spjd 1244168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1245168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1246168404Spjd "be part of this pool, though their\n\texact " 1247168404Spjd "configuration cannot be determined.\n")); 1248168404Spjd } 1249168404Spjd} 1250168404Spjd 1251168404Spjd/* 1252168404Spjd * Perform the import for the given configuration. This passes the heavy 1253185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1254185029Spjd * within the pool. 1255168404Spjd */ 1256168404Spjdstatic int 1257168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1258185029Spjd int force, nvlist_t *props, boolean_t allowfaulted) 1259168404Spjd{ 1260168404Spjd zpool_handle_t *zhp; 1261168404Spjd char *name; 1262168404Spjd uint64_t state; 1263168404Spjd uint64_t version; 1264185029Spjd int error = 0; 1265168404Spjd 1266168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1267168404Spjd &name) == 0); 1268168404Spjd 1269168404Spjd verify(nvlist_lookup_uint64(config, 1270168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1271168404Spjd verify(nvlist_lookup_uint64(config, 1272168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1273185029Spjd if (version > SPA_VERSION) { 1274168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1275168404Spjd "is formatted using a newer ZFS version\n"), name); 1276168404Spjd return (1); 1277168404Spjd } else if (state != POOL_STATE_EXPORTED && !force) { 1278168498Spjd uint64_t hostid; 1279168498Spjd 1280168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1281168498Spjd &hostid) == 0) { 1282168498Spjd if ((unsigned long)hostid != gethostid()) { 1283168498Spjd char *hostname; 1284168498Spjd uint64_t timestamp; 1285168498Spjd time_t t; 1286168498Spjd 1287168498Spjd verify(nvlist_lookup_string(config, 1288168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1289168498Spjd verify(nvlist_lookup_uint64(config, 1290168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1291168498Spjd t = timestamp; 1292168498Spjd (void) fprintf(stderr, gettext("cannot import " 1293168498Spjd "'%s': pool may be in use from other " 1294168498Spjd "system, it was last accessed by %s " 1295168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1296168498Spjd (unsigned long)hostid, 1297168498Spjd asctime(localtime(&t))); 1298168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1299168498Spjd "import anyway\n")); 1300168498Spjd return (1); 1301168498Spjd } 1302168498Spjd } else { 1303168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1304168498Spjd "pool may be in use from other system\n"), name); 1305168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1306168498Spjd "anyway\n")); 1307168498Spjd return (1); 1308168498Spjd } 1309168404Spjd } 1310168404Spjd 1311185029Spjd if (zpool_import_props(g_zfs, config, newname, props, 1312185029Spjd allowfaulted) != 0) 1313168404Spjd return (1); 1314168404Spjd 1315168404Spjd if (newname != NULL) 1316168404Spjd name = (char *)newname; 1317168404Spjd 1318185029Spjd verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL); 1319168404Spjd 1320168404Spjd if (zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1321168404Spjd zpool_close(zhp); 1322168404Spjd return (1); 1323168404Spjd } 1324168404Spjd 1325168404Spjd zpool_close(zhp); 1326185029Spjd return (error); 1327168404Spjd} 1328168404Spjd 1329168404Spjd/* 1330168404Spjd * zpool import [-d dir] [-D] 1331185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1332185029Spjd * [-d dir | -c cachefile] [-f] -a 1333185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1334185029Spjd * [-d dir | -c cachefile] [-f] <pool | id> [newpool] 1335168404Spjd * 1336185029Spjd * -c Read pool information from a cachefile instead of searching 1337185029Spjd * devices. 1338185029Spjd * 1339168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1340168404Spjd * one directory can be specified using multiple '-d' options. 1341168404Spjd * 1342168404Spjd * -D Scan for previously destroyed pools or import all or only 1343168404Spjd * specified destroyed pools. 1344168404Spjd * 1345168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1346168404Spjd * the given root. The pool will remain exported when the machine 1347168404Spjd * is rebooted. 1348168404Spjd * 1349168404Spjd * -f Force import, even if it appears that the pool is active. 1350168404Spjd * 1351185029Spjd * -F Import even in the presence of faulted vdevs. This is an 1352185029Spjd * intentionally undocumented option for testing purposes, and 1353185029Spjd * treats the pool configuration as complete, leaving any bad 1354185029Spjd * vdevs in the FAULTED state. 1355185029Spjd * 1356168404Spjd * -a Import all pools found. 1357168404Spjd * 1358185029Spjd * -o Set property=value and/or temporary mount options (without '='). 1359185029Spjd * 1360168404Spjd * The import command scans for pools to import, and import pools based on pool 1361168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 1362168404Spjd */ 1363168404Spjdint 1364168404Spjdzpool_do_import(int argc, char **argv) 1365168404Spjd{ 1366168404Spjd char **searchdirs = NULL; 1367168404Spjd int nsearch = 0; 1368168404Spjd int c; 1369168404Spjd int err; 1370185029Spjd nvlist_t *pools = NULL; 1371168404Spjd boolean_t do_all = B_FALSE; 1372168404Spjd boolean_t do_destroyed = B_FALSE; 1373168404Spjd char *mntopts = NULL; 1374168404Spjd boolean_t do_force = B_FALSE; 1375168404Spjd nvpair_t *elem; 1376168404Spjd nvlist_t *config; 1377185029Spjd uint64_t searchguid = 0; 1378185029Spjd char *searchname = NULL; 1379185029Spjd char *propval; 1380168404Spjd nvlist_t *found_config; 1381185029Spjd nvlist_t *props = NULL; 1382168404Spjd boolean_t first; 1383185029Spjd boolean_t allow_faulted = B_FALSE; 1384168404Spjd uint64_t pool_state; 1385185029Spjd char *cachefile = NULL; 1386168404Spjd 1387168404Spjd /* check options */ 1388185029Spjd while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) { 1389168404Spjd switch (c) { 1390168404Spjd case 'a': 1391168404Spjd do_all = B_TRUE; 1392168404Spjd break; 1393185029Spjd case 'c': 1394185029Spjd cachefile = optarg; 1395185029Spjd break; 1396168404Spjd case 'd': 1397168404Spjd if (searchdirs == NULL) { 1398168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1399168404Spjd } else { 1400168404Spjd char **tmp = safe_malloc((nsearch + 1) * 1401168404Spjd sizeof (char *)); 1402168404Spjd bcopy(searchdirs, tmp, nsearch * 1403168404Spjd sizeof (char *)); 1404168404Spjd free(searchdirs); 1405168404Spjd searchdirs = tmp; 1406168404Spjd } 1407168404Spjd searchdirs[nsearch++] = optarg; 1408168404Spjd break; 1409168404Spjd case 'D': 1410168404Spjd do_destroyed = B_TRUE; 1411168404Spjd break; 1412168404Spjd case 'f': 1413168404Spjd do_force = B_TRUE; 1414168404Spjd break; 1415185029Spjd case 'F': 1416185029Spjd allow_faulted = B_TRUE; 1417185029Spjd break; 1418168404Spjd case 'o': 1419185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 1420185029Spjd *propval = '\0'; 1421185029Spjd propval++; 1422185029Spjd if (add_prop_list(optarg, propval, 1423185029Spjd &props, B_TRUE)) 1424185029Spjd goto error; 1425185029Spjd } else { 1426185029Spjd mntopts = optarg; 1427185029Spjd } 1428168404Spjd break; 1429168404Spjd case 'R': 1430185029Spjd if (add_prop_list(zpool_prop_to_name( 1431185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 1432185029Spjd goto error; 1433185029Spjd if (nvlist_lookup_string(props, 1434185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 1435185029Spjd &propval) == 0) 1436185029Spjd break; 1437185029Spjd if (add_prop_list(zpool_prop_to_name( 1438185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1439185029Spjd goto error; 1440168404Spjd break; 1441168404Spjd case ':': 1442168404Spjd (void) fprintf(stderr, gettext("missing argument for " 1443168404Spjd "'%c' option\n"), optopt); 1444168404Spjd usage(B_FALSE); 1445168404Spjd break; 1446168404Spjd case '?': 1447168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1448168404Spjd optopt); 1449168404Spjd usage(B_FALSE); 1450168404Spjd } 1451168404Spjd } 1452168404Spjd 1453168404Spjd argc -= optind; 1454168404Spjd argv += optind; 1455168404Spjd 1456185029Spjd if (cachefile && nsearch != 0) { 1457185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 1458185029Spjd usage(B_FALSE); 1459185029Spjd } 1460185029Spjd 1461168404Spjd if (searchdirs == NULL) { 1462168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1463185029Spjd searchdirs[0] = "/dev/dsk"; 1464168404Spjd nsearch = 1; 1465168404Spjd } 1466168404Spjd 1467168404Spjd /* check argument count */ 1468168404Spjd if (do_all) { 1469168404Spjd if (argc != 0) { 1470168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1471168404Spjd usage(B_FALSE); 1472168404Spjd } 1473168404Spjd } else { 1474168404Spjd if (argc > 2) { 1475168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1476168404Spjd usage(B_FALSE); 1477168404Spjd } 1478168404Spjd 1479168404Spjd /* 1480168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 1481168404Spjd * here because otherwise any attempt to discover pools will 1482168404Spjd * silently fail. 1483168404Spjd */ 1484168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 1485168404Spjd (void) fprintf(stderr, gettext("cannot " 1486168404Spjd "discover pools: permission denied\n")); 1487168404Spjd free(searchdirs); 1488168404Spjd return (1); 1489168404Spjd } 1490168404Spjd } 1491168404Spjd 1492168404Spjd /* 1493168404Spjd * Depending on the arguments given, we do one of the following: 1494168404Spjd * 1495168404Spjd * <none> Iterate through all pools and display information about 1496168404Spjd * each one. 1497168404Spjd * 1498168404Spjd * -a Iterate through all pools and try to import each one. 1499168404Spjd * 1500168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 1501168404Spjd * name and import that one. 1502168404Spjd * 1503168404Spjd * -D Above options applies only to destroyed pools. 1504168404Spjd */ 1505168404Spjd if (argc != 0) { 1506168404Spjd char *endptr; 1507168404Spjd 1508168404Spjd errno = 0; 1509168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 1510168404Spjd if (errno != 0 || *endptr != '\0') 1511168404Spjd searchname = argv[0]; 1512168404Spjd found_config = NULL; 1513168404Spjd } 1514168404Spjd 1515185029Spjd if (cachefile) { 1516185029Spjd pools = zpool_find_import_cached(g_zfs, cachefile, searchname, 1517185029Spjd searchguid); 1518185029Spjd } else if (searchname != NULL) { 1519185029Spjd pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs, 1520185029Spjd searchname); 1521185029Spjd } else { 1522185029Spjd /* 1523185029Spjd * It's OK to search by guid even if searchguid is 0. 1524185029Spjd */ 1525185029Spjd pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs, 1526185029Spjd searchguid); 1527185029Spjd } 1528185029Spjd 1529185029Spjd if (pools == NULL) { 1530185029Spjd if (argc != 0) { 1531185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1532185029Spjd "no such pool available\n"), argv[0]); 1533185029Spjd } 1534185029Spjd free(searchdirs); 1535185029Spjd return (1); 1536185029Spjd } 1537185029Spjd 1538185029Spjd /* 1539185029Spjd * At this point we have a list of import candidate configs. Even if 1540185029Spjd * we were searching by pool name or guid, we still need to 1541185029Spjd * post-process the list to deal with pool state and possible 1542185029Spjd * duplicate names. 1543185029Spjd */ 1544168404Spjd err = 0; 1545168404Spjd elem = NULL; 1546168404Spjd first = B_TRUE; 1547168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 1548168404Spjd 1549168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 1550168404Spjd 1551168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1552168404Spjd &pool_state) == 0); 1553168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 1554168404Spjd continue; 1555168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 1556168404Spjd continue; 1557168404Spjd 1558168404Spjd if (argc == 0) { 1559168404Spjd if (first) 1560168404Spjd first = B_FALSE; 1561168404Spjd else if (!do_all) 1562168404Spjd (void) printf("\n"); 1563168404Spjd 1564168404Spjd if (do_all) 1565168404Spjd err |= do_import(config, NULL, mntopts, 1566185029Spjd do_force, props, allow_faulted); 1567168404Spjd else 1568168404Spjd show_import(config); 1569168404Spjd } else if (searchname != NULL) { 1570168404Spjd char *name; 1571168404Spjd 1572168404Spjd /* 1573168404Spjd * We are searching for a pool based on name. 1574168404Spjd */ 1575168404Spjd verify(nvlist_lookup_string(config, 1576168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 1577168404Spjd 1578168404Spjd if (strcmp(name, searchname) == 0) { 1579168404Spjd if (found_config != NULL) { 1580168404Spjd (void) fprintf(stderr, gettext( 1581168404Spjd "cannot import '%s': more than " 1582168404Spjd "one matching pool\n"), searchname); 1583168404Spjd (void) fprintf(stderr, gettext( 1584168404Spjd "import by numeric ID instead\n")); 1585168404Spjd err = B_TRUE; 1586168404Spjd } 1587168404Spjd found_config = config; 1588168404Spjd } 1589168404Spjd } else { 1590168404Spjd uint64_t guid; 1591168404Spjd 1592168404Spjd /* 1593168404Spjd * Search for a pool by guid. 1594168404Spjd */ 1595168404Spjd verify(nvlist_lookup_uint64(config, 1596168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 1597168404Spjd 1598168404Spjd if (guid == searchguid) 1599168404Spjd found_config = config; 1600168404Spjd } 1601168404Spjd } 1602168404Spjd 1603168404Spjd /* 1604168404Spjd * If we were searching for a specific pool, verify that we found a 1605168404Spjd * pool, and then do the import. 1606168404Spjd */ 1607168404Spjd if (argc != 0 && err == 0) { 1608168404Spjd if (found_config == NULL) { 1609168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1610168404Spjd "no such pool available\n"), argv[0]); 1611168404Spjd err = B_TRUE; 1612168404Spjd } else { 1613168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 1614185029Spjd argv[1], mntopts, do_force, props, allow_faulted); 1615168404Spjd } 1616168404Spjd } 1617168404Spjd 1618168404Spjd /* 1619168404Spjd * If we were just looking for pools, report an error if none were 1620168404Spjd * found. 1621168404Spjd */ 1622168404Spjd if (argc == 0 && first) 1623168404Spjd (void) fprintf(stderr, 1624168404Spjd gettext("no pools available to import\n")); 1625168404Spjd 1626185029Spjderror: 1627185029Spjd nvlist_free(props); 1628168404Spjd nvlist_free(pools); 1629168404Spjd free(searchdirs); 1630168404Spjd 1631168404Spjd return (err ? 1 : 0); 1632168404Spjd} 1633168404Spjd 1634168404Spjdtypedef struct iostat_cbdata { 1635168404Spjd zpool_list_t *cb_list; 1636168404Spjd int cb_verbose; 1637168404Spjd int cb_iteration; 1638168404Spjd int cb_namewidth; 1639168404Spjd} iostat_cbdata_t; 1640168404Spjd 1641168404Spjdstatic void 1642168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 1643168404Spjd{ 1644168404Spjd int i = 0; 1645168404Spjd 1646168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 1647168404Spjd (void) printf("-"); 1648168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 1649168404Spjd} 1650168404Spjd 1651168404Spjdstatic void 1652168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 1653168404Spjd{ 1654168404Spjd (void) printf("%*s capacity operations bandwidth\n", 1655168404Spjd cb->cb_namewidth, ""); 1656168404Spjd (void) printf("%-*s used avail read write read write\n", 1657168404Spjd cb->cb_namewidth, "pool"); 1658168404Spjd print_iostat_separator(cb); 1659168404Spjd} 1660168404Spjd 1661168404Spjd/* 1662168404Spjd * Display a single statistic. 1663168404Spjd */ 1664185029Spjdstatic void 1665168404Spjdprint_one_stat(uint64_t value) 1666168404Spjd{ 1667168404Spjd char buf[64]; 1668168404Spjd 1669168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 1670168404Spjd (void) printf(" %5s", buf); 1671168404Spjd} 1672168404Spjd 1673168404Spjd/* 1674168404Spjd * Print out all the statistics for the given vdev. This can either be the 1675168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 1676168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 1677168404Spjd */ 1678168404Spjdvoid 1679168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 1680168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 1681168404Spjd{ 1682168404Spjd nvlist_t **oldchild, **newchild; 1683168404Spjd uint_t c, children; 1684168404Spjd vdev_stat_t *oldvs, *newvs; 1685168404Spjd vdev_stat_t zerovs = { 0 }; 1686168404Spjd uint64_t tdelta; 1687168404Spjd double scale; 1688168404Spjd char *vname; 1689168404Spjd 1690168404Spjd if (oldnv != NULL) { 1691168404Spjd verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, 1692168404Spjd (uint64_t **)&oldvs, &c) == 0); 1693168404Spjd } else { 1694168404Spjd oldvs = &zerovs; 1695168404Spjd } 1696168404Spjd 1697168404Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, 1698168404Spjd (uint64_t **)&newvs, &c) == 0); 1699168404Spjd 1700168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 1701168404Spjd (void) printf("%*s%s", depth, "", name); 1702168404Spjd else 1703168404Spjd (void) printf("%*s%s%*s", depth, "", name, 1704168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 1705168404Spjd 1706168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 1707168404Spjd 1708168404Spjd if (tdelta == 0) 1709168404Spjd scale = 1.0; 1710168404Spjd else 1711168404Spjd scale = (double)NANOSEC / tdelta; 1712168404Spjd 1713168404Spjd /* only toplevel vdevs have capacity stats */ 1714168404Spjd if (newvs->vs_space == 0) { 1715168404Spjd (void) printf(" - -"); 1716168404Spjd } else { 1717168404Spjd print_one_stat(newvs->vs_alloc); 1718168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 1719168404Spjd } 1720168404Spjd 1721168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 1722168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 1723168404Spjd 1724168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 1725168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 1726168404Spjd 1727168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 1728168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 1729168404Spjd 1730168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 1731168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 1732168404Spjd 1733168404Spjd (void) printf("\n"); 1734168404Spjd 1735168404Spjd if (!cb->cb_verbose) 1736168404Spjd return; 1737168404Spjd 1738168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 1739168404Spjd &newchild, &children) != 0) 1740168404Spjd return; 1741168404Spjd 1742168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 1743168404Spjd &oldchild, &c) != 0) 1744168404Spjd return; 1745168404Spjd 1746168404Spjd for (c = 0; c < children; c++) { 1747168404Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1748168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1749168404Spjd newchild[c], cb, depth + 2); 1750168404Spjd free(vname); 1751168404Spjd } 1752185029Spjd 1753185029Spjd /* 1754185029Spjd * Include level 2 ARC devices in iostat output 1755185029Spjd */ 1756185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 1757185029Spjd &newchild, &children) != 0) 1758185029Spjd return; 1759185029Spjd 1760185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 1761185029Spjd &oldchild, &c) != 0) 1762185029Spjd return; 1763185029Spjd 1764185029Spjd if (children > 0) { 1765185029Spjd (void) printf("%-*s - - - - - " 1766185029Spjd "-\n", cb->cb_namewidth, "cache"); 1767185029Spjd for (c = 0; c < children; c++) { 1768185029Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c]); 1769185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 1770185029Spjd newchild[c], cb, depth + 2); 1771185029Spjd free(vname); 1772185029Spjd } 1773185029Spjd } 1774168404Spjd} 1775168404Spjd 1776168404Spjdstatic int 1777168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 1778168404Spjd{ 1779168404Spjd iostat_cbdata_t *cb = data; 1780168404Spjd boolean_t missing; 1781168404Spjd 1782168404Spjd /* 1783168404Spjd * If the pool has disappeared, remove it from the list and continue. 1784168404Spjd */ 1785168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 1786168404Spjd return (-1); 1787168404Spjd 1788168404Spjd if (missing) 1789168404Spjd pool_list_remove(cb->cb_list, zhp); 1790168404Spjd 1791168404Spjd return (0); 1792168404Spjd} 1793168404Spjd 1794168404Spjd/* 1795168404Spjd * Callback to print out the iostats for the given pool. 1796168404Spjd */ 1797168404Spjdint 1798168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 1799168404Spjd{ 1800168404Spjd iostat_cbdata_t *cb = data; 1801168404Spjd nvlist_t *oldconfig, *newconfig; 1802168404Spjd nvlist_t *oldnvroot, *newnvroot; 1803168404Spjd 1804168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 1805168404Spjd 1806168404Spjd if (cb->cb_iteration == 1) 1807168404Spjd oldconfig = NULL; 1808168404Spjd 1809168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 1810168404Spjd &newnvroot) == 0); 1811168404Spjd 1812168404Spjd if (oldconfig == NULL) 1813168404Spjd oldnvroot = NULL; 1814168404Spjd else 1815168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 1816168404Spjd &oldnvroot) == 0); 1817168404Spjd 1818168404Spjd /* 1819168404Spjd * Print out the statistics for the pool. 1820168404Spjd */ 1821168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 1822168404Spjd 1823168404Spjd if (cb->cb_verbose) 1824168404Spjd print_iostat_separator(cb); 1825168404Spjd 1826168404Spjd return (0); 1827168404Spjd} 1828168404Spjd 1829168404Spjdint 1830168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 1831168404Spjd{ 1832168404Spjd iostat_cbdata_t *cb = data; 1833168404Spjd nvlist_t *config, *nvroot; 1834168404Spjd 1835168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 1836168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1837168404Spjd &nvroot) == 0); 1838168404Spjd if (!cb->cb_verbose) 1839168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 1840168404Spjd else 1841168404Spjd cb->cb_namewidth = max_width(zhp, nvroot, 0, 0); 1842168404Spjd } 1843168404Spjd 1844168404Spjd /* 1845168404Spjd * The width must fall into the range [10,38]. The upper limit is the 1846168404Spjd * maximum we can have and still fit in 80 columns. 1847168404Spjd */ 1848168404Spjd if (cb->cb_namewidth < 10) 1849168404Spjd cb->cb_namewidth = 10; 1850168404Spjd if (cb->cb_namewidth > 38) 1851168404Spjd cb->cb_namewidth = 38; 1852168404Spjd 1853168404Spjd return (0); 1854168404Spjd} 1855168404Spjd 1856168404Spjd/* 1857168404Spjd * zpool iostat [-v] [pool] ... [interval [count]] 1858168404Spjd * 1859168404Spjd * -v Display statistics for individual vdevs 1860168404Spjd * 1861168404Spjd * This command can be tricky because we want to be able to deal with pool 1862168404Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 1863168404Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 1864168404Spjd * on pool_list_update() to detect the addition of new pools. Configuration 1865168404Spjd * changes are all handled within libzfs. 1866168404Spjd */ 1867168404Spjdint 1868168404Spjdzpool_do_iostat(int argc, char **argv) 1869168404Spjd{ 1870168404Spjd int c; 1871168404Spjd int ret; 1872168404Spjd int npools; 1873168404Spjd unsigned long interval = 0, count = 0; 1874168404Spjd zpool_list_t *list; 1875168404Spjd boolean_t verbose = B_FALSE; 1876168404Spjd iostat_cbdata_t cb; 1877168404Spjd 1878168404Spjd /* check options */ 1879168404Spjd while ((c = getopt(argc, argv, "v")) != -1) { 1880168404Spjd switch (c) { 1881168404Spjd case 'v': 1882168404Spjd verbose = B_TRUE; 1883168404Spjd break; 1884168404Spjd case '?': 1885168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1886168404Spjd optopt); 1887168404Spjd usage(B_FALSE); 1888168404Spjd } 1889168404Spjd } 1890168404Spjd 1891168404Spjd argc -= optind; 1892168404Spjd argv += optind; 1893168404Spjd 1894168404Spjd /* 1895168404Spjd * Determine if the last argument is an integer or a pool name 1896168404Spjd */ 1897168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 1898168404Spjd char *end; 1899168404Spjd 1900168404Spjd errno = 0; 1901168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 1902168404Spjd 1903168404Spjd if (*end == '\0' && errno == 0) { 1904168404Spjd if (interval == 0) { 1905168404Spjd (void) fprintf(stderr, gettext("interval " 1906168404Spjd "cannot be zero\n")); 1907168404Spjd usage(B_FALSE); 1908168404Spjd } 1909168404Spjd 1910168404Spjd /* 1911168404Spjd * Ignore the last parameter 1912168404Spjd */ 1913168404Spjd argc--; 1914168404Spjd } else { 1915168404Spjd /* 1916168404Spjd * If this is not a valid number, just plow on. The 1917168404Spjd * user will get a more informative error message later 1918168404Spjd * on. 1919168404Spjd */ 1920168404Spjd interval = 0; 1921168404Spjd } 1922168404Spjd } 1923168404Spjd 1924168404Spjd /* 1925168404Spjd * If the last argument is also an integer, then we have both a count 1926168404Spjd * and an integer. 1927168404Spjd */ 1928168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 1929168404Spjd char *end; 1930168404Spjd 1931168404Spjd errno = 0; 1932168404Spjd count = interval; 1933168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 1934168404Spjd 1935168404Spjd if (*end == '\0' && errno == 0) { 1936168404Spjd if (interval == 0) { 1937168404Spjd (void) fprintf(stderr, gettext("interval " 1938168404Spjd "cannot be zero\n")); 1939168404Spjd usage(B_FALSE); 1940168404Spjd } 1941168404Spjd 1942168404Spjd /* 1943168404Spjd * Ignore the last parameter 1944168404Spjd */ 1945168404Spjd argc--; 1946168404Spjd } else { 1947168404Spjd interval = 0; 1948168404Spjd } 1949168404Spjd } 1950168404Spjd 1951168404Spjd /* 1952168404Spjd * Construct the list of all interesting pools. 1953168404Spjd */ 1954168404Spjd ret = 0; 1955168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 1956168404Spjd return (1); 1957168404Spjd 1958168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 1959168404Spjd pool_list_free(list); 1960168404Spjd return (1); 1961168404Spjd } 1962168404Spjd 1963168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 1964168404Spjd pool_list_free(list); 1965168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 1966168404Spjd return (1); 1967168404Spjd } 1968168404Spjd 1969168404Spjd /* 1970168404Spjd * Enter the main iostat loop. 1971168404Spjd */ 1972168404Spjd cb.cb_list = list; 1973168404Spjd cb.cb_verbose = verbose; 1974168404Spjd cb.cb_iteration = 0; 1975168404Spjd cb.cb_namewidth = 0; 1976168404Spjd 1977168404Spjd for (;;) { 1978168404Spjd pool_list_update(list); 1979168404Spjd 1980168404Spjd if ((npools = pool_list_count(list)) == 0) 1981168404Spjd break; 1982168404Spjd 1983168404Spjd /* 1984168404Spjd * Refresh all statistics. This is done as an explicit step 1985168404Spjd * before calculating the maximum name width, so that any 1986168404Spjd * configuration changes are properly accounted for. 1987168404Spjd */ 1988168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 1989168404Spjd 1990168404Spjd /* 1991168404Spjd * Iterate over all pools to determine the maximum width 1992168404Spjd * for the pool / device name column across all pools. 1993168404Spjd */ 1994168404Spjd cb.cb_namewidth = 0; 1995168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 1996168404Spjd 1997168404Spjd /* 1998168404Spjd * If it's the first time, or verbose mode, print the header. 1999168404Spjd */ 2000168404Spjd if (++cb.cb_iteration == 1 || verbose) 2001168404Spjd print_iostat_header(&cb); 2002168404Spjd 2003168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2004168404Spjd 2005168404Spjd /* 2006168404Spjd * If there's more than one pool, and we're not in verbose mode 2007168404Spjd * (which prints a separator for us), then print a separator. 2008168404Spjd */ 2009168404Spjd if (npools > 1 && !verbose) 2010168404Spjd print_iostat_separator(&cb); 2011168404Spjd 2012168404Spjd if (verbose) 2013168404Spjd (void) printf("\n"); 2014168404Spjd 2015168404Spjd /* 2016168404Spjd * Flush the output so that redirection to a file isn't buffered 2017168404Spjd * indefinitely. 2018168404Spjd */ 2019168404Spjd (void) fflush(stdout); 2020168404Spjd 2021168404Spjd if (interval == 0) 2022168404Spjd break; 2023168404Spjd 2024168404Spjd if (count != 0 && --count == 0) 2025168404Spjd break; 2026168404Spjd 2027168404Spjd (void) sleep(interval); 2028168404Spjd } 2029168404Spjd 2030168404Spjd pool_list_free(list); 2031168404Spjd 2032168404Spjd return (ret); 2033168404Spjd} 2034168404Spjd 2035168404Spjdtypedef struct list_cbdata { 2036168404Spjd boolean_t cb_scripted; 2037168404Spjd boolean_t cb_first; 2038185029Spjd zprop_list_t *cb_proplist; 2039168404Spjd} list_cbdata_t; 2040168404Spjd 2041168404Spjd/* 2042168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2043168404Spjd */ 2044185029Spjdstatic void 2045185029Spjdprint_header(zprop_list_t *pl) 2046168404Spjd{ 2047185029Spjd const char *header; 2048185029Spjd boolean_t first = B_TRUE; 2049185029Spjd boolean_t right_justify; 2050168404Spjd 2051185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2052185029Spjd if (pl->pl_prop == ZPROP_INVAL) 2053185029Spjd continue; 2054185029Spjd 2055185029Spjd if (!first) 2056168404Spjd (void) printf(" "); 2057168404Spjd else 2058185029Spjd first = B_FALSE; 2059168404Spjd 2060185029Spjd header = zpool_prop_column_name(pl->pl_prop); 2061185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2062185029Spjd 2063185029Spjd if (pl->pl_next == NULL && !right_justify) 2064185029Spjd (void) printf("%s", header); 2065185029Spjd else if (right_justify) 2066185029Spjd (void) printf("%*s", pl->pl_width, header); 2067185029Spjd else 2068185029Spjd (void) printf("%-*s", pl->pl_width, header); 2069168404Spjd } 2070168404Spjd 2071168404Spjd (void) printf("\n"); 2072168404Spjd} 2073168404Spjd 2074185029Spjd/* 2075185029Spjd * Given a pool and a list of properties, print out all the properties according 2076185029Spjd * to the described layout. 2077185029Spjd */ 2078185029Spjdstatic void 2079185029Spjdprint_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted) 2080168404Spjd{ 2081185029Spjd boolean_t first = B_TRUE; 2082185029Spjd char property[ZPOOL_MAXPROPLEN]; 2083185029Spjd char *propstr; 2084185029Spjd boolean_t right_justify; 2085185029Spjd int width; 2086168404Spjd 2087185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2088185029Spjd if (!first) { 2089185029Spjd if (scripted) 2090168404Spjd (void) printf("\t"); 2091168404Spjd else 2092168404Spjd (void) printf(" "); 2093185029Spjd } else { 2094185029Spjd first = B_FALSE; 2095168404Spjd } 2096168404Spjd 2097185029Spjd right_justify = B_FALSE; 2098185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2099185029Spjd if (zpool_get_prop(zhp, pl->pl_prop, property, 2100185029Spjd sizeof (property), NULL) != 0) 2101185029Spjd propstr = "-"; 2102168404Spjd else 2103185029Spjd propstr = property; 2104168404Spjd 2105185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2106185029Spjd } else { 2107185029Spjd propstr = "-"; 2108185029Spjd } 2109168404Spjd 2110185029Spjd width = pl->pl_width; 2111168404Spjd 2112185029Spjd /* 2113185029Spjd * If this is being called in scripted mode, or if this is the 2114185029Spjd * last column and it is left-justified, don't include a width 2115185029Spjd * format specifier. 2116185029Spjd */ 2117185029Spjd if (scripted || (pl->pl_next == NULL && !right_justify)) 2118185029Spjd (void) printf("%s", propstr); 2119185029Spjd else if (right_justify) 2120185029Spjd (void) printf("%*s", width, propstr); 2121185029Spjd else 2122185029Spjd (void) printf("%-*s", width, propstr); 2123185029Spjd } 2124168404Spjd 2125185029Spjd (void) printf("\n"); 2126185029Spjd} 2127168404Spjd 2128185029Spjd/* 2129185029Spjd * Generic callback function to list a pool. 2130185029Spjd */ 2131185029Spjdint 2132185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 2133185029Spjd{ 2134185029Spjd list_cbdata_t *cbp = data; 2135168404Spjd 2136185029Spjd if (cbp->cb_first) { 2137185029Spjd if (!cbp->cb_scripted) 2138185029Spjd print_header(cbp->cb_proplist); 2139185029Spjd cbp->cb_first = B_FALSE; 2140168404Spjd } 2141168404Spjd 2142185029Spjd print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted); 2143168404Spjd 2144168404Spjd return (0); 2145168404Spjd} 2146168404Spjd 2147168404Spjd/* 2148185029Spjd * zpool list [-H] [-o prop[,prop]*] [pool] ... 2149168404Spjd * 2150185029Spjd * -H Scripted mode. Don't display headers, and separate properties 2151185029Spjd * by a single tab. 2152185029Spjd * -o List of properties to display. Defaults to 2153185029Spjd * "name,size,used,available,capacity,health,altroot" 2154168404Spjd * 2155168404Spjd * List all pools in the system, whether or not they're healthy. Output space 2156168404Spjd * statistics for each one, as well as health status summary. 2157168404Spjd */ 2158168404Spjdint 2159168404Spjdzpool_do_list(int argc, char **argv) 2160168404Spjd{ 2161168404Spjd int c; 2162168404Spjd int ret; 2163168404Spjd list_cbdata_t cb = { 0 }; 2164185029Spjd static char default_props[] = 2165185029Spjd "name,size,used,available,capacity,health,altroot"; 2166185029Spjd char *props = default_props; 2167168404Spjd 2168168404Spjd /* check options */ 2169168404Spjd while ((c = getopt(argc, argv, ":Ho:")) != -1) { 2170168404Spjd switch (c) { 2171168404Spjd case 'H': 2172168404Spjd cb.cb_scripted = B_TRUE; 2173168404Spjd break; 2174168404Spjd case 'o': 2175185029Spjd props = optarg; 2176168404Spjd break; 2177168404Spjd case ':': 2178168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2179168404Spjd "'%c' option\n"), optopt); 2180168404Spjd usage(B_FALSE); 2181168404Spjd break; 2182168404Spjd case '?': 2183168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2184168404Spjd optopt); 2185168404Spjd usage(B_FALSE); 2186168404Spjd } 2187168404Spjd } 2188168404Spjd 2189168404Spjd argc -= optind; 2190168404Spjd argv += optind; 2191168404Spjd 2192185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 2193185029Spjd usage(B_FALSE); 2194168404Spjd 2195185029Spjd cb.cb_first = B_TRUE; 2196168404Spjd 2197185029Spjd ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 2198185029Spjd list_callback, &cb); 2199168404Spjd 2200185029Spjd zprop_free_list(cb.cb_proplist); 2201168404Spjd 2202185029Spjd if (argc == 0 && cb.cb_first && !cb.cb_scripted) { 2203168404Spjd (void) printf(gettext("no pools available\n")); 2204168404Spjd return (0); 2205168404Spjd } 2206168404Spjd 2207168404Spjd return (ret); 2208168404Spjd} 2209168404Spjd 2210168404Spjdstatic nvlist_t * 2211168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name) 2212168404Spjd{ 2213168404Spjd nvlist_t **child; 2214168404Spjd uint_t c, children; 2215168404Spjd nvlist_t *match; 2216168404Spjd char *path; 2217168404Spjd 2218168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2219168404Spjd &child, &children) != 0) { 2220168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2221168404Spjd if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV)-1) == 0) 2222168404Spjd name += sizeof(_PATH_DEV)-1; 2223168404Spjd if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV)-1) == 0) 2224168404Spjd path += sizeof(_PATH_DEV)-1; 2225168404Spjd if (strcmp(name, path) == 0) 2226168404Spjd return (nv); 2227168404Spjd return (NULL); 2228168404Spjd } 2229168404Spjd 2230168404Spjd for (c = 0; c < children; c++) 2231168404Spjd if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 2232168404Spjd return (match); 2233168404Spjd 2234168404Spjd return (NULL); 2235168404Spjd} 2236168404Spjd 2237168404Spjdstatic int 2238168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 2239168404Spjd{ 2240168404Spjd boolean_t force = B_FALSE; 2241168404Spjd int c; 2242168404Spjd nvlist_t *nvroot; 2243168404Spjd char *poolname, *old_disk, *new_disk; 2244168404Spjd zpool_handle_t *zhp; 2245168404Spjd int ret; 2246168404Spjd 2247168404Spjd /* check options */ 2248168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 2249168404Spjd switch (c) { 2250168404Spjd case 'f': 2251168404Spjd force = B_TRUE; 2252168404Spjd break; 2253168404Spjd case '?': 2254168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2255168404Spjd optopt); 2256168404Spjd usage(B_FALSE); 2257168404Spjd } 2258168404Spjd } 2259168404Spjd 2260168404Spjd argc -= optind; 2261168404Spjd argv += optind; 2262168404Spjd 2263168404Spjd /* get pool name and check number of arguments */ 2264168404Spjd if (argc < 1) { 2265168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 2266168404Spjd usage(B_FALSE); 2267168404Spjd } 2268168404Spjd 2269168404Spjd poolname = argv[0]; 2270168404Spjd 2271168404Spjd if (argc < 2) { 2272168404Spjd (void) fprintf(stderr, 2273168404Spjd gettext("missing <device> specification\n")); 2274168404Spjd usage(B_FALSE); 2275168404Spjd } 2276168404Spjd 2277168404Spjd old_disk = argv[1]; 2278168404Spjd 2279168404Spjd if (argc < 3) { 2280168404Spjd if (!replacing) { 2281168404Spjd (void) fprintf(stderr, 2282168404Spjd gettext("missing <new_device> specification\n")); 2283168404Spjd usage(B_FALSE); 2284168404Spjd } 2285168404Spjd new_disk = old_disk; 2286168404Spjd argc -= 1; 2287168404Spjd argv += 1; 2288168404Spjd } else { 2289168404Spjd new_disk = argv[2]; 2290168404Spjd argc -= 2; 2291168404Spjd argv += 2; 2292168404Spjd } 2293168404Spjd 2294168404Spjd if (argc > 1) { 2295168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2296168404Spjd usage(B_FALSE); 2297168404Spjd } 2298168404Spjd 2299168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2300168404Spjd return (1); 2301168404Spjd 2302185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 2303168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 2304168404Spjd poolname); 2305168404Spjd zpool_close(zhp); 2306168404Spjd return (1); 2307168404Spjd } 2308168404Spjd 2309185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 2310185029Spjd argc, argv); 2311168404Spjd if (nvroot == NULL) { 2312168404Spjd zpool_close(zhp); 2313168404Spjd return (1); 2314168404Spjd } 2315168404Spjd 2316168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 2317168404Spjd 2318168404Spjd nvlist_free(nvroot); 2319168404Spjd zpool_close(zhp); 2320168404Spjd 2321168404Spjd return (ret); 2322168404Spjd} 2323168404Spjd 2324168404Spjd/* 2325168404Spjd * zpool replace [-f] <pool> <device> <new_device> 2326168404Spjd * 2327168404Spjd * -f Force attach, even if <new_device> appears to be in use. 2328168404Spjd * 2329168404Spjd * Replace <device> with <new_device>. 2330168404Spjd */ 2331168404Spjd/* ARGSUSED */ 2332168404Spjdint 2333168404Spjdzpool_do_replace(int argc, char **argv) 2334168404Spjd{ 2335168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 2336168404Spjd} 2337168404Spjd 2338168404Spjd/* 2339168404Spjd * zpool attach [-f] <pool> <device> <new_device> 2340168404Spjd * 2341168404Spjd * -f Force attach, even if <new_device> appears to be in use. 2342168404Spjd * 2343168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 2344168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 2345168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 2346168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 2347168404Spjd */ 2348168404Spjdint 2349168404Spjdzpool_do_attach(int argc, char **argv) 2350168404Spjd{ 2351168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 2352168404Spjd} 2353168404Spjd 2354168404Spjd/* 2355168404Spjd * zpool detach [-f] <pool> <device> 2356168404Spjd * 2357168404Spjd * -f Force detach of <device>, even if DTLs argue against it 2358168404Spjd * (not supported yet) 2359168404Spjd * 2360168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 2361168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 2362168404Spjd * has the only valid copy of some data. 2363168404Spjd */ 2364168404Spjd/* ARGSUSED */ 2365168404Spjdint 2366168404Spjdzpool_do_detach(int argc, char **argv) 2367168404Spjd{ 2368168404Spjd int c; 2369168404Spjd char *poolname, *path; 2370168404Spjd zpool_handle_t *zhp; 2371168404Spjd int ret; 2372168404Spjd 2373168404Spjd /* check options */ 2374168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 2375168404Spjd switch (c) { 2376168404Spjd case 'f': 2377168404Spjd case '?': 2378168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2379168404Spjd optopt); 2380168404Spjd usage(B_FALSE); 2381168404Spjd } 2382168404Spjd } 2383168404Spjd 2384168404Spjd argc -= optind; 2385168404Spjd argv += optind; 2386168404Spjd 2387168404Spjd /* get pool name and check number of arguments */ 2388168404Spjd if (argc < 1) { 2389168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 2390168404Spjd usage(B_FALSE); 2391168404Spjd } 2392168404Spjd 2393168404Spjd if (argc < 2) { 2394168404Spjd (void) fprintf(stderr, 2395168404Spjd gettext("missing <device> specification\n")); 2396168404Spjd usage(B_FALSE); 2397168404Spjd } 2398168404Spjd 2399168404Spjd poolname = argv[0]; 2400168404Spjd path = argv[1]; 2401168404Spjd 2402168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2403168404Spjd return (1); 2404168404Spjd 2405168404Spjd ret = zpool_vdev_detach(zhp, path); 2406168404Spjd 2407168404Spjd zpool_close(zhp); 2408168404Spjd 2409168404Spjd return (ret); 2410168404Spjd} 2411168404Spjd 2412168404Spjd/* 2413168404Spjd * zpool online <pool> <device> ... 2414168404Spjd */ 2415168404Spjdint 2416168404Spjdzpool_do_online(int argc, char **argv) 2417168404Spjd{ 2418168404Spjd int c, i; 2419168404Spjd char *poolname; 2420168404Spjd zpool_handle_t *zhp; 2421168404Spjd int ret = 0; 2422185029Spjd vdev_state_t newstate; 2423168404Spjd 2424168404Spjd /* check options */ 2425168404Spjd while ((c = getopt(argc, argv, "t")) != -1) { 2426168404Spjd switch (c) { 2427168404Spjd case 't': 2428168404Spjd case '?': 2429168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2430168404Spjd optopt); 2431168404Spjd usage(B_FALSE); 2432168404Spjd } 2433168404Spjd } 2434168404Spjd 2435168404Spjd argc -= optind; 2436168404Spjd argv += optind; 2437168404Spjd 2438168404Spjd /* get pool name and check number of arguments */ 2439168404Spjd if (argc < 1) { 2440168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 2441168404Spjd usage(B_FALSE); 2442168404Spjd } 2443168404Spjd if (argc < 2) { 2444168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 2445168404Spjd usage(B_FALSE); 2446168404Spjd } 2447168404Spjd 2448168404Spjd poolname = argv[0]; 2449168404Spjd 2450168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2451168404Spjd return (1); 2452168404Spjd 2453185029Spjd for (i = 1; i < argc; i++) { 2454185029Spjd if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) { 2455185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 2456185029Spjd (void) printf(gettext("warning: device '%s' " 2457185029Spjd "onlined, but remains in faulted state\n"), 2458185029Spjd argv[i]); 2459185029Spjd if (newstate == VDEV_STATE_FAULTED) 2460185029Spjd (void) printf(gettext("use 'zpool " 2461185029Spjd "clear' to restore a faulted " 2462185029Spjd "device\n")); 2463185029Spjd else 2464185029Spjd (void) printf(gettext("use 'zpool " 2465185029Spjd "replace' to replace devices " 2466185029Spjd "that are no longer present\n")); 2467185029Spjd } 2468185029Spjd } else { 2469168404Spjd ret = 1; 2470185029Spjd } 2471185029Spjd } 2472168404Spjd 2473168404Spjd zpool_close(zhp); 2474168404Spjd 2475168404Spjd return (ret); 2476168404Spjd} 2477168404Spjd 2478168404Spjd/* 2479168404Spjd * zpool offline [-ft] <pool> <device> ... 2480168404Spjd * 2481168404Spjd * -f Force the device into the offline state, even if doing 2482168404Spjd * so would appear to compromise pool availability. 2483168404Spjd * (not supported yet) 2484168404Spjd * 2485168404Spjd * -t Only take the device off-line temporarily. The offline 2486168404Spjd * state will not be persistent across reboots. 2487168404Spjd */ 2488168404Spjd/* ARGSUSED */ 2489168404Spjdint 2490168404Spjdzpool_do_offline(int argc, char **argv) 2491168404Spjd{ 2492168404Spjd int c, i; 2493168404Spjd char *poolname; 2494168404Spjd zpool_handle_t *zhp; 2495168404Spjd int ret = 0; 2496168404Spjd boolean_t istmp = B_FALSE; 2497168404Spjd 2498168404Spjd /* check options */ 2499168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 2500168404Spjd switch (c) { 2501168404Spjd case 't': 2502168404Spjd istmp = B_TRUE; 2503168404Spjd break; 2504168404Spjd case 'f': 2505168404Spjd case '?': 2506168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2507168404Spjd optopt); 2508168404Spjd usage(B_FALSE); 2509168404Spjd } 2510168404Spjd } 2511168404Spjd 2512168404Spjd argc -= optind; 2513168404Spjd argv += optind; 2514168404Spjd 2515168404Spjd /* get pool name and check number of arguments */ 2516168404Spjd if (argc < 1) { 2517168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 2518168404Spjd usage(B_FALSE); 2519168404Spjd } 2520168404Spjd if (argc < 2) { 2521168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 2522168404Spjd usage(B_FALSE); 2523168404Spjd } 2524168404Spjd 2525168404Spjd poolname = argv[0]; 2526168404Spjd 2527168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 2528168404Spjd return (1); 2529168404Spjd 2530185029Spjd for (i = 1; i < argc; i++) { 2531185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 2532168404Spjd ret = 1; 2533185029Spjd } 2534168404Spjd 2535168404Spjd zpool_close(zhp); 2536168404Spjd 2537168404Spjd return (ret); 2538168404Spjd} 2539168404Spjd 2540168404Spjd/* 2541168404Spjd * zpool clear <pool> [device] 2542168404Spjd * 2543168404Spjd * Clear all errors associated with a pool or a particular device. 2544168404Spjd */ 2545168404Spjdint 2546168404Spjdzpool_do_clear(int argc, char **argv) 2547168404Spjd{ 2548168404Spjd int ret = 0; 2549168404Spjd zpool_handle_t *zhp; 2550168404Spjd char *pool, *device; 2551168404Spjd 2552168404Spjd if (argc < 2) { 2553168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 2554168404Spjd usage(B_FALSE); 2555168404Spjd } 2556168404Spjd 2557168404Spjd if (argc > 3) { 2558168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2559168404Spjd usage(B_FALSE); 2560168404Spjd } 2561168404Spjd 2562168404Spjd pool = argv[1]; 2563168404Spjd device = argc == 3 ? argv[2] : NULL; 2564168404Spjd 2565185029Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 2566168404Spjd return (1); 2567168404Spjd 2568168404Spjd if (zpool_clear(zhp, device) != 0) 2569168404Spjd ret = 1; 2570168404Spjd 2571168404Spjd zpool_close(zhp); 2572168404Spjd 2573168404Spjd return (ret); 2574168404Spjd} 2575168404Spjd 2576168404Spjdtypedef struct scrub_cbdata { 2577168404Spjd int cb_type; 2578168404Spjd int cb_argc; 2579168404Spjd char **cb_argv; 2580168404Spjd} scrub_cbdata_t; 2581168404Spjd 2582168404Spjdint 2583168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 2584168404Spjd{ 2585168404Spjd scrub_cbdata_t *cb = data; 2586168404Spjd int err; 2587168404Spjd 2588168404Spjd /* 2589168404Spjd * Ignore faulted pools. 2590168404Spjd */ 2591168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2592168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 2593168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 2594168404Spjd return (1); 2595168404Spjd } 2596168404Spjd 2597168404Spjd err = zpool_scrub(zhp, cb->cb_type); 2598168404Spjd 2599168404Spjd return (err != 0); 2600168404Spjd} 2601168404Spjd 2602168404Spjd/* 2603168404Spjd * zpool scrub [-s] <pool> ... 2604168404Spjd * 2605168404Spjd * -s Stop. Stops any in-progress scrub. 2606168404Spjd */ 2607168404Spjdint 2608168404Spjdzpool_do_scrub(int argc, char **argv) 2609168404Spjd{ 2610168404Spjd int c; 2611168404Spjd scrub_cbdata_t cb; 2612168404Spjd 2613168404Spjd cb.cb_type = POOL_SCRUB_EVERYTHING; 2614168404Spjd 2615168404Spjd /* check options */ 2616168404Spjd while ((c = getopt(argc, argv, "s")) != -1) { 2617168404Spjd switch (c) { 2618168404Spjd case 's': 2619168404Spjd cb.cb_type = POOL_SCRUB_NONE; 2620168404Spjd break; 2621168404Spjd case '?': 2622168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2623168404Spjd optopt); 2624168404Spjd usage(B_FALSE); 2625168404Spjd } 2626168404Spjd } 2627168404Spjd 2628168404Spjd cb.cb_argc = argc; 2629168404Spjd cb.cb_argv = argv; 2630168404Spjd argc -= optind; 2631168404Spjd argv += optind; 2632168404Spjd 2633168404Spjd if (argc < 1) { 2634168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 2635168404Spjd usage(B_FALSE); 2636168404Spjd } 2637168404Spjd 2638168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 2639168404Spjd} 2640168404Spjd 2641168404Spjdtypedef struct status_cbdata { 2642168404Spjd int cb_count; 2643168404Spjd boolean_t cb_allpools; 2644168404Spjd boolean_t cb_verbose; 2645168404Spjd boolean_t cb_explain; 2646168404Spjd boolean_t cb_first; 2647168404Spjd} status_cbdata_t; 2648168404Spjd 2649168404Spjd/* 2650168404Spjd * Print out detailed scrub status. 2651168404Spjd */ 2652168404Spjdvoid 2653168404Spjdprint_scrub_status(nvlist_t *nvroot) 2654168404Spjd{ 2655168404Spjd vdev_stat_t *vs; 2656168404Spjd uint_t vsc; 2657168404Spjd time_t start, end, now; 2658168404Spjd double fraction_done; 2659185029Spjd uint64_t examined, total, minutes_left, minutes_taken; 2660168404Spjd char *scrub_type; 2661168404Spjd 2662168404Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 2663168404Spjd (uint64_t **)&vs, &vsc) == 0); 2664168404Spjd 2665168404Spjd /* 2666168404Spjd * If there's never been a scrub, there's not much to say. 2667168404Spjd */ 2668168404Spjd if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { 2669168404Spjd (void) printf(gettext("none requested\n")); 2670168404Spjd return; 2671168404Spjd } 2672168404Spjd 2673168404Spjd scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2674168404Spjd "resilver" : "scrub"; 2675168404Spjd 2676168404Spjd start = vs->vs_scrub_start; 2677168404Spjd end = vs->vs_scrub_end; 2678168404Spjd now = time(NULL); 2679168404Spjd examined = vs->vs_scrub_examined; 2680168404Spjd total = vs->vs_alloc; 2681168404Spjd 2682168404Spjd if (end != 0) { 2683185029Spjd minutes_taken = (uint64_t)((end - start) / 60); 2684185029Spjd 2685185029Spjd (void) printf(gettext("%s %s after %lluh%um with %llu errors " 2686185029Spjd "on %s"), 2687168404Spjd scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", 2688185029Spjd (u_longlong_t)(minutes_taken / 60), 2689185029Spjd (uint_t)(minutes_taken % 60), 2690168404Spjd (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); 2691168404Spjd return; 2692168404Spjd } 2693168404Spjd 2694168404Spjd if (examined == 0) 2695168404Spjd examined = 1; 2696168404Spjd if (examined > total) 2697168404Spjd total = examined; 2698168404Spjd 2699168404Spjd fraction_done = (double)examined / total; 2700168404Spjd minutes_left = (uint64_t)((now - start) * 2701168404Spjd (1 - fraction_done) / fraction_done / 60); 2702185029Spjd minutes_taken = (uint64_t)((now - start) / 60); 2703168404Spjd 2704185029Spjd (void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, " 2705185029Spjd "%lluh%um to go\n"), 2706185029Spjd scrub_type, (u_longlong_t)(minutes_taken / 60), 2707185029Spjd (uint_t)(minutes_taken % 60), 100 * fraction_done, 2708168404Spjd (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); 2709168404Spjd} 2710168404Spjd 2711168404Spjdtypedef struct spare_cbdata { 2712168404Spjd uint64_t cb_guid; 2713168404Spjd zpool_handle_t *cb_zhp; 2714168404Spjd} spare_cbdata_t; 2715168404Spjd 2716168404Spjdstatic boolean_t 2717168404Spjdfind_vdev(nvlist_t *nv, uint64_t search) 2718168404Spjd{ 2719168404Spjd uint64_t guid; 2720168404Spjd nvlist_t **child; 2721168404Spjd uint_t c, children; 2722168404Spjd 2723168404Spjd if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 2724168404Spjd search == guid) 2725168404Spjd return (B_TRUE); 2726168404Spjd 2727168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2728168404Spjd &child, &children) == 0) { 2729168404Spjd for (c = 0; c < children; c++) 2730168404Spjd if (find_vdev(child[c], search)) 2731168404Spjd return (B_TRUE); 2732168404Spjd } 2733168404Spjd 2734168404Spjd return (B_FALSE); 2735168404Spjd} 2736168404Spjd 2737168404Spjdstatic int 2738168404Spjdfind_spare(zpool_handle_t *zhp, void *data) 2739168404Spjd{ 2740168404Spjd spare_cbdata_t *cbp = data; 2741168404Spjd nvlist_t *config, *nvroot; 2742168404Spjd 2743168404Spjd config = zpool_get_config(zhp, NULL); 2744168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2745168404Spjd &nvroot) == 0); 2746168404Spjd 2747168404Spjd if (find_vdev(nvroot, cbp->cb_guid)) { 2748168404Spjd cbp->cb_zhp = zhp; 2749168404Spjd return (1); 2750168404Spjd } 2751168404Spjd 2752168404Spjd zpool_close(zhp); 2753168404Spjd return (0); 2754168404Spjd} 2755168404Spjd 2756168404Spjd/* 2757168404Spjd * Print out configuration state as requested by status_callback. 2758168404Spjd */ 2759168404Spjdvoid 2760168404Spjdprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 2761185029Spjd int namewidth, int depth, boolean_t isspare, boolean_t print_logs) 2762168404Spjd{ 2763168404Spjd nvlist_t **child; 2764168404Spjd uint_t c, children; 2765168404Spjd vdev_stat_t *vs; 2766168404Spjd char rbuf[6], wbuf[6], cbuf[6], repaired[7]; 2767168404Spjd char *vname; 2768168404Spjd uint64_t notpresent; 2769168404Spjd spare_cbdata_t cb; 2770185029Spjd char *state; 2771168404Spjd 2772168404Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 2773168404Spjd (uint64_t **)&vs, &c) == 0); 2774168404Spjd 2775168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2776168404Spjd &child, &children) != 0) 2777168404Spjd children = 0; 2778168404Spjd 2779185029Spjd state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 2780168404Spjd if (isspare) { 2781168404Spjd /* 2782168404Spjd * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 2783168404Spjd * online drives. 2784168404Spjd */ 2785168404Spjd if (vs->vs_aux == VDEV_AUX_SPARED) 2786168404Spjd state = "INUSE"; 2787168404Spjd else if (vs->vs_state == VDEV_STATE_HEALTHY) 2788168404Spjd state = "AVAIL"; 2789168404Spjd } 2790168404Spjd 2791168404Spjd (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 2792168404Spjd name, state); 2793168404Spjd 2794168404Spjd if (!isspare) { 2795168404Spjd zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 2796168404Spjd zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 2797168404Spjd zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 2798168404Spjd (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 2799168404Spjd } 2800168404Spjd 2801168404Spjd if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2802168404Spjd ¬present) == 0) { 2803168404Spjd char *path; 2804168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 2805168404Spjd (void) printf(" was %s", path); 2806168404Spjd } else if (vs->vs_aux != 0) { 2807168404Spjd (void) printf(" "); 2808168404Spjd 2809168404Spjd switch (vs->vs_aux) { 2810168404Spjd case VDEV_AUX_OPEN_FAILED: 2811168404Spjd (void) printf(gettext("cannot open")); 2812168404Spjd break; 2813168404Spjd 2814168404Spjd case VDEV_AUX_BAD_GUID_SUM: 2815168404Spjd (void) printf(gettext("missing device")); 2816168404Spjd break; 2817168404Spjd 2818168404Spjd case VDEV_AUX_NO_REPLICAS: 2819168404Spjd (void) printf(gettext("insufficient replicas")); 2820168404Spjd break; 2821168404Spjd 2822168404Spjd case VDEV_AUX_VERSION_NEWER: 2823168404Spjd (void) printf(gettext("newer version")); 2824168404Spjd break; 2825168404Spjd 2826168404Spjd case VDEV_AUX_SPARED: 2827168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 2828168404Spjd &cb.cb_guid) == 0); 2829168404Spjd if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 2830168404Spjd if (strcmp(zpool_get_name(cb.cb_zhp), 2831168404Spjd zpool_get_name(zhp)) == 0) 2832168404Spjd (void) printf(gettext("currently in " 2833168404Spjd "use")); 2834168404Spjd else 2835168404Spjd (void) printf(gettext("in use by " 2836168404Spjd "pool '%s'"), 2837168404Spjd zpool_get_name(cb.cb_zhp)); 2838168404Spjd zpool_close(cb.cb_zhp); 2839168404Spjd } else { 2840168404Spjd (void) printf(gettext("currently in use")); 2841168404Spjd } 2842168404Spjd break; 2843168404Spjd 2844185029Spjd case VDEV_AUX_ERR_EXCEEDED: 2845185029Spjd (void) printf(gettext("too many errors")); 2846185029Spjd break; 2847185029Spjd 2848185029Spjd case VDEV_AUX_IO_FAILURE: 2849185029Spjd (void) printf(gettext("experienced I/O failures")); 2850185029Spjd break; 2851185029Spjd 2852185029Spjd case VDEV_AUX_BAD_LOG: 2853185029Spjd (void) printf(gettext("bad intent log")); 2854185029Spjd break; 2855185029Spjd 2856168404Spjd default: 2857168404Spjd (void) printf(gettext("corrupted data")); 2858168404Spjd break; 2859168404Spjd } 2860168404Spjd } else if (vs->vs_scrub_repaired != 0 && children == 0) { 2861168404Spjd /* 2862168404Spjd * Report bytes resilvered/repaired on leaf devices. 2863168404Spjd */ 2864168404Spjd zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); 2865168404Spjd (void) printf(gettext(" %s %s"), repaired, 2866168404Spjd (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? 2867168404Spjd "resilvered" : "repaired"); 2868168404Spjd } 2869168404Spjd 2870168404Spjd (void) printf("\n"); 2871168404Spjd 2872168404Spjd for (c = 0; c < children; c++) { 2873185029Spjd uint64_t is_log = B_FALSE; 2874185029Spjd 2875185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 2876185029Spjd &is_log); 2877185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 2878185029Spjd continue; 2879168404Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c]); 2880168404Spjd print_status_config(zhp, vname, child[c], 2881185029Spjd namewidth, depth + 2, isspare, B_FALSE); 2882168404Spjd free(vname); 2883168404Spjd } 2884168404Spjd} 2885168404Spjd 2886168404Spjdstatic void 2887168404Spjdprint_error_log(zpool_handle_t *zhp) 2888168404Spjd{ 2889185029Spjd nvlist_t *nverrlist = NULL; 2890168404Spjd nvpair_t *elem; 2891168404Spjd char *pathname; 2892168404Spjd size_t len = MAXPATHLEN * 2; 2893168404Spjd 2894168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 2895168404Spjd (void) printf("errors: List of errors unavailable " 2896168404Spjd "(insufficient privileges)\n"); 2897168404Spjd return; 2898168404Spjd } 2899168404Spjd 2900168404Spjd (void) printf("errors: Permanent errors have been " 2901168404Spjd "detected in the following files:\n\n"); 2902168404Spjd 2903168404Spjd pathname = safe_malloc(len); 2904168404Spjd elem = NULL; 2905168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 2906168404Spjd nvlist_t *nv; 2907168404Spjd uint64_t dsobj, obj; 2908168404Spjd 2909168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 2910168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 2911168404Spjd &dsobj) == 0); 2912168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 2913168404Spjd &obj) == 0); 2914168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 2915168404Spjd (void) printf("%7s %s\n", "", pathname); 2916168404Spjd } 2917168404Spjd free(pathname); 2918168404Spjd nvlist_free(nverrlist); 2919168404Spjd} 2920168404Spjd 2921168404Spjdstatic void 2922168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 2923168404Spjd int namewidth) 2924168404Spjd{ 2925168404Spjd uint_t i; 2926168404Spjd char *name; 2927168404Spjd 2928168404Spjd if (nspares == 0) 2929168404Spjd return; 2930168404Spjd 2931168404Spjd (void) printf(gettext("\tspares\n")); 2932168404Spjd 2933168404Spjd for (i = 0; i < nspares; i++) { 2934168404Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i]); 2935168404Spjd print_status_config(zhp, name, spares[i], 2936185029Spjd namewidth, 2, B_TRUE, B_FALSE); 2937168404Spjd free(name); 2938168404Spjd } 2939168404Spjd} 2940168404Spjd 2941185029Spjdstatic void 2942185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 2943185029Spjd int namewidth) 2944185029Spjd{ 2945185029Spjd uint_t i; 2946185029Spjd char *name; 2947185029Spjd 2948185029Spjd if (nl2cache == 0) 2949185029Spjd return; 2950185029Spjd 2951185029Spjd (void) printf(gettext("\tcache\n")); 2952185029Spjd 2953185029Spjd for (i = 0; i < nl2cache; i++) { 2954185029Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i]); 2955185029Spjd print_status_config(zhp, name, l2cache[i], 2956185029Spjd namewidth, 2, B_FALSE, B_FALSE); 2957185029Spjd free(name); 2958185029Spjd } 2959185029Spjd} 2960185029Spjd 2961168404Spjd/* 2962168404Spjd * Display a summary of pool status. Displays a summary such as: 2963168404Spjd * 2964168404Spjd * pool: tank 2965168404Spjd * status: DEGRADED 2966168404Spjd * reason: One or more devices ... 2967168404Spjd * see: http://www.sun.com/msg/ZFS-xxxx-01 2968168404Spjd * config: 2969168404Spjd * mirror DEGRADED 2970168404Spjd * c1t0d0 OK 2971168404Spjd * c2t0d0 UNAVAIL 2972168404Spjd * 2973168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 2974168404Spjd * option is specified, then we print out error rate information as well. 2975168404Spjd */ 2976168404Spjdint 2977168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 2978168404Spjd{ 2979168404Spjd status_cbdata_t *cbp = data; 2980168404Spjd nvlist_t *config, *nvroot; 2981168404Spjd char *msgid; 2982168404Spjd int reason; 2983168404Spjd const char *health; 2984168404Spjd uint_t c; 2985168404Spjd vdev_stat_t *vs; 2986168404Spjd 2987168404Spjd config = zpool_get_config(zhp, NULL); 2988168404Spjd reason = zpool_get_status(zhp, &msgid); 2989168404Spjd 2990168404Spjd cbp->cb_count++; 2991168404Spjd 2992168404Spjd /* 2993168404Spjd * If we were given 'zpool status -x', only report those pools with 2994168404Spjd * problems. 2995168404Spjd */ 2996168404Spjd if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) { 2997168404Spjd if (!cbp->cb_allpools) { 2998168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 2999168404Spjd zpool_get_name(zhp)); 3000168404Spjd if (cbp->cb_first) 3001168404Spjd cbp->cb_first = B_FALSE; 3002168404Spjd } 3003168404Spjd return (0); 3004168404Spjd } 3005168404Spjd 3006168404Spjd if (cbp->cb_first) 3007168404Spjd cbp->cb_first = B_FALSE; 3008168404Spjd else 3009168404Spjd (void) printf("\n"); 3010168404Spjd 3011168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3012168404Spjd &nvroot) == 0); 3013168404Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 3014168404Spjd (uint64_t **)&vs, &c) == 0); 3015185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 3016168404Spjd 3017168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 3018168404Spjd (void) printf(gettext(" state: %s\n"), health); 3019168404Spjd 3020168404Spjd switch (reason) { 3021168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 3022168404Spjd (void) printf(gettext("status: One or more devices could not " 3023168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 3024168404Spjd "continue functioning in a degraded state.\n")); 3025168404Spjd (void) printf(gettext("action: Attach the missing device and " 3026168404Spjd "online it using 'zpool online'.\n")); 3027168404Spjd break; 3028168404Spjd 3029168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 3030168404Spjd (void) printf(gettext("status: One or more devices could not " 3031168404Spjd "be opened. There are insufficient\n\treplicas for the " 3032168404Spjd "pool to continue functioning.\n")); 3033168404Spjd (void) printf(gettext("action: Attach the missing device and " 3034168404Spjd "online it using 'zpool online'.\n")); 3035168404Spjd break; 3036168404Spjd 3037168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 3038168404Spjd (void) printf(gettext("status: One or more devices could not " 3039168404Spjd "be used because the label is missing or\n\tinvalid. " 3040168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 3041168404Spjd "functioning in a degraded state.\n")); 3042168404Spjd (void) printf(gettext("action: Replace the device using " 3043168404Spjd "'zpool replace'.\n")); 3044168404Spjd break; 3045168404Spjd 3046168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 3047168404Spjd (void) printf(gettext("status: One or more devices could not " 3048168404Spjd "be used because the label is missing \n\tor invalid. " 3049168404Spjd "There are insufficient replicas for the pool to " 3050168404Spjd "continue\n\tfunctioning.\n")); 3051168404Spjd (void) printf(gettext("action: Destroy and re-create the pool " 3052168404Spjd "from a backup source.\n")); 3053168404Spjd break; 3054168404Spjd 3055168404Spjd case ZPOOL_STATUS_FAILING_DEV: 3056168404Spjd (void) printf(gettext("status: One or more devices has " 3057168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 3058168404Spjd "made to correct the error. Applications are " 3059168404Spjd "unaffected.\n")); 3060168404Spjd (void) printf(gettext("action: Determine if the device needs " 3061168404Spjd "to be replaced, and clear the errors\n\tusing " 3062168404Spjd "'zpool clear' or replace the device with 'zpool " 3063168404Spjd "replace'.\n")); 3064168404Spjd break; 3065168404Spjd 3066168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 3067168404Spjd (void) printf(gettext("status: One or more devices has " 3068168404Spjd "been taken offline by the administrator.\n\tSufficient " 3069168404Spjd "replicas exist for the pool to continue functioning in " 3070168404Spjd "a\n\tdegraded state.\n")); 3071168404Spjd (void) printf(gettext("action: Online the device using " 3072168404Spjd "'zpool online' or replace the device with\n\t'zpool " 3073168404Spjd "replace'.\n")); 3074168404Spjd break; 3075168404Spjd 3076168404Spjd case ZPOOL_STATUS_RESILVERING: 3077168404Spjd (void) printf(gettext("status: One or more devices is " 3078168404Spjd "currently being resilvered. The pool will\n\tcontinue " 3079168404Spjd "to function, possibly in a degraded state.\n")); 3080168404Spjd (void) printf(gettext("action: Wait for the resilver to " 3081168404Spjd "complete.\n")); 3082168404Spjd break; 3083168404Spjd 3084168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 3085168404Spjd (void) printf(gettext("status: One or more devices has " 3086168404Spjd "experienced an error resulting in data\n\tcorruption. " 3087168404Spjd "Applications may be affected.\n")); 3088168404Spjd (void) printf(gettext("action: Restore the file in question " 3089168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 3090168404Spjd "backup.\n")); 3091168404Spjd break; 3092168404Spjd 3093168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 3094168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 3095168404Spjd "and the pool cannot be opened.\n")); 3096168404Spjd (void) printf(gettext("action: Destroy and re-create the pool " 3097168404Spjd "from a backup source.\n")); 3098168404Spjd break; 3099168404Spjd 3100168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 3101168404Spjd (void) printf(gettext("status: The pool is formatted using an " 3102168404Spjd "older on-disk format. The pool can\n\tstill be used, but " 3103168404Spjd "some features are unavailable.\n")); 3104168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 3105168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 3106168404Spjd "be accessible on older software versions.\n")); 3107168404Spjd break; 3108168404Spjd 3109168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 3110168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 3111168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 3112168404Spjd "be accessed on this system.\n")); 3113168404Spjd (void) printf(gettext("action: Access the pool from a system " 3114168404Spjd "running more recent software, or\n\trestore the pool from " 3115168404Spjd "backup.\n")); 3116168404Spjd break; 3117168404Spjd 3118185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 3119185029Spjd (void) printf(gettext("status: One or more devices are " 3120185029Spjd "faulted in response to persistent errors.\n\tSufficient " 3121185029Spjd "replicas exist for the pool to continue functioning " 3122185029Spjd "in a\n\tdegraded state.\n")); 3123185029Spjd (void) printf(gettext("action: Replace the faulted device, " 3124185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 3125185029Spjd break; 3126185029Spjd 3127185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 3128185029Spjd (void) printf(gettext("status: One or more devices are " 3129185029Spjd "faulted in response to persistent errors. There are " 3130185029Spjd "insufficient replicas for the pool to\n\tcontinue " 3131185029Spjd "functioning.\n")); 3132185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 3133185029Spjd "from a backup source. Manually marking the device\n" 3134185029Spjd "\trepaired using 'zpool clear' may allow some data " 3135185029Spjd "to be recovered.\n")); 3136185029Spjd break; 3137185029Spjd 3138185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 3139185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 3140185029Spjd (void) printf(gettext("status: One or more devices are " 3141185029Spjd "faulted in response to IO failures.\n")); 3142185029Spjd (void) printf(gettext("action: Make sure the affected devices " 3143185029Spjd "are connected, then run 'zpool clear'.\n")); 3144185029Spjd break; 3145185029Spjd 3146185029Spjd case ZPOOL_STATUS_BAD_LOG: 3147185029Spjd (void) printf(gettext("status: An intent log record " 3148185029Spjd "could not be read.\n" 3149185029Spjd "\tWaiting for adminstrator intervention to fix the " 3150185029Spjd "faulted pool.\n")); 3151185029Spjd (void) printf(gettext("action: Either restore the affected " 3152185029Spjd "device(s) and run 'zpool online',\n" 3153185029Spjd "\tor ignore the intent log records by running " 3154185029Spjd "'zpool clear'.\n")); 3155185029Spjd break; 3156185029Spjd 3157168404Spjd default: 3158168404Spjd /* 3159168404Spjd * The remaining errors can't actually be generated, yet. 3160168404Spjd */ 3161168404Spjd assert(reason == ZPOOL_STATUS_OK); 3162168404Spjd } 3163168404Spjd 3164168404Spjd if (msgid != NULL) 3165168404Spjd (void) printf(gettext(" see: http://www.sun.com/msg/%s\n"), 3166168404Spjd msgid); 3167168404Spjd 3168168404Spjd if (config != NULL) { 3169168404Spjd int namewidth; 3170168404Spjd uint64_t nerr; 3171185029Spjd nvlist_t **spares, **l2cache; 3172185029Spjd uint_t nspares, nl2cache; 3173168404Spjd 3174168404Spjd 3175168404Spjd (void) printf(gettext(" scrub: ")); 3176168404Spjd print_scrub_status(nvroot); 3177168404Spjd 3178168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 3179168404Spjd if (namewidth < 10) 3180168404Spjd namewidth = 10; 3181168404Spjd 3182168404Spjd (void) printf(gettext("config:\n\n")); 3183168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 3184168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 3185168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 3186185029Spjd namewidth, 0, B_FALSE, B_FALSE); 3187185029Spjd if (num_logs(nvroot) > 0) 3188185029Spjd print_status_config(zhp, "logs", nvroot, namewidth, 0, 3189185029Spjd B_FALSE, B_TRUE); 3190168404Spjd 3191185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 3192185029Spjd &l2cache, &nl2cache) == 0) 3193185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 3194185029Spjd 3195168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 3196168404Spjd &spares, &nspares) == 0) 3197168404Spjd print_spares(zhp, spares, nspares, namewidth); 3198168404Spjd 3199168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 3200168404Spjd &nerr) == 0) { 3201168404Spjd nvlist_t *nverrlist = NULL; 3202168404Spjd 3203168404Spjd /* 3204168404Spjd * If the approximate error count is small, get a 3205168404Spjd * precise count by fetching the entire log and 3206168404Spjd * uniquifying the results. 3207168404Spjd */ 3208185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 3209168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 3210168404Spjd nvpair_t *elem; 3211168404Spjd 3212168404Spjd elem = NULL; 3213168404Spjd nerr = 0; 3214168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 3215168404Spjd elem)) != NULL) { 3216168404Spjd nerr++; 3217168404Spjd } 3218168404Spjd } 3219168404Spjd nvlist_free(nverrlist); 3220168404Spjd 3221168404Spjd (void) printf("\n"); 3222168404Spjd 3223168404Spjd if (nerr == 0) 3224168404Spjd (void) printf(gettext("errors: No known data " 3225168404Spjd "errors\n")); 3226168404Spjd else if (!cbp->cb_verbose) 3227168404Spjd (void) printf(gettext("errors: %llu data " 3228168404Spjd "errors, use '-v' for a list\n"), 3229168404Spjd (u_longlong_t)nerr); 3230168404Spjd else 3231168404Spjd print_error_log(zhp); 3232168404Spjd } 3233168404Spjd } else { 3234168404Spjd (void) printf(gettext("config: The configuration cannot be " 3235168404Spjd "determined.\n")); 3236168404Spjd } 3237168404Spjd 3238168404Spjd return (0); 3239168404Spjd} 3240168404Spjd 3241168404Spjd/* 3242168404Spjd * zpool status [-vx] [pool] ... 3243168404Spjd * 3244168404Spjd * -v Display complete error logs 3245168404Spjd * -x Display only pools with potential problems 3246168404Spjd * 3247168404Spjd * Describes the health status of all pools or some subset. 3248168404Spjd */ 3249168404Spjdint 3250168404Spjdzpool_do_status(int argc, char **argv) 3251168404Spjd{ 3252168404Spjd int c; 3253168404Spjd int ret; 3254168404Spjd status_cbdata_t cb = { 0 }; 3255168404Spjd 3256168404Spjd /* check options */ 3257168404Spjd while ((c = getopt(argc, argv, "vx")) != -1) { 3258168404Spjd switch (c) { 3259168404Spjd case 'v': 3260168404Spjd cb.cb_verbose = B_TRUE; 3261168404Spjd break; 3262168404Spjd case 'x': 3263168404Spjd cb.cb_explain = B_TRUE; 3264168404Spjd break; 3265168404Spjd case '?': 3266168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3267168404Spjd optopt); 3268168404Spjd usage(B_FALSE); 3269168404Spjd } 3270168404Spjd } 3271168404Spjd 3272168404Spjd argc -= optind; 3273168404Spjd argv += optind; 3274168404Spjd 3275168404Spjd cb.cb_first = B_TRUE; 3276168404Spjd 3277168404Spjd if (argc == 0) 3278168404Spjd cb.cb_allpools = B_TRUE; 3279168404Spjd 3280168404Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); 3281168404Spjd 3282168404Spjd if (argc == 0 && cb.cb_count == 0) 3283168404Spjd (void) printf(gettext("no pools available\n")); 3284168404Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 3285168404Spjd (void) printf(gettext("all pools are healthy\n")); 3286168404Spjd 3287168404Spjd return (ret); 3288168404Spjd} 3289168404Spjd 3290168404Spjdtypedef struct upgrade_cbdata { 3291168404Spjd int cb_all; 3292168404Spjd int cb_first; 3293168404Spjd int cb_newer; 3294168404Spjd int cb_argc; 3295185029Spjd uint64_t cb_version; 3296168404Spjd char **cb_argv; 3297168404Spjd} upgrade_cbdata_t; 3298168404Spjd 3299168404Spjdstatic int 3300168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 3301168404Spjd{ 3302168404Spjd upgrade_cbdata_t *cbp = arg; 3303168404Spjd nvlist_t *config; 3304168404Spjd uint64_t version; 3305168404Spjd int ret = 0; 3306168404Spjd 3307168404Spjd config = zpool_get_config(zhp, NULL); 3308168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 3309168404Spjd &version) == 0); 3310168404Spjd 3311185029Spjd if (!cbp->cb_newer && version < SPA_VERSION) { 3312168404Spjd if (!cbp->cb_all) { 3313168404Spjd if (cbp->cb_first) { 3314168404Spjd (void) printf(gettext("The following pools are " 3315168404Spjd "out of date, and can be upgraded. After " 3316168404Spjd "being\nupgraded, these pools will no " 3317168404Spjd "longer be accessible by older software " 3318168404Spjd "versions.\n\n")); 3319168404Spjd (void) printf(gettext("VER POOL\n")); 3320168404Spjd (void) printf(gettext("--- ------------\n")); 3321168404Spjd cbp->cb_first = B_FALSE; 3322168404Spjd } 3323168404Spjd 3324168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 3325168404Spjd zpool_get_name(zhp)); 3326168404Spjd } else { 3327168404Spjd cbp->cb_first = B_FALSE; 3328185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 3329168404Spjd if (!ret) { 3330168404Spjd (void) printf(gettext("Successfully upgraded " 3331185029Spjd "'%s'\n\n"), zpool_get_name(zhp)); 3332168404Spjd } 3333168404Spjd } 3334185029Spjd } else if (cbp->cb_newer && version > SPA_VERSION) { 3335168404Spjd assert(!cbp->cb_all); 3336168404Spjd 3337168404Spjd if (cbp->cb_first) { 3338168404Spjd (void) printf(gettext("The following pools are " 3339168404Spjd "formatted using a newer software version and\n" 3340168404Spjd "cannot be accessed on the current system.\n\n")); 3341168404Spjd (void) printf(gettext("VER POOL\n")); 3342168404Spjd (void) printf(gettext("--- ------------\n")); 3343168404Spjd cbp->cb_first = B_FALSE; 3344168404Spjd } 3345168404Spjd 3346168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 3347168404Spjd zpool_get_name(zhp)); 3348168404Spjd } 3349168404Spjd 3350168404Spjd zpool_close(zhp); 3351168404Spjd return (ret); 3352168404Spjd} 3353168404Spjd 3354168404Spjd/* ARGSUSED */ 3355168404Spjdstatic int 3356168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 3357168404Spjd{ 3358185029Spjd upgrade_cbdata_t *cbp = data; 3359185029Spjd uint64_t cur_version; 3360168404Spjd int ret; 3361168404Spjd 3362185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 3363185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 3364185029Spjd "Pool 'log' must be renamed using export and import" 3365185029Spjd " to upgrade.\n")); 3366185029Spjd return (1); 3367185029Spjd } 3368168404Spjd 3369185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 3370185029Spjd if (cur_version > cbp->cb_version) { 3371168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 3372185029Spjd "using more current version '%llu'.\n"), 3373185029Spjd zpool_get_name(zhp), cur_version); 3374185029Spjd return (0); 3375185029Spjd } 3376185029Spjd if (cur_version == cbp->cb_version) { 3377185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 3378168404Spjd "using the current version.\n"), zpool_get_name(zhp)); 3379168404Spjd return (0); 3380168404Spjd } 3381168404Spjd 3382185029Spjd ret = zpool_upgrade(zhp, cbp->cb_version); 3383168404Spjd 3384168404Spjd if (!ret) { 3385168404Spjd (void) printf(gettext("Successfully upgraded '%s' " 3386185029Spjd "from version %llu to version %llu\n\n"), 3387185029Spjd zpool_get_name(zhp), (u_longlong_t)cur_version, 3388185029Spjd (u_longlong_t)cbp->cb_version); 3389168404Spjd } 3390168404Spjd 3391168404Spjd return (ret != 0); 3392168404Spjd} 3393168404Spjd 3394168404Spjd/* 3395168404Spjd * zpool upgrade 3396168404Spjd * zpool upgrade -v 3397185029Spjd * zpool upgrade [-V version] <-a | pool ...> 3398168404Spjd * 3399168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 3400168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 3401168404Spjd * upgrade all pools. 3402168404Spjd */ 3403168404Spjdint 3404168404Spjdzpool_do_upgrade(int argc, char **argv) 3405168404Spjd{ 3406168404Spjd int c; 3407168404Spjd upgrade_cbdata_t cb = { 0 }; 3408168404Spjd int ret = 0; 3409168404Spjd boolean_t showversions = B_FALSE; 3410185029Spjd char *end; 3411168404Spjd 3412185029Spjd 3413168404Spjd /* check options */ 3414185029Spjd while ((c = getopt(argc, argv, "avV:")) != -1) { 3415168404Spjd switch (c) { 3416168404Spjd case 'a': 3417168404Spjd cb.cb_all = B_TRUE; 3418168404Spjd break; 3419168404Spjd case 'v': 3420168404Spjd showversions = B_TRUE; 3421168404Spjd break; 3422185029Spjd case 'V': 3423185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 3424185029Spjd if (*end != '\0' || cb.cb_version > SPA_VERSION || 3425185029Spjd cb.cb_version < SPA_VERSION_1) { 3426185029Spjd (void) fprintf(stderr, 3427185029Spjd gettext("invalid version '%s'\n"), optarg); 3428185029Spjd usage(B_FALSE); 3429185029Spjd } 3430185029Spjd break; 3431168404Spjd case '?': 3432168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3433168404Spjd optopt); 3434168404Spjd usage(B_FALSE); 3435168404Spjd } 3436168404Spjd } 3437168404Spjd 3438168404Spjd cb.cb_argc = argc; 3439168404Spjd cb.cb_argv = argv; 3440168404Spjd argc -= optind; 3441168404Spjd argv += optind; 3442168404Spjd 3443185029Spjd if (cb.cb_version == 0) { 3444185029Spjd cb.cb_version = SPA_VERSION; 3445185029Spjd } else if (!cb.cb_all && argc == 0) { 3446185029Spjd (void) fprintf(stderr, gettext("-V option is " 3447185029Spjd "incompatible with other arguments\n")); 3448185029Spjd usage(B_FALSE); 3449185029Spjd } 3450185029Spjd 3451168404Spjd if (showversions) { 3452168404Spjd if (cb.cb_all || argc != 0) { 3453168404Spjd (void) fprintf(stderr, gettext("-v option is " 3454168404Spjd "incompatible with other arguments\n")); 3455168404Spjd usage(B_FALSE); 3456168404Spjd } 3457168404Spjd } else if (cb.cb_all) { 3458168404Spjd if (argc != 0) { 3459185029Spjd (void) fprintf(stderr, gettext("-a option should not " 3460185029Spjd "be used along with a pool name\n")); 3461168404Spjd usage(B_FALSE); 3462168404Spjd } 3463168404Spjd } 3464168404Spjd 3465185029Spjd (void) printf(gettext("This system is currently running " 3466185029Spjd "ZFS pool version %llu.\n\n"), SPA_VERSION); 3467168404Spjd cb.cb_first = B_TRUE; 3468168404Spjd if (showversions) { 3469168404Spjd (void) printf(gettext("The following versions are " 3470168404Spjd "supported:\n\n")); 3471168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 3472168404Spjd (void) printf("--- -----------------------------------------" 3473168404Spjd "---------------\n"); 3474168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 3475168404Spjd (void) printf(gettext(" 2 Ditto blocks " 3476168404Spjd "(replicated metadata)\n")); 3477168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 3478168404Spjd "RAID-Z\n")); 3479168404Spjd (void) printf(gettext(" 4 zpool history\n")); 3480168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 3481168404Spjd "algorithm\n")); 3482185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 3483185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 3484185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 3485185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 3486185029Spjd "properties\n")); 3487185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 3488185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 3489185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 3490185029Spjd (void) printf(gettext(" 13 snapused property\n")); 3491185029Spjd (void) printf(gettext("For more information on a particular " 3492168404Spjd "version, including supported releases, see:\n\n")); 3493168404Spjd (void) printf("http://www.opensolaris.org/os/community/zfs/" 3494168404Spjd "version/N\n\n"); 3495168404Spjd (void) printf(gettext("Where 'N' is the version number.\n")); 3496168404Spjd } else if (argc == 0) { 3497168404Spjd int notfound; 3498168404Spjd 3499168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3500168404Spjd notfound = cb.cb_first; 3501168404Spjd 3502168404Spjd if (!cb.cb_all && ret == 0) { 3503168404Spjd if (!cb.cb_first) 3504168404Spjd (void) printf("\n"); 3505168404Spjd cb.cb_first = B_TRUE; 3506168404Spjd cb.cb_newer = B_TRUE; 3507168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 3508168404Spjd if (!cb.cb_first) { 3509168404Spjd notfound = B_FALSE; 3510168404Spjd (void) printf("\n"); 3511168404Spjd } 3512168404Spjd } 3513168404Spjd 3514168404Spjd if (ret == 0) { 3515168404Spjd if (notfound) 3516168404Spjd (void) printf(gettext("All pools are formatted " 3517168404Spjd "using this version.\n")); 3518168404Spjd else if (!cb.cb_all) 3519168404Spjd (void) printf(gettext("Use 'zpool upgrade -v' " 3520168404Spjd "for a list of available versions and " 3521168404Spjd "their associated\nfeatures.\n")); 3522168404Spjd } 3523168404Spjd } else { 3524168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, 3525168404Spjd upgrade_one, &cb); 3526168404Spjd } 3527168404Spjd 3528168404Spjd return (ret); 3529168404Spjd} 3530168404Spjd 3531185029Spjdtypedef struct hist_cbdata { 3532185029Spjd boolean_t first; 3533185029Spjd int longfmt; 3534185029Spjd int internal; 3535185029Spjd} hist_cbdata_t; 3536185029Spjd 3537185029Spjdchar *hist_event_table[LOG_END] = { 3538185029Spjd "invalid event", 3539185029Spjd "pool create", 3540185029Spjd "vdev add", 3541185029Spjd "pool remove", 3542185029Spjd "pool destroy", 3543185029Spjd "pool export", 3544185029Spjd "pool import", 3545185029Spjd "vdev attach", 3546185029Spjd "vdev replace", 3547185029Spjd "vdev detach", 3548185029Spjd "vdev online", 3549185029Spjd "vdev offline", 3550185029Spjd "vdev upgrade", 3551185029Spjd "pool clear", 3552185029Spjd "pool scrub", 3553185029Spjd "pool property set", 3554185029Spjd "create", 3555185029Spjd "clone", 3556185029Spjd "destroy", 3557185029Spjd "destroy_begin_sync", 3558185029Spjd "inherit", 3559185029Spjd "property set", 3560185029Spjd "quota set", 3561185029Spjd "permission update", 3562185029Spjd "permission remove", 3563185029Spjd "permission who remove", 3564185029Spjd "promote", 3565185029Spjd "receive", 3566185029Spjd "rename", 3567185029Spjd "reservation set", 3568185029Spjd "replay_inc_sync", 3569185029Spjd "replay_full_sync", 3570185029Spjd "rollback", 3571185029Spjd "snapshot", 3572185029Spjd "filesystem version upgrade", 3573185029Spjd "refquota set", 3574185029Spjd "refreservation set", 3575185029Spjd "pool scrub done", 3576185029Spjd}; 3577185029Spjd 3578168404Spjd/* 3579168404Spjd * Print out the command history for a specific pool. 3580168404Spjd */ 3581168404Spjdstatic int 3582168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 3583168404Spjd{ 3584168404Spjd nvlist_t *nvhis; 3585168404Spjd nvlist_t **records; 3586168404Spjd uint_t numrecords; 3587168404Spjd char *cmdstr; 3588185029Spjd char *pathstr; 3589168404Spjd uint64_t dst_time; 3590168404Spjd time_t tsec; 3591168404Spjd struct tm t; 3592168404Spjd char tbuf[30]; 3593168404Spjd int ret, i; 3594185029Spjd uint64_t who; 3595185029Spjd struct passwd *pwd; 3596185029Spjd char *hostname; 3597185029Spjd char *zonename; 3598185029Spjd char internalstr[MAXPATHLEN]; 3599185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 3600185029Spjd uint64_t txg; 3601185029Spjd uint64_t ievent; 3602168404Spjd 3603185029Spjd cb->first = B_FALSE; 3604168404Spjd 3605168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 3606168404Spjd 3607168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 3608168404Spjd return (ret); 3609168404Spjd 3610168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 3611168404Spjd &records, &numrecords) == 0); 3612168404Spjd for (i = 0; i < numrecords; i++) { 3613168404Spjd if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME, 3614185029Spjd &dst_time) != 0) 3615185029Spjd continue; 3616185029Spjd 3617185029Spjd /* is it an internal event or a standard event? */ 3618185029Spjd if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD, 3619185029Spjd &cmdstr) != 0) { 3620185029Spjd if (cb->internal == 0) 3621185029Spjd continue; 3622185029Spjd 3623185029Spjd if (nvlist_lookup_uint64(records[i], 3624185029Spjd ZPOOL_HIST_INT_EVENT, &ievent) != 0) 3625185029Spjd continue; 3626185029Spjd verify(nvlist_lookup_uint64(records[i], 3627185029Spjd ZPOOL_HIST_TXG, &txg) == 0); 3628185029Spjd verify(nvlist_lookup_string(records[i], 3629185029Spjd ZPOOL_HIST_INT_STR, &pathstr) == 0); 3630185029Spjd if (ievent >= LOG_END) 3631185029Spjd continue; 3632185029Spjd (void) snprintf(internalstr, 3633185029Spjd sizeof (internalstr), 3634185029Spjd "[internal %s txg:%lld] %s", 3635185029Spjd hist_event_table[ievent], txg, 3636185029Spjd pathstr); 3637185029Spjd cmdstr = internalstr; 3638168404Spjd } 3639185029Spjd tsec = dst_time; 3640185029Spjd (void) localtime_r(&tsec, &t); 3641185029Spjd (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 3642185029Spjd (void) printf("%s %s", tbuf, cmdstr); 3643185029Spjd 3644185029Spjd if (!cb->longfmt) { 3645185029Spjd (void) printf("\n"); 3646185029Spjd continue; 3647185029Spjd } 3648185029Spjd (void) printf(" ["); 3649185029Spjd if (nvlist_lookup_uint64(records[i], 3650185029Spjd ZPOOL_HIST_WHO, &who) == 0) { 3651185029Spjd pwd = getpwuid((uid_t)who); 3652185029Spjd if (pwd) 3653185029Spjd (void) printf("user %s on", 3654185029Spjd pwd->pw_name); 3655185029Spjd else 3656185029Spjd (void) printf("user %d on", 3657185029Spjd (int)who); 3658185029Spjd } else { 3659185029Spjd (void) printf(gettext("no info]\n")); 3660185029Spjd continue; 3661185029Spjd } 3662185029Spjd if (nvlist_lookup_string(records[i], 3663185029Spjd ZPOOL_HIST_HOST, &hostname) == 0) { 3664185029Spjd (void) printf(" %s", hostname); 3665185029Spjd } 3666185029Spjd if (nvlist_lookup_string(records[i], 3667185029Spjd ZPOOL_HIST_ZONE, &zonename) == 0) { 3668185029Spjd (void) printf(":%s", zonename); 3669185029Spjd } 3670185029Spjd 3671185029Spjd (void) printf("]"); 3672185029Spjd (void) printf("\n"); 3673168404Spjd } 3674168404Spjd (void) printf("\n"); 3675168404Spjd nvlist_free(nvhis); 3676168404Spjd 3677168404Spjd return (ret); 3678168404Spjd} 3679168404Spjd 3680168404Spjd/* 3681168404Spjd * zpool history <pool> 3682168404Spjd * 3683168404Spjd * Displays the history of commands that modified pools. 3684168404Spjd */ 3685185029Spjd 3686185029Spjd 3687168404Spjdint 3688168404Spjdzpool_do_history(int argc, char **argv) 3689168404Spjd{ 3690185029Spjd hist_cbdata_t cbdata = { 0 }; 3691168404Spjd int ret; 3692185029Spjd int c; 3693168404Spjd 3694185029Spjd cbdata.first = B_TRUE; 3695185029Spjd /* check options */ 3696185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 3697185029Spjd switch (c) { 3698185029Spjd case 'l': 3699185029Spjd cbdata.longfmt = 1; 3700185029Spjd break; 3701185029Spjd case 'i': 3702185029Spjd cbdata.internal = 1; 3703185029Spjd break; 3704185029Spjd case '?': 3705185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3706185029Spjd optopt); 3707185029Spjd usage(B_FALSE); 3708185029Spjd } 3709185029Spjd } 3710168404Spjd argc -= optind; 3711168404Spjd argv += optind; 3712168404Spjd 3713168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 3714185029Spjd &cbdata); 3715168404Spjd 3716185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 3717168404Spjd (void) printf(gettext("no pools available\n")); 3718168404Spjd return (0); 3719168404Spjd } 3720168404Spjd 3721168404Spjd return (ret); 3722168404Spjd} 3723168404Spjd 3724168404Spjdstatic int 3725168404Spjdget_callback(zpool_handle_t *zhp, void *data) 3726168404Spjd{ 3727185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 3728168404Spjd char value[MAXNAMELEN]; 3729185029Spjd zprop_source_t srctype; 3730185029Spjd zprop_list_t *pl; 3731168404Spjd 3732168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 3733168404Spjd 3734168404Spjd /* 3735185029Spjd * Skip the special fake placeholder. This will also skip 3736185029Spjd * over the name property when 'all' is specified. 3737168404Spjd */ 3738185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 3739168404Spjd pl == cbp->cb_proplist) 3740168404Spjd continue; 3741168404Spjd 3742168404Spjd if (zpool_get_prop(zhp, pl->pl_prop, 3743168404Spjd value, sizeof (value), &srctype) != 0) 3744168404Spjd continue; 3745168404Spjd 3746185029Spjd zprop_print_one_property(zpool_get_name(zhp), cbp, 3747168404Spjd zpool_prop_to_name(pl->pl_prop), value, srctype, NULL); 3748168404Spjd } 3749168404Spjd return (0); 3750168404Spjd} 3751168404Spjd 3752168404Spjdint 3753168404Spjdzpool_do_get(int argc, char **argv) 3754168404Spjd{ 3755185029Spjd zprop_get_cbdata_t cb = { 0 }; 3756185029Spjd zprop_list_t fake_name = { 0 }; 3757168404Spjd int ret; 3758168404Spjd 3759168404Spjd if (argc < 3) 3760168404Spjd usage(B_FALSE); 3761168404Spjd 3762168404Spjd cb.cb_first = B_TRUE; 3763185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 3764168404Spjd cb.cb_columns[0] = GET_COL_NAME; 3765168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 3766168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 3767168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 3768185029Spjd cb.cb_type = ZFS_TYPE_POOL; 3769168404Spjd 3770185029Spjd if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, 3771185029Spjd ZFS_TYPE_POOL) != 0) 3772168404Spjd usage(B_FALSE); 3773168404Spjd 3774168404Spjd if (cb.cb_proplist != NULL) { 3775185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 3776168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 3777168404Spjd fake_name.pl_next = cb.cb_proplist; 3778168404Spjd cb.cb_proplist = &fake_name; 3779168404Spjd } 3780168404Spjd 3781168404Spjd ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, 3782168404Spjd get_callback, &cb); 3783168404Spjd 3784168404Spjd if (cb.cb_proplist == &fake_name) 3785185029Spjd zprop_free_list(fake_name.pl_next); 3786168404Spjd else 3787185029Spjd zprop_free_list(cb.cb_proplist); 3788168404Spjd 3789168404Spjd return (ret); 3790168404Spjd} 3791168404Spjd 3792168404Spjdtypedef struct set_cbdata { 3793168404Spjd char *cb_propname; 3794168404Spjd char *cb_value; 3795168404Spjd boolean_t cb_any_successful; 3796168404Spjd} set_cbdata_t; 3797168404Spjd 3798168404Spjdint 3799168404Spjdset_callback(zpool_handle_t *zhp, void *data) 3800168404Spjd{ 3801168404Spjd int error; 3802168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 3803168404Spjd 3804168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 3805168404Spjd 3806168404Spjd if (!error) 3807168404Spjd cb->cb_any_successful = B_TRUE; 3808168404Spjd 3809168404Spjd return (error); 3810168404Spjd} 3811168404Spjd 3812168404Spjdint 3813168404Spjdzpool_do_set(int argc, char **argv) 3814168404Spjd{ 3815168404Spjd set_cbdata_t cb = { 0 }; 3816168404Spjd int error; 3817168404Spjd 3818168404Spjd if (argc > 1 && argv[1][0] == '-') { 3819168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3820168404Spjd argv[1][1]); 3821168404Spjd usage(B_FALSE); 3822168404Spjd } 3823168404Spjd 3824168404Spjd if (argc < 2) { 3825168404Spjd (void) fprintf(stderr, gettext("missing property=value " 3826168404Spjd "argument\n")); 3827168404Spjd usage(B_FALSE); 3828168404Spjd } 3829168404Spjd 3830168404Spjd if (argc < 3) { 3831168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3832168404Spjd usage(B_FALSE); 3833168404Spjd } 3834168404Spjd 3835168404Spjd if (argc > 3) { 3836168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 3837168404Spjd usage(B_FALSE); 3838168404Spjd } 3839168404Spjd 3840168404Spjd cb.cb_propname = argv[1]; 3841168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 3842168404Spjd if (cb.cb_value == NULL) { 3843168404Spjd (void) fprintf(stderr, gettext("missing value in " 3844168404Spjd "property=value argument\n")); 3845168404Spjd usage(B_FALSE); 3846168404Spjd } 3847168404Spjd 3848168404Spjd *(cb.cb_value) = '\0'; 3849168404Spjd cb.cb_value++; 3850168404Spjd 3851168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 3852168404Spjd set_callback, &cb); 3853168404Spjd 3854168404Spjd return (error); 3855168404Spjd} 3856168404Spjd 3857168404Spjdstatic int 3858168404Spjdfind_command_idx(char *command, int *idx) 3859168404Spjd{ 3860168404Spjd int i; 3861168404Spjd 3862168404Spjd for (i = 0; i < NCOMMAND; i++) { 3863168404Spjd if (command_table[i].name == NULL) 3864168404Spjd continue; 3865168404Spjd 3866168404Spjd if (strcmp(command, command_table[i].name) == 0) { 3867168404Spjd *idx = i; 3868168404Spjd return (0); 3869168404Spjd } 3870168404Spjd } 3871168404Spjd return (1); 3872168404Spjd} 3873168404Spjd 3874168404Spjdint 3875168404Spjdmain(int argc, char **argv) 3876168404Spjd{ 3877168404Spjd int ret; 3878168404Spjd int i; 3879168404Spjd char *cmdname; 3880168404Spjd 3881168404Spjd (void) setlocale(LC_ALL, ""); 3882168404Spjd (void) textdomain(TEXT_DOMAIN); 3883168404Spjd 3884168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 3885168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 3886168404Spjd "initialize ZFS library\n")); 3887168404Spjd return (1); 3888168404Spjd } 3889168404Spjd 3890168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 3891168404Spjd 3892168404Spjd opterr = 0; 3893168404Spjd 3894168404Spjd /* 3895168404Spjd * Make sure the user has specified some command. 3896168404Spjd */ 3897168404Spjd if (argc < 2) { 3898168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 3899168404Spjd usage(B_FALSE); 3900168404Spjd } 3901168404Spjd 3902168404Spjd cmdname = argv[1]; 3903168404Spjd 3904168404Spjd /* 3905168404Spjd * Special case '-?' 3906168404Spjd */ 3907168404Spjd if (strcmp(cmdname, "-?") == 0) 3908168404Spjd usage(B_TRUE); 3909168404Spjd 3910185029Spjd zpool_set_history_str("zpool", argc, argv, history_str); 3911185029Spjd verify(zpool_stage_history(g_zfs, history_str) == 0); 3912185029Spjd 3913168404Spjd /* 3914168404Spjd * Run the appropriate command. 3915168404Spjd */ 3916168404Spjd if (find_command_idx(cmdname, &i) == 0) { 3917168404Spjd current_command = &command_table[i]; 3918168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 3919185029Spjd } else if (strchr(cmdname, '=')) { 3920185029Spjd verify(find_command_idx("set", &i) == 0); 3921185029Spjd current_command = &command_table[i]; 3922185029Spjd ret = command_table[i].func(argc, argv); 3923185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 3924185029Spjd /* 3925185029Spjd * 'freeze' is a vile debugging abomination, so we treat 3926185029Spjd * it as such. 3927185029Spjd */ 3928168404Spjd char buf[16384]; 3929168404Spjd int fd = open(ZFS_DEV, O_RDWR); 3930168404Spjd (void) strcpy((void *)buf, argv[2]); 3931168404Spjd return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf)); 3932185029Spjd } else { 3933168404Spjd (void) fprintf(stderr, gettext("unrecognized " 3934168404Spjd "command '%s'\n"), cmdname); 3935168404Spjd usage(B_FALSE); 3936168404Spjd } 3937168404Spjd 3938168404Spjd libzfs_fini(g_zfs); 3939168404Spjd 3940168404Spjd /* 3941168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3942168404Spjd * for the purposes of running ::findleaks. 3943168404Spjd */ 3944168404Spjd if (getenv("ZFS_ABORT") != NULL) { 3945168404Spjd (void) printf("dumping core by request\n"); 3946168404Spjd abort(); 3947168404Spjd } 3948168404Spjd 3949168404Spjd return (ret); 3950168404Spjd} 3951