Print this page
2882 implement libzfs_core
2883 changing "canmount" property to "on" should not always remount dataset
2900 "zfs snapshot" should be able to create multiple, arbitrary snapshots at once
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Chris Siden <christopher.siden@delphix.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Bill Pijewski <wdp@joyent.com>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/zpool/zpool_main.c
+++ new/usr/src/cmd/zpool/zpool_main.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
25 25 * Copyright (c) 2012 by Delphix. All rights reserved.
26 26 * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
27 27 */
28 28
29 29 #include <assert.h>
30 30 #include <ctype.h>
31 31 #include <dirent.h>
32 32 #include <errno.h>
33 33 #include <fcntl.h>
34 34 #include <libgen.h>
35 35 #include <libintl.h>
36 36 #include <libuutil.h>
37 37 #include <locale.h>
38 38 #include <stdio.h>
39 39 #include <stdlib.h>
40 40 #include <string.h>
41 41 #include <strings.h>
42 42 #include <unistd.h>
43 43 #include <priv.h>
44 44 #include <pwd.h>
45 45 #include <zone.h>
46 46 #include <zfs_prop.h>
47 47 #include <sys/fs/zfs.h>
48 48 #include <sys/stat.h>
49 49
50 50 #include <libzfs.h>
51 51
52 52 #include "zpool_util.h"
53 53 #include "zfs_comutil.h"
54 54 #include "zfeature_common.h"
55 55
56 56 #include "statcommon.h"
57 57
58 58 static int zpool_do_create(int, char **);
59 59 static int zpool_do_destroy(int, char **);
60 60
61 61 static int zpool_do_add(int, char **);
62 62 static int zpool_do_remove(int, char **);
63 63
64 64 static int zpool_do_list(int, char **);
65 65 static int zpool_do_iostat(int, char **);
66 66 static int zpool_do_status(int, char **);
67 67
68 68 static int zpool_do_online(int, char **);
69 69 static int zpool_do_offline(int, char **);
70 70 static int zpool_do_clear(int, char **);
71 71 static int zpool_do_reopen(int, char **);
72 72
73 73 static int zpool_do_reguid(int, char **);
74 74
75 75 static int zpool_do_attach(int, char **);
76 76 static int zpool_do_detach(int, char **);
77 77 static int zpool_do_replace(int, char **);
78 78 static int zpool_do_split(int, char **);
79 79
80 80 static int zpool_do_scrub(int, char **);
81 81
82 82 static int zpool_do_import(int, char **);
83 83 static int zpool_do_export(int, char **);
84 84
85 85 static int zpool_do_upgrade(int, char **);
86 86
87 87 static int zpool_do_history(int, char **);
88 88
89 89 static int zpool_do_get(int, char **);
90 90 static int zpool_do_set(int, char **);
91 91
92 92 /*
93 93 * These libumem hooks provide a reasonable set of defaults for the allocator's
94 94 * debugging facilities.
95 95 */
96 96
97 97 #ifdef DEBUG
98 98 const char *
99 99 _umem_debug_init(void)
100 100 {
101 101 return ("default,verbose"); /* $UMEM_DEBUG setting */
102 102 }
103 103
104 104 const char *
105 105 _umem_logging_init(void)
106 106 {
107 107 return ("fail,contents"); /* $UMEM_LOGGING setting */
108 108 }
109 109 #endif
110 110
111 111 typedef enum {
112 112 HELP_ADD,
113 113 HELP_ATTACH,
114 114 HELP_CLEAR,
115 115 HELP_CREATE,
116 116 HELP_DESTROY,
117 117 HELP_DETACH,
118 118 HELP_EXPORT,
119 119 HELP_HISTORY,
120 120 HELP_IMPORT,
121 121 HELP_IOSTAT,
122 122 HELP_LIST,
123 123 HELP_OFFLINE,
124 124 HELP_ONLINE,
125 125 HELP_REPLACE,
126 126 HELP_REMOVE,
127 127 HELP_SCRUB,
128 128 HELP_STATUS,
129 129 HELP_UPGRADE,
130 130 HELP_GET,
131 131 HELP_SET,
132 132 HELP_SPLIT,
133 133 HELP_REGUID,
134 134 HELP_REOPEN
135 135 } zpool_help_t;
136 136
137 137
138 138 typedef struct zpool_command {
139 139 const char *name;
140 140 int (*func)(int, char **);
141 141 zpool_help_t usage;
142 142 } zpool_command_t;
143 143
144 144 /*
145 145 * Master command table. Each ZFS command has a name, associated function, and
146 146 * usage message. The usage messages need to be internationalized, so we have
147 147 * to have a function to return the usage message based on a command index.
148 148 *
149 149 * These commands are organized according to how they are displayed in the usage
150 150 * message. An empty command (one with a NULL name) indicates an empty line in
151 151 * the generic usage message.
152 152 */
153 153 static zpool_command_t command_table[] = {
154 154 { "create", zpool_do_create, HELP_CREATE },
155 155 { "destroy", zpool_do_destroy, HELP_DESTROY },
156 156 { NULL },
157 157 { "add", zpool_do_add, HELP_ADD },
158 158 { "remove", zpool_do_remove, HELP_REMOVE },
159 159 { NULL },
160 160 { "list", zpool_do_list, HELP_LIST },
161 161 { "iostat", zpool_do_iostat, HELP_IOSTAT },
162 162 { "status", zpool_do_status, HELP_STATUS },
163 163 { NULL },
164 164 { "online", zpool_do_online, HELP_ONLINE },
165 165 { "offline", zpool_do_offline, HELP_OFFLINE },
166 166 { "clear", zpool_do_clear, HELP_CLEAR },
167 167 { "reopen", zpool_do_reopen, HELP_REOPEN },
168 168 { NULL },
169 169 { "attach", zpool_do_attach, HELP_ATTACH },
170 170 { "detach", zpool_do_detach, HELP_DETACH },
171 171 { "replace", zpool_do_replace, HELP_REPLACE },
172 172 { "split", zpool_do_split, HELP_SPLIT },
173 173 { NULL },
174 174 { "scrub", zpool_do_scrub, HELP_SCRUB },
175 175 { NULL },
176 176 { "import", zpool_do_import, HELP_IMPORT },
177 177 { "export", zpool_do_export, HELP_EXPORT },
↓ open down ↓ |
177 lines elided |
↑ open up ↑ |
178 178 { "upgrade", zpool_do_upgrade, HELP_UPGRADE },
179 179 { "reguid", zpool_do_reguid, HELP_REGUID },
180 180 { NULL },
181 181 { "history", zpool_do_history, HELP_HISTORY },
182 182 { "get", zpool_do_get, HELP_GET },
183 183 { "set", zpool_do_set, HELP_SET },
184 184 };
185 185
186 186 #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
187 187
188 -zpool_command_t *current_command;
188 +static zpool_command_t *current_command;
189 189 static char history_str[HIS_MAX_RECORD_LEN];
190 -
190 +static boolean_t log_history = B_TRUE;
191 191 static uint_t timestamp_fmt = NODATE;
192 192
193 193 static const char *
194 194 get_usage(zpool_help_t idx) {
195 195 switch (idx) {
196 196 case HELP_ADD:
197 197 return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
198 198 case HELP_ATTACH:
199 199 return (gettext("\tattach [-f] <pool> <device> "
200 200 "<new-device>\n"));
201 201 case HELP_CLEAR:
202 202 return (gettext("\tclear [-nF] <pool> [device]\n"));
203 203 case HELP_CREATE:
204 204 return (gettext("\tcreate [-fnd] [-o property=value] ... \n"
205 205 "\t [-O file-system-property=value] ... \n"
206 206 "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
207 207 case HELP_DESTROY:
208 208 return (gettext("\tdestroy [-f] <pool>\n"));
209 209 case HELP_DETACH:
210 210 return (gettext("\tdetach <pool> <device>\n"));
211 211 case HELP_EXPORT:
212 212 return (gettext("\texport [-f] <pool> ...\n"));
213 213 case HELP_HISTORY:
214 214 return (gettext("\thistory [-il] [<pool>] ...\n"));
215 215 case HELP_IMPORT:
216 216 return (gettext("\timport [-d dir] [-D]\n"
217 217 "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
218 218 "\timport [-o mntopts] [-o property=value] ... \n"
219 219 "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
220 220 "[-R root] [-F [-n]] -a\n"
221 221 "\timport [-o mntopts] [-o property=value] ... \n"
222 222 "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
223 223 "[-R root] [-F [-n]]\n"
224 224 "\t <pool | id> [newpool]\n"));
225 225 case HELP_IOSTAT:
226 226 return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
227 227 "[count]]\n"));
228 228 case HELP_LIST:
229 229 return (gettext("\tlist [-H] [-o property[,...]] "
230 230 "[-T d|u] [pool] ... [interval [count]]\n"));
231 231 case HELP_OFFLINE:
232 232 return (gettext("\toffline [-t] <pool> <device> ...\n"));
233 233 case HELP_ONLINE:
234 234 return (gettext("\tonline <pool> <device> ...\n"));
235 235 case HELP_REPLACE:
236 236 return (gettext("\treplace [-f] <pool> <device> "
237 237 "[new-device]\n"));
238 238 case HELP_REMOVE:
239 239 return (gettext("\tremove <pool> <device> ...\n"));
240 240 case HELP_REOPEN:
241 241 return (""); /* Undocumented command */
242 242 case HELP_SCRUB:
243 243 return (gettext("\tscrub [-s] <pool> ...\n"));
244 244 case HELP_STATUS:
245 245 return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
246 246 "[count]]\n"));
247 247 case HELP_UPGRADE:
248 248 return (gettext("\tupgrade\n"
249 249 "\tupgrade -v\n"
250 250 "\tupgrade [-V version] <-a | pool ...>\n"));
251 251 case HELP_GET:
252 252 return (gettext("\tget <\"all\" | property[,...]> "
253 253 "<pool> ...\n"));
254 254 case HELP_SET:
255 255 return (gettext("\tset <property=value> <pool> \n"));
256 256 case HELP_SPLIT:
257 257 return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
258 258 "\t [-o property=value] <pool> <newpool> "
259 259 "[<device> ...]\n"));
260 260 case HELP_REGUID:
261 261 return (gettext("\treguid <pool>\n"));
262 262 }
263 263
264 264 abort();
265 265 /* NOTREACHED */
266 266 }
267 267
268 268
269 269 /*
270 270 * Callback routine that will print out a pool property value.
271 271 */
272 272 static int
273 273 print_prop_cb(int prop, void *cb)
274 274 {
275 275 FILE *fp = cb;
276 276
277 277 (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop));
278 278
279 279 if (zpool_prop_readonly(prop))
280 280 (void) fprintf(fp, " NO ");
281 281 else
282 282 (void) fprintf(fp, " YES ");
283 283
284 284 if (zpool_prop_values(prop) == NULL)
285 285 (void) fprintf(fp, "-\n");
286 286 else
287 287 (void) fprintf(fp, "%s\n", zpool_prop_values(prop));
288 288
289 289 return (ZPROP_CONT);
290 290 }
291 291
292 292 /*
293 293 * Display usage message. If we're inside a command, display only the usage for
294 294 * that command. Otherwise, iterate over the entire command table and display
295 295 * a complete usage message.
296 296 */
297 297 void
298 298 usage(boolean_t requested)
299 299 {
300 300 FILE *fp = requested ? stdout : stderr;
301 301
302 302 if (current_command == NULL) {
303 303 int i;
304 304
305 305 (void) fprintf(fp, gettext("usage: zpool command args ...\n"));
306 306 (void) fprintf(fp,
307 307 gettext("where 'command' is one of the following:\n\n"));
308 308
309 309 for (i = 0; i < NCOMMAND; i++) {
310 310 if (command_table[i].name == NULL)
311 311 (void) fprintf(fp, "\n");
312 312 else
313 313 (void) fprintf(fp, "%s",
314 314 get_usage(command_table[i].usage));
315 315 }
316 316 } else {
317 317 (void) fprintf(fp, gettext("usage:\n"));
318 318 (void) fprintf(fp, "%s", get_usage(current_command->usage));
319 319 }
320 320
321 321 if (current_command != NULL &&
322 322 ((strcmp(current_command->name, "set") == 0) ||
323 323 (strcmp(current_command->name, "get") == 0) ||
324 324 (strcmp(current_command->name, "list") == 0))) {
325 325
326 326 (void) fprintf(fp,
327 327 gettext("\nthe following properties are supported:\n"));
328 328
329 329 (void) fprintf(fp, "\n\t%-15s %s %s\n\n",
330 330 "PROPERTY", "EDIT", "VALUES");
331 331
332 332 /* Iterate over all properties */
333 333 (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
334 334 ZFS_TYPE_POOL);
335 335
336 336 (void) fprintf(fp, "\t%-15s ", "feature@...");
337 337 (void) fprintf(fp, "YES disabled | enabled | active\n");
338 338
339 339 (void) fprintf(fp, gettext("\nThe feature@ properties must be "
340 340 "appended with a feature name.\nSee zpool-features(5).\n"));
341 341 }
342 342
343 343 /*
344 344 * See comments at end of main().
345 345 */
346 346 if (getenv("ZFS_ABORT") != NULL) {
347 347 (void) printf("dumping core by request\n");
348 348 abort();
349 349 }
350 350
351 351 exit(requested ? 0 : 2);
352 352 }
353 353
354 354 void
355 355 print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
356 356 boolean_t print_logs)
357 357 {
358 358 nvlist_t **child;
359 359 uint_t c, children;
360 360 char *vname;
361 361
362 362 if (name != NULL)
363 363 (void) printf("\t%*s%s\n", indent, "", name);
364 364
365 365 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
366 366 &child, &children) != 0)
367 367 return;
368 368
369 369 for (c = 0; c < children; c++) {
370 370 uint64_t is_log = B_FALSE;
371 371
372 372 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
373 373 &is_log);
374 374 if ((is_log && !print_logs) || (!is_log && print_logs))
375 375 continue;
376 376
377 377 vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
378 378 print_vdev_tree(zhp, vname, child[c], indent + 2,
379 379 B_FALSE);
380 380 free(vname);
381 381 }
382 382 }
383 383
384 384 /*
385 385 * Add a property pair (name, string-value) into a property nvlist.
386 386 */
387 387 static int
388 388 add_prop_list(const char *propname, char *propval, nvlist_t **props,
389 389 boolean_t poolprop)
390 390 {
391 391 zpool_prop_t prop = ZPROP_INVAL;
392 392 zfs_prop_t fprop;
393 393 nvlist_t *proplist;
394 394 const char *normnm;
395 395 char *strval;
396 396
397 397 if (*props == NULL &&
398 398 nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
399 399 (void) fprintf(stderr,
400 400 gettext("internal error: out of memory\n"));
401 401 return (1);
402 402 }
403 403
404 404 proplist = *props;
405 405
406 406 if (poolprop) {
407 407 if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
408 408 !zpool_prop_feature(propname)) {
409 409 (void) fprintf(stderr, gettext("property '%s' is "
410 410 "not a valid pool property\n"), propname);
411 411 return (2);
412 412 }
413 413 if (zpool_prop_feature(propname))
414 414 normnm = propname;
415 415 else
416 416 normnm = zpool_prop_to_name(prop);
417 417 } else {
418 418 if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
419 419 normnm = zfs_prop_to_name(fprop);
420 420 } else {
421 421 normnm = propname;
422 422 }
423 423 }
424 424
425 425 if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
426 426 prop != ZPOOL_PROP_CACHEFILE) {
427 427 (void) fprintf(stderr, gettext("property '%s' "
428 428 "specified multiple times\n"), propname);
429 429 return (2);
430 430 }
431 431
432 432 if (nvlist_add_string(proplist, normnm, propval) != 0) {
433 433 (void) fprintf(stderr, gettext("internal "
434 434 "error: out of memory\n"));
435 435 return (1);
436 436 }
437 437
438 438 return (0);
439 439 }
440 440
441 441 /*
442 442 * zpool add [-fn] <pool> <vdev> ...
443 443 *
444 444 * -f Force addition of devices, even if they appear in use
445 445 * -n Do not add the devices, but display the resulting layout if
446 446 * they were to be added.
447 447 *
448 448 * Adds the given vdevs to 'pool'. As with create, the bulk of this work is
449 449 * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
450 450 * libzfs.
451 451 */
452 452 int
453 453 zpool_do_add(int argc, char **argv)
454 454 {
455 455 boolean_t force = B_FALSE;
456 456 boolean_t dryrun = B_FALSE;
457 457 int c;
458 458 nvlist_t *nvroot;
459 459 char *poolname;
460 460 int ret;
461 461 zpool_handle_t *zhp;
462 462 nvlist_t *config;
463 463
464 464 /* check options */
465 465 while ((c = getopt(argc, argv, "fn")) != -1) {
466 466 switch (c) {
467 467 case 'f':
468 468 force = B_TRUE;
469 469 break;
470 470 case 'n':
471 471 dryrun = B_TRUE;
472 472 break;
473 473 case '?':
474 474 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
475 475 optopt);
476 476 usage(B_FALSE);
477 477 }
478 478 }
479 479
480 480 argc -= optind;
481 481 argv += optind;
482 482
483 483 /* get pool name and check number of arguments */
484 484 if (argc < 1) {
485 485 (void) fprintf(stderr, gettext("missing pool name argument\n"));
486 486 usage(B_FALSE);
487 487 }
488 488 if (argc < 2) {
489 489 (void) fprintf(stderr, gettext("missing vdev specification\n"));
490 490 usage(B_FALSE);
491 491 }
492 492
493 493 poolname = argv[0];
494 494
495 495 argc--;
496 496 argv++;
497 497
498 498 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
499 499 return (1);
500 500
501 501 if ((config = zpool_get_config(zhp, NULL)) == NULL) {
502 502 (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
503 503 poolname);
504 504 zpool_close(zhp);
505 505 return (1);
506 506 }
507 507
508 508 /* pass off to get_vdev_spec for processing */
509 509 nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
510 510 argc, argv);
511 511 if (nvroot == NULL) {
512 512 zpool_close(zhp);
513 513 return (1);
514 514 }
515 515
516 516 if (dryrun) {
517 517 nvlist_t *poolnvroot;
518 518
519 519 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
520 520 &poolnvroot) == 0);
521 521
522 522 (void) printf(gettext("would update '%s' to the following "
523 523 "configuration:\n"), zpool_get_name(zhp));
524 524
525 525 /* print original main pool and new tree */
526 526 print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
527 527 print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
528 528
529 529 /* Do the same for the logs */
530 530 if (num_logs(poolnvroot) > 0) {
531 531 print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
532 532 print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
533 533 } else if (num_logs(nvroot) > 0) {
534 534 print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
535 535 }
536 536
537 537 ret = 0;
538 538 } else {
539 539 ret = (zpool_add(zhp, nvroot) != 0);
540 540 }
541 541
542 542 nvlist_free(nvroot);
543 543 zpool_close(zhp);
544 544
545 545 return (ret);
546 546 }
547 547
548 548 /*
549 549 * zpool remove <pool> <vdev> ...
550 550 *
551 551 * Removes the given vdev from the pool. Currently, this supports removing
552 552 * spares, cache, and log devices from the pool.
553 553 */
554 554 int
555 555 zpool_do_remove(int argc, char **argv)
556 556 {
557 557 char *poolname;
558 558 int i, ret = 0;
559 559 zpool_handle_t *zhp;
560 560
561 561 argc--;
562 562 argv++;
563 563
564 564 /* get pool name and check number of arguments */
565 565 if (argc < 1) {
566 566 (void) fprintf(stderr, gettext("missing pool name argument\n"));
567 567 usage(B_FALSE);
568 568 }
569 569 if (argc < 2) {
570 570 (void) fprintf(stderr, gettext("missing device\n"));
571 571 usage(B_FALSE);
572 572 }
573 573
574 574 poolname = argv[0];
575 575
576 576 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
577 577 return (1);
578 578
579 579 for (i = 1; i < argc; i++) {
580 580 if (zpool_vdev_remove(zhp, argv[i]) != 0)
581 581 ret = 1;
582 582 }
583 583
584 584 return (ret);
585 585 }
586 586
587 587 /*
588 588 * zpool create [-fnd] [-o property=value] ...
589 589 * [-O file-system-property=value] ...
590 590 * [-R root] [-m mountpoint] <pool> <dev> ...
591 591 *
592 592 * -f Force creation, even if devices appear in use
593 593 * -n Do not create the pool, but display the resulting layout if it
594 594 * were to be created.
595 595 * -R Create a pool under an alternate root
596 596 * -m Set default mountpoint for the root dataset. By default it's
597 597 * '/<pool>'
598 598 * -o Set property=value.
599 599 * -d Don't automatically enable all supported pool features
600 600 * (individual features can be enabled with -o).
601 601 * -O Set fsproperty=value in the pool's root file system
602 602 *
603 603 * Creates the named pool according to the given vdev specification. The
604 604 * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once
605 605 * we get the nvlist back from get_vdev_spec(), we either print out the contents
606 606 * (if '-n' was specified), or pass it to libzfs to do the creation.
607 607 */
608 608 int
609 609 zpool_do_create(int argc, char **argv)
610 610 {
611 611 boolean_t force = B_FALSE;
612 612 boolean_t dryrun = B_FALSE;
613 613 boolean_t enable_all_pool_feat = B_TRUE;
614 614 int c;
615 615 nvlist_t *nvroot = NULL;
616 616 char *poolname;
617 617 int ret = 1;
618 618 char *altroot = NULL;
619 619 char *mountpoint = NULL;
620 620 nvlist_t *fsprops = NULL;
621 621 nvlist_t *props = NULL;
622 622 char *propval;
623 623
624 624 /* check options */
625 625 while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) {
626 626 switch (c) {
627 627 case 'f':
628 628 force = B_TRUE;
629 629 break;
630 630 case 'n':
631 631 dryrun = B_TRUE;
632 632 break;
633 633 case 'd':
634 634 enable_all_pool_feat = B_FALSE;
635 635 break;
636 636 case 'R':
637 637 altroot = optarg;
638 638 if (add_prop_list(zpool_prop_to_name(
639 639 ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
640 640 goto errout;
641 641 if (nvlist_lookup_string(props,
642 642 zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
643 643 &propval) == 0)
644 644 break;
645 645 if (add_prop_list(zpool_prop_to_name(
646 646 ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
647 647 goto errout;
648 648 break;
649 649 case 'm':
650 650 mountpoint = optarg;
651 651 break;
652 652 case 'o':
653 653 if ((propval = strchr(optarg, '=')) == NULL) {
654 654 (void) fprintf(stderr, gettext("missing "
655 655 "'=' for -o option\n"));
656 656 goto errout;
657 657 }
658 658 *propval = '\0';
659 659 propval++;
660 660
661 661 if (add_prop_list(optarg, propval, &props, B_TRUE))
662 662 goto errout;
663 663
664 664 /*
665 665 * If the user is creating a pool that doesn't support
666 666 * feature flags, don't enable any features.
667 667 */
668 668 if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
669 669 char *end;
670 670 u_longlong_t ver;
671 671
672 672 ver = strtoull(propval, &end, 10);
673 673 if (*end == '\0' &&
674 674 ver < SPA_VERSION_FEATURES) {
675 675 enable_all_pool_feat = B_FALSE;
676 676 }
677 677 }
678 678 break;
679 679 case 'O':
680 680 if ((propval = strchr(optarg, '=')) == NULL) {
681 681 (void) fprintf(stderr, gettext("missing "
682 682 "'=' for -O option\n"));
683 683 goto errout;
684 684 }
685 685 *propval = '\0';
686 686 propval++;
687 687
688 688 if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
689 689 goto errout;
690 690 break;
691 691 case ':':
692 692 (void) fprintf(stderr, gettext("missing argument for "
693 693 "'%c' option\n"), optopt);
694 694 goto badusage;
695 695 case '?':
696 696 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
697 697 optopt);
698 698 goto badusage;
699 699 }
700 700 }
701 701
702 702 argc -= optind;
703 703 argv += optind;
704 704
705 705 /* get pool name and check number of arguments */
706 706 if (argc < 1) {
707 707 (void) fprintf(stderr, gettext("missing pool name argument\n"));
708 708 goto badusage;
709 709 }
710 710 if (argc < 2) {
711 711 (void) fprintf(stderr, gettext("missing vdev specification\n"));
712 712 goto badusage;
713 713 }
714 714
715 715 poolname = argv[0];
716 716
717 717 /*
718 718 * As a special case, check for use of '/' in the name, and direct the
719 719 * user to use 'zfs create' instead.
720 720 */
721 721 if (strchr(poolname, '/') != NULL) {
722 722 (void) fprintf(stderr, gettext("cannot create '%s': invalid "
723 723 "character '/' in pool name\n"), poolname);
724 724 (void) fprintf(stderr, gettext("use 'zfs create' to "
725 725 "create a dataset\n"));
726 726 goto errout;
727 727 }
728 728
729 729 /* pass off to get_vdev_spec for bulk processing */
730 730 nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
731 731 argc - 1, argv + 1);
732 732 if (nvroot == NULL)
733 733 goto errout;
734 734
735 735 /* make_root_vdev() allows 0 toplevel children if there are spares */
736 736 if (!zfs_allocatable_devs(nvroot)) {
737 737 (void) fprintf(stderr, gettext("invalid vdev "
738 738 "specification: at least one toplevel vdev must be "
739 739 "specified\n"));
740 740 goto errout;
741 741 }
742 742
743 743 if (altroot != NULL && altroot[0] != '/') {
744 744 (void) fprintf(stderr, gettext("invalid alternate root '%s': "
745 745 "must be an absolute path\n"), altroot);
746 746 goto errout;
747 747 }
748 748
749 749 /*
750 750 * Check the validity of the mountpoint and direct the user to use the
751 751 * '-m' mountpoint option if it looks like its in use.
752 752 */
753 753 if (mountpoint == NULL ||
754 754 (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
755 755 strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
756 756 char buf[MAXPATHLEN];
757 757 DIR *dirp;
758 758
759 759 if (mountpoint && mountpoint[0] != '/') {
760 760 (void) fprintf(stderr, gettext("invalid mountpoint "
761 761 "'%s': must be an absolute path, 'legacy', or "
762 762 "'none'\n"), mountpoint);
763 763 goto errout;
764 764 }
765 765
766 766 if (mountpoint == NULL) {
767 767 if (altroot != NULL)
768 768 (void) snprintf(buf, sizeof (buf), "%s/%s",
769 769 altroot, poolname);
770 770 else
771 771 (void) snprintf(buf, sizeof (buf), "/%s",
772 772 poolname);
773 773 } else {
774 774 if (altroot != NULL)
775 775 (void) snprintf(buf, sizeof (buf), "%s%s",
776 776 altroot, mountpoint);
777 777 else
778 778 (void) snprintf(buf, sizeof (buf), "%s",
779 779 mountpoint);
780 780 }
781 781
782 782 if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
783 783 (void) fprintf(stderr, gettext("mountpoint '%s' : "
784 784 "%s\n"), buf, strerror(errno));
785 785 (void) fprintf(stderr, gettext("use '-m' "
786 786 "option to provide a different default\n"));
787 787 goto errout;
788 788 } else if (dirp) {
789 789 int count = 0;
790 790
791 791 while (count < 3 && readdir(dirp) != NULL)
792 792 count++;
793 793 (void) closedir(dirp);
794 794
795 795 if (count > 2) {
796 796 (void) fprintf(stderr, gettext("mountpoint "
797 797 "'%s' exists and is not empty\n"), buf);
798 798 (void) fprintf(stderr, gettext("use '-m' "
799 799 "option to provide a "
800 800 "different default\n"));
801 801 goto errout;
802 802 }
803 803 }
804 804 }
805 805
806 806 if (dryrun) {
807 807 /*
808 808 * For a dry run invocation, print out a basic message and run
809 809 * through all the vdevs in the list and print out in an
810 810 * appropriate hierarchy.
811 811 */
812 812 (void) printf(gettext("would create '%s' with the "
813 813 "following layout:\n\n"), poolname);
814 814
815 815 print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
816 816 if (num_logs(nvroot) > 0)
817 817 print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
818 818
819 819 ret = 0;
820 820 } else {
821 821 /*
822 822 * Hand off to libzfs.
823 823 */
824 824 if (enable_all_pool_feat) {
825 825 int i;
826 826 for (i = 0; i < SPA_FEATURES; i++) {
827 827 char propname[MAXPATHLEN];
828 828 zfeature_info_t *feat = &spa_feature_table[i];
829 829
830 830 (void) snprintf(propname, sizeof (propname),
831 831 "feature@%s", feat->fi_uname);
832 832
833 833 /*
834 834 * Skip feature if user specified it manually
835 835 * on the command line.
836 836 */
837 837 if (nvlist_exists(props, propname))
838 838 continue;
839 839
840 840 if (add_prop_list(propname, ZFS_FEATURE_ENABLED,
841 841 &props, B_TRUE) != 0)
842 842 goto errout;
843 843 }
844 844 }
845 845 if (zpool_create(g_zfs, poolname,
846 846 nvroot, props, fsprops) == 0) {
847 847 zfs_handle_t *pool = zfs_open(g_zfs, poolname,
848 848 ZFS_TYPE_FILESYSTEM);
849 849 if (pool != NULL) {
850 850 if (mountpoint != NULL)
851 851 verify(zfs_prop_set(pool,
852 852 zfs_prop_to_name(
853 853 ZFS_PROP_MOUNTPOINT),
854 854 mountpoint) == 0);
855 855 if (zfs_mount(pool, NULL, 0) == 0)
856 856 ret = zfs_shareall(pool);
857 857 zfs_close(pool);
858 858 }
859 859 } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
860 860 (void) fprintf(stderr, gettext("pool name may have "
861 861 "been omitted\n"));
862 862 }
863 863 }
864 864
865 865 errout:
866 866 nvlist_free(nvroot);
867 867 nvlist_free(fsprops);
868 868 nvlist_free(props);
869 869 return (ret);
870 870 badusage:
871 871 nvlist_free(fsprops);
872 872 nvlist_free(props);
873 873 usage(B_FALSE);
874 874 return (2);
875 875 }
876 876
877 877 /*
878 878 * zpool destroy <pool>
879 879 *
880 880 * -f Forcefully unmount any datasets
881 881 *
882 882 * Destroy the given pool. Automatically unmounts any datasets in the pool.
883 883 */
884 884 int
885 885 zpool_do_destroy(int argc, char **argv)
886 886 {
887 887 boolean_t force = B_FALSE;
888 888 int c;
889 889 char *pool;
890 890 zpool_handle_t *zhp;
891 891 int ret;
892 892
893 893 /* check options */
894 894 while ((c = getopt(argc, argv, "f")) != -1) {
895 895 switch (c) {
896 896 case 'f':
897 897 force = B_TRUE;
898 898 break;
899 899 case '?':
900 900 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
901 901 optopt);
902 902 usage(B_FALSE);
903 903 }
904 904 }
905 905
906 906 argc -= optind;
907 907 argv += optind;
908 908
909 909 /* check arguments */
910 910 if (argc < 1) {
911 911 (void) fprintf(stderr, gettext("missing pool argument\n"));
912 912 usage(B_FALSE);
913 913 }
914 914 if (argc > 1) {
915 915 (void) fprintf(stderr, gettext("too many arguments\n"));
916 916 usage(B_FALSE);
917 917 }
918 918
919 919 pool = argv[0];
920 920
921 921 if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
922 922 /*
923 923 * As a special case, check for use of '/' in the name, and
924 924 * direct the user to use 'zfs destroy' instead.
925 925 */
926 926 if (strchr(pool, '/') != NULL)
927 927 (void) fprintf(stderr, gettext("use 'zfs destroy' to "
↓ open down ↓ |
727 lines elided |
↑ open up ↑ |
928 928 "destroy a dataset\n"));
929 929 return (1);
930 930 }
931 931
932 932 if (zpool_disable_datasets(zhp, force) != 0) {
933 933 (void) fprintf(stderr, gettext("could not destroy '%s': "
934 934 "could not unmount datasets\n"), zpool_get_name(zhp));
935 935 return (1);
936 936 }
937 937
938 - ret = (zpool_destroy(zhp) != 0);
938 + /* The history must be logged as part of the export */
939 + log_history = B_FALSE;
940 +
941 + ret = (zpool_destroy(zhp, history_str) != 0);
939 942
940 943 zpool_close(zhp);
941 944
942 945 return (ret);
943 946 }
944 947
945 948 /*
946 949 * zpool export [-f] <pool> ...
947 950 *
948 951 * -f Forcefully unmount datasets
949 952 *
950 953 * Export the given pools. By default, the command will attempt to cleanly
951 954 * unmount any active datasets within the pool. If the '-f' flag is specified,
952 955 * then the datasets will be forcefully unmounted.
953 956 */
954 957 int
955 958 zpool_do_export(int argc, char **argv)
956 959 {
957 960 boolean_t force = B_FALSE;
958 961 boolean_t hardforce = B_FALSE;
959 962 int c;
960 963 zpool_handle_t *zhp;
961 964 int ret;
962 965 int i;
963 966
964 967 /* check options */
965 968 while ((c = getopt(argc, argv, "fF")) != -1) {
966 969 switch (c) {
967 970 case 'f':
968 971 force = B_TRUE;
969 972 break;
970 973 case 'F':
971 974 hardforce = B_TRUE;
972 975 break;
973 976 case '?':
974 977 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
975 978 optopt);
976 979 usage(B_FALSE);
977 980 }
978 981 }
979 982
980 983 argc -= optind;
981 984 argv += optind;
982 985
983 986 /* check arguments */
984 987 if (argc < 1) {
985 988 (void) fprintf(stderr, gettext("missing pool argument\n"));
986 989 usage(B_FALSE);
987 990 }
988 991
989 992 ret = 0;
990 993 for (i = 0; i < argc; i++) {
991 994 if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
↓ open down ↓ |
43 lines elided |
↑ open up ↑ |
992 995 ret = 1;
993 996 continue;
994 997 }
995 998
996 999 if (zpool_disable_datasets(zhp, force) != 0) {
997 1000 ret = 1;
998 1001 zpool_close(zhp);
999 1002 continue;
1000 1003 }
1001 1004
1005 + /* The history must be logged as part of the export */
1006 + log_history = B_FALSE;
1007 +
1002 1008 if (hardforce) {
1003 - if (zpool_export_force(zhp) != 0)
1009 + if (zpool_export_force(zhp, history_str) != 0)
1004 1010 ret = 1;
1005 - } else if (zpool_export(zhp, force) != 0) {
1011 + } else if (zpool_export(zhp, force, history_str) != 0) {
1006 1012 ret = 1;
1007 1013 }
1008 1014
1009 1015 zpool_close(zhp);
1010 1016 }
1011 1017
1012 1018 return (ret);
1013 1019 }
1014 1020
1015 1021 /*
1016 1022 * Given a vdev configuration, determine the maximum width needed for the device
1017 1023 * name column.
1018 1024 */
1019 1025 static int
1020 1026 max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
1021 1027 {
1022 1028 char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
1023 1029 nvlist_t **child;
1024 1030 uint_t c, children;
1025 1031 int ret;
1026 1032
1027 1033 if (strlen(name) + depth > max)
1028 1034 max = strlen(name) + depth;
1029 1035
1030 1036 free(name);
1031 1037
1032 1038 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1033 1039 &child, &children) == 0) {
1034 1040 for (c = 0; c < children; c++)
1035 1041 if ((ret = max_width(zhp, child[c], depth + 2,
1036 1042 max)) > max)
1037 1043 max = ret;
1038 1044 }
1039 1045
1040 1046 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1041 1047 &child, &children) == 0) {
1042 1048 for (c = 0; c < children; c++)
1043 1049 if ((ret = max_width(zhp, child[c], depth + 2,
1044 1050 max)) > max)
1045 1051 max = ret;
1046 1052 }
1047 1053
1048 1054 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1049 1055 &child, &children) == 0) {
1050 1056 for (c = 0; c < children; c++)
1051 1057 if ((ret = max_width(zhp, child[c], depth + 2,
1052 1058 max)) > max)
1053 1059 max = ret;
1054 1060 }
1055 1061
1056 1062
1057 1063 return (max);
1058 1064 }
1059 1065
1060 1066 typedef struct spare_cbdata {
1061 1067 uint64_t cb_guid;
1062 1068 zpool_handle_t *cb_zhp;
1063 1069 } spare_cbdata_t;
1064 1070
1065 1071 static boolean_t
1066 1072 find_vdev(nvlist_t *nv, uint64_t search)
1067 1073 {
1068 1074 uint64_t guid;
1069 1075 nvlist_t **child;
1070 1076 uint_t c, children;
1071 1077
1072 1078 if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
1073 1079 search == guid)
1074 1080 return (B_TRUE);
1075 1081
1076 1082 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1077 1083 &child, &children) == 0) {
1078 1084 for (c = 0; c < children; c++)
1079 1085 if (find_vdev(child[c], search))
1080 1086 return (B_TRUE);
1081 1087 }
1082 1088
1083 1089 return (B_FALSE);
1084 1090 }
1085 1091
1086 1092 static int
1087 1093 find_spare(zpool_handle_t *zhp, void *data)
1088 1094 {
1089 1095 spare_cbdata_t *cbp = data;
1090 1096 nvlist_t *config, *nvroot;
1091 1097
1092 1098 config = zpool_get_config(zhp, NULL);
1093 1099 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1094 1100 &nvroot) == 0);
1095 1101
1096 1102 if (find_vdev(nvroot, cbp->cb_guid)) {
1097 1103 cbp->cb_zhp = zhp;
1098 1104 return (1);
1099 1105 }
1100 1106
1101 1107 zpool_close(zhp);
1102 1108 return (0);
1103 1109 }
1104 1110
1105 1111 /*
1106 1112 * Print out configuration state as requested by status_callback.
1107 1113 */
1108 1114 void
1109 1115 print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
1110 1116 int namewidth, int depth, boolean_t isspare)
1111 1117 {
1112 1118 nvlist_t **child;
1113 1119 uint_t c, children;
1114 1120 pool_scan_stat_t *ps = NULL;
1115 1121 vdev_stat_t *vs;
1116 1122 char rbuf[6], wbuf[6], cbuf[6];
1117 1123 char *vname;
1118 1124 uint64_t notpresent;
1119 1125 spare_cbdata_t cb;
1120 1126 char *state;
1121 1127
1122 1128 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1123 1129 &child, &children) != 0)
1124 1130 children = 0;
1125 1131
1126 1132 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1127 1133 (uint64_t **)&vs, &c) == 0);
1128 1134
1129 1135 state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1130 1136 if (isspare) {
1131 1137 /*
1132 1138 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1133 1139 * online drives.
1134 1140 */
1135 1141 if (vs->vs_aux == VDEV_AUX_SPARED)
1136 1142 state = "INUSE";
1137 1143 else if (vs->vs_state == VDEV_STATE_HEALTHY)
1138 1144 state = "AVAIL";
1139 1145 }
1140 1146
1141 1147 (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth,
1142 1148 name, state);
1143 1149
1144 1150 if (!isspare) {
1145 1151 zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1146 1152 zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1147 1153 zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
1148 1154 (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1149 1155 }
1150 1156
1151 1157 if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1152 1158 ¬present) == 0) {
1153 1159 char *path;
1154 1160 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
1155 1161 (void) printf(" was %s", path);
1156 1162 } else if (vs->vs_aux != 0) {
1157 1163 (void) printf(" ");
1158 1164
1159 1165 switch (vs->vs_aux) {
1160 1166 case VDEV_AUX_OPEN_FAILED:
1161 1167 (void) printf(gettext("cannot open"));
1162 1168 break;
1163 1169
1164 1170 case VDEV_AUX_BAD_GUID_SUM:
1165 1171 (void) printf(gettext("missing device"));
1166 1172 break;
1167 1173
1168 1174 case VDEV_AUX_NO_REPLICAS:
1169 1175 (void) printf(gettext("insufficient replicas"));
1170 1176 break;
1171 1177
1172 1178 case VDEV_AUX_VERSION_NEWER:
1173 1179 (void) printf(gettext("newer version"));
1174 1180 break;
1175 1181
1176 1182 case VDEV_AUX_UNSUP_FEAT:
1177 1183 (void) printf(gettext("unsupported feature(s)"));
1178 1184 break;
1179 1185
1180 1186 case VDEV_AUX_SPARED:
1181 1187 verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1182 1188 &cb.cb_guid) == 0);
1183 1189 if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
1184 1190 if (strcmp(zpool_get_name(cb.cb_zhp),
1185 1191 zpool_get_name(zhp)) == 0)
1186 1192 (void) printf(gettext("currently in "
1187 1193 "use"));
1188 1194 else
1189 1195 (void) printf(gettext("in use by "
1190 1196 "pool '%s'"),
1191 1197 zpool_get_name(cb.cb_zhp));
1192 1198 zpool_close(cb.cb_zhp);
1193 1199 } else {
1194 1200 (void) printf(gettext("currently in use"));
1195 1201 }
1196 1202 break;
1197 1203
1198 1204 case VDEV_AUX_ERR_EXCEEDED:
1199 1205 (void) printf(gettext("too many errors"));
1200 1206 break;
1201 1207
1202 1208 case VDEV_AUX_IO_FAILURE:
1203 1209 (void) printf(gettext("experienced I/O failures"));
1204 1210 break;
1205 1211
1206 1212 case VDEV_AUX_BAD_LOG:
1207 1213 (void) printf(gettext("bad intent log"));
1208 1214 break;
1209 1215
1210 1216 case VDEV_AUX_EXTERNAL:
1211 1217 (void) printf(gettext("external device fault"));
1212 1218 break;
1213 1219
1214 1220 case VDEV_AUX_SPLIT_POOL:
1215 1221 (void) printf(gettext("split into new pool"));
1216 1222 break;
1217 1223
1218 1224 default:
1219 1225 (void) printf(gettext("corrupted data"));
1220 1226 break;
1221 1227 }
1222 1228 }
1223 1229
1224 1230 (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
1225 1231 (uint64_t **)&ps, &c);
1226 1232
1227 1233 if (ps && ps->pss_state == DSS_SCANNING &&
1228 1234 vs->vs_scan_processed != 0 && children == 0) {
1229 1235 (void) printf(gettext(" (%s)"),
1230 1236 (ps->pss_func == POOL_SCAN_RESILVER) ?
1231 1237 "resilvering" : "repairing");
1232 1238 }
1233 1239
1234 1240 (void) printf("\n");
1235 1241
1236 1242 for (c = 0; c < children; c++) {
1237 1243 uint64_t islog = B_FALSE, ishole = B_FALSE;
1238 1244
1239 1245 /* Don't print logs or holes here */
1240 1246 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1241 1247 &islog);
1242 1248 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
1243 1249 &ishole);
1244 1250 if (islog || ishole)
1245 1251 continue;
1246 1252 vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1247 1253 print_status_config(zhp, vname, child[c],
1248 1254 namewidth, depth + 2, isspare);
1249 1255 free(vname);
1250 1256 }
1251 1257 }
1252 1258
1253 1259
1254 1260 /*
1255 1261 * Print the configuration of an exported pool. Iterate over all vdevs in the
1256 1262 * pool, printing out the name and status for each one.
1257 1263 */
1258 1264 void
1259 1265 print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1260 1266 {
1261 1267 nvlist_t **child;
1262 1268 uint_t c, children;
1263 1269 vdev_stat_t *vs;
1264 1270 char *type, *vname;
1265 1271
1266 1272 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1267 1273 if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
1268 1274 strcmp(type, VDEV_TYPE_HOLE) == 0)
1269 1275 return;
1270 1276
1271 1277 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1272 1278 (uint64_t **)&vs, &c) == 0);
1273 1279
1274 1280 (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1275 1281 (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1276 1282
1277 1283 if (vs->vs_aux != 0) {
1278 1284 (void) printf(" ");
1279 1285
1280 1286 switch (vs->vs_aux) {
1281 1287 case VDEV_AUX_OPEN_FAILED:
1282 1288 (void) printf(gettext("cannot open"));
1283 1289 break;
1284 1290
1285 1291 case VDEV_AUX_BAD_GUID_SUM:
1286 1292 (void) printf(gettext("missing device"));
1287 1293 break;
1288 1294
1289 1295 case VDEV_AUX_NO_REPLICAS:
1290 1296 (void) printf(gettext("insufficient replicas"));
1291 1297 break;
1292 1298
1293 1299 case VDEV_AUX_VERSION_NEWER:
1294 1300 (void) printf(gettext("newer version"));
1295 1301 break;
1296 1302
1297 1303 case VDEV_AUX_UNSUP_FEAT:
1298 1304 (void) printf(gettext("unsupported feature(s)"));
1299 1305 break;
1300 1306
1301 1307 case VDEV_AUX_ERR_EXCEEDED:
1302 1308 (void) printf(gettext("too many errors"));
1303 1309 break;
1304 1310
1305 1311 default:
1306 1312 (void) printf(gettext("corrupted data"));
1307 1313 break;
1308 1314 }
1309 1315 }
1310 1316 (void) printf("\n");
1311 1317
1312 1318 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1313 1319 &child, &children) != 0)
1314 1320 return;
1315 1321
1316 1322 for (c = 0; c < children; c++) {
1317 1323 uint64_t is_log = B_FALSE;
1318 1324
1319 1325 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1320 1326 &is_log);
1321 1327 if (is_log)
1322 1328 continue;
1323 1329
1324 1330 vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
1325 1331 print_import_config(vname, child[c], namewidth, depth + 2);
1326 1332 free(vname);
1327 1333 }
1328 1334
1329 1335 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1330 1336 &child, &children) == 0) {
1331 1337 (void) printf(gettext("\tcache\n"));
1332 1338 for (c = 0; c < children; c++) {
1333 1339 vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1334 1340 (void) printf("\t %s\n", vname);
1335 1341 free(vname);
1336 1342 }
1337 1343 }
1338 1344
1339 1345 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1340 1346 &child, &children) == 0) {
1341 1347 (void) printf(gettext("\tspares\n"));
1342 1348 for (c = 0; c < children; c++) {
1343 1349 vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1344 1350 (void) printf("\t %s\n", vname);
1345 1351 free(vname);
1346 1352 }
1347 1353 }
1348 1354 }
1349 1355
1350 1356 /*
1351 1357 * Print log vdevs.
1352 1358 * Logs are recorded as top level vdevs in the main pool child array
1353 1359 * but with "is_log" set to 1. We use either print_status_config() or
1354 1360 * print_import_config() to print the top level logs then any log
1355 1361 * children (eg mirrored slogs) are printed recursively - which
1356 1362 * works because only the top level vdev is marked "is_log"
1357 1363 */
1358 1364 static void
1359 1365 print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
1360 1366 {
1361 1367 uint_t c, children;
1362 1368 nvlist_t **child;
1363 1369
1364 1370 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1365 1371 &children) != 0)
1366 1372 return;
1367 1373
1368 1374 (void) printf(gettext("\tlogs\n"));
1369 1375
1370 1376 for (c = 0; c < children; c++) {
1371 1377 uint64_t is_log = B_FALSE;
1372 1378 char *name;
1373 1379
1374 1380 (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1375 1381 &is_log);
1376 1382 if (!is_log)
1377 1383 continue;
1378 1384 name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1379 1385 if (verbose)
1380 1386 print_status_config(zhp, name, child[c], namewidth,
1381 1387 2, B_FALSE);
1382 1388 else
1383 1389 print_import_config(name, child[c], namewidth, 2);
1384 1390 free(name);
1385 1391 }
1386 1392 }
1387 1393
1388 1394 /*
1389 1395 * Display the status for the given pool.
1390 1396 */
1391 1397 static void
1392 1398 show_import(nvlist_t *config)
1393 1399 {
1394 1400 uint64_t pool_state;
1395 1401 vdev_stat_t *vs;
1396 1402 char *name;
1397 1403 uint64_t guid;
1398 1404 char *msgid;
1399 1405 nvlist_t *nvroot;
1400 1406 int reason;
1401 1407 const char *health;
1402 1408 uint_t vsc;
1403 1409 int namewidth;
1404 1410 char *comment;
1405 1411
1406 1412 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1407 1413 &name) == 0);
1408 1414 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1409 1415 &guid) == 0);
1410 1416 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1411 1417 &pool_state) == 0);
1412 1418 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1413 1419 &nvroot) == 0);
1414 1420
1415 1421 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
1416 1422 (uint64_t **)&vs, &vsc) == 0);
1417 1423 health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1418 1424
1419 1425 reason = zpool_import_status(config, &msgid);
1420 1426
1421 1427 (void) printf(gettext(" pool: %s\n"), name);
1422 1428 (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
1423 1429 (void) printf(gettext(" state: %s"), health);
1424 1430 if (pool_state == POOL_STATE_DESTROYED)
1425 1431 (void) printf(gettext(" (DESTROYED)"));
1426 1432 (void) printf("\n");
1427 1433
1428 1434 switch (reason) {
1429 1435 case ZPOOL_STATUS_MISSING_DEV_R:
1430 1436 case ZPOOL_STATUS_MISSING_DEV_NR:
1431 1437 case ZPOOL_STATUS_BAD_GUID_SUM:
1432 1438 (void) printf(gettext(" status: One or more devices are "
1433 1439 "missing from the system.\n"));
1434 1440 break;
1435 1441
1436 1442 case ZPOOL_STATUS_CORRUPT_LABEL_R:
1437 1443 case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1438 1444 (void) printf(gettext(" status: One or more devices contains "
1439 1445 "corrupted data.\n"));
1440 1446 break;
1441 1447
1442 1448 case ZPOOL_STATUS_CORRUPT_DATA:
1443 1449 (void) printf(
1444 1450 gettext(" status: The pool data is corrupted.\n"));
1445 1451 break;
1446 1452
1447 1453 case ZPOOL_STATUS_OFFLINE_DEV:
1448 1454 (void) printf(gettext(" status: One or more devices "
1449 1455 "are offlined.\n"));
1450 1456 break;
1451 1457
1452 1458 case ZPOOL_STATUS_CORRUPT_POOL:
1453 1459 (void) printf(gettext(" status: The pool metadata is "
1454 1460 "corrupted.\n"));
1455 1461 break;
1456 1462
1457 1463 case ZPOOL_STATUS_VERSION_OLDER:
1458 1464 (void) printf(gettext(" status: The pool is formatted using an "
1459 1465 "older on-disk version.\n"));
1460 1466 break;
1461 1467
1462 1468 case ZPOOL_STATUS_VERSION_NEWER:
1463 1469 (void) printf(gettext(" status: The pool is formatted using an "
1464 1470 "incompatible version.\n"));
1465 1471 break;
1466 1472
1467 1473 case ZPOOL_STATUS_UNSUP_FEAT_READ:
1468 1474 (void) printf(gettext("status: The pool uses the following "
1469 1475 "feature(s) not supported on this sytem:\n"));
1470 1476 zpool_print_unsup_feat(config);
1471 1477 break;
1472 1478
1473 1479 case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1474 1480 (void) printf(gettext("status: The pool can only be accessed "
1475 1481 "in read-only mode on this system. It\n\tcannot be "
1476 1482 "accessed in read-write mode because it uses the "
1477 1483 "following\n\tfeature(s) not supported on this system:\n"));
1478 1484 zpool_print_unsup_feat(config);
1479 1485 break;
1480 1486
1481 1487 case ZPOOL_STATUS_HOSTID_MISMATCH:
1482 1488 (void) printf(gettext(" status: The pool was last accessed by "
1483 1489 "another system.\n"));
1484 1490 break;
1485 1491
1486 1492 case ZPOOL_STATUS_FAULTED_DEV_R:
1487 1493 case ZPOOL_STATUS_FAULTED_DEV_NR:
1488 1494 (void) printf(gettext(" status: One or more devices are "
1489 1495 "faulted.\n"));
1490 1496 break;
1491 1497
1492 1498 case ZPOOL_STATUS_BAD_LOG:
1493 1499 (void) printf(gettext(" status: An intent log record cannot be "
1494 1500 "read.\n"));
1495 1501 break;
1496 1502
1497 1503 case ZPOOL_STATUS_RESILVERING:
1498 1504 (void) printf(gettext(" status: One or more devices were being "
1499 1505 "resilvered.\n"));
1500 1506 break;
1501 1507
1502 1508 default:
1503 1509 /*
1504 1510 * No other status can be seen when importing pools.
1505 1511 */
1506 1512 assert(reason == ZPOOL_STATUS_OK);
1507 1513 }
1508 1514
1509 1515 /*
1510 1516 * Print out an action according to the overall state of the pool.
1511 1517 */
1512 1518 if (vs->vs_state == VDEV_STATE_HEALTHY) {
1513 1519 if (reason == ZPOOL_STATUS_VERSION_OLDER)
1514 1520 (void) printf(gettext(" action: The pool can be "
1515 1521 "imported using its name or numeric identifier, "
1516 1522 "though\n\tsome features will not be available "
1517 1523 "without an explicit 'zpool upgrade'.\n"));
1518 1524 else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
1519 1525 (void) printf(gettext(" action: The pool can be "
1520 1526 "imported using its name or numeric "
1521 1527 "identifier and\n\tthe '-f' flag.\n"));
1522 1528 else
1523 1529 (void) printf(gettext(" action: The pool can be "
1524 1530 "imported using its name or numeric "
1525 1531 "identifier.\n"));
1526 1532 } else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1527 1533 (void) printf(gettext(" action: The pool can be imported "
1528 1534 "despite missing or damaged devices. The\n\tfault "
1529 1535 "tolerance of the pool may be compromised if imported.\n"));
1530 1536 } else {
1531 1537 switch (reason) {
1532 1538 case ZPOOL_STATUS_VERSION_NEWER:
1533 1539 (void) printf(gettext(" action: The pool cannot be "
1534 1540 "imported. Access the pool on a system running "
1535 1541 "newer\n\tsoftware, or recreate the pool from "
1536 1542 "backup.\n"));
1537 1543 break;
1538 1544 case ZPOOL_STATUS_UNSUP_FEAT_READ:
1539 1545 (void) printf(gettext("action: The pool cannot be "
1540 1546 "imported. Access the pool on a system that "
1541 1547 "supports\n\tthe required feature(s), or recreate "
1542 1548 "the pool from backup.\n"));
1543 1549 break;
1544 1550 case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1545 1551 (void) printf(gettext("action: The pool cannot be "
1546 1552 "imported in read-write mode. Import the pool "
1547 1553 "with\n"
1548 1554 "\t\"-o readonly=on\", access the pool on a system "
1549 1555 "that supports the\n\trequired feature(s), or "
1550 1556 "recreate the pool from backup.\n"));
1551 1557 break;
1552 1558 case ZPOOL_STATUS_MISSING_DEV_R:
1553 1559 case ZPOOL_STATUS_MISSING_DEV_NR:
1554 1560 case ZPOOL_STATUS_BAD_GUID_SUM:
1555 1561 (void) printf(gettext(" action: The pool cannot be "
1556 1562 "imported. Attach the missing\n\tdevices and try "
1557 1563 "again.\n"));
1558 1564 break;
1559 1565 default:
1560 1566 (void) printf(gettext(" action: The pool cannot be "
1561 1567 "imported due to damaged devices or data.\n"));
1562 1568 }
1563 1569 }
1564 1570
1565 1571 /* Print the comment attached to the pool. */
1566 1572 if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
1567 1573 (void) printf(gettext("comment: %s\n"), comment);
1568 1574
1569 1575 /*
1570 1576 * If the state is "closed" or "can't open", and the aux state
1571 1577 * is "corrupt data":
1572 1578 */
1573 1579 if (((vs->vs_state == VDEV_STATE_CLOSED) ||
1574 1580 (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
1575 1581 (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1576 1582 if (pool_state == POOL_STATE_DESTROYED)
1577 1583 (void) printf(gettext("\tThe pool was destroyed, "
1578 1584 "but can be imported using the '-Df' flags.\n"));
1579 1585 else if (pool_state != POOL_STATE_EXPORTED)
1580 1586 (void) printf(gettext("\tThe pool may be active on "
1581 1587 "another system, but can be imported using\n\t"
1582 1588 "the '-f' flag.\n"));
1583 1589 }
1584 1590
1585 1591 if (msgid != NULL)
1586 1592 (void) printf(gettext(" see: http://illumos.org/msg/%s\n"),
1587 1593 msgid);
1588 1594
1589 1595 (void) printf(gettext(" config:\n\n"));
1590 1596
1591 1597 namewidth = max_width(NULL, nvroot, 0, 0);
1592 1598 if (namewidth < 10)
1593 1599 namewidth = 10;
1594 1600
1595 1601 print_import_config(name, nvroot, namewidth, 0);
1596 1602 if (num_logs(nvroot) > 0)
1597 1603 print_logs(NULL, nvroot, namewidth, B_FALSE);
1598 1604
1599 1605 if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
1600 1606 (void) printf(gettext("\n\tAdditional devices are known to "
1601 1607 "be part of this pool, though their\n\texact "
1602 1608 "configuration cannot be determined.\n"));
1603 1609 }
1604 1610 }
1605 1611
1606 1612 /*
1607 1613 * Perform the import for the given configuration. This passes the heavy
1608 1614 * lifting off to zpool_import_props(), and then mounts the datasets contained
1609 1615 * within the pool.
1610 1616 */
1611 1617 static int
1612 1618 do_import(nvlist_t *config, const char *newname, const char *mntopts,
1613 1619 nvlist_t *props, int flags)
1614 1620 {
1615 1621 zpool_handle_t *zhp;
1616 1622 char *name;
1617 1623 uint64_t state;
1618 1624 uint64_t version;
1619 1625
1620 1626 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1621 1627 &name) == 0);
1622 1628
1623 1629 verify(nvlist_lookup_uint64(config,
1624 1630 ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1625 1631 verify(nvlist_lookup_uint64(config,
1626 1632 ZPOOL_CONFIG_VERSION, &version) == 0);
1627 1633 if (!SPA_VERSION_IS_SUPPORTED(version)) {
1628 1634 (void) fprintf(stderr, gettext("cannot import '%s': pool "
1629 1635 "is formatted using an unsupported ZFS version\n"), name);
1630 1636 return (1);
1631 1637 } else if (state != POOL_STATE_EXPORTED &&
1632 1638 !(flags & ZFS_IMPORT_ANY_HOST)) {
1633 1639 uint64_t hostid;
1634 1640
1635 1641 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
1636 1642 &hostid) == 0) {
1637 1643 if ((unsigned long)hostid != gethostid()) {
1638 1644 char *hostname;
1639 1645 uint64_t timestamp;
1640 1646 time_t t;
1641 1647
1642 1648 verify(nvlist_lookup_string(config,
1643 1649 ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
1644 1650 verify(nvlist_lookup_uint64(config,
1645 1651 ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0);
1646 1652 t = timestamp;
1647 1653 (void) fprintf(stderr, gettext("cannot import "
1648 1654 "'%s': pool may be in use from other "
1649 1655 "system, it was last accessed by %s "
1650 1656 "(hostid: 0x%lx) on %s"), name, hostname,
1651 1657 (unsigned long)hostid,
1652 1658 asctime(localtime(&t)));
1653 1659 (void) fprintf(stderr, gettext("use '-f' to "
1654 1660 "import anyway\n"));
1655 1661 return (1);
1656 1662 }
1657 1663 } else {
1658 1664 (void) fprintf(stderr, gettext("cannot import '%s': "
1659 1665 "pool may be in use from other system\n"), name);
1660 1666 (void) fprintf(stderr, gettext("use '-f' to import "
1661 1667 "anyway\n"));
1662 1668 return (1);
1663 1669 }
1664 1670 }
1665 1671
1666 1672 if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
1667 1673 return (1);
1668 1674
1669 1675 if (newname != NULL)
1670 1676 name = (char *)newname;
1671 1677
1672 1678 if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
1673 1679 return (1);
1674 1680
1675 1681 if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1676 1682 !(flags & ZFS_IMPORT_ONLY) &&
1677 1683 zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1678 1684 zpool_close(zhp);
1679 1685 return (1);
1680 1686 }
1681 1687
1682 1688 zpool_close(zhp);
1683 1689 return (0);
1684 1690 }
1685 1691
1686 1692 /*
1687 1693 * zpool import [-d dir] [-D]
1688 1694 * import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1689 1695 * [-d dir | -c cachefile] [-f] -a
1690 1696 * import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1691 1697 * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
1692 1698 *
1693 1699 * -c Read pool information from a cachefile instead of searching
1694 1700 * devices.
1695 1701 *
1696 1702 * -d Scan in a specific directory, other than /dev/dsk. More than
1697 1703 * one directory can be specified using multiple '-d' options.
1698 1704 *
1699 1705 * -D Scan for previously destroyed pools or import all or only
1700 1706 * specified destroyed pools.
1701 1707 *
1702 1708 * -R Temporarily import the pool, with all mountpoints relative to
1703 1709 * the given root. The pool will remain exported when the machine
1704 1710 * is rebooted.
1705 1711 *
1706 1712 * -V Import even in the presence of faulted vdevs. This is an
1707 1713 * intentionally undocumented option for testing purposes, and
1708 1714 * treats the pool configuration as complete, leaving any bad
1709 1715 * vdevs in the FAULTED state. In other words, it does verbatim
1710 1716 * import.
1711 1717 *
1712 1718 * -f Force import, even if it appears that the pool is active.
1713 1719 *
1714 1720 * -F Attempt rewind if necessary.
1715 1721 *
1716 1722 * -n See if rewind would work, but don't actually rewind.
1717 1723 *
1718 1724 * -N Import the pool but don't mount datasets.
1719 1725 *
1720 1726 * -T Specify a starting txg to use for import. This option is
1721 1727 * intentionally undocumented option for testing purposes.
1722 1728 *
1723 1729 * -a Import all pools found.
1724 1730 *
1725 1731 * -o Set property=value and/or temporary mount options (without '=').
1726 1732 *
1727 1733 * The import command scans for pools to import, and import pools based on pool
1728 1734 * name and GUID. The pool can also be renamed as part of the import process.
1729 1735 */
1730 1736 int
1731 1737 zpool_do_import(int argc, char **argv)
1732 1738 {
1733 1739 char **searchdirs = NULL;
1734 1740 int nsearch = 0;
1735 1741 int c;
1736 1742 int err = 0;
1737 1743 nvlist_t *pools = NULL;
1738 1744 boolean_t do_all = B_FALSE;
1739 1745 boolean_t do_destroyed = B_FALSE;
1740 1746 char *mntopts = NULL;
1741 1747 nvpair_t *elem;
1742 1748 nvlist_t *config;
1743 1749 uint64_t searchguid = 0;
1744 1750 char *searchname = NULL;
1745 1751 char *propval;
1746 1752 nvlist_t *found_config;
1747 1753 nvlist_t *policy = NULL;
1748 1754 nvlist_t *props = NULL;
1749 1755 boolean_t first;
1750 1756 int flags = ZFS_IMPORT_NORMAL;
1751 1757 uint32_t rewind_policy = ZPOOL_NO_REWIND;
1752 1758 boolean_t dryrun = B_FALSE;
1753 1759 boolean_t do_rewind = B_FALSE;
1754 1760 boolean_t xtreme_rewind = B_FALSE;
1755 1761 uint64_t pool_state, txg = -1ULL;
1756 1762 char *cachefile = NULL;
1757 1763 importargs_t idata = { 0 };
1758 1764 char *endptr;
1759 1765
1760 1766 /* check options */
1761 1767 while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
1762 1768 switch (c) {
1763 1769 case 'a':
1764 1770 do_all = B_TRUE;
1765 1771 break;
1766 1772 case 'c':
1767 1773 cachefile = optarg;
1768 1774 break;
1769 1775 case 'd':
1770 1776 if (searchdirs == NULL) {
1771 1777 searchdirs = safe_malloc(sizeof (char *));
1772 1778 } else {
1773 1779 char **tmp = safe_malloc((nsearch + 1) *
1774 1780 sizeof (char *));
1775 1781 bcopy(searchdirs, tmp, nsearch *
1776 1782 sizeof (char *));
1777 1783 free(searchdirs);
1778 1784 searchdirs = tmp;
1779 1785 }
1780 1786 searchdirs[nsearch++] = optarg;
1781 1787 break;
1782 1788 case 'D':
1783 1789 do_destroyed = B_TRUE;
1784 1790 break;
1785 1791 case 'f':
1786 1792 flags |= ZFS_IMPORT_ANY_HOST;
1787 1793 break;
1788 1794 case 'F':
1789 1795 do_rewind = B_TRUE;
1790 1796 break;
1791 1797 case 'm':
1792 1798 flags |= ZFS_IMPORT_MISSING_LOG;
1793 1799 break;
1794 1800 case 'n':
1795 1801 dryrun = B_TRUE;
1796 1802 break;
1797 1803 case 'N':
1798 1804 flags |= ZFS_IMPORT_ONLY;
1799 1805 break;
1800 1806 case 'o':
1801 1807 if ((propval = strchr(optarg, '=')) != NULL) {
1802 1808 *propval = '\0';
1803 1809 propval++;
1804 1810 if (add_prop_list(optarg, propval,
1805 1811 &props, B_TRUE))
1806 1812 goto error;
1807 1813 } else {
1808 1814 mntopts = optarg;
1809 1815 }
1810 1816 break;
1811 1817 case 'R':
1812 1818 if (add_prop_list(zpool_prop_to_name(
1813 1819 ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1814 1820 goto error;
1815 1821 if (nvlist_lookup_string(props,
1816 1822 zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
1817 1823 &propval) == 0)
1818 1824 break;
1819 1825 if (add_prop_list(zpool_prop_to_name(
1820 1826 ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1821 1827 goto error;
1822 1828 break;
1823 1829 case 'T':
1824 1830 errno = 0;
1825 1831 txg = strtoull(optarg, &endptr, 10);
1826 1832 if (errno != 0 || *endptr != '\0') {
1827 1833 (void) fprintf(stderr,
1828 1834 gettext("invalid txg value\n"));
1829 1835 usage(B_FALSE);
1830 1836 }
1831 1837 rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
1832 1838 break;
1833 1839 case 'V':
1834 1840 flags |= ZFS_IMPORT_VERBATIM;
1835 1841 break;
1836 1842 case 'X':
1837 1843 xtreme_rewind = B_TRUE;
1838 1844 break;
1839 1845 case ':':
1840 1846 (void) fprintf(stderr, gettext("missing argument for "
1841 1847 "'%c' option\n"), optopt);
1842 1848 usage(B_FALSE);
1843 1849 break;
1844 1850 case '?':
1845 1851 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
1846 1852 optopt);
1847 1853 usage(B_FALSE);
1848 1854 }
1849 1855 }
1850 1856
1851 1857 argc -= optind;
1852 1858 argv += optind;
1853 1859
1854 1860 if (cachefile && nsearch != 0) {
1855 1861 (void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
1856 1862 usage(B_FALSE);
1857 1863 }
1858 1864
1859 1865 if ((dryrun || xtreme_rewind) && !do_rewind) {
1860 1866 (void) fprintf(stderr,
1861 1867 gettext("-n or -X only meaningful with -F\n"));
1862 1868 usage(B_FALSE);
1863 1869 }
1864 1870 if (dryrun)
1865 1871 rewind_policy = ZPOOL_TRY_REWIND;
1866 1872 else if (do_rewind)
1867 1873 rewind_policy = ZPOOL_DO_REWIND;
1868 1874 if (xtreme_rewind)
1869 1875 rewind_policy |= ZPOOL_EXTREME_REWIND;
1870 1876
1871 1877 /* In the future, we can capture further policy and include it here */
1872 1878 if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
1873 1879 nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 ||
1874 1880 nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
1875 1881 goto error;
1876 1882
1877 1883 if (searchdirs == NULL) {
1878 1884 searchdirs = safe_malloc(sizeof (char *));
1879 1885 searchdirs[0] = "/dev/dsk";
1880 1886 nsearch = 1;
1881 1887 }
1882 1888
1883 1889 /* check argument count */
1884 1890 if (do_all) {
1885 1891 if (argc != 0) {
1886 1892 (void) fprintf(stderr, gettext("too many arguments\n"));
1887 1893 usage(B_FALSE);
1888 1894 }
1889 1895 } else {
1890 1896 if (argc > 2) {
1891 1897 (void) fprintf(stderr, gettext("too many arguments\n"));
1892 1898 usage(B_FALSE);
1893 1899 }
1894 1900
1895 1901 /*
1896 1902 * Check for the SYS_CONFIG privilege. We do this explicitly
1897 1903 * here because otherwise any attempt to discover pools will
1898 1904 * silently fail.
1899 1905 */
1900 1906 if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1901 1907 (void) fprintf(stderr, gettext("cannot "
1902 1908 "discover pools: permission denied\n"));
1903 1909 free(searchdirs);
1904 1910 nvlist_free(policy);
1905 1911 return (1);
1906 1912 }
1907 1913 }
1908 1914
1909 1915 /*
1910 1916 * Depending on the arguments given, we do one of the following:
1911 1917 *
1912 1918 * <none> Iterate through all pools and display information about
1913 1919 * each one.
1914 1920 *
1915 1921 * -a Iterate through all pools and try to import each one.
1916 1922 *
1917 1923 * <id> Find the pool that corresponds to the given GUID/pool
1918 1924 * name and import that one.
1919 1925 *
1920 1926 * -D Above options applies only to destroyed pools.
1921 1927 */
1922 1928 if (argc != 0) {
1923 1929 char *endptr;
1924 1930
1925 1931 errno = 0;
1926 1932 searchguid = strtoull(argv[0], &endptr, 10);
1927 1933 if (errno != 0 || *endptr != '\0')
1928 1934 searchname = argv[0];
1929 1935 found_config = NULL;
1930 1936
1931 1937 /*
1932 1938 * User specified a name or guid. Ensure it's unique.
1933 1939 */
1934 1940 idata.unique = B_TRUE;
1935 1941 }
1936 1942
1937 1943
1938 1944 idata.path = searchdirs;
1939 1945 idata.paths = nsearch;
1940 1946 idata.poolname = searchname;
1941 1947 idata.guid = searchguid;
1942 1948 idata.cachefile = cachefile;
1943 1949
1944 1950 pools = zpool_search_import(g_zfs, &idata);
1945 1951
1946 1952 if (pools != NULL && idata.exists &&
1947 1953 (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
1948 1954 (void) fprintf(stderr, gettext("cannot import '%s': "
1949 1955 "a pool with that name already exists\n"),
1950 1956 argv[0]);
1951 1957 (void) fprintf(stderr, gettext("use the form '%s "
1952 1958 "<pool | id> <newpool>' to give it a new name\n"),
1953 1959 "zpool import");
1954 1960 err = 1;
1955 1961 } else if (pools == NULL && idata.exists) {
1956 1962 (void) fprintf(stderr, gettext("cannot import '%s': "
1957 1963 "a pool with that name is already created/imported,\n"),
1958 1964 argv[0]);
1959 1965 (void) fprintf(stderr, gettext("and no additional pools "
1960 1966 "with that name were found\n"));
1961 1967 err = 1;
1962 1968 } else if (pools == NULL) {
1963 1969 if (argc != 0) {
1964 1970 (void) fprintf(stderr, gettext("cannot import '%s': "
1965 1971 "no such pool available\n"), argv[0]);
1966 1972 }
1967 1973 err = 1;
1968 1974 }
1969 1975
1970 1976 if (err == 1) {
1971 1977 free(searchdirs);
1972 1978 nvlist_free(policy);
1973 1979 return (1);
1974 1980 }
1975 1981
1976 1982 /*
1977 1983 * At this point we have a list of import candidate configs. Even if
1978 1984 * we were searching by pool name or guid, we still need to
1979 1985 * post-process the list to deal with pool state and possible
1980 1986 * duplicate names.
1981 1987 */
1982 1988 err = 0;
1983 1989 elem = NULL;
1984 1990 first = B_TRUE;
1985 1991 while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1986 1992
1987 1993 verify(nvpair_value_nvlist(elem, &config) == 0);
1988 1994
1989 1995 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1990 1996 &pool_state) == 0);
1991 1997 if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
1992 1998 continue;
1993 1999 if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
1994 2000 continue;
1995 2001
1996 2002 verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY,
1997 2003 policy) == 0);
1998 2004
1999 2005 if (argc == 0) {
2000 2006 if (first)
2001 2007 first = B_FALSE;
2002 2008 else if (!do_all)
2003 2009 (void) printf("\n");
2004 2010
2005 2011 if (do_all) {
2006 2012 err |= do_import(config, NULL, mntopts,
2007 2013 props, flags);
2008 2014 } else {
2009 2015 show_import(config);
2010 2016 }
2011 2017 } else if (searchname != NULL) {
2012 2018 char *name;
2013 2019
2014 2020 /*
2015 2021 * We are searching for a pool based on name.
2016 2022 */
2017 2023 verify(nvlist_lookup_string(config,
2018 2024 ZPOOL_CONFIG_POOL_NAME, &name) == 0);
2019 2025
2020 2026 if (strcmp(name, searchname) == 0) {
2021 2027 if (found_config != NULL) {
2022 2028 (void) fprintf(stderr, gettext(
2023 2029 "cannot import '%s': more than "
2024 2030 "one matching pool\n"), searchname);
2025 2031 (void) fprintf(stderr, gettext(
2026 2032 "import by numeric ID instead\n"));
2027 2033 err = B_TRUE;
2028 2034 }
2029 2035 found_config = config;
2030 2036 }
2031 2037 } else {
2032 2038 uint64_t guid;
2033 2039
2034 2040 /*
2035 2041 * Search for a pool by guid.
2036 2042 */
2037 2043 verify(nvlist_lookup_uint64(config,
2038 2044 ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
2039 2045
2040 2046 if (guid == searchguid)
2041 2047 found_config = config;
2042 2048 }
2043 2049 }
2044 2050
2045 2051 /*
2046 2052 * If we were searching for a specific pool, verify that we found a
2047 2053 * pool, and then do the import.
2048 2054 */
2049 2055 if (argc != 0 && err == 0) {
2050 2056 if (found_config == NULL) {
2051 2057 (void) fprintf(stderr, gettext("cannot import '%s': "
2052 2058 "no such pool available\n"), argv[0]);
2053 2059 err = B_TRUE;
2054 2060 } else {
2055 2061 err |= do_import(found_config, argc == 1 ? NULL :
2056 2062 argv[1], mntopts, props, flags);
2057 2063 }
2058 2064 }
2059 2065
2060 2066 /*
2061 2067 * If we were just looking for pools, report an error if none were
2062 2068 * found.
2063 2069 */
2064 2070 if (argc == 0 && first)
2065 2071 (void) fprintf(stderr,
2066 2072 gettext("no pools available to import\n"));
2067 2073
2068 2074 error:
2069 2075 nvlist_free(props);
2070 2076 nvlist_free(pools);
2071 2077 nvlist_free(policy);
2072 2078 free(searchdirs);
2073 2079
2074 2080 return (err ? 1 : 0);
2075 2081 }
2076 2082
2077 2083 typedef struct iostat_cbdata {
2078 2084 boolean_t cb_verbose;
2079 2085 int cb_namewidth;
2080 2086 int cb_iteration;
2081 2087 zpool_list_t *cb_list;
2082 2088 } iostat_cbdata_t;
2083 2089
2084 2090 static void
2085 2091 print_iostat_separator(iostat_cbdata_t *cb)
2086 2092 {
2087 2093 int i = 0;
2088 2094
2089 2095 for (i = 0; i < cb->cb_namewidth; i++)
2090 2096 (void) printf("-");
2091 2097 (void) printf(" ----- ----- ----- ----- ----- -----\n");
2092 2098 }
2093 2099
2094 2100 static void
2095 2101 print_iostat_header(iostat_cbdata_t *cb)
2096 2102 {
2097 2103 (void) printf("%*s capacity operations bandwidth\n",
2098 2104 cb->cb_namewidth, "");
2099 2105 (void) printf("%-*s alloc free read write read write\n",
2100 2106 cb->cb_namewidth, "pool");
2101 2107 print_iostat_separator(cb);
2102 2108 }
2103 2109
2104 2110 /*
2105 2111 * Display a single statistic.
2106 2112 */
2107 2113 static void
2108 2114 print_one_stat(uint64_t value)
2109 2115 {
2110 2116 char buf[64];
2111 2117
2112 2118 zfs_nicenum(value, buf, sizeof (buf));
2113 2119 (void) printf(" %5s", buf);
2114 2120 }
2115 2121
2116 2122 /*
2117 2123 * Print out all the statistics for the given vdev. This can either be the
2118 2124 * toplevel configuration, or called recursively. If 'name' is NULL, then this
2119 2125 * is a verbose output, and we don't want to display the toplevel pool stats.
2120 2126 */
2121 2127 void
2122 2128 print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
2123 2129 nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2124 2130 {
2125 2131 nvlist_t **oldchild, **newchild;
2126 2132 uint_t c, children;
2127 2133 vdev_stat_t *oldvs, *newvs;
2128 2134 vdev_stat_t zerovs = { 0 };
2129 2135 uint64_t tdelta;
2130 2136 double scale;
2131 2137 char *vname;
2132 2138
2133 2139 if (oldnv != NULL) {
2134 2140 verify(nvlist_lookup_uint64_array(oldnv,
2135 2141 ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2136 2142 } else {
2137 2143 oldvs = &zerovs;
2138 2144 }
2139 2145
2140 2146 verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2141 2147 (uint64_t **)&newvs, &c) == 0);
2142 2148
2143 2149 if (strlen(name) + depth > cb->cb_namewidth)
2144 2150 (void) printf("%*s%s", depth, "", name);
2145 2151 else
2146 2152 (void) printf("%*s%s%*s", depth, "", name,
2147 2153 (int)(cb->cb_namewidth - strlen(name) - depth), "");
2148 2154
2149 2155 tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
2150 2156
2151 2157 if (tdelta == 0)
2152 2158 scale = 1.0;
2153 2159 else
2154 2160 scale = (double)NANOSEC / tdelta;
2155 2161
2156 2162 /* only toplevel vdevs have capacity stats */
2157 2163 if (newvs->vs_space == 0) {
2158 2164 (void) printf(" - -");
2159 2165 } else {
2160 2166 print_one_stat(newvs->vs_alloc);
2161 2167 print_one_stat(newvs->vs_space - newvs->vs_alloc);
2162 2168 }
2163 2169
2164 2170 print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
2165 2171 oldvs->vs_ops[ZIO_TYPE_READ])));
2166 2172
2167 2173 print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2168 2174 oldvs->vs_ops[ZIO_TYPE_WRITE])));
2169 2175
2170 2176 print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2171 2177 oldvs->vs_bytes[ZIO_TYPE_READ])));
2172 2178
2173 2179 print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2174 2180 oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2175 2181
2176 2182 (void) printf("\n");
2177 2183
2178 2184 if (!cb->cb_verbose)
2179 2185 return;
2180 2186
2181 2187 if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2182 2188 &newchild, &children) != 0)
2183 2189 return;
2184 2190
2185 2191 if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2186 2192 &oldchild, &c) != 0)
2187 2193 return;
2188 2194
2189 2195 for (c = 0; c < children; c++) {
2190 2196 uint64_t ishole = B_FALSE, islog = B_FALSE;
2191 2197
2192 2198 (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
2193 2199 &ishole);
2194 2200
2195 2201 (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
2196 2202 &islog);
2197 2203
2198 2204 if (ishole || islog)
2199 2205 continue;
2200 2206
2201 2207 vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
2202 2208 print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2203 2209 newchild[c], cb, depth + 2);
2204 2210 free(vname);
2205 2211 }
2206 2212
2207 2213 /*
2208 2214 * Log device section
2209 2215 */
2210 2216
2211 2217 if (num_logs(newnv) > 0) {
2212 2218 (void) printf("%-*s - - - - - "
2213 2219 "-\n", cb->cb_namewidth, "logs");
2214 2220
2215 2221 for (c = 0; c < children; c++) {
2216 2222 uint64_t islog = B_FALSE;
2217 2223 (void) nvlist_lookup_uint64(newchild[c],
2218 2224 ZPOOL_CONFIG_IS_LOG, &islog);
2219 2225
2220 2226 if (islog) {
2221 2227 vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2222 2228 B_FALSE);
2223 2229 print_vdev_stats(zhp, vname, oldnv ?
2224 2230 oldchild[c] : NULL, newchild[c],
2225 2231 cb, depth + 2);
2226 2232 free(vname);
2227 2233 }
2228 2234 }
2229 2235
2230 2236 }
2231 2237
2232 2238 /*
2233 2239 * Include level 2 ARC devices in iostat output
2234 2240 */
2235 2241 if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
2236 2242 &newchild, &children) != 0)
2237 2243 return;
2238 2244
2239 2245 if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
2240 2246 &oldchild, &c) != 0)
2241 2247 return;
2242 2248
2243 2249 if (children > 0) {
2244 2250 (void) printf("%-*s - - - - - "
2245 2251 "-\n", cb->cb_namewidth, "cache");
2246 2252 for (c = 0; c < children; c++) {
2247 2253 vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2248 2254 B_FALSE);
2249 2255 print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2250 2256 newchild[c], cb, depth + 2);
2251 2257 free(vname);
2252 2258 }
2253 2259 }
2254 2260 }
2255 2261
2256 2262 static int
2257 2263 refresh_iostat(zpool_handle_t *zhp, void *data)
2258 2264 {
2259 2265 iostat_cbdata_t *cb = data;
2260 2266 boolean_t missing;
2261 2267
2262 2268 /*
2263 2269 * If the pool has disappeared, remove it from the list and continue.
2264 2270 */
2265 2271 if (zpool_refresh_stats(zhp, &missing) != 0)
2266 2272 return (-1);
2267 2273
2268 2274 if (missing)
2269 2275 pool_list_remove(cb->cb_list, zhp);
2270 2276
2271 2277 return (0);
2272 2278 }
2273 2279
2274 2280 /*
2275 2281 * Callback to print out the iostats for the given pool.
2276 2282 */
2277 2283 int
2278 2284 print_iostat(zpool_handle_t *zhp, void *data)
2279 2285 {
2280 2286 iostat_cbdata_t *cb = data;
2281 2287 nvlist_t *oldconfig, *newconfig;
2282 2288 nvlist_t *oldnvroot, *newnvroot;
2283 2289
2284 2290 newconfig = zpool_get_config(zhp, &oldconfig);
2285 2291
2286 2292 if (cb->cb_iteration == 1)
2287 2293 oldconfig = NULL;
2288 2294
2289 2295 verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2290 2296 &newnvroot) == 0);
2291 2297
2292 2298 if (oldconfig == NULL)
2293 2299 oldnvroot = NULL;
2294 2300 else
2295 2301 verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2296 2302 &oldnvroot) == 0);
2297 2303
2298 2304 /*
2299 2305 * Print out the statistics for the pool.
2300 2306 */
2301 2307 print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2302 2308
2303 2309 if (cb->cb_verbose)
2304 2310 print_iostat_separator(cb);
2305 2311
2306 2312 return (0);
2307 2313 }
2308 2314
2309 2315 int
2310 2316 get_namewidth(zpool_handle_t *zhp, void *data)
2311 2317 {
2312 2318 iostat_cbdata_t *cb = data;
2313 2319 nvlist_t *config, *nvroot;
2314 2320
2315 2321 if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2316 2322 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2317 2323 &nvroot) == 0);
2318 2324 if (!cb->cb_verbose)
2319 2325 cb->cb_namewidth = strlen(zpool_get_name(zhp));
2320 2326 else
2321 2327 cb->cb_namewidth = max_width(zhp, nvroot, 0,
2322 2328 cb->cb_namewidth);
2323 2329 }
2324 2330
2325 2331 /*
2326 2332 * The width must fall into the range [10,38]. The upper limit is the
2327 2333 * maximum we can have and still fit in 80 columns.
2328 2334 */
2329 2335 if (cb->cb_namewidth < 10)
2330 2336 cb->cb_namewidth = 10;
2331 2337 if (cb->cb_namewidth > 38)
2332 2338 cb->cb_namewidth = 38;
2333 2339
2334 2340 return (0);
2335 2341 }
2336 2342
2337 2343 /*
2338 2344 * Parse the input string, get the 'interval' and 'count' value if there is one.
2339 2345 */
2340 2346 static void
2341 2347 get_interval_count(int *argcp, char **argv, unsigned long *iv,
2342 2348 unsigned long *cnt)
2343 2349 {
2344 2350 unsigned long interval = 0, count = 0;
2345 2351 int argc = *argcp, errno;
2346 2352
2347 2353 /*
2348 2354 * Determine if the last argument is an integer or a pool name
2349 2355 */
2350 2356 if (argc > 0 && isdigit(argv[argc - 1][0])) {
2351 2357 char *end;
2352 2358
2353 2359 errno = 0;
2354 2360 interval = strtoul(argv[argc - 1], &end, 10);
2355 2361
2356 2362 if (*end == '\0' && errno == 0) {
2357 2363 if (interval == 0) {
2358 2364 (void) fprintf(stderr, gettext("interval "
2359 2365 "cannot be zero\n"));
2360 2366 usage(B_FALSE);
2361 2367 }
2362 2368 /*
2363 2369 * Ignore the last parameter
2364 2370 */
2365 2371 argc--;
2366 2372 } else {
2367 2373 /*
2368 2374 * If this is not a valid number, just plow on. The
2369 2375 * user will get a more informative error message later
2370 2376 * on.
2371 2377 */
2372 2378 interval = 0;
2373 2379 }
2374 2380 }
2375 2381
2376 2382 /*
2377 2383 * If the last argument is also an integer, then we have both a count
2378 2384 * and an interval.
2379 2385 */
2380 2386 if (argc > 0 && isdigit(argv[argc - 1][0])) {
2381 2387 char *end;
2382 2388
2383 2389 errno = 0;
2384 2390 count = interval;
2385 2391 interval = strtoul(argv[argc - 1], &end, 10);
2386 2392
2387 2393 if (*end == '\0' && errno == 0) {
2388 2394 if (interval == 0) {
2389 2395 (void) fprintf(stderr, gettext("interval "
2390 2396 "cannot be zero\n"));
2391 2397 usage(B_FALSE);
2392 2398 }
2393 2399
2394 2400 /*
2395 2401 * Ignore the last parameter
2396 2402 */
2397 2403 argc--;
2398 2404 } else {
2399 2405 interval = 0;
2400 2406 }
2401 2407 }
2402 2408
2403 2409 *iv = interval;
2404 2410 *cnt = count;
2405 2411 *argcp = argc;
2406 2412 }
2407 2413
2408 2414 static void
2409 2415 get_timestamp_arg(char c)
2410 2416 {
2411 2417 if (c == 'u')
2412 2418 timestamp_fmt = UDATE;
2413 2419 else if (c == 'd')
2414 2420 timestamp_fmt = DDATE;
2415 2421 else
2416 2422 usage(B_FALSE);
2417 2423 }
2418 2424
2419 2425 /*
2420 2426 * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
2421 2427 *
2422 2428 * -v Display statistics for individual vdevs
2423 2429 * -T Display a timestamp in date(1) or Unix format
2424 2430 *
2425 2431 * This command can be tricky because we want to be able to deal with pool
2426 2432 * creation/destruction as well as vdev configuration changes. The bulk of this
2427 2433 * processing is handled by the pool_list_* routines in zpool_iter.c. We rely
2428 2434 * on pool_list_update() to detect the addition of new pools. Configuration
2429 2435 * changes are all handled within libzfs.
2430 2436 */
2431 2437 int
2432 2438 zpool_do_iostat(int argc, char **argv)
2433 2439 {
2434 2440 int c;
2435 2441 int ret;
2436 2442 int npools;
2437 2443 unsigned long interval = 0, count = 0;
2438 2444 zpool_list_t *list;
2439 2445 boolean_t verbose = B_FALSE;
2440 2446 iostat_cbdata_t cb;
2441 2447
2442 2448 /* check options */
2443 2449 while ((c = getopt(argc, argv, "T:v")) != -1) {
2444 2450 switch (c) {
2445 2451 case 'T':
2446 2452 get_timestamp_arg(*optarg);
2447 2453 break;
2448 2454 case 'v':
2449 2455 verbose = B_TRUE;
2450 2456 break;
2451 2457 case '?':
2452 2458 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2453 2459 optopt);
2454 2460 usage(B_FALSE);
2455 2461 }
2456 2462 }
2457 2463
2458 2464 argc -= optind;
2459 2465 argv += optind;
2460 2466
2461 2467 get_interval_count(&argc, argv, &interval, &count);
2462 2468
2463 2469 /*
2464 2470 * Construct the list of all interesting pools.
2465 2471 */
2466 2472 ret = 0;
2467 2473 if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2468 2474 return (1);
2469 2475
2470 2476 if (pool_list_count(list) == 0 && argc != 0) {
2471 2477 pool_list_free(list);
2472 2478 return (1);
2473 2479 }
2474 2480
2475 2481 if (pool_list_count(list) == 0 && interval == 0) {
2476 2482 pool_list_free(list);
2477 2483 (void) fprintf(stderr, gettext("no pools available\n"));
2478 2484 return (1);
2479 2485 }
2480 2486
2481 2487 /*
2482 2488 * Enter the main iostat loop.
2483 2489 */
2484 2490 cb.cb_list = list;
2485 2491 cb.cb_verbose = verbose;
2486 2492 cb.cb_iteration = 0;
2487 2493 cb.cb_namewidth = 0;
2488 2494
2489 2495 for (;;) {
2490 2496 pool_list_update(list);
2491 2497
2492 2498 if ((npools = pool_list_count(list)) == 0)
2493 2499 break;
2494 2500
2495 2501 /*
2496 2502 * Refresh all statistics. This is done as an explicit step
2497 2503 * before calculating the maximum name width, so that any
2498 2504 * configuration changes are properly accounted for.
2499 2505 */
2500 2506 (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2501 2507
2502 2508 /*
2503 2509 * Iterate over all pools to determine the maximum width
2504 2510 * for the pool / device name column across all pools.
2505 2511 */
2506 2512 cb.cb_namewidth = 0;
2507 2513 (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2508 2514
2509 2515 if (timestamp_fmt != NODATE)
2510 2516 print_timestamp(timestamp_fmt);
2511 2517
2512 2518 /*
2513 2519 * If it's the first time, or verbose mode, print the header.
2514 2520 */
2515 2521 if (++cb.cb_iteration == 1 || verbose)
2516 2522 print_iostat_header(&cb);
2517 2523
2518 2524 (void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2519 2525
2520 2526 /*
2521 2527 * If there's more than one pool, and we're not in verbose mode
2522 2528 * (which prints a separator for us), then print a separator.
2523 2529 */
2524 2530 if (npools > 1 && !verbose)
2525 2531 print_iostat_separator(&cb);
2526 2532
2527 2533 if (verbose)
2528 2534 (void) printf("\n");
2529 2535
2530 2536 /*
2531 2537 * Flush the output so that redirection to a file isn't buffered
2532 2538 * indefinitely.
2533 2539 */
2534 2540 (void) fflush(stdout);
2535 2541
2536 2542 if (interval == 0)
2537 2543 break;
2538 2544
2539 2545 if (count != 0 && --count == 0)
2540 2546 break;
2541 2547
2542 2548 (void) sleep(interval);
2543 2549 }
2544 2550
2545 2551 pool_list_free(list);
2546 2552
2547 2553 return (ret);
2548 2554 }
2549 2555
2550 2556 typedef struct list_cbdata {
2551 2557 boolean_t cb_verbose;
2552 2558 int cb_namewidth;
2553 2559 boolean_t cb_scripted;
2554 2560 zprop_list_t *cb_proplist;
2555 2561 } list_cbdata_t;
2556 2562
2557 2563 /*
2558 2564 * Given a list of columns to display, output appropriate headers for each one.
2559 2565 */
2560 2566 static void
2561 2567 print_header(list_cbdata_t *cb)
2562 2568 {
2563 2569 zprop_list_t *pl = cb->cb_proplist;
2564 2570 char headerbuf[ZPOOL_MAXPROPLEN];
2565 2571 const char *header;
2566 2572 boolean_t first = B_TRUE;
2567 2573 boolean_t right_justify;
2568 2574 size_t width = 0;
2569 2575
2570 2576 for (; pl != NULL; pl = pl->pl_next) {
2571 2577 width = pl->pl_width;
2572 2578 if (first && cb->cb_verbose) {
2573 2579 /*
2574 2580 * Reset the width to accommodate the verbose listing
2575 2581 * of devices.
2576 2582 */
2577 2583 width = cb->cb_namewidth;
2578 2584 }
2579 2585
2580 2586 if (!first)
2581 2587 (void) printf(" ");
2582 2588 else
2583 2589 first = B_FALSE;
2584 2590
2585 2591 right_justify = B_FALSE;
2586 2592 if (pl->pl_prop != ZPROP_INVAL) {
2587 2593 header = zpool_prop_column_name(pl->pl_prop);
2588 2594 right_justify = zpool_prop_align_right(pl->pl_prop);
2589 2595 } else {
2590 2596 int i;
2591 2597
2592 2598 for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
2593 2599 headerbuf[i] = toupper(pl->pl_user_prop[i]);
2594 2600 headerbuf[i] = '\0';
2595 2601 header = headerbuf;
2596 2602 }
2597 2603
2598 2604 if (pl->pl_next == NULL && !right_justify)
2599 2605 (void) printf("%s", header);
2600 2606 else if (right_justify)
2601 2607 (void) printf("%*s", width, header);
2602 2608 else
2603 2609 (void) printf("%-*s", width, header);
2604 2610
2605 2611 }
2606 2612
2607 2613 (void) printf("\n");
2608 2614 }
2609 2615
2610 2616 /*
2611 2617 * Given a pool and a list of properties, print out all the properties according
2612 2618 * to the described layout.
2613 2619 */
2614 2620 static void
2615 2621 print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
2616 2622 {
2617 2623 zprop_list_t *pl = cb->cb_proplist;
2618 2624 boolean_t first = B_TRUE;
2619 2625 char property[ZPOOL_MAXPROPLEN];
2620 2626 char *propstr;
2621 2627 boolean_t right_justify;
2622 2628 size_t width;
2623 2629
2624 2630 for (; pl != NULL; pl = pl->pl_next) {
2625 2631
2626 2632 width = pl->pl_width;
2627 2633 if (first && cb->cb_verbose) {
2628 2634 /*
2629 2635 * Reset the width to accommodate the verbose listing
2630 2636 * of devices.
2631 2637 */
2632 2638 width = cb->cb_namewidth;
2633 2639 }
2634 2640
2635 2641 if (!first) {
2636 2642 if (cb->cb_scripted)
2637 2643 (void) printf("\t");
2638 2644 else
2639 2645 (void) printf(" ");
2640 2646 } else {
2641 2647 first = B_FALSE;
2642 2648 }
2643 2649
2644 2650 right_justify = B_FALSE;
2645 2651 if (pl->pl_prop != ZPROP_INVAL) {
2646 2652 if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ &&
2647 2653 zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0)
2648 2654 propstr = "-";
2649 2655 else if (zpool_get_prop(zhp, pl->pl_prop, property,
2650 2656 sizeof (property), NULL) != 0)
2651 2657 propstr = "-";
2652 2658 else
2653 2659 propstr = property;
2654 2660
2655 2661 right_justify = zpool_prop_align_right(pl->pl_prop);
2656 2662 } else if ((zpool_prop_feature(pl->pl_user_prop) ||
2657 2663 zpool_prop_unsupported(pl->pl_user_prop)) &&
2658 2664 zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
2659 2665 sizeof (property)) == 0) {
2660 2666 propstr = property;
2661 2667 } else {
2662 2668 propstr = "-";
2663 2669 }
2664 2670
2665 2671
2666 2672 /*
2667 2673 * If this is being called in scripted mode, or if this is the
2668 2674 * last column and it is left-justified, don't include a width
2669 2675 * format specifier.
2670 2676 */
2671 2677 if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
2672 2678 (void) printf("%s", propstr);
2673 2679 else if (right_justify)
2674 2680 (void) printf("%*s", width, propstr);
2675 2681 else
2676 2682 (void) printf("%-*s", width, propstr);
2677 2683 }
2678 2684
2679 2685 (void) printf("\n");
2680 2686 }
2681 2687
2682 2688 static void
2683 2689 print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted)
2684 2690 {
2685 2691 char propval[64];
2686 2692 boolean_t fixed;
2687 2693 size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
2688 2694
2689 2695 zfs_nicenum(value, propval, sizeof (propval));
2690 2696
2691 2697 if (prop == ZPOOL_PROP_EXPANDSZ && value == 0)
2692 2698 (void) strlcpy(propval, "-", sizeof (propval));
2693 2699
2694 2700 if (scripted)
2695 2701 (void) printf("\t%s", propval);
2696 2702 else
2697 2703 (void) printf(" %*s", width, propval);
2698 2704 }
2699 2705
2700 2706 void
2701 2707 print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
2702 2708 list_cbdata_t *cb, int depth)
2703 2709 {
2704 2710 nvlist_t **child;
2705 2711 vdev_stat_t *vs;
2706 2712 uint_t c, children;
2707 2713 char *vname;
2708 2714 boolean_t scripted = cb->cb_scripted;
2709 2715
2710 2716 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
2711 2717 (uint64_t **)&vs, &c) == 0);
2712 2718
2713 2719 if (name != NULL) {
2714 2720 if (scripted)
2715 2721 (void) printf("\t%s", name);
2716 2722 else if (strlen(name) + depth > cb->cb_namewidth)
2717 2723 (void) printf("%*s%s", depth, "", name);
2718 2724 else
2719 2725 (void) printf("%*s%s%*s", depth, "", name,
2720 2726 (int)(cb->cb_namewidth - strlen(name) - depth), "");
2721 2727
2722 2728 /* only toplevel vdevs have capacity stats */
2723 2729 if (vs->vs_space == 0) {
2724 2730 if (scripted)
2725 2731 (void) printf("\t-\t-\t-");
2726 2732 else
2727 2733 (void) printf(" - - -");
2728 2734 } else {
2729 2735 print_one_column(ZPOOL_PROP_SIZE, vs->vs_space,
2730 2736 scripted);
2731 2737 print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc,
2732 2738 scripted);
2733 2739 print_one_column(ZPOOL_PROP_FREE,
2734 2740 vs->vs_space - vs->vs_alloc, scripted);
2735 2741 }
2736 2742 print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize,
2737 2743 scripted);
2738 2744 (void) printf("\n");
2739 2745 }
2740 2746
2741 2747 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2742 2748 &child, &children) != 0)
2743 2749 return;
2744 2750
2745 2751 for (c = 0; c < children; c++) {
2746 2752 uint64_t ishole = B_FALSE;
2747 2753
2748 2754 if (nvlist_lookup_uint64(child[c],
2749 2755 ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
2750 2756 continue;
2751 2757
2752 2758 vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
2753 2759 print_list_stats(zhp, vname, child[c], cb, depth + 2);
2754 2760 free(vname);
2755 2761 }
2756 2762
2757 2763 /*
2758 2764 * Include level 2 ARC devices in iostat output
2759 2765 */
2760 2766 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
2761 2767 &child, &children) != 0)
2762 2768 return;
2763 2769
2764 2770 if (children > 0) {
2765 2771 (void) printf("%-*s - - - - - "
2766 2772 "-\n", cb->cb_namewidth, "cache");
2767 2773 for (c = 0; c < children; c++) {
2768 2774 vname = zpool_vdev_name(g_zfs, zhp, child[c],
2769 2775 B_FALSE);
2770 2776 print_list_stats(zhp, vname, child[c], cb, depth + 2);
2771 2777 free(vname);
2772 2778 }
2773 2779 }
2774 2780 }
2775 2781
2776 2782
2777 2783 /*
2778 2784 * Generic callback function to list a pool.
2779 2785 */
2780 2786 int
2781 2787 list_callback(zpool_handle_t *zhp, void *data)
2782 2788 {
2783 2789 list_cbdata_t *cbp = data;
2784 2790 nvlist_t *config;
2785 2791 nvlist_t *nvroot;
2786 2792
2787 2793 config = zpool_get_config(zhp, NULL);
2788 2794
2789 2795 print_pool(zhp, cbp);
2790 2796 if (!cbp->cb_verbose)
2791 2797 return (0);
2792 2798
2793 2799 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2794 2800 &nvroot) == 0);
2795 2801 print_list_stats(zhp, NULL, nvroot, cbp, 0);
2796 2802
2797 2803 return (0);
2798 2804 }
2799 2805
2800 2806 /*
2801 2807 * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
2802 2808 *
2803 2809 * -H Scripted mode. Don't display headers, and separate properties
2804 2810 * by a single tab.
2805 2811 * -o List of properties to display. Defaults to
2806 2812 * "name,size,allocated,free,capacity,health,altroot"
2807 2813 * -T Display a timestamp in date(1) or Unix format
2808 2814 *
2809 2815 * List all pools in the system, whether or not they're healthy. Output space
2810 2816 * statistics for each one, as well as health status summary.
2811 2817 */
2812 2818 int
2813 2819 zpool_do_list(int argc, char **argv)
2814 2820 {
2815 2821 int c;
2816 2822 int ret;
2817 2823 list_cbdata_t cb = { 0 };
2818 2824 static char default_props[] =
2819 2825 "name,size,allocated,free,expandsize,capacity,dedupratio,"
2820 2826 "health,altroot";
2821 2827 char *props = default_props;
2822 2828 unsigned long interval = 0, count = 0;
2823 2829 zpool_list_t *list;
2824 2830 boolean_t first = B_TRUE;
2825 2831
2826 2832 /* check options */
2827 2833 while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) {
2828 2834 switch (c) {
2829 2835 case 'H':
2830 2836 cb.cb_scripted = B_TRUE;
2831 2837 break;
2832 2838 case 'o':
2833 2839 props = optarg;
2834 2840 break;
2835 2841 case 'T':
2836 2842 get_timestamp_arg(*optarg);
2837 2843 break;
2838 2844 case 'v':
2839 2845 cb.cb_verbose = B_TRUE;
2840 2846 break;
2841 2847 case ':':
2842 2848 (void) fprintf(stderr, gettext("missing argument for "
2843 2849 "'%c' option\n"), optopt);
2844 2850 usage(B_FALSE);
2845 2851 break;
2846 2852 case '?':
2847 2853 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2848 2854 optopt);
2849 2855 usage(B_FALSE);
2850 2856 }
2851 2857 }
2852 2858
2853 2859 argc -= optind;
2854 2860 argv += optind;
2855 2861
2856 2862 get_interval_count(&argc, argv, &interval, &count);
2857 2863
2858 2864 if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
2859 2865 usage(B_FALSE);
2860 2866
2861 2867 if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL)
2862 2868 return (1);
2863 2869
2864 2870 if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
2865 2871 (void) printf(gettext("no pools available\n"));
2866 2872 zprop_free_list(cb.cb_proplist);
2867 2873 return (0);
2868 2874 }
2869 2875
2870 2876 for (;;) {
2871 2877 pool_list_update(list);
2872 2878
2873 2879 if (pool_list_count(list) == 0)
2874 2880 break;
2875 2881
2876 2882 cb.cb_namewidth = 0;
2877 2883 (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2878 2884
2879 2885 if (timestamp_fmt != NODATE)
2880 2886 print_timestamp(timestamp_fmt);
2881 2887
2882 2888 if (!cb.cb_scripted && (first || cb.cb_verbose)) {
2883 2889 print_header(&cb);
2884 2890 first = B_FALSE;
2885 2891 }
2886 2892 ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
2887 2893
2888 2894 if (interval == 0)
2889 2895 break;
2890 2896
2891 2897 if (count != 0 && --count == 0)
2892 2898 break;
2893 2899
2894 2900 (void) sleep(interval);
2895 2901 }
2896 2902
2897 2903 zprop_free_list(cb.cb_proplist);
2898 2904 return (ret);
2899 2905 }
2900 2906
2901 2907 static nvlist_t *
2902 2908 zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2903 2909 {
2904 2910 nvlist_t **child;
2905 2911 uint_t c, children;
2906 2912 nvlist_t *match;
2907 2913 char *path;
2908 2914
2909 2915 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2910 2916 &child, &children) != 0) {
2911 2917 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2912 2918 if (strncmp(name, "/dev/dsk/", 9) == 0)
2913 2919 name += 9;
2914 2920 if (strncmp(path, "/dev/dsk/", 9) == 0)
2915 2921 path += 9;
2916 2922 if (strcmp(name, path) == 0)
2917 2923 return (nv);
2918 2924 return (NULL);
2919 2925 }
2920 2926
2921 2927 for (c = 0; c < children; c++)
2922 2928 if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2923 2929 return (match);
2924 2930
2925 2931 return (NULL);
2926 2932 }
2927 2933
2928 2934 static int
2929 2935 zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2930 2936 {
2931 2937 boolean_t force = B_FALSE;
2932 2938 int c;
2933 2939 nvlist_t *nvroot;
2934 2940 char *poolname, *old_disk, *new_disk;
2935 2941 zpool_handle_t *zhp;
2936 2942 int ret;
2937 2943
2938 2944 /* check options */
2939 2945 while ((c = getopt(argc, argv, "f")) != -1) {
2940 2946 switch (c) {
2941 2947 case 'f':
2942 2948 force = B_TRUE;
2943 2949 break;
2944 2950 case '?':
2945 2951 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2946 2952 optopt);
2947 2953 usage(B_FALSE);
2948 2954 }
2949 2955 }
2950 2956
2951 2957 argc -= optind;
2952 2958 argv += optind;
2953 2959
2954 2960 /* get pool name and check number of arguments */
2955 2961 if (argc < 1) {
2956 2962 (void) fprintf(stderr, gettext("missing pool name argument\n"));
2957 2963 usage(B_FALSE);
2958 2964 }
2959 2965
2960 2966 poolname = argv[0];
2961 2967
2962 2968 if (argc < 2) {
2963 2969 (void) fprintf(stderr,
2964 2970 gettext("missing <device> specification\n"));
2965 2971 usage(B_FALSE);
2966 2972 }
2967 2973
2968 2974 old_disk = argv[1];
2969 2975
2970 2976 if (argc < 3) {
2971 2977 if (!replacing) {
2972 2978 (void) fprintf(stderr,
2973 2979 gettext("missing <new_device> specification\n"));
2974 2980 usage(B_FALSE);
2975 2981 }
2976 2982 new_disk = old_disk;
2977 2983 argc -= 1;
2978 2984 argv += 1;
2979 2985 } else {
2980 2986 new_disk = argv[2];
2981 2987 argc -= 2;
2982 2988 argv += 2;
2983 2989 }
2984 2990
2985 2991 if (argc > 1) {
2986 2992 (void) fprintf(stderr, gettext("too many arguments\n"));
2987 2993 usage(B_FALSE);
2988 2994 }
2989 2995
2990 2996 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2991 2997 return (1);
2992 2998
2993 2999 if (zpool_get_config(zhp, NULL) == NULL) {
2994 3000 (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2995 3001 poolname);
2996 3002 zpool_close(zhp);
2997 3003 return (1);
2998 3004 }
2999 3005
3000 3006 nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
3001 3007 argc, argv);
3002 3008 if (nvroot == NULL) {
3003 3009 zpool_close(zhp);
3004 3010 return (1);
3005 3011 }
3006 3012
3007 3013 ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
3008 3014
3009 3015 nvlist_free(nvroot);
3010 3016 zpool_close(zhp);
3011 3017
3012 3018 return (ret);
3013 3019 }
3014 3020
3015 3021 /*
3016 3022 * zpool replace [-f] <pool> <device> <new_device>
3017 3023 *
3018 3024 * -f Force attach, even if <new_device> appears to be in use.
3019 3025 *
3020 3026 * Replace <device> with <new_device>.
3021 3027 */
3022 3028 /* ARGSUSED */
3023 3029 int
3024 3030 zpool_do_replace(int argc, char **argv)
3025 3031 {
3026 3032 return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
3027 3033 }
3028 3034
3029 3035 /*
3030 3036 * zpool attach [-f] <pool> <device> <new_device>
3031 3037 *
3032 3038 * -f Force attach, even if <new_device> appears to be in use.
3033 3039 *
3034 3040 * Attach <new_device> to the mirror containing <device>. If <device> is not
3035 3041 * part of a mirror, then <device> will be transformed into a mirror of
3036 3042 * <device> and <new_device>. In either case, <new_device> will begin life
3037 3043 * with a DTL of [0, now], and will immediately begin to resilver itself.
3038 3044 */
3039 3045 int
3040 3046 zpool_do_attach(int argc, char **argv)
3041 3047 {
3042 3048 return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
3043 3049 }
3044 3050
3045 3051 /*
3046 3052 * zpool detach [-f] <pool> <device>
3047 3053 *
3048 3054 * -f Force detach of <device>, even if DTLs argue against it
3049 3055 * (not supported yet)
3050 3056 *
3051 3057 * Detach a device from a mirror. The operation will be refused if <device>
3052 3058 * is the last device in the mirror, or if the DTLs indicate that this device
3053 3059 * has the only valid copy of some data.
3054 3060 */
3055 3061 /* ARGSUSED */
3056 3062 int
3057 3063 zpool_do_detach(int argc, char **argv)
3058 3064 {
3059 3065 int c;
3060 3066 char *poolname, *path;
3061 3067 zpool_handle_t *zhp;
3062 3068 int ret;
3063 3069
3064 3070 /* check options */
3065 3071 while ((c = getopt(argc, argv, "f")) != -1) {
3066 3072 switch (c) {
3067 3073 case 'f':
3068 3074 case '?':
3069 3075 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3070 3076 optopt);
3071 3077 usage(B_FALSE);
3072 3078 }
3073 3079 }
3074 3080
3075 3081 argc -= optind;
3076 3082 argv += optind;
3077 3083
3078 3084 /* get pool name and check number of arguments */
3079 3085 if (argc < 1) {
3080 3086 (void) fprintf(stderr, gettext("missing pool name argument\n"));
3081 3087 usage(B_FALSE);
3082 3088 }
3083 3089
3084 3090 if (argc < 2) {
3085 3091 (void) fprintf(stderr,
3086 3092 gettext("missing <device> specification\n"));
3087 3093 usage(B_FALSE);
3088 3094 }
3089 3095
3090 3096 poolname = argv[0];
3091 3097 path = argv[1];
3092 3098
3093 3099 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3094 3100 return (1);
3095 3101
3096 3102 ret = zpool_vdev_detach(zhp, path);
3097 3103
3098 3104 zpool_close(zhp);
3099 3105
3100 3106 return (ret);
3101 3107 }
3102 3108
3103 3109 /*
3104 3110 * zpool split [-n] [-o prop=val] ...
3105 3111 * [-o mntopt] ...
3106 3112 * [-R altroot] <pool> <newpool> [<device> ...]
3107 3113 *
3108 3114 * -n Do not split the pool, but display the resulting layout if
3109 3115 * it were to be split.
3110 3116 * -o Set property=value, or set mount options.
3111 3117 * -R Mount the split-off pool under an alternate root.
3112 3118 *
3113 3119 * Splits the named pool and gives it the new pool name. Devices to be split
3114 3120 * off may be listed, provided that no more than one device is specified
3115 3121 * per top-level vdev mirror. The newly split pool is left in an exported
3116 3122 * state unless -R is specified.
3117 3123 *
3118 3124 * Restrictions: the top-level of the pool pool must only be made up of
3119 3125 * mirrors; all devices in the pool must be healthy; no device may be
3120 3126 * undergoing a resilvering operation.
3121 3127 */
3122 3128 int
3123 3129 zpool_do_split(int argc, char **argv)
3124 3130 {
3125 3131 char *srcpool, *newpool, *propval;
3126 3132 char *mntopts = NULL;
3127 3133 splitflags_t flags;
3128 3134 int c, ret = 0;
3129 3135 zpool_handle_t *zhp;
3130 3136 nvlist_t *config, *props = NULL;
3131 3137
3132 3138 flags.dryrun = B_FALSE;
3133 3139 flags.import = B_FALSE;
3134 3140
3135 3141 /* check options */
3136 3142 while ((c = getopt(argc, argv, ":R:no:")) != -1) {
3137 3143 switch (c) {
3138 3144 case 'R':
3139 3145 flags.import = B_TRUE;
3140 3146 if (add_prop_list(
3141 3147 zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
3142 3148 &props, B_TRUE) != 0) {
3143 3149 if (props)
3144 3150 nvlist_free(props);
3145 3151 usage(B_FALSE);
3146 3152 }
3147 3153 break;
3148 3154 case 'n':
3149 3155 flags.dryrun = B_TRUE;
3150 3156 break;
3151 3157 case 'o':
3152 3158 if ((propval = strchr(optarg, '=')) != NULL) {
3153 3159 *propval = '\0';
3154 3160 propval++;
3155 3161 if (add_prop_list(optarg, propval,
3156 3162 &props, B_TRUE) != 0) {
3157 3163 if (props)
3158 3164 nvlist_free(props);
3159 3165 usage(B_FALSE);
3160 3166 }
3161 3167 } else {
3162 3168 mntopts = optarg;
3163 3169 }
3164 3170 break;
3165 3171 case ':':
3166 3172 (void) fprintf(stderr, gettext("missing argument for "
3167 3173 "'%c' option\n"), optopt);
3168 3174 usage(B_FALSE);
3169 3175 break;
3170 3176 case '?':
3171 3177 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3172 3178 optopt);
3173 3179 usage(B_FALSE);
3174 3180 break;
3175 3181 }
3176 3182 }
3177 3183
3178 3184 if (!flags.import && mntopts != NULL) {
3179 3185 (void) fprintf(stderr, gettext("setting mntopts is only "
3180 3186 "valid when importing the pool\n"));
3181 3187 usage(B_FALSE);
3182 3188 }
3183 3189
3184 3190 argc -= optind;
3185 3191 argv += optind;
3186 3192
3187 3193 if (argc < 1) {
3188 3194 (void) fprintf(stderr, gettext("Missing pool name\n"));
3189 3195 usage(B_FALSE);
3190 3196 }
3191 3197 if (argc < 2) {
3192 3198 (void) fprintf(stderr, gettext("Missing new pool name\n"));
3193 3199 usage(B_FALSE);
3194 3200 }
3195 3201
3196 3202 srcpool = argv[0];
3197 3203 newpool = argv[1];
3198 3204
3199 3205 argc -= 2;
3200 3206 argv += 2;
3201 3207
3202 3208 if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
3203 3209 return (1);
3204 3210
3205 3211 config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
3206 3212 if (config == NULL) {
3207 3213 ret = 1;
3208 3214 } else {
3209 3215 if (flags.dryrun) {
3210 3216 (void) printf(gettext("would create '%s' with the "
3211 3217 "following layout:\n\n"), newpool);
3212 3218 print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
3213 3219 }
3214 3220 nvlist_free(config);
3215 3221 }
3216 3222
3217 3223 zpool_close(zhp);
3218 3224
3219 3225 if (ret != 0 || flags.dryrun || !flags.import)
3220 3226 return (ret);
3221 3227
3222 3228 /*
3223 3229 * The split was successful. Now we need to open the new
3224 3230 * pool and import it.
3225 3231 */
3226 3232 if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
3227 3233 return (1);
3228 3234 if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
3229 3235 zpool_enable_datasets(zhp, mntopts, 0) != 0) {
3230 3236 ret = 1;
3231 3237 (void) fprintf(stderr, gettext("Split was succssful, but "
3232 3238 "the datasets could not all be mounted\n"));
3233 3239 (void) fprintf(stderr, gettext("Try doing '%s' with a "
3234 3240 "different altroot\n"), "zpool import");
3235 3241 }
3236 3242 zpool_close(zhp);
3237 3243
3238 3244 return (ret);
3239 3245 }
3240 3246
3241 3247
3242 3248
3243 3249 /*
3244 3250 * zpool online <pool> <device> ...
3245 3251 */
3246 3252 int
3247 3253 zpool_do_online(int argc, char **argv)
3248 3254 {
3249 3255 int c, i;
3250 3256 char *poolname;
3251 3257 zpool_handle_t *zhp;
3252 3258 int ret = 0;
3253 3259 vdev_state_t newstate;
3254 3260 int flags = 0;
3255 3261
3256 3262 /* check options */
3257 3263 while ((c = getopt(argc, argv, "et")) != -1) {
3258 3264 switch (c) {
3259 3265 case 'e':
3260 3266 flags |= ZFS_ONLINE_EXPAND;
3261 3267 break;
3262 3268 case 't':
3263 3269 case '?':
3264 3270 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3265 3271 optopt);
3266 3272 usage(B_FALSE);
3267 3273 }
3268 3274 }
3269 3275
3270 3276 argc -= optind;
3271 3277 argv += optind;
3272 3278
3273 3279 /* get pool name and check number of arguments */
3274 3280 if (argc < 1) {
3275 3281 (void) fprintf(stderr, gettext("missing pool name\n"));
3276 3282 usage(B_FALSE);
3277 3283 }
3278 3284 if (argc < 2) {
3279 3285 (void) fprintf(stderr, gettext("missing device name\n"));
3280 3286 usage(B_FALSE);
3281 3287 }
3282 3288
3283 3289 poolname = argv[0];
3284 3290
3285 3291 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3286 3292 return (1);
3287 3293
3288 3294 for (i = 1; i < argc; i++) {
3289 3295 if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
3290 3296 if (newstate != VDEV_STATE_HEALTHY) {
3291 3297 (void) printf(gettext("warning: device '%s' "
3292 3298 "onlined, but remains in faulted state\n"),
3293 3299 argv[i]);
3294 3300 if (newstate == VDEV_STATE_FAULTED)
3295 3301 (void) printf(gettext("use 'zpool "
3296 3302 "clear' to restore a faulted "
3297 3303 "device\n"));
3298 3304 else
3299 3305 (void) printf(gettext("use 'zpool "
3300 3306 "replace' to replace devices "
3301 3307 "that are no longer present\n"));
3302 3308 }
3303 3309 } else {
3304 3310 ret = 1;
3305 3311 }
3306 3312 }
3307 3313
3308 3314 zpool_close(zhp);
3309 3315
3310 3316 return (ret);
3311 3317 }
3312 3318
3313 3319 /*
3314 3320 * zpool offline [-ft] <pool> <device> ...
3315 3321 *
3316 3322 * -f Force the device into the offline state, even if doing
3317 3323 * so would appear to compromise pool availability.
3318 3324 * (not supported yet)
3319 3325 *
3320 3326 * -t Only take the device off-line temporarily. The offline
3321 3327 * state will not be persistent across reboots.
3322 3328 */
3323 3329 /* ARGSUSED */
3324 3330 int
3325 3331 zpool_do_offline(int argc, char **argv)
3326 3332 {
3327 3333 int c, i;
3328 3334 char *poolname;
3329 3335 zpool_handle_t *zhp;
3330 3336 int ret = 0;
3331 3337 boolean_t istmp = B_FALSE;
3332 3338
3333 3339 /* check options */
3334 3340 while ((c = getopt(argc, argv, "ft")) != -1) {
3335 3341 switch (c) {
3336 3342 case 't':
3337 3343 istmp = B_TRUE;
3338 3344 break;
3339 3345 case 'f':
3340 3346 case '?':
3341 3347 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3342 3348 optopt);
3343 3349 usage(B_FALSE);
3344 3350 }
3345 3351 }
3346 3352
3347 3353 argc -= optind;
3348 3354 argv += optind;
3349 3355
3350 3356 /* get pool name and check number of arguments */
3351 3357 if (argc < 1) {
3352 3358 (void) fprintf(stderr, gettext("missing pool name\n"));
3353 3359 usage(B_FALSE);
3354 3360 }
3355 3361 if (argc < 2) {
3356 3362 (void) fprintf(stderr, gettext("missing device name\n"));
3357 3363 usage(B_FALSE);
3358 3364 }
3359 3365
3360 3366 poolname = argv[0];
3361 3367
3362 3368 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3363 3369 return (1);
3364 3370
3365 3371 for (i = 1; i < argc; i++) {
3366 3372 if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
3367 3373 ret = 1;
3368 3374 }
3369 3375
3370 3376 zpool_close(zhp);
3371 3377
3372 3378 return (ret);
3373 3379 }
3374 3380
3375 3381 /*
3376 3382 * zpool clear <pool> [device]
3377 3383 *
3378 3384 * Clear all errors associated with a pool or a particular device.
3379 3385 */
3380 3386 int
3381 3387 zpool_do_clear(int argc, char **argv)
3382 3388 {
3383 3389 int c;
3384 3390 int ret = 0;
3385 3391 boolean_t dryrun = B_FALSE;
3386 3392 boolean_t do_rewind = B_FALSE;
3387 3393 boolean_t xtreme_rewind = B_FALSE;
3388 3394 uint32_t rewind_policy = ZPOOL_NO_REWIND;
3389 3395 nvlist_t *policy = NULL;
3390 3396 zpool_handle_t *zhp;
3391 3397 char *pool, *device;
3392 3398
3393 3399 /* check options */
3394 3400 while ((c = getopt(argc, argv, "FnX")) != -1) {
3395 3401 switch (c) {
3396 3402 case 'F':
3397 3403 do_rewind = B_TRUE;
3398 3404 break;
3399 3405 case 'n':
3400 3406 dryrun = B_TRUE;
3401 3407 break;
3402 3408 case 'X':
3403 3409 xtreme_rewind = B_TRUE;
3404 3410 break;
3405 3411 case '?':
3406 3412 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3407 3413 optopt);
3408 3414 usage(B_FALSE);
3409 3415 }
3410 3416 }
3411 3417
3412 3418 argc -= optind;
3413 3419 argv += optind;
3414 3420
3415 3421 if (argc < 1) {
3416 3422 (void) fprintf(stderr, gettext("missing pool name\n"));
3417 3423 usage(B_FALSE);
3418 3424 }
3419 3425
3420 3426 if (argc > 2) {
3421 3427 (void) fprintf(stderr, gettext("too many arguments\n"));
3422 3428 usage(B_FALSE);
3423 3429 }
3424 3430
3425 3431 if ((dryrun || xtreme_rewind) && !do_rewind) {
3426 3432 (void) fprintf(stderr,
3427 3433 gettext("-n or -X only meaningful with -F\n"));
3428 3434 usage(B_FALSE);
3429 3435 }
3430 3436 if (dryrun)
3431 3437 rewind_policy = ZPOOL_TRY_REWIND;
3432 3438 else if (do_rewind)
3433 3439 rewind_policy = ZPOOL_DO_REWIND;
3434 3440 if (xtreme_rewind)
3435 3441 rewind_policy |= ZPOOL_EXTREME_REWIND;
3436 3442
3437 3443 /* In future, further rewind policy choices can be passed along here */
3438 3444 if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
3439 3445 nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
3440 3446 return (1);
3441 3447
3442 3448 pool = argv[0];
3443 3449 device = argc == 2 ? argv[1] : NULL;
3444 3450
3445 3451 if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
3446 3452 nvlist_free(policy);
3447 3453 return (1);
3448 3454 }
3449 3455
3450 3456 if (zpool_clear(zhp, device, policy) != 0)
3451 3457 ret = 1;
3452 3458
3453 3459 zpool_close(zhp);
3454 3460
3455 3461 nvlist_free(policy);
3456 3462
3457 3463 return (ret);
3458 3464 }
3459 3465
3460 3466 /*
3461 3467 * zpool reguid <pool>
3462 3468 */
3463 3469 int
3464 3470 zpool_do_reguid(int argc, char **argv)
3465 3471 {
3466 3472 int c;
3467 3473 char *poolname;
3468 3474 zpool_handle_t *zhp;
3469 3475 int ret = 0;
3470 3476
3471 3477 /* check options */
3472 3478 while ((c = getopt(argc, argv, "")) != -1) {
3473 3479 switch (c) {
3474 3480 case '?':
3475 3481 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3476 3482 optopt);
3477 3483 usage(B_FALSE);
3478 3484 }
3479 3485 }
3480 3486
3481 3487 argc -= optind;
3482 3488 argv += optind;
3483 3489
3484 3490 /* get pool name and check number of arguments */
3485 3491 if (argc < 1) {
3486 3492 (void) fprintf(stderr, gettext("missing pool name\n"));
3487 3493 usage(B_FALSE);
3488 3494 }
3489 3495
3490 3496 if (argc > 1) {
3491 3497 (void) fprintf(stderr, gettext("too many arguments\n"));
3492 3498 usage(B_FALSE);
3493 3499 }
3494 3500
3495 3501 poolname = argv[0];
3496 3502 if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3497 3503 return (1);
3498 3504
3499 3505 ret = zpool_reguid(zhp);
3500 3506
3501 3507 zpool_close(zhp);
3502 3508 return (ret);
3503 3509 }
3504 3510
3505 3511
3506 3512 /*
3507 3513 * zpool reopen <pool>
3508 3514 *
3509 3515 * Reopen the pool so that the kernel can update the sizes of all vdevs.
3510 3516 *
3511 3517 * NOTE: This command is currently undocumented. If the command is ever
3512 3518 * exposed then the appropriate usage() messages will need to be made.
3513 3519 */
3514 3520 int
3515 3521 zpool_do_reopen(int argc, char **argv)
3516 3522 {
3517 3523 int ret = 0;
3518 3524 zpool_handle_t *zhp;
3519 3525 char *pool;
3520 3526
3521 3527 argc--;
3522 3528 argv++;
3523 3529
3524 3530 if (argc != 1)
3525 3531 return (2);
3526 3532
3527 3533 pool = argv[0];
3528 3534 if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
3529 3535 return (1);
3530 3536
3531 3537 ret = zpool_reopen(zhp);
3532 3538 zpool_close(zhp);
3533 3539 return (ret);
3534 3540 }
3535 3541
3536 3542 typedef struct scrub_cbdata {
3537 3543 int cb_type;
3538 3544 int cb_argc;
3539 3545 char **cb_argv;
3540 3546 } scrub_cbdata_t;
3541 3547
3542 3548 int
3543 3549 scrub_callback(zpool_handle_t *zhp, void *data)
3544 3550 {
3545 3551 scrub_cbdata_t *cb = data;
3546 3552 int err;
3547 3553
3548 3554 /*
3549 3555 * Ignore faulted pools.
3550 3556 */
3551 3557 if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
3552 3558 (void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
3553 3559 "currently unavailable\n"), zpool_get_name(zhp));
3554 3560 return (1);
3555 3561 }
3556 3562
3557 3563 err = zpool_scan(zhp, cb->cb_type);
3558 3564
3559 3565 return (err != 0);
3560 3566 }
3561 3567
3562 3568 /*
3563 3569 * zpool scrub [-s] <pool> ...
3564 3570 *
3565 3571 * -s Stop. Stops any in-progress scrub.
3566 3572 */
3567 3573 int
3568 3574 zpool_do_scrub(int argc, char **argv)
3569 3575 {
3570 3576 int c;
3571 3577 scrub_cbdata_t cb;
3572 3578
3573 3579 cb.cb_type = POOL_SCAN_SCRUB;
3574 3580
3575 3581 /* check options */
3576 3582 while ((c = getopt(argc, argv, "s")) != -1) {
3577 3583 switch (c) {
3578 3584 case 's':
3579 3585 cb.cb_type = POOL_SCAN_NONE;
3580 3586 break;
3581 3587 case '?':
3582 3588 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
3583 3589 optopt);
3584 3590 usage(B_FALSE);
3585 3591 }
3586 3592 }
3587 3593
3588 3594 cb.cb_argc = argc;
3589 3595 cb.cb_argv = argv;
3590 3596 argc -= optind;
3591 3597 argv += optind;
3592 3598
3593 3599 if (argc < 1) {
3594 3600 (void) fprintf(stderr, gettext("missing pool name argument\n"));
3595 3601 usage(B_FALSE);
3596 3602 }
3597 3603
3598 3604 return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
3599 3605 }
3600 3606
3601 3607 typedef struct status_cbdata {
3602 3608 int cb_count;
3603 3609 boolean_t cb_allpools;
3604 3610 boolean_t cb_verbose;
3605 3611 boolean_t cb_explain;
3606 3612 boolean_t cb_first;
3607 3613 boolean_t cb_dedup_stats;
3608 3614 } status_cbdata_t;
3609 3615
3610 3616 /*
3611 3617 * Print out detailed scrub status.
3612 3618 */
3613 3619 void
3614 3620 print_scan_status(pool_scan_stat_t *ps)
3615 3621 {
3616 3622 time_t start, end;
3617 3623 uint64_t elapsed, mins_left, hours_left;
3618 3624 uint64_t pass_exam, examined, total;
3619 3625 uint_t rate;
3620 3626 double fraction_done;
3621 3627 char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
3622 3628
3623 3629 (void) printf(gettext(" scan: "));
3624 3630
3625 3631 /* If there's never been a scan, there's not much to say. */
3626 3632 if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
3627 3633 ps->pss_func >= POOL_SCAN_FUNCS) {
3628 3634 (void) printf(gettext("none requested\n"));
3629 3635 return;
3630 3636 }
3631 3637
3632 3638 start = ps->pss_start_time;
3633 3639 end = ps->pss_end_time;
3634 3640 zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
3635 3641
3636 3642 assert(ps->pss_func == POOL_SCAN_SCRUB ||
3637 3643 ps->pss_func == POOL_SCAN_RESILVER);
3638 3644 /*
3639 3645 * Scan is finished or canceled.
3640 3646 */
3641 3647 if (ps->pss_state == DSS_FINISHED) {
3642 3648 uint64_t minutes_taken = (end - start) / 60;
3643 3649 char *fmt;
3644 3650
3645 3651 if (ps->pss_func == POOL_SCAN_SCRUB) {
3646 3652 fmt = gettext("scrub repaired %s in %lluh%um with "
3647 3653 "%llu errors on %s");
3648 3654 } else if (ps->pss_func == POOL_SCAN_RESILVER) {
3649 3655 fmt = gettext("resilvered %s in %lluh%um with "
3650 3656 "%llu errors on %s");
3651 3657 }
3652 3658 /* LINTED */
3653 3659 (void) printf(fmt, processed_buf,
3654 3660 (u_longlong_t)(minutes_taken / 60),
3655 3661 (uint_t)(minutes_taken % 60),
3656 3662 (u_longlong_t)ps->pss_errors,
3657 3663 ctime((time_t *)&end));
3658 3664 return;
3659 3665 } else if (ps->pss_state == DSS_CANCELED) {
3660 3666 if (ps->pss_func == POOL_SCAN_SCRUB) {
3661 3667 (void) printf(gettext("scrub canceled on %s"),
3662 3668 ctime(&end));
3663 3669 } else if (ps->pss_func == POOL_SCAN_RESILVER) {
3664 3670 (void) printf(gettext("resilver canceled on %s"),
3665 3671 ctime(&end));
3666 3672 }
3667 3673 return;
3668 3674 }
3669 3675
3670 3676 assert(ps->pss_state == DSS_SCANNING);
3671 3677
3672 3678 /*
3673 3679 * Scan is in progress.
3674 3680 */
3675 3681 if (ps->pss_func == POOL_SCAN_SCRUB) {
3676 3682 (void) printf(gettext("scrub in progress since %s"),
3677 3683 ctime(&start));
3678 3684 } else if (ps->pss_func == POOL_SCAN_RESILVER) {
3679 3685 (void) printf(gettext("resilver in progress since %s"),
3680 3686 ctime(&start));
3681 3687 }
3682 3688
3683 3689 examined = ps->pss_examined ? ps->pss_examined : 1;
3684 3690 total = ps->pss_to_examine;
3685 3691 fraction_done = (double)examined / total;
3686 3692
3687 3693 /* elapsed time for this pass */
3688 3694 elapsed = time(NULL) - ps->pss_pass_start;
3689 3695 elapsed = elapsed ? elapsed : 1;
3690 3696 pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
3691 3697 rate = pass_exam / elapsed;
3692 3698 rate = rate ? rate : 1;
3693 3699 mins_left = ((total - examined) / rate) / 60;
3694 3700 hours_left = mins_left / 60;
3695 3701
3696 3702 zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
3697 3703 zfs_nicenum(total, total_buf, sizeof (total_buf));
3698 3704 zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
3699 3705
3700 3706 /*
3701 3707 * do not print estimated time if hours_left is more than 30 days
3702 3708 */
3703 3709 (void) printf(gettext(" %s scanned out of %s at %s/s"),
3704 3710 examined_buf, total_buf, rate_buf);
3705 3711 if (hours_left < (30 * 24)) {
3706 3712 (void) printf(gettext(", %lluh%um to go\n"),
3707 3713 (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
3708 3714 } else {
3709 3715 (void) printf(gettext(
3710 3716 ", (scan is slow, no estimated time)\n"));
3711 3717 }
3712 3718
3713 3719 if (ps->pss_func == POOL_SCAN_RESILVER) {
3714 3720 (void) printf(gettext(" %s resilvered, %.2f%% done\n"),
3715 3721 processed_buf, 100 * fraction_done);
3716 3722 } else if (ps->pss_func == POOL_SCAN_SCRUB) {
3717 3723 (void) printf(gettext(" %s repaired, %.2f%% done\n"),
3718 3724 processed_buf, 100 * fraction_done);
3719 3725 }
3720 3726 }
3721 3727
3722 3728 static void
3723 3729 print_error_log(zpool_handle_t *zhp)
3724 3730 {
3725 3731 nvlist_t *nverrlist = NULL;
3726 3732 nvpair_t *elem;
3727 3733 char *pathname;
3728 3734 size_t len = MAXPATHLEN * 2;
3729 3735
3730 3736 if (zpool_get_errlog(zhp, &nverrlist) != 0) {
3731 3737 (void) printf("errors: List of errors unavailable "
3732 3738 "(insufficient privileges)\n");
3733 3739 return;
3734 3740 }
3735 3741
3736 3742 (void) printf("errors: Permanent errors have been "
3737 3743 "detected in the following files:\n\n");
3738 3744
3739 3745 pathname = safe_malloc(len);
3740 3746 elem = NULL;
3741 3747 while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
3742 3748 nvlist_t *nv;
3743 3749 uint64_t dsobj, obj;
3744 3750
3745 3751 verify(nvpair_value_nvlist(elem, &nv) == 0);
3746 3752 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
3747 3753 &dsobj) == 0);
3748 3754 verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
3749 3755 &obj) == 0);
3750 3756 zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
3751 3757 (void) printf("%7s %s\n", "", pathname);
3752 3758 }
3753 3759 free(pathname);
3754 3760 nvlist_free(nverrlist);
3755 3761 }
3756 3762
3757 3763 static void
3758 3764 print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
3759 3765 int namewidth)
3760 3766 {
3761 3767 uint_t i;
3762 3768 char *name;
3763 3769
3764 3770 if (nspares == 0)
3765 3771 return;
3766 3772
3767 3773 (void) printf(gettext("\tspares\n"));
3768 3774
3769 3775 for (i = 0; i < nspares; i++) {
3770 3776 name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
3771 3777 print_status_config(zhp, name, spares[i],
3772 3778 namewidth, 2, B_TRUE);
3773 3779 free(name);
3774 3780 }
3775 3781 }
3776 3782
3777 3783 static void
3778 3784 print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
3779 3785 int namewidth)
3780 3786 {
3781 3787 uint_t i;
3782 3788 char *name;
3783 3789
3784 3790 if (nl2cache == 0)
3785 3791 return;
3786 3792
3787 3793 (void) printf(gettext("\tcache\n"));
3788 3794
3789 3795 for (i = 0; i < nl2cache; i++) {
3790 3796 name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
3791 3797 print_status_config(zhp, name, l2cache[i],
3792 3798 namewidth, 2, B_FALSE);
3793 3799 free(name);
3794 3800 }
3795 3801 }
3796 3802
3797 3803 static void
3798 3804 print_dedup_stats(nvlist_t *config)
3799 3805 {
3800 3806 ddt_histogram_t *ddh;
3801 3807 ddt_stat_t *dds;
3802 3808 ddt_object_t *ddo;
3803 3809 uint_t c;
3804 3810
3805 3811 /*
3806 3812 * If the pool was faulted then we may not have been able to
3807 3813 * obtain the config. Otherwise, if we have anything in the dedup
3808 3814 * table continue processing the stats.
3809 3815 */
3810 3816 if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
3811 3817 (uint64_t **)&ddo, &c) != 0)
3812 3818 return;
3813 3819
3814 3820 (void) printf("\n");
3815 3821 (void) printf(gettext(" dedup: "));
3816 3822 if (ddo->ddo_count == 0) {
3817 3823 (void) printf(gettext("no DDT entries\n"));
3818 3824 return;
3819 3825 }
3820 3826
3821 3827 (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
3822 3828 (u_longlong_t)ddo->ddo_count,
3823 3829 (u_longlong_t)ddo->ddo_dspace,
3824 3830 (u_longlong_t)ddo->ddo_mspace);
3825 3831
3826 3832 verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
3827 3833 (uint64_t **)&dds, &c) == 0);
3828 3834 verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
3829 3835 (uint64_t **)&ddh, &c) == 0);
3830 3836 zpool_dump_ddt(dds, ddh);
3831 3837 }
3832 3838
3833 3839 /*
3834 3840 * Display a summary of pool status. Displays a summary such as:
3835 3841 *
3836 3842 * pool: tank
3837 3843 * status: DEGRADED
3838 3844 * reason: One or more devices ...
3839 3845 * see: http://illumos.org/msg/ZFS-xxxx-01
3840 3846 * config:
3841 3847 * mirror DEGRADED
3842 3848 * c1t0d0 OK
3843 3849 * c2t0d0 UNAVAIL
3844 3850 *
3845 3851 * When given the '-v' option, we print out the complete config. If the '-e'
3846 3852 * option is specified, then we print out error rate information as well.
3847 3853 */
3848 3854 int
3849 3855 status_callback(zpool_handle_t *zhp, void *data)
3850 3856 {
3851 3857 status_cbdata_t *cbp = data;
3852 3858 nvlist_t *config, *nvroot;
3853 3859 char *msgid;
3854 3860 int reason;
3855 3861 const char *health;
3856 3862 uint_t c;
3857 3863 vdev_stat_t *vs;
3858 3864
3859 3865 config = zpool_get_config(zhp, NULL);
3860 3866 reason = zpool_get_status(zhp, &msgid);
3861 3867
3862 3868 cbp->cb_count++;
3863 3869
3864 3870 /*
3865 3871 * If we were given 'zpool status -x', only report those pools with
3866 3872 * problems.
3867 3873 */
3868 3874 if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
3869 3875 if (!cbp->cb_allpools) {
3870 3876 (void) printf(gettext("pool '%s' is healthy\n"),
3871 3877 zpool_get_name(zhp));
3872 3878 if (cbp->cb_first)
3873 3879 cbp->cb_first = B_FALSE;
3874 3880 }
3875 3881 return (0);
3876 3882 }
3877 3883
3878 3884 if (cbp->cb_first)
3879 3885 cbp->cb_first = B_FALSE;
3880 3886 else
3881 3887 (void) printf("\n");
3882 3888
3883 3889 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
3884 3890 &nvroot) == 0);
3885 3891 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
3886 3892 (uint64_t **)&vs, &c) == 0);
3887 3893 health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3888 3894
3889 3895 (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp));
3890 3896 (void) printf(gettext(" state: %s\n"), health);
3891 3897
3892 3898 switch (reason) {
3893 3899 case ZPOOL_STATUS_MISSING_DEV_R:
3894 3900 (void) printf(gettext("status: One or more devices could not "
3895 3901 "be opened. Sufficient replicas exist for\n\tthe pool to "
3896 3902 "continue functioning in a degraded state.\n"));
3897 3903 (void) printf(gettext("action: Attach the missing device and "
3898 3904 "online it using 'zpool online'.\n"));
3899 3905 break;
3900 3906
3901 3907 case ZPOOL_STATUS_MISSING_DEV_NR:
3902 3908 (void) printf(gettext("status: One or more devices could not "
3903 3909 "be opened. There are insufficient\n\treplicas for the "
3904 3910 "pool to continue functioning.\n"));
3905 3911 (void) printf(gettext("action: Attach the missing device and "
3906 3912 "online it using 'zpool online'.\n"));
3907 3913 break;
3908 3914
3909 3915 case ZPOOL_STATUS_CORRUPT_LABEL_R:
3910 3916 (void) printf(gettext("status: One or more devices could not "
3911 3917 "be used because the label is missing or\n\tinvalid. "
3912 3918 "Sufficient replicas exist for the pool to continue\n\t"
3913 3919 "functioning in a degraded state.\n"));
3914 3920 (void) printf(gettext("action: Replace the device using "
3915 3921 "'zpool replace'.\n"));
3916 3922 break;
3917 3923
3918 3924 case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3919 3925 (void) printf(gettext("status: One or more devices could not "
3920 3926 "be used because the label is missing \n\tor invalid. "
3921 3927 "There are insufficient replicas for the pool to "
3922 3928 "continue\n\tfunctioning.\n"));
3923 3929 zpool_explain_recover(zpool_get_handle(zhp),
3924 3930 zpool_get_name(zhp), reason, config);
3925 3931 break;
3926 3932
3927 3933 case ZPOOL_STATUS_FAILING_DEV:
3928 3934 (void) printf(gettext("status: One or more devices has "
3929 3935 "experienced an unrecoverable error. An\n\tattempt was "
3930 3936 "made to correct the error. Applications are "
3931 3937 "unaffected.\n"));
3932 3938 (void) printf(gettext("action: Determine if the device needs "
3933 3939 "to be replaced, and clear the errors\n\tusing "
3934 3940 "'zpool clear' or replace the device with 'zpool "
3935 3941 "replace'.\n"));
3936 3942 break;
3937 3943
3938 3944 case ZPOOL_STATUS_OFFLINE_DEV:
3939 3945 (void) printf(gettext("status: One or more devices has "
3940 3946 "been taken offline by the administrator.\n\tSufficient "
3941 3947 "replicas exist for the pool to continue functioning in "
3942 3948 "a\n\tdegraded state.\n"));
3943 3949 (void) printf(gettext("action: Online the device using "
3944 3950 "'zpool online' or replace the device with\n\t'zpool "
3945 3951 "replace'.\n"));
3946 3952 break;
3947 3953
3948 3954 case ZPOOL_STATUS_REMOVED_DEV:
3949 3955 (void) printf(gettext("status: One or more devices has "
3950 3956 "been removed by the administrator.\n\tSufficient "
3951 3957 "replicas exist for the pool to continue functioning in "
3952 3958 "a\n\tdegraded state.\n"));
3953 3959 (void) printf(gettext("action: Online the device using "
3954 3960 "'zpool online' or replace the device with\n\t'zpool "
3955 3961 "replace'.\n"));
3956 3962 break;
3957 3963
3958 3964 case ZPOOL_STATUS_RESILVERING:
3959 3965 (void) printf(gettext("status: One or more devices is "
3960 3966 "currently being resilvered. The pool will\n\tcontinue "
3961 3967 "to function, possibly in a degraded state.\n"));
3962 3968 (void) printf(gettext("action: Wait for the resilver to "
3963 3969 "complete.\n"));
3964 3970 break;
3965 3971
3966 3972 case ZPOOL_STATUS_CORRUPT_DATA:
3967 3973 (void) printf(gettext("status: One or more devices has "
3968 3974 "experienced an error resulting in data\n\tcorruption. "
3969 3975 "Applications may be affected.\n"));
3970 3976 (void) printf(gettext("action: Restore the file in question "
3971 3977 "if possible. Otherwise restore the\n\tentire pool from "
3972 3978 "backup.\n"));
3973 3979 break;
3974 3980
3975 3981 case ZPOOL_STATUS_CORRUPT_POOL:
3976 3982 (void) printf(gettext("status: The pool metadata is corrupted "
3977 3983 "and the pool cannot be opened.\n"));
3978 3984 zpool_explain_recover(zpool_get_handle(zhp),
3979 3985 zpool_get_name(zhp), reason, config);
3980 3986 break;
3981 3987
3982 3988 case ZPOOL_STATUS_VERSION_OLDER:
3983 3989 (void) printf(gettext("status: The pool is formatted using an "
3984 3990 "older on-disk format. The pool can\n\tstill be used, but "
3985 3991 "some features are unavailable.\n"));
3986 3992 (void) printf(gettext("action: Upgrade the pool using 'zpool "
3987 3993 "upgrade'. Once this is done, the\n\tpool will no longer "
3988 3994 "be accessible on older software versions.\n"));
3989 3995 break;
3990 3996
3991 3997 case ZPOOL_STATUS_VERSION_NEWER:
3992 3998 (void) printf(gettext("status: The pool has been upgraded to a "
3993 3999 "newer, incompatible on-disk version.\n\tThe pool cannot "
3994 4000 "be accessed on this system.\n"));
3995 4001 (void) printf(gettext("action: Access the pool from a system "
3996 4002 "running more recent software, or\n\trestore the pool from "
3997 4003 "backup.\n"));
3998 4004 break;
3999 4005
4000 4006 case ZPOOL_STATUS_UNSUP_FEAT_READ:
4001 4007 (void) printf(gettext("status: The pool cannot be accessed on "
4002 4008 "this system because it uses the\n\tfollowing feature(s) "
4003 4009 "not supported on this system:\n"));
4004 4010 zpool_print_unsup_feat(config);
4005 4011 (void) printf("\n");
4006 4012 (void) printf(gettext("action: Access the pool from a system "
4007 4013 "that supports the required feature(s),\n\tor restore the "
4008 4014 "pool from backup.\n"));
4009 4015 break;
4010 4016
4011 4017 case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
4012 4018 (void) printf(gettext("status: The pool can only be accessed "
4013 4019 "in read-only mode on this system. It\n\tcannot be "
4014 4020 "accessed in read-write mode because it uses the "
4015 4021 "following\n\tfeature(s) not supported on this system:\n"));
4016 4022 zpool_print_unsup_feat(config);
4017 4023 (void) printf("\n");
4018 4024 (void) printf(gettext("action: The pool cannot be accessed in "
4019 4025 "read-write mode. Import the pool with\n"
4020 4026 "\t\"-o readonly=on\", access the pool from a system that "
4021 4027 "supports the\n\trequired feature(s), or restore the "
4022 4028 "pool from backup.\n"));
4023 4029 break;
4024 4030
4025 4031 case ZPOOL_STATUS_FAULTED_DEV_R:
4026 4032 (void) printf(gettext("status: One or more devices are "
4027 4033 "faulted in response to persistent errors.\n\tSufficient "
4028 4034 "replicas exist for the pool to continue functioning "
4029 4035 "in a\n\tdegraded state.\n"));
4030 4036 (void) printf(gettext("action: Replace the faulted device, "
4031 4037 "or use 'zpool clear' to mark the device\n\trepaired.\n"));
4032 4038 break;
4033 4039
4034 4040 case ZPOOL_STATUS_FAULTED_DEV_NR:
4035 4041 (void) printf(gettext("status: One or more devices are "
4036 4042 "faulted in response to persistent errors. There are "
4037 4043 "insufficient replicas for the pool to\n\tcontinue "
4038 4044 "functioning.\n"));
4039 4045 (void) printf(gettext("action: Destroy and re-create the pool "
4040 4046 "from a backup source. Manually marking the device\n"
4041 4047 "\trepaired using 'zpool clear' may allow some data "
4042 4048 "to be recovered.\n"));
4043 4049 break;
4044 4050
4045 4051 case ZPOOL_STATUS_IO_FAILURE_WAIT:
4046 4052 case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
4047 4053 (void) printf(gettext("status: One or more devices are "
4048 4054 "faulted in response to IO failures.\n"));
4049 4055 (void) printf(gettext("action: Make sure the affected devices "
4050 4056 "are connected, then run 'zpool clear'.\n"));
4051 4057 break;
4052 4058
4053 4059 case ZPOOL_STATUS_BAD_LOG:
4054 4060 (void) printf(gettext("status: An intent log record "
4055 4061 "could not be read.\n"
4056 4062 "\tWaiting for adminstrator intervention to fix the "
4057 4063 "faulted pool.\n"));
4058 4064 (void) printf(gettext("action: Either restore the affected "
4059 4065 "device(s) and run 'zpool online',\n"
4060 4066 "\tor ignore the intent log records by running "
4061 4067 "'zpool clear'.\n"));
4062 4068 break;
4063 4069
4064 4070 default:
4065 4071 /*
4066 4072 * The remaining errors can't actually be generated, yet.
4067 4073 */
4068 4074 assert(reason == ZPOOL_STATUS_OK);
4069 4075 }
4070 4076
4071 4077 if (msgid != NULL)
4072 4078 (void) printf(gettext(" see: http://illumos.org/msg/%s\n"),
4073 4079 msgid);
4074 4080
4075 4081 if (config != NULL) {
4076 4082 int namewidth;
4077 4083 uint64_t nerr;
4078 4084 nvlist_t **spares, **l2cache;
4079 4085 uint_t nspares, nl2cache;
4080 4086 pool_scan_stat_t *ps = NULL;
4081 4087
4082 4088 (void) nvlist_lookup_uint64_array(nvroot,
4083 4089 ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
4084 4090 print_scan_status(ps);
4085 4091
4086 4092 namewidth = max_width(zhp, nvroot, 0, 0);
4087 4093 if (namewidth < 10)
4088 4094 namewidth = 10;
4089 4095
4090 4096 (void) printf(gettext("config:\n\n"));
4091 4097 (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth,
4092 4098 "NAME", "STATE", "READ", "WRITE", "CKSUM");
4093 4099 print_status_config(zhp, zpool_get_name(zhp), nvroot,
4094 4100 namewidth, 0, B_FALSE);
4095 4101
4096 4102 if (num_logs(nvroot) > 0)
4097 4103 print_logs(zhp, nvroot, namewidth, B_TRUE);
4098 4104 if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
4099 4105 &l2cache, &nl2cache) == 0)
4100 4106 print_l2cache(zhp, l2cache, nl2cache, namewidth);
4101 4107
4102 4108 if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
4103 4109 &spares, &nspares) == 0)
4104 4110 print_spares(zhp, spares, nspares, namewidth);
4105 4111
4106 4112 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
4107 4113 &nerr) == 0) {
4108 4114 nvlist_t *nverrlist = NULL;
4109 4115
4110 4116 /*
4111 4117 * If the approximate error count is small, get a
4112 4118 * precise count by fetching the entire log and
4113 4119 * uniquifying the results.
4114 4120 */
4115 4121 if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
4116 4122 zpool_get_errlog(zhp, &nverrlist) == 0) {
4117 4123 nvpair_t *elem;
4118 4124
4119 4125 elem = NULL;
4120 4126 nerr = 0;
4121 4127 while ((elem = nvlist_next_nvpair(nverrlist,
4122 4128 elem)) != NULL) {
4123 4129 nerr++;
4124 4130 }
4125 4131 }
4126 4132 nvlist_free(nverrlist);
4127 4133
4128 4134 (void) printf("\n");
4129 4135
4130 4136 if (nerr == 0)
4131 4137 (void) printf(gettext("errors: No known data "
4132 4138 "errors\n"));
4133 4139 else if (!cbp->cb_verbose)
4134 4140 (void) printf(gettext("errors: %llu data "
4135 4141 "errors, use '-v' for a list\n"),
4136 4142 (u_longlong_t)nerr);
4137 4143 else
4138 4144 print_error_log(zhp);
4139 4145 }
4140 4146
4141 4147 if (cbp->cb_dedup_stats)
4142 4148 print_dedup_stats(config);
4143 4149 } else {
4144 4150 (void) printf(gettext("config: The configuration cannot be "
4145 4151 "determined.\n"));
4146 4152 }
4147 4153
4148 4154 return (0);
4149 4155 }
4150 4156
4151 4157 /*
4152 4158 * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
4153 4159 *
4154 4160 * -v Display complete error logs
4155 4161 * -x Display only pools with potential problems
4156 4162 * -D Display dedup status (undocumented)
4157 4163 * -T Display a timestamp in date(1) or Unix format
4158 4164 *
4159 4165 * Describes the health status of all pools or some subset.
4160 4166 */
4161 4167 int
4162 4168 zpool_do_status(int argc, char **argv)
4163 4169 {
4164 4170 int c;
4165 4171 int ret;
4166 4172 unsigned long interval = 0, count = 0;
4167 4173 status_cbdata_t cb = { 0 };
4168 4174
4169 4175 /* check options */
4170 4176 while ((c = getopt(argc, argv, "vxDT:")) != -1) {
4171 4177 switch (c) {
4172 4178 case 'v':
4173 4179 cb.cb_verbose = B_TRUE;
4174 4180 break;
4175 4181 case 'x':
4176 4182 cb.cb_explain = B_TRUE;
4177 4183 break;
4178 4184 case 'D':
4179 4185 cb.cb_dedup_stats = B_TRUE;
4180 4186 break;
4181 4187 case 'T':
4182 4188 get_timestamp_arg(*optarg);
4183 4189 break;
4184 4190 case '?':
4185 4191 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
4186 4192 optopt);
4187 4193 usage(B_FALSE);
4188 4194 }
4189 4195 }
4190 4196
4191 4197 argc -= optind;
4192 4198 argv += optind;
4193 4199
4194 4200 get_interval_count(&argc, argv, &interval, &count);
4195 4201
4196 4202 if (argc == 0)
4197 4203 cb.cb_allpools = B_TRUE;
4198 4204
4199 4205 cb.cb_first = B_TRUE;
4200 4206
4201 4207 for (;;) {
4202 4208 if (timestamp_fmt != NODATE)
4203 4209 print_timestamp(timestamp_fmt);
4204 4210
4205 4211 ret = for_each_pool(argc, argv, B_TRUE, NULL,
4206 4212 status_callback, &cb);
4207 4213
4208 4214 if (argc == 0 && cb.cb_count == 0)
4209 4215 (void) printf(gettext("no pools available\n"));
4210 4216 else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
4211 4217 (void) printf(gettext("all pools are healthy\n"));
4212 4218
4213 4219 if (ret != 0)
4214 4220 return (ret);
4215 4221
4216 4222 if (interval == 0)
4217 4223 break;
4218 4224
4219 4225 if (count != 0 && --count == 0)
4220 4226 break;
4221 4227
4222 4228 (void) sleep(interval);
4223 4229 }
4224 4230
4225 4231 return (0);
4226 4232 }
4227 4233
4228 4234 typedef struct upgrade_cbdata {
4229 4235 int cb_all;
4230 4236 int cb_first;
4231 4237 int cb_newer;
4232 4238 int cb_argc;
4233 4239 uint64_t cb_version;
4234 4240 char **cb_argv;
4235 4241 } upgrade_cbdata_t;
4236 4242
4237 4243 static int
4238 4244 upgrade_cb(zpool_handle_t *zhp, void *arg)
4239 4245 {
4240 4246 upgrade_cbdata_t *cbp = arg;
4241 4247 nvlist_t *config;
4242 4248 uint64_t version;
4243 4249 int ret = 0;
4244 4250
4245 4251 config = zpool_get_config(zhp, NULL);
4246 4252 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4247 4253 &version) == 0);
4248 4254
4249 4255 if (!cbp->cb_newer && SPA_VERSION_IS_SUPPORTED(version) &&
4250 4256 version != SPA_VERSION) {
4251 4257 if (!cbp->cb_all) {
4252 4258 if (cbp->cb_first) {
4253 4259 (void) printf(gettext("The following pools are "
4254 4260 "out of date, and can be upgraded. After "
4255 4261 "being\nupgraded, these pools will no "
4256 4262 "longer be accessible by older software "
4257 4263 "versions.\n\n"));
4258 4264 (void) printf(gettext("VER POOL\n"));
4259 4265 (void) printf(gettext("--- ------------\n"));
4260 4266 cbp->cb_first = B_FALSE;
4261 4267 }
↓ open down ↓ |
3246 lines elided |
↑ open up ↑ |
4262 4268
4263 4269 (void) printf("%2llu %s\n", (u_longlong_t)version,
4264 4270 zpool_get_name(zhp));
4265 4271 } else {
4266 4272 cbp->cb_first = B_FALSE;
4267 4273 ret = zpool_upgrade(zhp, cbp->cb_version);
4268 4274 if (!ret) {
4269 4275 (void) printf(gettext("Successfully upgraded "
4270 4276 "'%s'\n\n"), zpool_get_name(zhp));
4271 4277 }
4278 + /*
4279 + * If they did "zpool upgrade -a", then we could
4280 + * be doing ioctls to different pools. We need
4281 + * to log this history once to each pool, and bypass
4282 + * the normal history logging that happens in main().
4283 + */
4284 + (void) zpool_log_history(g_zfs, history_str);
4285 + log_history = B_FALSE;
4272 4286 }
4273 4287 } else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
4274 4288 assert(!cbp->cb_all);
4275 4289
4276 4290 if (cbp->cb_first) {
4277 4291 (void) printf(gettext("The following pools are "
4278 4292 "formatted using an unsupported software version "
4279 4293 "and\ncannot be accessed on the current "
4280 4294 "system.\n\n"));
4281 4295 (void) printf(gettext("VER POOL\n"));
4282 4296 (void) printf(gettext("--- ------------\n"));
4283 4297 cbp->cb_first = B_FALSE;
4284 4298 }
4285 4299
4286 4300 (void) printf("%2llu %s\n", (u_longlong_t)version,
4287 4301 zpool_get_name(zhp));
4288 4302 }
4289 4303
4290 4304 zpool_close(zhp);
4291 4305 return (ret);
4292 4306 }
4293 4307
4294 4308 /* ARGSUSED */
4295 4309 static int
4296 4310 upgrade_one(zpool_handle_t *zhp, void *data)
4297 4311 {
4298 4312 upgrade_cbdata_t *cbp = data;
4299 4313 uint64_t cur_version;
4300 4314 int ret;
4301 4315
4302 4316 if (strcmp("log", zpool_get_name(zhp)) == 0) {
4303 4317 (void) printf(gettext("'log' is now a reserved word\n"
4304 4318 "Pool 'log' must be renamed using export and import"
4305 4319 " to upgrade.\n"));
4306 4320 return (1);
4307 4321 }
4308 4322
4309 4323 cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
4310 4324 if (cur_version > cbp->cb_version) {
4311 4325 (void) printf(gettext("Pool '%s' is already formatted "
4312 4326 "using more current version '%llu'.\n"),
4313 4327 zpool_get_name(zhp), cur_version);
4314 4328 return (0);
4315 4329 }
4316 4330 if (cur_version == cbp->cb_version) {
4317 4331 (void) printf(gettext("Pool '%s' is already formatted "
4318 4332 "using the current version.\n"), zpool_get_name(zhp));
4319 4333 return (0);
4320 4334 }
4321 4335
4322 4336 ret = zpool_upgrade(zhp, cbp->cb_version);
4323 4337
4324 4338 if (!ret) {
4325 4339 (void) printf(gettext("Successfully upgraded '%s' "
4326 4340 "from version %llu to version %llu\n\n"),
4327 4341 zpool_get_name(zhp), (u_longlong_t)cur_version,
4328 4342 (u_longlong_t)cbp->cb_version);
4329 4343 }
4330 4344
4331 4345 return (ret != 0);
4332 4346 }
4333 4347
4334 4348 /*
4335 4349 * zpool upgrade
4336 4350 * zpool upgrade -v
4337 4351 * zpool upgrade [-V version] <-a | pool ...>
4338 4352 *
4339 4353 * With no arguments, display downrev'd ZFS pool available for upgrade.
4340 4354 * Individual pools can be upgraded by specifying the pool, and '-a' will
4341 4355 * upgrade all pools.
4342 4356 */
4343 4357 int
4344 4358 zpool_do_upgrade(int argc, char **argv)
4345 4359 {
4346 4360 int c;
4347 4361 upgrade_cbdata_t cb = { 0 };
4348 4362 int ret = 0;
4349 4363 boolean_t showversions = B_FALSE;
4350 4364 char *end;
4351 4365
4352 4366
4353 4367 /* check options */
4354 4368 while ((c = getopt(argc, argv, ":avV:")) != -1) {
4355 4369 switch (c) {
4356 4370 case 'a':
4357 4371 cb.cb_all = B_TRUE;
4358 4372 break;
4359 4373 case 'v':
4360 4374 showversions = B_TRUE;
4361 4375 break;
4362 4376 case 'V':
4363 4377 cb.cb_version = strtoll(optarg, &end, 10);
4364 4378 if (*end != '\0' ||
4365 4379 !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
4366 4380 (void) fprintf(stderr,
4367 4381 gettext("invalid version '%s'\n"), optarg);
4368 4382 usage(B_FALSE);
4369 4383 }
4370 4384 break;
4371 4385 case ':':
4372 4386 (void) fprintf(stderr, gettext("missing argument for "
4373 4387 "'%c' option\n"), optopt);
4374 4388 usage(B_FALSE);
4375 4389 break;
4376 4390 case '?':
4377 4391 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
4378 4392 optopt);
4379 4393 usage(B_FALSE);
4380 4394 }
4381 4395 }
4382 4396
4383 4397 cb.cb_argc = argc;
4384 4398 cb.cb_argv = argv;
4385 4399 argc -= optind;
4386 4400 argv += optind;
4387 4401
4388 4402 if (cb.cb_version == 0) {
4389 4403 cb.cb_version = SPA_VERSION;
4390 4404 } else if (!cb.cb_all && argc == 0) {
4391 4405 (void) fprintf(stderr, gettext("-V option is "
4392 4406 "incompatible with other arguments\n"));
4393 4407 usage(B_FALSE);
4394 4408 }
4395 4409
4396 4410 if (showversions) {
4397 4411 if (cb.cb_all || argc != 0) {
4398 4412 (void) fprintf(stderr, gettext("-v option is "
4399 4413 "incompatible with other arguments\n"));
4400 4414 usage(B_FALSE);
4401 4415 }
4402 4416 } else if (cb.cb_all) {
4403 4417 if (argc != 0) {
4404 4418 (void) fprintf(stderr, gettext("-a option should not "
4405 4419 "be used along with a pool name\n"));
4406 4420 usage(B_FALSE);
4407 4421 }
4408 4422 }
4409 4423
4410 4424 (void) printf(gettext("This system supports ZFS pool feature "
4411 4425 "flags.\n\n"));
4412 4426 cb.cb_first = B_TRUE;
4413 4427 if (showversions) {
4414 4428 (void) printf(gettext("The following versions are "
4415 4429 "supported:\n\n"));
4416 4430 (void) printf(gettext("VER DESCRIPTION\n"));
4417 4431 (void) printf("--- -----------------------------------------"
4418 4432 "---------------\n");
4419 4433 (void) printf(gettext(" 1 Initial ZFS version\n"));
4420 4434 (void) printf(gettext(" 2 Ditto blocks "
4421 4435 "(replicated metadata)\n"));
4422 4436 (void) printf(gettext(" 3 Hot spares and double parity "
4423 4437 "RAID-Z\n"));
4424 4438 (void) printf(gettext(" 4 zpool history\n"));
4425 4439 (void) printf(gettext(" 5 Compression using the gzip "
4426 4440 "algorithm\n"));
4427 4441 (void) printf(gettext(" 6 bootfs pool property\n"));
4428 4442 (void) printf(gettext(" 7 Separate intent log devices\n"));
4429 4443 (void) printf(gettext(" 8 Delegated administration\n"));
4430 4444 (void) printf(gettext(" 9 refquota and refreservation "
4431 4445 "properties\n"));
4432 4446 (void) printf(gettext(" 10 Cache devices\n"));
4433 4447 (void) printf(gettext(" 11 Improved scrub performance\n"));
4434 4448 (void) printf(gettext(" 12 Snapshot properties\n"));
4435 4449 (void) printf(gettext(" 13 snapused property\n"));
4436 4450 (void) printf(gettext(" 14 passthrough-x aclinherit\n"));
4437 4451 (void) printf(gettext(" 15 user/group space accounting\n"));
4438 4452 (void) printf(gettext(" 16 stmf property support\n"));
4439 4453 (void) printf(gettext(" 17 Triple-parity RAID-Z\n"));
4440 4454 (void) printf(gettext(" 18 Snapshot user holds\n"));
4441 4455 (void) printf(gettext(" 19 Log device removal\n"));
4442 4456 (void) printf(gettext(" 20 Compression using zle "
4443 4457 "(zero-length encoding)\n"));
4444 4458 (void) printf(gettext(" 21 Deduplication\n"));
4445 4459 (void) printf(gettext(" 22 Received properties\n"));
4446 4460 (void) printf(gettext(" 23 Slim ZIL\n"));
4447 4461 (void) printf(gettext(" 24 System attributes\n"));
4448 4462 (void) printf(gettext(" 25 Improved scrub stats\n"));
4449 4463 (void) printf(gettext(" 26 Improved snapshot deletion "
4450 4464 "performance\n"));
4451 4465 (void) printf(gettext(" 27 Improved snapshot creation "
4452 4466 "performance\n"));
4453 4467 (void) printf(gettext(" 28 Multiple vdev replacements\n"));
4454 4468 (void) printf(gettext("\nFor more information on a particular "
4455 4469 "version, including supported releases,\n"));
4456 4470 (void) printf(gettext("see the ZFS Administration Guide.\n\n"));
4457 4471 } else if (argc == 0) {
4458 4472 int notfound;
4459 4473
4460 4474 ret = zpool_iter(g_zfs, upgrade_cb, &cb);
4461 4475 notfound = cb.cb_first;
4462 4476
4463 4477 if (!cb.cb_all && ret == 0) {
4464 4478 if (!cb.cb_first)
4465 4479 (void) printf("\n");
4466 4480 cb.cb_first = B_TRUE;
4467 4481 cb.cb_newer = B_TRUE;
4468 4482 ret = zpool_iter(g_zfs, upgrade_cb, &cb);
4469 4483 if (!cb.cb_first) {
4470 4484 notfound = B_FALSE;
4471 4485 (void) printf("\n");
4472 4486 }
4473 4487 }
4474 4488
4475 4489 if (ret == 0) {
4476 4490 if (notfound)
4477 4491 (void) printf(gettext("All pools are formatted "
4478 4492 "using this version.\n"));
4479 4493 else if (!cb.cb_all)
4480 4494 (void) printf(gettext("Use 'zpool upgrade -v' "
4481 4495 "for a list of available versions and "
4482 4496 "their associated\nfeatures.\n"));
4483 4497 }
↓ open down ↓ |
202 lines elided |
↑ open up ↑ |
4484 4498 } else {
4485 4499 ret = for_each_pool(argc, argv, B_FALSE, NULL,
4486 4500 upgrade_one, &cb);
4487 4501 }
4488 4502
4489 4503 return (ret);
4490 4504 }
4491 4505
4492 4506 typedef struct hist_cbdata {
4493 4507 boolean_t first;
4494 - int longfmt;
4495 - int internal;
4508 + boolean_t longfmt;
4509 + boolean_t internal;
4496 4510 } hist_cbdata_t;
4497 4511
4498 4512 /*
4499 4513 * Print out the command history for a specific pool.
4500 4514 */
4501 4515 static int
4502 4516 get_history_one(zpool_handle_t *zhp, void *data)
4503 4517 {
4504 4518 nvlist_t *nvhis;
4505 4519 nvlist_t **records;
4506 4520 uint_t numrecords;
4507 - char *cmdstr;
4508 - char *pathstr;
4509 - uint64_t dst_time;
4510 - time_t tsec;
4511 - struct tm t;
4512 - char tbuf[30];
4513 4521 int ret, i;
4514 - uint64_t who;
4515 - struct passwd *pwd;
4516 - char *hostname;
4517 - char *zonename;
4518 - char internalstr[MAXPATHLEN];
4519 4522 hist_cbdata_t *cb = (hist_cbdata_t *)data;
4520 - uint64_t txg;
4521 - uint64_t ievent;
4522 4523
4523 4524 cb->first = B_FALSE;
4524 4525
4525 4526 (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
4526 4527
4527 4528 if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
4528 4529 return (ret);
4529 4530
4530 4531 verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
4531 4532 &records, &numrecords) == 0);
4532 4533 for (i = 0; i < numrecords; i++) {
4533 - if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
4534 - &dst_time) != 0)
4535 - continue;
4534 + nvlist_t *rec = records[i];
4535 + char tbuf[30] = "";
4536 4536
4537 - /* is it an internal event or a standard event? */
4538 - if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
4539 - &cmdstr) != 0) {
4540 - if (cb->internal == 0)
4537 + if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
4538 + time_t tsec;
4539 + struct tm t;
4540 +
4541 + tsec = fnvlist_lookup_uint64(records[i],
4542 + ZPOOL_HIST_TIME);
4543 + (void) localtime_r(&tsec, &t);
4544 + (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
4545 + }
4546 +
4547 + if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
4548 + (void) printf("%s %s", tbuf,
4549 + fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
4550 + } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
4551 + int ievent =
4552 + fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
4553 + if (!cb->internal)
4541 4554 continue;
4542 -
4543 - if (nvlist_lookup_uint64(records[i],
4544 - ZPOOL_HIST_INT_EVENT, &ievent) != 0)
4555 + if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
4556 + (void) printf("%s unrecognized record:\n",
4557 + tbuf);
4558 + dump_nvlist(rec, 4);
4559 + continue;
4560 + }
4561 + (void) printf("%s [internal %s txg:%lld] %s", tbuf,
4562 + zfs_history_event_names[ievent],
4563 + fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
4564 + fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
4565 + } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
4566 + if (!cb->internal)
4545 4567 continue;
4546 - verify(nvlist_lookup_uint64(records[i],
4547 - ZPOOL_HIST_TXG, &txg) == 0);
4548 - verify(nvlist_lookup_string(records[i],
4549 - ZPOOL_HIST_INT_STR, &pathstr) == 0);
4550 - if (ievent >= LOG_END)
4568 + (void) printf("%s [txg:%lld] %s", tbuf,
4569 + fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
4570 + fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
4571 + if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
4572 + (void) printf(" %s (%llu)",
4573 + fnvlist_lookup_string(rec,
4574 + ZPOOL_HIST_DSNAME),
4575 + fnvlist_lookup_uint64(rec,
4576 + ZPOOL_HIST_DSID));
4577 + }
4578 + (void) printf(" %s", fnvlist_lookup_string(rec,
4579 + ZPOOL_HIST_INT_STR));
4580 + } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
4581 + if (!cb->internal)
4551 4582 continue;
4552 - (void) snprintf(internalstr,
4553 - sizeof (internalstr),
4554 - "[internal %s txg:%lld] %s",
4555 - zfs_history_event_names[ievent], txg,
4556 - pathstr);
4557 - cmdstr = internalstr;
4558 - }
4559 - tsec = dst_time;
4560 - (void) localtime_r(&tsec, &t);
4561 - (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
4562 - (void) printf("%s %s", tbuf, cmdstr);
4583 + (void) printf("%s ioctl %s\n", tbuf,
4584 + fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
4585 + if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
4586 + (void) printf(" input:\n");
4587 + dump_nvlist(fnvlist_lookup_nvlist(rec,
4588 + ZPOOL_HIST_INPUT_NVL), 8);
4589 + }
4590 + if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
4591 + (void) printf(" output:\n");
4592 + dump_nvlist(fnvlist_lookup_nvlist(rec,
4593 + ZPOOL_HIST_OUTPUT_NVL), 8);
4594 + }
4595 + } else {
4596 + if (!cb->internal)
4597 + continue;
4598 + (void) printf("%s unrecognized record:\n", tbuf);
4599 + dump_nvlist(rec, 4);
4600 + }
4563 4601
4564 4602 if (!cb->longfmt) {
4565 4603 (void) printf("\n");
4566 4604 continue;
4567 4605 }
4568 4606 (void) printf(" [");
4569 - if (nvlist_lookup_uint64(records[i],
4570 - ZPOOL_HIST_WHO, &who) == 0) {
4571 - pwd = getpwuid((uid_t)who);
4572 - if (pwd)
4573 - (void) printf("user %s on",
4574 - pwd->pw_name);
4575 - else
4576 - (void) printf("user %d on",
4577 - (int)who);
4578 - } else {
4579 - (void) printf(gettext("no info]\n"));
4580 - continue;
4607 + if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
4608 + uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
4609 + struct passwd *pwd = getpwuid(who);
4610 + (void) printf("user %d ", (int)who);
4611 + if (pwd != NULL)
4612 + (void) printf("(%s) ", pwd->pw_name);
4613 + }
4614 + if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
4615 + (void) printf("on %s",
4616 + fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
4617 + }
4618 + if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
4619 + (void) printf(":%s",
4620 + fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
4581 4621 }
4582 - if (nvlist_lookup_string(records[i],
4583 - ZPOOL_HIST_HOST, &hostname) == 0) {
4584 - (void) printf(" %s", hostname);
4585 - }
4586 - if (nvlist_lookup_string(records[i],
4587 - ZPOOL_HIST_ZONE, &zonename) == 0) {
4588 - (void) printf(":%s", zonename);
4589 - }
4590 -
4591 4622 (void) printf("]");
4592 4623 (void) printf("\n");
4593 4624 }
4594 4625 (void) printf("\n");
4595 4626 nvlist_free(nvhis);
4596 4627
4597 4628 return (ret);
4598 4629 }
4599 4630
4600 4631 /*
4601 4632 * zpool history <pool>
4602 4633 *
4603 4634 * Displays the history of commands that modified pools.
4604 4635 */
4605 -
4606 -
4607 4636 int
4608 4637 zpool_do_history(int argc, char **argv)
4609 4638 {
4610 4639 hist_cbdata_t cbdata = { 0 };
4611 4640 int ret;
4612 4641 int c;
4613 4642
4614 4643 cbdata.first = B_TRUE;
4615 4644 /* check options */
4616 4645 while ((c = getopt(argc, argv, "li")) != -1) {
4617 4646 switch (c) {
4618 4647 case 'l':
4619 - cbdata.longfmt = 1;
4648 + cbdata.longfmt = B_TRUE;
4620 4649 break;
4621 4650 case 'i':
4622 - cbdata.internal = 1;
4651 + cbdata.internal = B_TRUE;
4623 4652 break;
4624 4653 case '?':
4625 4654 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
4626 4655 optopt);
4627 4656 usage(B_FALSE);
4628 4657 }
4629 4658 }
4630 4659 argc -= optind;
4631 4660 argv += optind;
4632 4661
4633 4662 ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one,
4634 4663 &cbdata);
4635 4664
4636 4665 if (argc == 0 && cbdata.first == B_TRUE) {
4637 4666 (void) printf(gettext("no pools available\n"));
4638 4667 return (0);
4639 4668 }
4640 4669
4641 4670 return (ret);
4642 4671 }
4643 4672
4644 4673 static int
4645 4674 get_callback(zpool_handle_t *zhp, void *data)
4646 4675 {
4647 4676 zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
4648 4677 char value[MAXNAMELEN];
4649 4678 zprop_source_t srctype;
4650 4679 zprop_list_t *pl;
4651 4680
4652 4681 for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
4653 4682
4654 4683 /*
4655 4684 * Skip the special fake placeholder. This will also skip
4656 4685 * over the name property when 'all' is specified.
4657 4686 */
4658 4687 if (pl->pl_prop == ZPOOL_PROP_NAME &&
4659 4688 pl == cbp->cb_proplist)
4660 4689 continue;
4661 4690
4662 4691 if (pl->pl_prop == ZPROP_INVAL &&
4663 4692 (zpool_prop_feature(pl->pl_user_prop) ||
4664 4693 zpool_prop_unsupported(pl->pl_user_prop))) {
4665 4694 srctype = ZPROP_SRC_LOCAL;
4666 4695
4667 4696 if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
4668 4697 value, sizeof (value)) == 0) {
4669 4698 zprop_print_one_property(zpool_get_name(zhp),
4670 4699 cbp, pl->pl_user_prop, value, srctype,
4671 4700 NULL, NULL);
4672 4701 }
4673 4702 } else {
4674 4703 if (zpool_get_prop(zhp, pl->pl_prop, value,
4675 4704 sizeof (value), &srctype) != 0)
4676 4705 continue;
4677 4706
4678 4707 zprop_print_one_property(zpool_get_name(zhp), cbp,
4679 4708 zpool_prop_to_name(pl->pl_prop), value, srctype,
4680 4709 NULL, NULL);
4681 4710 }
4682 4711 }
4683 4712 return (0);
4684 4713 }
4685 4714
4686 4715 int
4687 4716 zpool_do_get(int argc, char **argv)
4688 4717 {
4689 4718 zprop_get_cbdata_t cb = { 0 };
4690 4719 zprop_list_t fake_name = { 0 };
4691 4720 int ret;
4692 4721
4693 4722 if (argc < 2) {
4694 4723 (void) fprintf(stderr, gettext("missing property "
4695 4724 "argument\n"));
4696 4725 usage(B_FALSE);
4697 4726 }
4698 4727
4699 4728 cb.cb_first = B_TRUE;
4700 4729 cb.cb_sources = ZPROP_SRC_ALL;
4701 4730 cb.cb_columns[0] = GET_COL_NAME;
4702 4731 cb.cb_columns[1] = GET_COL_PROPERTY;
4703 4732 cb.cb_columns[2] = GET_COL_VALUE;
4704 4733 cb.cb_columns[3] = GET_COL_SOURCE;
4705 4734 cb.cb_type = ZFS_TYPE_POOL;
4706 4735
4707 4736 if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
4708 4737 ZFS_TYPE_POOL) != 0)
4709 4738 usage(B_FALSE);
4710 4739
4711 4740 if (cb.cb_proplist != NULL) {
4712 4741 fake_name.pl_prop = ZPOOL_PROP_NAME;
4713 4742 fake_name.pl_width = strlen(gettext("NAME"));
4714 4743 fake_name.pl_next = cb.cb_proplist;
4715 4744 cb.cb_proplist = &fake_name;
4716 4745 }
4717 4746
4718 4747 ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
4719 4748 get_callback, &cb);
4720 4749
4721 4750 if (cb.cb_proplist == &fake_name)
4722 4751 zprop_free_list(fake_name.pl_next);
4723 4752 else
4724 4753 zprop_free_list(cb.cb_proplist);
4725 4754
4726 4755 return (ret);
4727 4756 }
4728 4757
4729 4758 typedef struct set_cbdata {
4730 4759 char *cb_propname;
4731 4760 char *cb_value;
4732 4761 boolean_t cb_any_successful;
4733 4762 } set_cbdata_t;
4734 4763
4735 4764 int
4736 4765 set_callback(zpool_handle_t *zhp, void *data)
4737 4766 {
4738 4767 int error;
4739 4768 set_cbdata_t *cb = (set_cbdata_t *)data;
4740 4769
4741 4770 error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
4742 4771
4743 4772 if (!error)
4744 4773 cb->cb_any_successful = B_TRUE;
4745 4774
4746 4775 return (error);
4747 4776 }
4748 4777
4749 4778 int
4750 4779 zpool_do_set(int argc, char **argv)
4751 4780 {
4752 4781 set_cbdata_t cb = { 0 };
4753 4782 int error;
4754 4783
4755 4784 if (argc > 1 && argv[1][0] == '-') {
4756 4785 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
4757 4786 argv[1][1]);
4758 4787 usage(B_FALSE);
4759 4788 }
4760 4789
4761 4790 if (argc < 2) {
4762 4791 (void) fprintf(stderr, gettext("missing property=value "
4763 4792 "argument\n"));
4764 4793 usage(B_FALSE);
4765 4794 }
4766 4795
4767 4796 if (argc < 3) {
4768 4797 (void) fprintf(stderr, gettext("missing pool name\n"));
4769 4798 usage(B_FALSE);
4770 4799 }
4771 4800
4772 4801 if (argc > 3) {
4773 4802 (void) fprintf(stderr, gettext("too many pool names\n"));
4774 4803 usage(B_FALSE);
4775 4804 }
4776 4805
4777 4806 cb.cb_propname = argv[1];
4778 4807 cb.cb_value = strchr(cb.cb_propname, '=');
4779 4808 if (cb.cb_value == NULL) {
4780 4809 (void) fprintf(stderr, gettext("missing value in "
4781 4810 "property=value argument\n"));
4782 4811 usage(B_FALSE);
4783 4812 }
4784 4813
4785 4814 *(cb.cb_value) = '\0';
4786 4815 cb.cb_value++;
4787 4816
4788 4817 error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
4789 4818 set_callback, &cb);
4790 4819
4791 4820 return (error);
4792 4821 }
4793 4822
4794 4823 static int
4795 4824 find_command_idx(char *command, int *idx)
4796 4825 {
4797 4826 int i;
4798 4827
4799 4828 for (i = 0; i < NCOMMAND; i++) {
4800 4829 if (command_table[i].name == NULL)
4801 4830 continue;
4802 4831
4803 4832 if (strcmp(command, command_table[i].name) == 0) {
4804 4833 *idx = i;
4805 4834 return (0);
4806 4835 }
4807 4836 }
4808 4837 return (1);
4809 4838 }
4810 4839
4811 4840 int
4812 4841 main(int argc, char **argv)
4813 4842 {
4814 4843 int ret;
4815 4844 int i;
4816 4845 char *cmdname;
4817 4846
4818 4847 (void) setlocale(LC_ALL, "");
4819 4848 (void) textdomain(TEXT_DOMAIN);
4820 4849
4821 4850 if ((g_zfs = libzfs_init()) == NULL) {
4822 4851 (void) fprintf(stderr, gettext("internal error: failed to "
4823 4852 "initialize ZFS library\n"));
4824 4853 return (1);
4825 4854 }
4826 4855
4827 4856 libzfs_print_on_error(g_zfs, B_TRUE);
4828 4857
4829 4858 opterr = 0;
4830 4859
4831 4860 /*
4832 4861 * Make sure the user has specified some command.
4833 4862 */
4834 4863 if (argc < 2) {
4835 4864 (void) fprintf(stderr, gettext("missing command\n"));
4836 4865 usage(B_FALSE);
↓ open down ↓ |
204 lines elided |
↑ open up ↑ |
4837 4866 }
4838 4867
4839 4868 cmdname = argv[1];
4840 4869
4841 4870 /*
4842 4871 * Special case '-?'
4843 4872 */
4844 4873 if (strcmp(cmdname, "-?") == 0)
4845 4874 usage(B_TRUE);
4846 4875
4847 - zpool_set_history_str("zpool", argc, argv, history_str);
4848 - verify(zpool_stage_history(g_zfs, history_str) == 0);
4876 + zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
4849 4877
4850 4878 /*
4851 4879 * Run the appropriate command.
4852 4880 */
4853 4881 if (find_command_idx(cmdname, &i) == 0) {
4854 4882 current_command = &command_table[i];
4855 4883 ret = command_table[i].func(argc - 1, argv + 1);
4856 4884 } else if (strchr(cmdname, '=')) {
4857 4885 verify(find_command_idx("set", &i) == 0);
4858 4886 current_command = &command_table[i];
4859 4887 ret = command_table[i].func(argc, argv);
4860 4888 } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
4861 4889 /*
4862 4890 * 'freeze' is a vile debugging abomination, so we treat
4863 4891 * it as such.
4864 4892 */
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
4865 4893 char buf[16384];
4866 4894 int fd = open(ZFS_DEV, O_RDWR);
4867 4895 (void) strcpy((void *)buf, argv[2]);
4868 4896 return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
4869 4897 } else {
4870 4898 (void) fprintf(stderr, gettext("unrecognized "
4871 4899 "command '%s'\n"), cmdname);
4872 4900 usage(B_FALSE);
4873 4901 }
4874 4902
4903 + if (ret == 0 && log_history)
4904 + (void) zpool_log_history(g_zfs, history_str);
4905 +
4875 4906 libzfs_fini(g_zfs);
4876 4907
4877 4908 /*
4878 4909 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4879 4910 * for the purposes of running ::findleaks.
4880 4911 */
4881 4912 if (getenv("ZFS_ABORT") != NULL) {
4882 4913 (void) printf("dumping core by request\n");
4883 4914 abort();
4884 4915 }
4885 4916
4886 4917 return (ret);
4887 4918 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX