1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <assert.h> 30 #include <ctype.h> 31 #include <errno.h> 32 #include <libgen.h> 33 #include <libintl.h> 34 #include <libuutil.h> 35 #include <locale.h> 36 #include <stddef.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <strings.h> 40 #include <unistd.h> 41 #include <fcntl.h> 42 #include <zone.h> 43 #include <sys/mkdev.h> 44 #include <sys/mntent.h> 45 #include <sys/mnttab.h> 46 #include <sys/mount.h> 47 #include <sys/stat.h> 48 49 #include <libzfs.h> 50 51 #include "zfs_iter.h" 52 #include "zfs_util.h" 53 54 libzfs_handle_t *g_zfs; 55 56 static FILE *mnttab_file; 57 58 static int zfs_do_clone(int argc, char **argv); 59 static int zfs_do_create(int argc, char **argv); 60 static int zfs_do_destroy(int argc, char **argv); 61 static int zfs_do_get(int argc, char **argv); 62 static int zfs_do_inherit(int argc, char **argv); 63 static int zfs_do_list(int argc, char **argv); 64 static int zfs_do_mount(int argc, char **argv); 65 static int zfs_do_rename(int argc, char **argv); 66 static int zfs_do_rollback(int argc, char **argv); 67 static int zfs_do_set(int argc, char **argv); 68 static int zfs_do_snapshot(int argc, char **argv); 69 static int zfs_do_unmount(int argc, char **argv); 70 static int zfs_do_share(int argc, char **argv); 71 static int zfs_do_unshare(int argc, char **argv); 72 static int zfs_do_send(int argc, char **argv); 73 static int zfs_do_receive(int argc, char **argv); 74 static int zfs_do_promote(int argc, char **argv); 75 76 /* 77 * These libumem hooks provide a reasonable set of defaults for the allocator's 78 * debugging facilities. 79 */ 80 const char * 81 _umem_debug_init(void) 82 { 83 return ("default,verbose"); /* $UMEM_DEBUG setting */ 84 } 85 86 const char * 87 _umem_logging_init(void) 88 { 89 return ("fail,contents"); /* $UMEM_LOGGING setting */ 90 } 91 92 typedef enum { 93 HELP_CLONE, 94 HELP_CREATE, 95 HELP_DESTROY, 96 HELP_GET, 97 HELP_INHERIT, 98 HELP_LIST, 99 HELP_MOUNT, 100 HELP_PROMOTE, 101 HELP_RECEIVE, 102 HELP_RENAME, 103 HELP_ROLLBACK, 104 HELP_SEND, 105 HELP_SET, 106 HELP_SHARE, 107 HELP_SNAPSHOT, 108 HELP_UNMOUNT, 109 HELP_UNSHARE 110 } zfs_help_t; 111 112 typedef struct zfs_command { 113 const char *name; 114 int (*func)(int argc, char **argv); 115 zfs_help_t usage; 116 } zfs_command_t; 117 118 /* 119 * Master command table. Each ZFS command has a name, associated function, and 120 * usage message. The usage messages need to be internationalized, so we have 121 * to have a function to return the usage message based on a command index. 122 * 123 * These commands are organized according to how they are displayed in the usage 124 * message. An empty command (one with a NULL name) indicates an empty line in 125 * the generic usage message. 126 */ 127 static zfs_command_t command_table[] = { 128 { "create", zfs_do_create, HELP_CREATE }, 129 { "destroy", zfs_do_destroy, HELP_DESTROY }, 130 { NULL }, 131 { "snapshot", zfs_do_snapshot, HELP_SNAPSHOT }, 132 { "rollback", zfs_do_rollback, HELP_ROLLBACK }, 133 { "clone", zfs_do_clone, HELP_CLONE }, 134 { "promote", zfs_do_promote, HELP_PROMOTE }, 135 { "rename", zfs_do_rename, HELP_RENAME }, 136 { NULL }, 137 { "list", zfs_do_list, HELP_LIST }, 138 { NULL }, 139 { "set", zfs_do_set, HELP_SET }, 140 { "get", zfs_do_get, HELP_GET }, 141 { "inherit", zfs_do_inherit, HELP_INHERIT }, 142 { NULL }, 143 { "mount", zfs_do_mount, HELP_MOUNT }, 144 { NULL }, 145 { "unmount", zfs_do_unmount, HELP_UNMOUNT }, 146 { NULL }, 147 { "share", zfs_do_share, HELP_SHARE }, 148 { NULL }, 149 { "unshare", zfs_do_unshare, HELP_UNSHARE }, 150 { NULL }, 151 { "send", zfs_do_send, HELP_SEND }, 152 { "receive", zfs_do_receive, HELP_RECEIVE }, 153 }; 154 155 #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 156 157 zfs_command_t *current_command; 158 159 static const char * 160 get_usage(zfs_help_t idx) 161 { 162 switch (idx) { 163 case HELP_CLONE: 164 return (gettext("\tclone <snapshot> <filesystem|volume>\n")); 165 case HELP_CREATE: 166 return (gettext("\tcreate [[-o property=value] ... ] " 167 "<filesystem>\n" 168 "\tcreate [-s] [-b blocksize] [[-o property=value] ...]\n" 169 "\t -V <size> <volume>\n")); 170 case HELP_DESTROY: 171 return (gettext("\tdestroy [-rRf] " 172 "<filesystem|volume|snapshot>\n")); 173 case HELP_GET: 174 return (gettext("\tget [-rHp] [-o field[,field]...] " 175 "[-s source[,source]...]\n" 176 "\t <all | property[,property]...> " 177 "[filesystem|volume|snapshot] ...\n")); 178 case HELP_INHERIT: 179 return (gettext("\tinherit [-r] <property> " 180 "<filesystem|volume> ...\n")); 181 case HELP_LIST: 182 return (gettext("\tlist [-rH] [-o property[,property]...] " 183 "[-t type[,type]...]\n" 184 "\t [-s property [-s property]...]" 185 " [-S property [-S property]...]\n" 186 "\t [filesystem|volume|snapshot] ...\n")); 187 case HELP_MOUNT: 188 return (gettext("\tmount\n" 189 "\tmount [-o opts] [-O] -a\n" 190 "\tmount [-o opts] [-O] <filesystem>\n")); 191 case HELP_PROMOTE: 192 return (gettext("\tpromote <clone filesystem>\n")); 193 case HELP_RECEIVE: 194 return (gettext("\treceive [-vnF] <filesystem|volume|" 195 "snapshot>\n" 196 "\treceive [-vnF] -d <filesystem>\n")); 197 case HELP_RENAME: 198 return (gettext("\trename <filesystem|volume|snapshot> " 199 "<filesystem|volume|snapshot>\n")); 200 case HELP_ROLLBACK: 201 return (gettext("\trollback [-rRf] <snapshot>\n")); 202 case HELP_SEND: 203 return (gettext("\tsend [-i <snapshot>] <snapshot>\n")); 204 case HELP_SET: 205 return (gettext("\tset <property=value> " 206 "<filesystem|volume> ...\n")); 207 case HELP_SHARE: 208 return (gettext("\tshare -a\n" 209 "\tshare <filesystem>\n")); 210 case HELP_SNAPSHOT: 211 return (gettext("\tsnapshot [-r] " 212 "<filesystem@name|volume@name>\n")); 213 case HELP_UNMOUNT: 214 return (gettext("\tunmount [-f] -a\n" 215 "\tunmount [-f] <filesystem|mountpoint>\n")); 216 case HELP_UNSHARE: 217 return (gettext("\tunshare [-f] -a\n" 218 "\tunshare [-f] <filesystem|mountpoint>\n")); 219 } 220 221 abort(); 222 /* NOTREACHED */ 223 } 224 225 /* 226 * Utility function to guarantee malloc() success. 227 */ 228 void * 229 safe_malloc(size_t size) 230 { 231 void *data; 232 233 if ((data = calloc(1, size)) == NULL) { 234 (void) fprintf(stderr, "internal error: out of memory\n"); 235 exit(1); 236 } 237 238 return (data); 239 } 240 241 /* 242 * Display usage message. If we're inside a command, display only the usage for 243 * that command. Otherwise, iterate over the entire command table and display 244 * a complete usage message. 245 */ 246 static void 247 usage(boolean_t requested) 248 { 249 int i; 250 boolean_t show_properties = B_FALSE; 251 FILE *fp = requested ? stdout : stderr; 252 253 if (current_command == NULL) { 254 255 (void) fprintf(fp, gettext("usage: zfs command args ...\n")); 256 (void) fprintf(fp, 257 gettext("where 'command' is one of the following:\n\n")); 258 259 for (i = 0; i < NCOMMAND; i++) { 260 if (command_table[i].name == NULL) 261 (void) fprintf(fp, "\n"); 262 else 263 (void) fprintf(fp, "%s", 264 get_usage(command_table[i].usage)); 265 } 266 267 (void) fprintf(fp, gettext("\nEach dataset is of the form: " 268 "pool/[dataset/]*dataset[@name]\n")); 269 } else { 270 (void) fprintf(fp, gettext("usage:\n")); 271 (void) fprintf(fp, "%s", get_usage(current_command->usage)); 272 } 273 274 if (current_command != NULL && 275 (strcmp(current_command->name, "set") == 0 || 276 strcmp(current_command->name, "get") == 0 || 277 strcmp(current_command->name, "inherit") == 0 || 278 strcmp(current_command->name, "list") == 0)) 279 show_properties = B_TRUE; 280 281 if (show_properties) { 282 283 (void) fprintf(fp, 284 gettext("\nThe following properties are supported:\n")); 285 286 (void) fprintf(fp, "\n\t%-13s %s %s %s\n\n", 287 "PROPERTY", "EDIT", "INHERIT", "VALUES"); 288 289 for (i = 0; i < ZFS_NPROP_VISIBLE; i++) { 290 (void) fprintf(fp, "\t%-13s ", zfs_prop_to_name(i)); 291 292 if (zfs_prop_readonly(i)) 293 (void) fprintf(fp, " NO "); 294 else 295 (void) fprintf(fp, " YES "); 296 297 if (zfs_prop_inheritable(i)) 298 (void) fprintf(fp, " YES "); 299 else 300 (void) fprintf(fp, " NO "); 301 302 if (zfs_prop_values(i) == NULL) 303 (void) fprintf(fp, "-\n"); 304 else 305 (void) fprintf(fp, "%s\n", zfs_prop_values(i)); 306 } 307 (void) fprintf(fp, gettext("\nSizes are specified in bytes " 308 "with standard units such as K, M, G, etc.\n")); 309 (void) fprintf(fp, gettext("\n\nUser-defined properties can " 310 "be specified by using a name containing a colon (:).\n")); 311 } else { 312 /* 313 * TRANSLATION NOTE: 314 * "zfs set|get" must not be localised this is the 315 * command name and arguments. 316 */ 317 (void) fprintf(fp, 318 gettext("\nFor the property list, run: zfs set|get\n")); 319 } 320 321 /* 322 * See comments at end of main(). 323 */ 324 if (getenv("ZFS_ABORT") != NULL) { 325 (void) printf("dumping core by request\n"); 326 abort(); 327 } 328 329 exit(requested ? 0 : 2); 330 } 331 332 /* 333 * zfs clone <fs, snap, vol> fs 334 * 335 * Given an existing dataset, create a writable copy whose initial contents 336 * are the same as the source. The newly created dataset maintains a 337 * dependency on the original; the original cannot be destroyed so long as 338 * the clone exists. 339 */ 340 static int 341 zfs_do_clone(int argc, char **argv) 342 { 343 zfs_handle_t *zhp; 344 int ret; 345 346 /* check options */ 347 if (argc > 1 && argv[1][0] == '-') { 348 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 349 argv[1][1]); 350 usage(B_FALSE); 351 } 352 353 /* check number of arguments */ 354 if (argc < 2) { 355 (void) fprintf(stderr, gettext("missing source dataset " 356 "argument\n")); 357 usage(B_FALSE); 358 } 359 if (argc < 3) { 360 (void) fprintf(stderr, gettext("missing target dataset " 361 "argument\n")); 362 usage(B_FALSE); 363 } 364 if (argc > 3) { 365 (void) fprintf(stderr, gettext("too many arguments\n")); 366 usage(B_FALSE); 367 } 368 369 /* open the source dataset */ 370 if ((zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_SNAPSHOT)) == NULL) 371 return (1); 372 373 /* pass to libzfs */ 374 ret = zfs_clone(zhp, argv[2], NULL); 375 376 /* create the mountpoint if necessary */ 377 if (ret == 0) { 378 zfs_handle_t *clone = zfs_open(g_zfs, argv[2], ZFS_TYPE_ANY); 379 if (clone != NULL) { 380 if ((ret = zfs_mount(clone, NULL, 0)) == 0) 381 ret = zfs_share(clone); 382 zfs_close(clone); 383 } 384 zpool_log_history(g_zfs, argc, argv, argv[2], B_FALSE, B_FALSE); 385 } 386 387 zfs_close(zhp); 388 389 return (ret == 0 ? 0 : 1); 390 } 391 392 /* 393 * zfs create [-o prop=value] ... fs 394 * zfs create [-s] [-b blocksize] [-o prop=value] ... -V vol size 395 * 396 * Create a new dataset. This command can be used to create filesystems 397 * and volumes. Snapshot creation is handled by 'zfs snapshot'. 398 * For volumes, the user must specify a size to be used. 399 * 400 * The '-s' flag applies only to volumes, and indicates that we should not try 401 * to set the reservation for this volume. By default we set a reservation 402 * equal to the size for any volume. 403 */ 404 static int 405 zfs_do_create(int argc, char **argv) 406 { 407 zfs_type_t type = ZFS_TYPE_FILESYSTEM; 408 zfs_handle_t *zhp = NULL; 409 uint64_t volsize; 410 int c; 411 boolean_t noreserve = B_FALSE; 412 int ret = 1; 413 nvlist_t *props = NULL; 414 uint64_t intval; 415 char *propname; 416 char *propval = NULL; 417 char *strval; 418 419 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 420 (void) fprintf(stderr, gettext("internal error: " 421 "out of memory\n")); 422 return (1); 423 } 424 425 /* check options */ 426 while ((c = getopt(argc, argv, ":V:b:so:")) != -1) { 427 switch (c) { 428 case 'V': 429 type = ZFS_TYPE_VOLUME; 430 if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) { 431 (void) fprintf(stderr, gettext("bad volume " 432 "size '%s': %s\n"), optarg, 433 libzfs_error_description(g_zfs)); 434 goto error; 435 } 436 437 if (nvlist_add_uint64(props, 438 zfs_prop_to_name(ZFS_PROP_VOLSIZE), 439 intval) != 0) { 440 (void) fprintf(stderr, gettext("internal " 441 "error: out of memory\n")); 442 goto error; 443 } 444 volsize = intval; 445 break; 446 case 'b': 447 if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) { 448 (void) fprintf(stderr, gettext("bad volume " 449 "block size '%s': %s\n"), optarg, 450 libzfs_error_description(g_zfs)); 451 goto error; 452 } 453 454 if (nvlist_add_uint64(props, 455 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 456 intval) != 0) { 457 (void) fprintf(stderr, gettext("internal " 458 "error: out of memory\n")); 459 goto error; 460 } 461 break; 462 case 'o': 463 propname = optarg; 464 if ((propval = strchr(propname, '=')) == NULL) { 465 (void) fprintf(stderr, gettext("missing " 466 "'=' for -o option\n")); 467 goto error; 468 } 469 *propval = '\0'; 470 propval++; 471 if (nvlist_lookup_string(props, propname, 472 &strval) == 0) { 473 (void) fprintf(stderr, gettext("property '%s' " 474 "specified multiple times\n"), propname); 475 goto error; 476 } 477 if (nvlist_add_string(props, propname, propval) != 0) { 478 (void) fprintf(stderr, gettext("internal " 479 "error: out of memory\n")); 480 goto error; 481 } 482 break; 483 case 's': 484 noreserve = B_TRUE; 485 break; 486 case ':': 487 (void) fprintf(stderr, gettext("missing size " 488 "argument\n")); 489 goto badusage; 490 break; 491 case '?': 492 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 493 optopt); 494 goto badusage; 495 } 496 } 497 498 if (noreserve && type != ZFS_TYPE_VOLUME) { 499 (void) fprintf(stderr, gettext("'-s' can only be used when " 500 "creating a volume\n")); 501 goto badusage; 502 } 503 504 argc -= optind; 505 argv += optind; 506 507 /* check number of arguments */ 508 if (argc == 0) { 509 (void) fprintf(stderr, gettext("missing %s argument\n"), 510 zfs_type_to_name(type)); 511 goto badusage; 512 } 513 if (argc > 1) { 514 (void) fprintf(stderr, gettext("too many arguments\n")); 515 goto badusage; 516 } 517 518 if (type == ZFS_TYPE_VOLUME && !noreserve && 519 nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_RESERVATION), 520 &strval) != 0) { 521 if (nvlist_add_uint64(props, 522 zfs_prop_to_name(ZFS_PROP_RESERVATION), 523 volsize) != 0) { 524 (void) fprintf(stderr, gettext("internal " 525 "error: out of memory\n")); 526 nvlist_free(props); 527 return (1); 528 } 529 } 530 531 /* pass to libzfs */ 532 if (zfs_create(g_zfs, argv[0], type, props) != 0) 533 goto error; 534 535 if (propval != NULL) 536 *(propval - 1) = '='; 537 zpool_log_history(g_zfs, argc + optind, argv - optind, argv[0], 538 B_FALSE, B_FALSE); 539 540 if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_ANY)) == NULL) 541 goto error; 542 543 /* 544 * Mount and/or share the new filesystem as appropriate. We provide a 545 * verbose error message to let the user know that their filesystem was 546 * in fact created, even if we failed to mount or share it. 547 */ 548 if (zfs_mount(zhp, NULL, 0) != 0) { 549 (void) fprintf(stderr, gettext("filesystem successfully " 550 "created, but not mounted\n")); 551 ret = 1; 552 } else if (zfs_share(zhp) != 0) { 553 (void) fprintf(stderr, gettext("filesystem successfully " 554 "created, but not shared\n")); 555 ret = 1; 556 } else { 557 ret = 0; 558 } 559 560 error: 561 if (zhp) 562 zfs_close(zhp); 563 nvlist_free(props); 564 return (ret); 565 badusage: 566 nvlist_free(props); 567 usage(B_FALSE); 568 return (2); 569 } 570 571 /* 572 * zfs destroy [-rf] <fs, snap, vol> 573 * 574 * -r Recursively destroy all children 575 * -R Recursively destroy all dependents, including clones 576 * -f Force unmounting of any dependents 577 * 578 * Destroys the given dataset. By default, it will unmount any filesystems, 579 * and refuse to destroy a dataset that has any dependents. A dependent can 580 * either be a child, or a clone of a child. 581 */ 582 typedef struct destroy_cbdata { 583 boolean_t cb_first; 584 int cb_force; 585 int cb_recurse; 586 int cb_error; 587 int cb_needforce; 588 int cb_doclones; 589 boolean_t cb_closezhp; 590 zfs_handle_t *cb_target; 591 char *cb_snapname; 592 } destroy_cbdata_t; 593 594 /* 595 * Check for any dependents based on the '-r' or '-R' flags. 596 */ 597 static int 598 destroy_check_dependent(zfs_handle_t *zhp, void *data) 599 { 600 destroy_cbdata_t *cbp = data; 601 const char *tname = zfs_get_name(cbp->cb_target); 602 const char *name = zfs_get_name(zhp); 603 604 if (strncmp(tname, name, strlen(tname)) == 0 && 605 (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) { 606 /* 607 * This is a direct descendant, not a clone somewhere else in 608 * the hierarchy. 609 */ 610 if (cbp->cb_recurse) 611 goto out; 612 613 if (cbp->cb_first) { 614 (void) fprintf(stderr, gettext("cannot destroy '%s': " 615 "%s has children\n"), 616 zfs_get_name(cbp->cb_target), 617 zfs_type_to_name(zfs_get_type(cbp->cb_target))); 618 (void) fprintf(stderr, gettext("use '-r' to destroy " 619 "the following datasets:\n")); 620 cbp->cb_first = B_FALSE; 621 cbp->cb_error = 1; 622 } 623 624 (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); 625 } else { 626 /* 627 * This is a clone. We only want to report this if the '-r' 628 * wasn't specified, or the target is a snapshot. 629 */ 630 if (!cbp->cb_recurse && 631 zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT) 632 goto out; 633 634 if (cbp->cb_first) { 635 (void) fprintf(stderr, gettext("cannot destroy '%s': " 636 "%s has dependent clones\n"), 637 zfs_get_name(cbp->cb_target), 638 zfs_type_to_name(zfs_get_type(cbp->cb_target))); 639 (void) fprintf(stderr, gettext("use '-R' to destroy " 640 "the following datasets:\n")); 641 cbp->cb_first = B_FALSE; 642 cbp->cb_error = 1; 643 } 644 645 (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); 646 } 647 648 out: 649 zfs_close(zhp); 650 return (0); 651 } 652 653 static int 654 destroy_callback(zfs_handle_t *zhp, void *data) 655 { 656 destroy_cbdata_t *cbp = data; 657 658 /* 659 * Ignore pools (which we've already flagged as an error before getting 660 * here. 661 */ 662 if (strchr(zfs_get_name(zhp), '/') == NULL && 663 zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { 664 zfs_close(zhp); 665 return (0); 666 } 667 668 /* 669 * Bail out on the first error. 670 */ 671 if (zfs_unmount(zhp, NULL, cbp->cb_force ? MS_FORCE : 0) != 0 || 672 zfs_destroy(zhp) != 0) { 673 zfs_close(zhp); 674 return (-1); 675 } 676 677 zfs_close(zhp); 678 return (0); 679 } 680 681 static int 682 destroy_snap_clones(zfs_handle_t *zhp, void *arg) 683 { 684 destroy_cbdata_t *cbp = arg; 685 char thissnap[MAXPATHLEN]; 686 zfs_handle_t *szhp; 687 boolean_t closezhp = cbp->cb_closezhp; 688 int rv; 689 690 (void) snprintf(thissnap, sizeof (thissnap), 691 "%s@%s", zfs_get_name(zhp), cbp->cb_snapname); 692 693 libzfs_print_on_error(g_zfs, B_FALSE); 694 szhp = zfs_open(g_zfs, thissnap, ZFS_TYPE_SNAPSHOT); 695 libzfs_print_on_error(g_zfs, B_TRUE); 696 if (szhp) { 697 /* 698 * Destroy any clones of this snapshot 699 */ 700 if (zfs_iter_dependents(szhp, B_FALSE, destroy_callback, 701 cbp) != 0) { 702 zfs_close(szhp); 703 if (closezhp) 704 zfs_close(zhp); 705 return (-1); 706 } 707 zfs_close(szhp); 708 } 709 710 cbp->cb_closezhp = B_TRUE; 711 rv = zfs_iter_filesystems(zhp, destroy_snap_clones, arg); 712 if (closezhp) 713 zfs_close(zhp); 714 return (rv); 715 } 716 717 static int 718 zfs_do_destroy(int argc, char **argv) 719 { 720 destroy_cbdata_t cb = { 0 }; 721 int c; 722 zfs_handle_t *zhp; 723 char *cp; 724 725 /* check options */ 726 while ((c = getopt(argc, argv, "frR")) != -1) { 727 switch (c) { 728 case 'f': 729 cb.cb_force = 1; 730 break; 731 case 'r': 732 cb.cb_recurse = 1; 733 break; 734 case 'R': 735 cb.cb_recurse = 1; 736 cb.cb_doclones = 1; 737 break; 738 case '?': 739 default: 740 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 741 optopt); 742 usage(B_FALSE); 743 } 744 } 745 746 argc -= optind; 747 argv += optind; 748 749 /* check number of arguments */ 750 if (argc == 0) { 751 (void) fprintf(stderr, gettext("missing path argument\n")); 752 usage(B_FALSE); 753 } 754 if (argc > 1) { 755 (void) fprintf(stderr, gettext("too many arguments\n")); 756 usage(B_FALSE); 757 } 758 759 /* 760 * If we are doing recursive destroy of a snapshot, then the 761 * named snapshot may not exist. Go straight to libzfs. 762 */ 763 if (cb.cb_recurse && (cp = strchr(argv[0], '@'))) { 764 int ret; 765 766 *cp = '\0'; 767 if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_ANY)) == NULL) 768 return (1); 769 *cp = '@'; 770 cp++; 771 772 if (cb.cb_doclones) { 773 cb.cb_snapname = cp; 774 if (destroy_snap_clones(zhp, &cb) != 0) { 775 zfs_close(zhp); 776 return (1); 777 } 778 } 779 780 ret = zfs_destroy_snaps(zhp, cp); 781 zfs_close(zhp); 782 if (ret) { 783 (void) fprintf(stderr, 784 gettext("no snapshots destroyed\n")); 785 } 786 return (ret != 0); 787 } 788 789 790 /* Open the given dataset */ 791 if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_ANY)) == NULL) 792 return (1); 793 794 cb.cb_target = zhp; 795 796 /* 797 * Perform an explicit check for pools before going any further. 798 */ 799 if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL && 800 zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { 801 (void) fprintf(stderr, gettext("cannot destroy '%s': " 802 "operation does not apply to pools\n"), 803 zfs_get_name(zhp)); 804 (void) fprintf(stderr, gettext("use 'zfs destroy -r " 805 "%s' to destroy all datasets in the pool\n"), 806 zfs_get_name(zhp)); 807 (void) fprintf(stderr, gettext("use 'zpool destroy %s' " 808 "to destroy the pool itself\n"), zfs_get_name(zhp)); 809 zfs_close(zhp); 810 return (1); 811 } 812 813 /* 814 * Check for any dependents and/or clones. 815 */ 816 cb.cb_first = B_TRUE; 817 if (!cb.cb_doclones && 818 zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent, 819 &cb) != 0) { 820 zfs_close(zhp); 821 return (1); 822 } 823 824 825 if (cb.cb_error || 826 zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) != 0) { 827 zfs_close(zhp); 828 return (1); 829 } 830 831 /* 832 * Do the real thing. The callback will close the handle regardless of 833 * whether it succeeds or not. 834 */ 835 if (destroy_callback(zhp, &cb) != 0) 836 return (1); 837 838 zpool_log_history(g_zfs, argc + optind, argv - optind, argv[0], 839 B_FALSE, B_FALSE); 840 841 return (0); 842 } 843 844 /* 845 * zfs get [-rHp] [-o field[,field]...] [-s source[,source]...] 846 * < all | property[,property]... > < fs | snap | vol > ... 847 * 848 * -r recurse over any child datasets 849 * -H scripted mode. Headers are stripped, and fields are separated 850 * by tabs instead of spaces. 851 * -o Set of fields to display. One of "name,property,value,source". 852 * Default is all four. 853 * -s Set of sources to allow. One of 854 * "local,default,inherited,temporary,none". Default is all 855 * five. 856 * -p Display values in parsable (literal) format. 857 * 858 * Prints properties for the given datasets. The user can control which 859 * columns to display as well as which property types to allow. 860 */ 861 typedef struct get_cbdata { 862 int cb_sources; 863 int cb_columns[4]; 864 int cb_colwidths[5]; 865 boolean_t cb_scripted; 866 boolean_t cb_literal; 867 boolean_t cb_first; 868 zfs_proplist_t *cb_proplist; 869 } get_cbdata_t; 870 871 #define GET_COL_NAME 1 872 #define GET_COL_PROPERTY 2 873 #define GET_COL_VALUE 3 874 #define GET_COL_SOURCE 4 875 876 /* 877 * Print the column headers for 'zfs get'. 878 */ 879 static void 880 print_get_headers(get_cbdata_t *cbp) 881 { 882 zfs_proplist_t *pl = cbp->cb_proplist; 883 int i; 884 char *title; 885 size_t len; 886 887 cbp->cb_first = B_FALSE; 888 if (cbp->cb_scripted) 889 return; 890 891 /* 892 * Start with the length of the column headers. 893 */ 894 cbp->cb_colwidths[GET_COL_NAME] = strlen(gettext("NAME")); 895 cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(gettext("PROPERTY")); 896 cbp->cb_colwidths[GET_COL_VALUE] = strlen(gettext("VALUE")); 897 cbp->cb_colwidths[GET_COL_SOURCE] = strlen(gettext("SOURCE")); 898 899 /* 900 * Go through and calculate the widths for each column. For the 901 * 'source' column, we kludge it up by taking the worst-case scenario of 902 * inheriting from the longest name. This is acceptable because in the 903 * majority of cases 'SOURCE' is the last column displayed, and we don't 904 * use the width anyway. Note that the 'VALUE' column can be oversized, 905 * if the name of the property is much longer the any values we find. 906 */ 907 for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 908 /* 909 * 'PROPERTY' column 910 */ 911 if (pl->pl_prop != ZFS_PROP_INVAL) { 912 len = strlen(zfs_prop_to_name(pl->pl_prop)); 913 if (len > cbp->cb_colwidths[GET_COL_PROPERTY]) 914 cbp->cb_colwidths[GET_COL_PROPERTY] = len; 915 } else { 916 len = strlen(pl->pl_user_prop); 917 if (len > cbp->cb_colwidths[GET_COL_PROPERTY]) 918 cbp->cb_colwidths[GET_COL_PROPERTY] = len; 919 } 920 921 /* 922 * 'VALUE' column 923 */ 924 if ((pl->pl_prop != ZFS_PROP_NAME || !pl->pl_all) && 925 pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE]) 926 cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width; 927 928 /* 929 * 'NAME' and 'SOURCE' columns 930 */ 931 if (pl->pl_prop == ZFS_PROP_NAME && 932 pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) { 933 cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width; 934 cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width + 935 strlen(gettext("inherited from")); 936 } 937 } 938 939 /* 940 * Now go through and print the headers. 941 */ 942 for (i = 0; i < 4; i++) { 943 switch (cbp->cb_columns[i]) { 944 case GET_COL_NAME: 945 title = gettext("NAME"); 946 break; 947 case GET_COL_PROPERTY: 948 title = gettext("PROPERTY"); 949 break; 950 case GET_COL_VALUE: 951 title = gettext("VALUE"); 952 break; 953 case GET_COL_SOURCE: 954 title = gettext("SOURCE"); 955 break; 956 default: 957 title = NULL; 958 } 959 960 if (title != NULL) { 961 if (i == 3 || cbp->cb_columns[i + 1] == 0) 962 (void) printf("%s", title); 963 else 964 (void) printf("%-*s ", 965 cbp->cb_colwidths[cbp->cb_columns[i]], 966 title); 967 } 968 } 969 (void) printf("\n"); 970 } 971 972 /* 973 * Display a single line of output, according to the settings in the callback 974 * structure. 975 */ 976 static void 977 print_one_property(zfs_handle_t *zhp, get_cbdata_t *cbp, const char *propname, 978 const char *value, zfs_source_t sourcetype, const char *source) 979 { 980 int i; 981 const char *str; 982 char buf[128]; 983 984 /* 985 * Ignore those source types that the user has chosen to ignore. 986 */ 987 if ((sourcetype & cbp->cb_sources) == 0) 988 return; 989 990 if (cbp->cb_first) 991 print_get_headers(cbp); 992 993 for (i = 0; i < 4; i++) { 994 switch (cbp->cb_columns[i]) { 995 case GET_COL_NAME: 996 str = zfs_get_name(zhp); 997 break; 998 999 case GET_COL_PROPERTY: 1000 str = propname; 1001 break; 1002 1003 case GET_COL_VALUE: 1004 str = value; 1005 break; 1006 1007 case GET_COL_SOURCE: 1008 switch (sourcetype) { 1009 case ZFS_SRC_NONE: 1010 str = "-"; 1011 break; 1012 1013 case ZFS_SRC_DEFAULT: 1014 str = "default"; 1015 break; 1016 1017 case ZFS_SRC_LOCAL: 1018 str = "local"; 1019 break; 1020 1021 case ZFS_SRC_TEMPORARY: 1022 str = "temporary"; 1023 break; 1024 1025 case ZFS_SRC_INHERITED: 1026 (void) snprintf(buf, sizeof (buf), 1027 "inherited from %s", source); 1028 str = buf; 1029 break; 1030 } 1031 break; 1032 1033 default: 1034 continue; 1035 } 1036 1037 if (cbp->cb_columns[i + 1] == 0) 1038 (void) printf("%s", str); 1039 else if (cbp->cb_scripted) 1040 (void) printf("%s\t", str); 1041 else 1042 (void) printf("%-*s ", 1043 cbp->cb_colwidths[cbp->cb_columns[i]], 1044 str); 1045 1046 } 1047 1048 (void) printf("\n"); 1049 } 1050 1051 /* 1052 * Invoked to display the properties for a single dataset. 1053 */ 1054 static int 1055 get_callback(zfs_handle_t *zhp, void *data) 1056 { 1057 char buf[ZFS_MAXPROPLEN]; 1058 zfs_source_t sourcetype; 1059 char source[ZFS_MAXNAMELEN]; 1060 get_cbdata_t *cbp = data; 1061 nvlist_t *userprop = zfs_get_user_props(zhp); 1062 zfs_proplist_t *pl = cbp->cb_proplist; 1063 nvlist_t *propval; 1064 char *strval; 1065 char *sourceval; 1066 1067 for (; pl != NULL; pl = pl->pl_next) { 1068 /* 1069 * Skip the special fake placeholder. This will also skip over 1070 * the name property when 'all' is specified. 1071 */ 1072 if (pl->pl_prop == ZFS_PROP_NAME && 1073 pl == cbp->cb_proplist) 1074 continue; 1075 1076 if (pl->pl_prop != ZFS_PROP_INVAL) { 1077 if (zfs_prop_get(zhp, pl->pl_prop, buf, 1078 sizeof (buf), &sourcetype, source, 1079 sizeof (source), 1080 cbp->cb_literal) != 0) { 1081 if (pl->pl_all) 1082 continue; 1083 sourcetype = ZFS_SRC_NONE; 1084 (void) strlcpy(buf, "-", sizeof (buf)); 1085 } 1086 1087 print_one_property(zhp, cbp, 1088 zfs_prop_to_name(pl->pl_prop), 1089 buf, sourcetype, source); 1090 } else { 1091 if (nvlist_lookup_nvlist(userprop, 1092 pl->pl_user_prop, &propval) != 0) { 1093 if (pl->pl_all) 1094 continue; 1095 sourcetype = ZFS_SRC_NONE; 1096 strval = "-"; 1097 } else { 1098 verify(nvlist_lookup_string(propval, 1099 ZFS_PROP_VALUE, &strval) == 0); 1100 verify(nvlist_lookup_string(propval, 1101 ZFS_PROP_SOURCE, &sourceval) == 0); 1102 1103 if (strcmp(sourceval, 1104 zfs_get_name(zhp)) == 0) { 1105 sourcetype = ZFS_SRC_LOCAL; 1106 } else { 1107 sourcetype = ZFS_SRC_INHERITED; 1108 (void) strlcpy(source, 1109 sourceval, sizeof (source)); 1110 } 1111 } 1112 1113 print_one_property(zhp, cbp, 1114 pl->pl_user_prop, strval, sourcetype, 1115 source); 1116 } 1117 } 1118 1119 return (0); 1120 } 1121 1122 static int 1123 zfs_do_get(int argc, char **argv) 1124 { 1125 get_cbdata_t cb = { 0 }; 1126 boolean_t recurse = B_FALSE; 1127 int i, c; 1128 char *value, *fields; 1129 int ret; 1130 zfs_proplist_t fake_name = { 0 }; 1131 1132 /* 1133 * Set up default columns and sources. 1134 */ 1135 cb.cb_sources = ZFS_SRC_ALL; 1136 cb.cb_columns[0] = GET_COL_NAME; 1137 cb.cb_columns[1] = GET_COL_PROPERTY; 1138 cb.cb_columns[2] = GET_COL_VALUE; 1139 cb.cb_columns[3] = GET_COL_SOURCE; 1140 1141 /* check options */ 1142 while ((c = getopt(argc, argv, ":o:s:rHp")) != -1) { 1143 switch (c) { 1144 case 'p': 1145 cb.cb_literal = B_TRUE; 1146 break; 1147 case 'r': 1148 recurse = B_TRUE; 1149 break; 1150 case 'H': 1151 cb.cb_scripted = B_TRUE; 1152 break; 1153 case ':': 1154 (void) fprintf(stderr, gettext("missing argument for " 1155 "'%c' option\n"), optopt); 1156 usage(B_FALSE); 1157 break; 1158 case 'o': 1159 /* 1160 * Process the set of columns to display. We zero out 1161 * the structure to give us a blank slate. 1162 */ 1163 bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 1164 i = 0; 1165 while (*optarg != '\0') { 1166 static char *col_subopts[] = 1167 { "name", "property", "value", "source", 1168 NULL }; 1169 1170 if (i == 4) { 1171 (void) fprintf(stderr, gettext("too " 1172 "many fields given to -o " 1173 "option\n")); 1174 usage(B_FALSE); 1175 } 1176 1177 switch (getsubopt(&optarg, col_subopts, 1178 &value)) { 1179 case 0: 1180 cb.cb_columns[i++] = GET_COL_NAME; 1181 break; 1182 case 1: 1183 cb.cb_columns[i++] = GET_COL_PROPERTY; 1184 break; 1185 case 2: 1186 cb.cb_columns[i++] = GET_COL_VALUE; 1187 break; 1188 case 3: 1189 cb.cb_columns[i++] = GET_COL_SOURCE; 1190 break; 1191 default: 1192 (void) fprintf(stderr, 1193 gettext("invalid column name " 1194 "'%s'\n"), value); 1195 usage(B_FALSE); 1196 } 1197 } 1198 break; 1199 1200 case 's': 1201 cb.cb_sources = 0; 1202 while (*optarg != '\0') { 1203 static char *source_subopts[] = { 1204 "local", "default", "inherited", 1205 "temporary", "none", NULL }; 1206 1207 switch (getsubopt(&optarg, source_subopts, 1208 &value)) { 1209 case 0: 1210 cb.cb_sources |= ZFS_SRC_LOCAL; 1211 break; 1212 case 1: 1213 cb.cb_sources |= ZFS_SRC_DEFAULT; 1214 break; 1215 case 2: 1216 cb.cb_sources |= ZFS_SRC_INHERITED; 1217 break; 1218 case 3: 1219 cb.cb_sources |= ZFS_SRC_TEMPORARY; 1220 break; 1221 case 4: 1222 cb.cb_sources |= ZFS_SRC_NONE; 1223 break; 1224 default: 1225 (void) fprintf(stderr, 1226 gettext("invalid source " 1227 "'%s'\n"), value); 1228 usage(B_FALSE); 1229 } 1230 } 1231 break; 1232 1233 case '?': 1234 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1235 optopt); 1236 usage(B_FALSE); 1237 } 1238 } 1239 1240 argc -= optind; 1241 argv += optind; 1242 1243 if (argc < 1) { 1244 (void) fprintf(stderr, gettext("missing property " 1245 "argument\n")); 1246 usage(B_FALSE); 1247 } 1248 1249 fields = argv[0]; 1250 1251 if (zfs_get_proplist(g_zfs, fields, &cb.cb_proplist) != 0) 1252 usage(B_FALSE); 1253 1254 argc--; 1255 argv++; 1256 1257 /* 1258 * As part of zfs_expand_proplist(), we keep track of the maximum column 1259 * width for each property. For the 'NAME' (and 'SOURCE') columns, we 1260 * need to know the maximum name length. However, the user likely did 1261 * not specify 'name' as one of the properties to fetch, so we need to 1262 * make sure we always include at least this property for 1263 * print_get_headers() to work properly. 1264 */ 1265 if (cb.cb_proplist != NULL) { 1266 fake_name.pl_prop = ZFS_PROP_NAME; 1267 fake_name.pl_width = strlen(gettext("NAME")); 1268 fake_name.pl_next = cb.cb_proplist; 1269 cb.cb_proplist = &fake_name; 1270 } 1271 1272 cb.cb_first = B_TRUE; 1273 1274 /* run for each object */ 1275 ret = zfs_for_each(argc, argv, recurse, ZFS_TYPE_ANY, NULL, 1276 &cb.cb_proplist, get_callback, &cb); 1277 1278 if (cb.cb_proplist == &fake_name) 1279 zfs_free_proplist(fake_name.pl_next); 1280 else 1281 zfs_free_proplist(cb.cb_proplist); 1282 1283 return (ret); 1284 } 1285 1286 /* 1287 * inherit [-r] <property> <fs|vol> ... 1288 * 1289 * -r Recurse over all children 1290 * 1291 * For each dataset specified on the command line, inherit the given property 1292 * from its parent. Inheriting a property at the pool level will cause it to 1293 * use the default value. The '-r' flag will recurse over all children, and is 1294 * useful for setting a property on a hierarchy-wide basis, regardless of any 1295 * local modifications for each dataset. 1296 */ 1297 typedef struct inherit_cbdata { 1298 char *cb_propname; 1299 boolean_t cb_any_successful; 1300 } inherit_cbdata_t; 1301 1302 static int 1303 inherit_callback(zfs_handle_t *zhp, void *data) 1304 { 1305 inherit_cbdata_t *cbp = data; 1306 int ret; 1307 1308 ret = zfs_prop_inherit(zhp, cbp->cb_propname); 1309 if (ret == 0) 1310 cbp->cb_any_successful = B_TRUE; 1311 return (ret != 0); 1312 } 1313 1314 static int 1315 zfs_do_inherit(int argc, char **argv) 1316 { 1317 boolean_t recurse = B_FALSE; 1318 int c; 1319 zfs_prop_t prop; 1320 inherit_cbdata_t cb; 1321 int ret; 1322 1323 /* check options */ 1324 while ((c = getopt(argc, argv, "r")) != -1) { 1325 switch (c) { 1326 case 'r': 1327 recurse = B_TRUE; 1328 break; 1329 case '?': 1330 default: 1331 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1332 optopt); 1333 usage(B_FALSE); 1334 } 1335 } 1336 1337 argc -= optind; 1338 argv += optind; 1339 1340 /* check number of arguments */ 1341 if (argc < 1) { 1342 (void) fprintf(stderr, gettext("missing property argument\n")); 1343 usage(B_FALSE); 1344 } 1345 if (argc < 2) { 1346 (void) fprintf(stderr, gettext("missing dataset argument\n")); 1347 usage(B_FALSE); 1348 } 1349 1350 cb.cb_propname = argv[0]; 1351 argc--; 1352 argv++; 1353 1354 if ((prop = zfs_name_to_prop(cb.cb_propname)) != ZFS_PROP_INVAL) { 1355 if (zfs_prop_readonly(prop)) { 1356 (void) fprintf(stderr, gettext( 1357 "%s property is read-only\n"), 1358 cb.cb_propname); 1359 return (1); 1360 } 1361 if (!zfs_prop_inheritable(prop)) { 1362 (void) fprintf(stderr, gettext("'%s' property cannot " 1363 "be inherited\n"), cb.cb_propname); 1364 if (prop == ZFS_PROP_QUOTA || 1365 prop == ZFS_PROP_RESERVATION) 1366 (void) fprintf(stderr, gettext("use 'zfs set " 1367 "%s=none' to clear\n"), cb.cb_propname); 1368 return (1); 1369 } 1370 } else if (!zfs_prop_user(cb.cb_propname)) { 1371 (void) fprintf(stderr, gettext( 1372 "invalid property '%s'\n"), 1373 cb.cb_propname); 1374 usage(B_FALSE); 1375 } 1376 1377 cb.cb_any_successful = B_FALSE; 1378 1379 ret = zfs_for_each(argc, argv, recurse, 1380 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, NULL, NULL, 1381 inherit_callback, &cb); 1382 1383 if (cb.cb_any_successful) { 1384 zpool_log_history(g_zfs, argc + optind + 1, argv - optind - 1, 1385 argv[0], B_FALSE, B_FALSE); 1386 } 1387 1388 return (ret); 1389 } 1390 1391 /* 1392 * list [-rH] [-o property[,property]...] [-t type[,type]...] 1393 * [-s property [-s property]...] [-S property [-S property]...] 1394 * <dataset> ... 1395 * 1396 * -r Recurse over all children 1397 * -H Scripted mode; elide headers and separate colums by tabs 1398 * -o Control which fields to display. 1399 * -t Control which object types to display. 1400 * -s Specify sort columns, descending order. 1401 * -S Specify sort columns, ascending order. 1402 * 1403 * When given no arguments, lists all filesystems in the system. 1404 * Otherwise, list the specified datasets, optionally recursing down them if 1405 * '-r' is specified. 1406 */ 1407 typedef struct list_cbdata { 1408 boolean_t cb_first; 1409 boolean_t cb_scripted; 1410 zfs_proplist_t *cb_proplist; 1411 } list_cbdata_t; 1412 1413 /* 1414 * Given a list of columns to display, output appropriate headers for each one. 1415 */ 1416 static void 1417 print_header(zfs_proplist_t *pl) 1418 { 1419 char headerbuf[ZFS_MAXPROPLEN]; 1420 const char *header; 1421 int i; 1422 boolean_t first = B_TRUE; 1423 boolean_t right_justify; 1424 1425 for (; pl != NULL; pl = pl->pl_next) { 1426 if (!first) { 1427 (void) printf(" "); 1428 } else { 1429 first = B_FALSE; 1430 } 1431 1432 right_justify = B_FALSE; 1433 if (pl->pl_prop != ZFS_PROP_INVAL) { 1434 header = zfs_prop_column_name(pl->pl_prop); 1435 right_justify = zfs_prop_align_right(pl->pl_prop); 1436 } else { 1437 for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 1438 headerbuf[i] = toupper(pl->pl_user_prop[i]); 1439 headerbuf[i] = '\0'; 1440 header = headerbuf; 1441 } 1442 1443 if (pl->pl_next == NULL && !right_justify) 1444 (void) printf("%s", header); 1445 else if (right_justify) 1446 (void) printf("%*s", pl->pl_width, header); 1447 else 1448 (void) printf("%-*s", pl->pl_width, header); 1449 } 1450 1451 (void) printf("\n"); 1452 } 1453 1454 /* 1455 * Given a dataset and a list of fields, print out all the properties according 1456 * to the described layout. 1457 */ 1458 static void 1459 print_dataset(zfs_handle_t *zhp, zfs_proplist_t *pl, int scripted) 1460 { 1461 boolean_t first = B_TRUE; 1462 char property[ZFS_MAXPROPLEN]; 1463 nvlist_t *userprops = zfs_get_user_props(zhp); 1464 nvlist_t *propval; 1465 char *propstr; 1466 boolean_t right_justify; 1467 int width; 1468 1469 for (; pl != NULL; pl = pl->pl_next) { 1470 if (!first) { 1471 if (scripted) 1472 (void) printf("\t"); 1473 else 1474 (void) printf(" "); 1475 } else { 1476 first = B_FALSE; 1477 } 1478 1479 right_justify = B_FALSE; 1480 if (pl->pl_prop != ZFS_PROP_INVAL) { 1481 if (zfs_prop_get(zhp, pl->pl_prop, property, 1482 sizeof (property), NULL, NULL, 0, B_FALSE) != 0) 1483 propstr = "-"; 1484 else 1485 propstr = property; 1486 1487 right_justify = zfs_prop_align_right(pl->pl_prop); 1488 } else { 1489 if (nvlist_lookup_nvlist(userprops, 1490 pl->pl_user_prop, &propval) != 0) 1491 propstr = "-"; 1492 else 1493 verify(nvlist_lookup_string(propval, 1494 ZFS_PROP_VALUE, &propstr) == 0); 1495 } 1496 1497 width = pl->pl_width; 1498 1499 /* 1500 * If this is being called in scripted mode, or if this is the 1501 * last column and it is left-justified, don't include a width 1502 * format specifier. 1503 */ 1504 if (scripted || (pl->pl_next == NULL && !right_justify)) 1505 (void) printf("%s", propstr); 1506 else if (right_justify) 1507 (void) printf("%*s", width, propstr); 1508 else 1509 (void) printf("%-*s", width, propstr); 1510 } 1511 1512 (void) printf("\n"); 1513 } 1514 1515 /* 1516 * Generic callback function to list a dataset or snapshot. 1517 */ 1518 static int 1519 list_callback(zfs_handle_t *zhp, void *data) 1520 { 1521 list_cbdata_t *cbp = data; 1522 1523 if (cbp->cb_first) { 1524 if (!cbp->cb_scripted) 1525 print_header(cbp->cb_proplist); 1526 cbp->cb_first = B_FALSE; 1527 } 1528 1529 print_dataset(zhp, cbp->cb_proplist, cbp->cb_scripted); 1530 1531 return (0); 1532 } 1533 1534 static int 1535 zfs_do_list(int argc, char **argv) 1536 { 1537 int c; 1538 boolean_t recurse = B_FALSE; 1539 boolean_t scripted = B_FALSE; 1540 static char default_fields[] = 1541 "name,used,available,referenced,mountpoint"; 1542 int types = ZFS_TYPE_ANY; 1543 char *fields = NULL; 1544 char *basic_fields = default_fields; 1545 list_cbdata_t cb = { 0 }; 1546 char *value; 1547 int ret; 1548 char *type_subopts[] = { "filesystem", "volume", "snapshot", NULL }; 1549 zfs_sort_column_t *sortcol = NULL; 1550 1551 /* check options */ 1552 while ((c = getopt(argc, argv, ":o:rt:Hs:S:")) != -1) { 1553 switch (c) { 1554 case 'o': 1555 fields = optarg; 1556 break; 1557 case 'r': 1558 recurse = B_TRUE; 1559 break; 1560 case 'H': 1561 scripted = B_TRUE; 1562 break; 1563 case 's': 1564 if (zfs_add_sort_column(&sortcol, optarg, 1565 B_FALSE) != 0) { 1566 (void) fprintf(stderr, 1567 gettext("invalid property '%s'\n"), optarg); 1568 usage(B_FALSE); 1569 } 1570 break; 1571 case 'S': 1572 if (zfs_add_sort_column(&sortcol, optarg, 1573 B_TRUE) != 0) { 1574 (void) fprintf(stderr, 1575 gettext("invalid property '%s'\n"), optarg); 1576 usage(B_FALSE); 1577 } 1578 break; 1579 case 't': 1580 types = 0; 1581 while (*optarg != '\0') { 1582 switch (getsubopt(&optarg, type_subopts, 1583 &value)) { 1584 case 0: 1585 types |= ZFS_TYPE_FILESYSTEM; 1586 break; 1587 case 1: 1588 types |= ZFS_TYPE_VOLUME; 1589 break; 1590 case 2: 1591 types |= ZFS_TYPE_SNAPSHOT; 1592 break; 1593 default: 1594 (void) fprintf(stderr, 1595 gettext("invalid type '%s'\n"), 1596 value); 1597 usage(B_FALSE); 1598 } 1599 } 1600 break; 1601 case ':': 1602 (void) fprintf(stderr, gettext("missing argument for " 1603 "'%c' option\n"), optopt); 1604 usage(B_FALSE); 1605 break; 1606 case '?': 1607 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1608 optopt); 1609 usage(B_FALSE); 1610 } 1611 } 1612 1613 argc -= optind; 1614 argv += optind; 1615 1616 if (fields == NULL) 1617 fields = basic_fields; 1618 1619 /* 1620 * If the user specifies '-o all', the zfs_get_proplist() doesn't 1621 * normally include the name of the dataset. For 'zfs list', we always 1622 * want this property to be first. 1623 */ 1624 if (zfs_get_proplist(g_zfs, fields, &cb.cb_proplist) != 0) 1625 usage(B_FALSE); 1626 1627 cb.cb_scripted = scripted; 1628 cb.cb_first = B_TRUE; 1629 1630 ret = zfs_for_each(argc, argv, recurse, types, sortcol, &cb.cb_proplist, 1631 list_callback, &cb); 1632 1633 zfs_free_proplist(cb.cb_proplist); 1634 zfs_free_sort_columns(sortcol); 1635 1636 if (ret == 0 && cb.cb_first) 1637 (void) printf(gettext("no datasets available\n")); 1638 1639 return (ret); 1640 } 1641 1642 /* 1643 * zfs rename <fs | snap | vol> <fs | snap | vol> 1644 * 1645 * Renames the given dataset to another of the same type. 1646 */ 1647 /* ARGSUSED */ 1648 static int 1649 zfs_do_rename(int argc, char **argv) 1650 { 1651 zfs_handle_t *zhp; 1652 int ret; 1653 1654 /* check options */ 1655 if (argc > 1 && argv[1][0] == '-') { 1656 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1657 argv[1][1]); 1658 usage(B_FALSE); 1659 } 1660 1661 /* check number of arguments */ 1662 if (argc < 2) { 1663 (void) fprintf(stderr, gettext("missing source dataset " 1664 "argument\n")); 1665 usage(B_FALSE); 1666 } 1667 if (argc < 3) { 1668 (void) fprintf(stderr, gettext("missing target dataset " 1669 "argument\n")); 1670 usage(B_FALSE); 1671 } 1672 if (argc > 3) { 1673 (void) fprintf(stderr, gettext("too many arguments\n")); 1674 usage(B_FALSE); 1675 } 1676 1677 if ((zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_ANY)) == NULL) 1678 return (1); 1679 1680 ret = (zfs_rename(zhp, argv[2]) != 0); 1681 1682 if (!ret) 1683 zpool_log_history(g_zfs, argc, argv, argv[2], B_FALSE, B_FALSE); 1684 1685 zfs_close(zhp); 1686 return (ret); 1687 } 1688 1689 /* 1690 * zfs promote <fs> 1691 * 1692 * Promotes the given clone fs to be the parent 1693 */ 1694 /* ARGSUSED */ 1695 static int 1696 zfs_do_promote(int argc, char **argv) 1697 { 1698 zfs_handle_t *zhp; 1699 int ret; 1700 1701 /* check options */ 1702 if (argc > 1 && argv[1][0] == '-') { 1703 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1704 argv[1][1]); 1705 usage(B_FALSE); 1706 } 1707 1708 /* check number of arguments */ 1709 if (argc < 2) { 1710 (void) fprintf(stderr, gettext("missing clone filesystem" 1711 " argument\n")); 1712 usage(B_FALSE); 1713 } 1714 if (argc > 2) { 1715 (void) fprintf(stderr, gettext("too many arguments\n")); 1716 usage(B_FALSE); 1717 } 1718 1719 zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 1720 if (zhp == NULL) 1721 return (1); 1722 1723 ret = (zfs_promote(zhp) != 0); 1724 1725 if (!ret) 1726 zpool_log_history(g_zfs, argc, argv, argv[1], B_FALSE, B_FALSE); 1727 1728 zfs_close(zhp); 1729 return (ret); 1730 } 1731 1732 /* 1733 * zfs rollback [-rfR] <snapshot> 1734 * 1735 * -r Delete any intervening snapshots before doing rollback 1736 * -R Delete any snapshots and their clones 1737 * -f Force unmount filesystems, even if they are in use. 1738 * 1739 * Given a filesystem, rollback to a specific snapshot, discarding any changes 1740 * since then and making it the active dataset. If more recent snapshots exist, 1741 * the command will complain unless the '-r' flag is given. 1742 */ 1743 typedef struct rollback_cbdata { 1744 uint64_t cb_create; 1745 boolean_t cb_first; 1746 int cb_doclones; 1747 char *cb_target; 1748 int cb_error; 1749 boolean_t cb_recurse; 1750 boolean_t cb_dependent; 1751 } rollback_cbdata_t; 1752 1753 /* 1754 * Report any snapshots more recent than the one specified. Used when '-r' is 1755 * not specified. We reuse this same callback for the snapshot dependents - if 1756 * 'cb_dependent' is set, then this is a dependent and we should report it 1757 * without checking the transaction group. 1758 */ 1759 static int 1760 rollback_check(zfs_handle_t *zhp, void *data) 1761 { 1762 rollback_cbdata_t *cbp = data; 1763 1764 if (cbp->cb_doclones) { 1765 zfs_close(zhp); 1766 return (0); 1767 } 1768 1769 if (!cbp->cb_dependent) { 1770 if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 && 1771 zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 1772 zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 1773 cbp->cb_create) { 1774 1775 if (cbp->cb_first && !cbp->cb_recurse) { 1776 (void) fprintf(stderr, gettext("cannot " 1777 "rollback to '%s': more recent snapshots " 1778 "exist\n"), 1779 cbp->cb_target); 1780 (void) fprintf(stderr, gettext("use '-r' to " 1781 "force deletion of the following " 1782 "snapshots:\n")); 1783 cbp->cb_first = 0; 1784 cbp->cb_error = 1; 1785 } 1786 1787 if (cbp->cb_recurse) { 1788 cbp->cb_dependent = B_TRUE; 1789 if (zfs_iter_dependents(zhp, B_TRUE, 1790 rollback_check, cbp) != 0) { 1791 zfs_close(zhp); 1792 return (-1); 1793 } 1794 cbp->cb_dependent = B_FALSE; 1795 } else { 1796 (void) fprintf(stderr, "%s\n", 1797 zfs_get_name(zhp)); 1798 } 1799 } 1800 } else { 1801 if (cbp->cb_first && cbp->cb_recurse) { 1802 (void) fprintf(stderr, gettext("cannot rollback to " 1803 "'%s': clones of previous snapshots exist\n"), 1804 cbp->cb_target); 1805 (void) fprintf(stderr, gettext("use '-R' to " 1806 "force deletion of the following clones and " 1807 "dependents:\n")); 1808 cbp->cb_first = 0; 1809 cbp->cb_error = 1; 1810 } 1811 1812 (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); 1813 } 1814 1815 zfs_close(zhp); 1816 return (0); 1817 } 1818 1819 static int 1820 zfs_do_rollback(int argc, char **argv) 1821 { 1822 int ret; 1823 int c; 1824 rollback_cbdata_t cb = { 0 }; 1825 zfs_handle_t *zhp, *snap; 1826 char parentname[ZFS_MAXNAMELEN]; 1827 char *delim; 1828 int force = 0; 1829 1830 /* check options */ 1831 while ((c = getopt(argc, argv, "rfR")) != -1) { 1832 switch (c) { 1833 case 'f': 1834 force = 1; 1835 break; 1836 case 'r': 1837 cb.cb_recurse = 1; 1838 break; 1839 case 'R': 1840 cb.cb_recurse = 1; 1841 cb.cb_doclones = 1; 1842 break; 1843 case '?': 1844 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1845 optopt); 1846 usage(B_FALSE); 1847 } 1848 } 1849 1850 argc -= optind; 1851 argv += optind; 1852 1853 /* check number of arguments */ 1854 if (argc < 1) { 1855 (void) fprintf(stderr, gettext("missing dataset argument\n")); 1856 usage(B_FALSE); 1857 } 1858 if (argc > 1) { 1859 (void) fprintf(stderr, gettext("too many arguments\n")); 1860 usage(B_FALSE); 1861 } 1862 1863 /* open the snapshot */ 1864 if ((snap = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL) 1865 return (1); 1866 1867 /* open the parent dataset */ 1868 (void) strlcpy(parentname, argv[0], sizeof (parentname)); 1869 verify((delim = strrchr(parentname, '@')) != NULL); 1870 *delim = '\0'; 1871 if ((zhp = zfs_open(g_zfs, parentname, ZFS_TYPE_ANY)) == NULL) { 1872 zfs_close(snap); 1873 return (1); 1874 } 1875 1876 /* 1877 * Check for more recent snapshots and/or clones based on the presence 1878 * of '-r' and '-R'. 1879 */ 1880 cb.cb_target = argv[0]; 1881 cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 1882 cb.cb_first = B_TRUE; 1883 cb.cb_error = 0; 1884 if ((ret = zfs_iter_children(zhp, rollback_check, &cb)) != 0) 1885 goto out; 1886 1887 if ((ret = cb.cb_error) != 0) 1888 goto out; 1889 1890 /* 1891 * Rollback parent to the given snapshot. 1892 */ 1893 ret = zfs_rollback(zhp, snap, force); 1894 1895 if (!ret) { 1896 zpool_log_history(g_zfs, argc + optind, argv - optind, argv[0], 1897 B_FALSE, B_FALSE); 1898 } 1899 1900 out: 1901 zfs_close(snap); 1902 zfs_close(zhp); 1903 1904 if (ret == 0) 1905 return (0); 1906 else 1907 return (1); 1908 } 1909 1910 /* 1911 * zfs set property=value { fs | snap | vol } ... 1912 * 1913 * Sets the given property for all datasets specified on the command line. 1914 */ 1915 typedef struct set_cbdata { 1916 char *cb_propname; 1917 char *cb_value; 1918 boolean_t cb_any_successful; 1919 } set_cbdata_t; 1920 1921 static int 1922 set_callback(zfs_handle_t *zhp, void *data) 1923 { 1924 set_cbdata_t *cbp = data; 1925 1926 if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) { 1927 switch (libzfs_errno(g_zfs)) { 1928 case EZFS_MOUNTFAILED: 1929 (void) fprintf(stderr, gettext("property may be set " 1930 "but unable to remount filesystem\n")); 1931 break; 1932 case EZFS_SHARENFSFAILED: 1933 (void) fprintf(stderr, gettext("property may be set " 1934 "but unable to reshare filesystem\n")); 1935 break; 1936 } 1937 return (1); 1938 } 1939 cbp->cb_any_successful = B_TRUE; 1940 return (0); 1941 } 1942 1943 static int 1944 zfs_do_set(int argc, char **argv) 1945 { 1946 set_cbdata_t cb; 1947 int ret; 1948 1949 /* check for options */ 1950 if (argc > 1 && argv[1][0] == '-') { 1951 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1952 argv[1][1]); 1953 usage(B_FALSE); 1954 } 1955 1956 /* check number of arguments */ 1957 if (argc < 2) { 1958 (void) fprintf(stderr, gettext("missing property=value " 1959 "argument\n")); 1960 usage(B_FALSE); 1961 } 1962 if (argc < 3) { 1963 (void) fprintf(stderr, gettext("missing dataset name\n")); 1964 usage(B_FALSE); 1965 } 1966 1967 /* validate property=value argument */ 1968 cb.cb_propname = argv[1]; 1969 if ((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) { 1970 (void) fprintf(stderr, gettext("missing value in " 1971 "property=value argument\n")); 1972 usage(B_FALSE); 1973 } 1974 1975 *cb.cb_value = '\0'; 1976 cb.cb_value++; 1977 cb.cb_any_successful = B_FALSE; 1978 1979 if (*cb.cb_propname == '\0') { 1980 (void) fprintf(stderr, 1981 gettext("missing property in property=value argument\n")); 1982 usage(B_FALSE); 1983 } 1984 1985 ret = zfs_for_each(argc - 2, argv + 2, B_FALSE, 1986 ZFS_TYPE_ANY, NULL, NULL, set_callback, &cb); 1987 1988 if (cb.cb_any_successful) { 1989 *(cb.cb_value - 1) = '='; 1990 zpool_log_history(g_zfs, argc, argv, argv[2], B_FALSE, B_FALSE); 1991 } 1992 1993 return (ret); 1994 } 1995 1996 /* 1997 * zfs snapshot [-r] <fs@snap> 1998 * 1999 * Creates a snapshot with the given name. While functionally equivalent to 2000 * 'zfs create', it is a separate command to diffferentiate intent. 2001 */ 2002 static int 2003 zfs_do_snapshot(int argc, char **argv) 2004 { 2005 int recursive = B_FALSE; 2006 int ret; 2007 char c; 2008 2009 /* check options */ 2010 while ((c = getopt(argc, argv, ":r")) != -1) { 2011 switch (c) { 2012 case 'r': 2013 recursive = B_TRUE; 2014 break; 2015 case '?': 2016 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2017 optopt); 2018 usage(B_FALSE); 2019 } 2020 } 2021 2022 argc -= optind; 2023 argv += optind; 2024 2025 /* check number of arguments */ 2026 if (argc < 1) { 2027 (void) fprintf(stderr, gettext("missing snapshot argument\n")); 2028 usage(B_FALSE); 2029 } 2030 if (argc > 1) { 2031 (void) fprintf(stderr, gettext("too many arguments\n")); 2032 usage(B_FALSE); 2033 } 2034 2035 ret = zfs_snapshot(g_zfs, argv[0], recursive); 2036 if (ret && recursive) 2037 (void) fprintf(stderr, gettext("no snapshots were created\n")); 2038 if (!ret) { 2039 zpool_log_history(g_zfs, argc + optind, argv - optind, argv[0], 2040 B_FALSE, B_FALSE); 2041 } 2042 return (ret != 0); 2043 } 2044 2045 /* 2046 * zfs send [-i <@snap>] <fs@snap> 2047 * 2048 * Send a backup stream to stdout. 2049 */ 2050 static int 2051 zfs_do_send(int argc, char **argv) 2052 { 2053 char *fromname = NULL; 2054 char *cp; 2055 zfs_handle_t *zhp; 2056 int c, err; 2057 2058 /* check options */ 2059 while ((c = getopt(argc, argv, ":i:")) != -1) { 2060 switch (c) { 2061 case 'i': 2062 if (fromname) 2063 usage(B_FALSE); 2064 fromname = optarg; 2065 break; 2066 case ':': 2067 (void) fprintf(stderr, gettext("missing argument for " 2068 "'%c' option\n"), optopt); 2069 usage(B_FALSE); 2070 break; 2071 case '?': 2072 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2073 optopt); 2074 usage(B_FALSE); 2075 } 2076 } 2077 2078 argc -= optind; 2079 argv += optind; 2080 2081 /* check number of arguments */ 2082 if (argc < 1) { 2083 (void) fprintf(stderr, gettext("missing snapshot argument\n")); 2084 usage(B_FALSE); 2085 } 2086 if (argc > 1) { 2087 (void) fprintf(stderr, gettext("too many arguments\n")); 2088 usage(B_FALSE); 2089 } 2090 2091 if (isatty(STDOUT_FILENO)) { 2092 (void) fprintf(stderr, 2093 gettext("Error: Stream can not be written to a terminal.\n" 2094 "You must redirect standard output.\n")); 2095 return (1); 2096 } 2097 2098 if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL) 2099 return (1); 2100 2101 /* 2102 * If they specified the full path to the snapshot, chop off 2103 * everything except the short name of the snapshot. 2104 */ 2105 if (fromname && (cp = strchr(fromname, '@')) != NULL) { 2106 if (cp != fromname && 2107 strncmp(argv[0], fromname, cp - fromname + 1)) { 2108 (void) fprintf(stderr, 2109 gettext("incremental source must be " 2110 "in same filesystem\n")); 2111 usage(B_FALSE); 2112 } 2113 fromname = cp + 1; 2114 if (strchr(fromname, '@') || strchr(fromname, '/')) { 2115 (void) fprintf(stderr, 2116 gettext("invalid incremental source\n")); 2117 usage(B_FALSE); 2118 } 2119 } 2120 2121 err = zfs_send(zhp, fromname); 2122 zfs_close(zhp); 2123 2124 return (err != 0); 2125 } 2126 2127 /* 2128 * zfs receive <fs@snap> 2129 * 2130 * Restore a backup stream from stdin. 2131 */ 2132 static int 2133 zfs_do_receive(int argc, char **argv) 2134 { 2135 int c, err; 2136 boolean_t isprefix = B_FALSE; 2137 boolean_t dryrun = B_FALSE; 2138 boolean_t verbose = B_FALSE; 2139 boolean_t force = B_FALSE; 2140 2141 /* check options */ 2142 while ((c = getopt(argc, argv, ":dnvF")) != -1) { 2143 switch (c) { 2144 case 'd': 2145 isprefix = B_TRUE; 2146 break; 2147 case 'n': 2148 dryrun = B_TRUE; 2149 break; 2150 case 'v': 2151 verbose = B_TRUE; 2152 break; 2153 case 'F': 2154 force = B_TRUE; 2155 break; 2156 case ':': 2157 (void) fprintf(stderr, gettext("missing argument for " 2158 "'%c' option\n"), optopt); 2159 usage(B_FALSE); 2160 break; 2161 case '?': 2162 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2163 optopt); 2164 usage(B_FALSE); 2165 } 2166 } 2167 2168 argc -= optind; 2169 argv += optind; 2170 2171 /* check number of arguments */ 2172 if (argc < 1) { 2173 (void) fprintf(stderr, gettext("missing snapshot argument\n")); 2174 usage(B_FALSE); 2175 } 2176 if (argc > 1) { 2177 (void) fprintf(stderr, gettext("too many arguments\n")); 2178 usage(B_FALSE); 2179 } 2180 2181 if (isatty(STDIN_FILENO)) { 2182 (void) fprintf(stderr, 2183 gettext("Error: Backup stream can not be read " 2184 "from a terminal.\n" 2185 "You must redirect standard input.\n")); 2186 return (1); 2187 } 2188 2189 err = zfs_receive(g_zfs, argv[0], isprefix, verbose, dryrun, force); 2190 2191 if (!err) { 2192 zpool_log_history(g_zfs, argc + optind, argv - optind, argv[0], 2193 B_FALSE, B_FALSE); 2194 } 2195 2196 return (err != 0); 2197 } 2198 2199 typedef struct get_all_cbdata { 2200 zfs_handle_t **cb_handles; 2201 size_t cb_alloc; 2202 size_t cb_used; 2203 uint_t cb_types; 2204 } get_all_cbdata_t; 2205 2206 static int 2207 get_one_dataset(zfs_handle_t *zhp, void *data) 2208 { 2209 get_all_cbdata_t *cbp = data; 2210 zfs_type_t type = zfs_get_type(zhp); 2211 2212 /* 2213 * Interate over any nested datasets. 2214 */ 2215 if (type == ZFS_TYPE_FILESYSTEM && 2216 zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) { 2217 zfs_close(zhp); 2218 return (1); 2219 } 2220 2221 /* 2222 * Skip any datasets whose type does not match. 2223 */ 2224 if ((type & cbp->cb_types) == 0) { 2225 zfs_close(zhp); 2226 return (0); 2227 } 2228 2229 if (cbp->cb_alloc == cbp->cb_used) { 2230 zfs_handle_t **handles; 2231 2232 if (cbp->cb_alloc == 0) 2233 cbp->cb_alloc = 64; 2234 else 2235 cbp->cb_alloc *= 2; 2236 2237 handles = safe_malloc(cbp->cb_alloc * sizeof (void *)); 2238 2239 if (cbp->cb_handles) { 2240 bcopy(cbp->cb_handles, handles, 2241 cbp->cb_used * sizeof (void *)); 2242 free(cbp->cb_handles); 2243 } 2244 2245 cbp->cb_handles = handles; 2246 } 2247 2248 cbp->cb_handles[cbp->cb_used++] = zhp; 2249 2250 return (0); 2251 } 2252 2253 static void 2254 get_all_datasets(uint_t types, zfs_handle_t ***dslist, size_t *count) 2255 { 2256 get_all_cbdata_t cb = { 0 }; 2257 cb.cb_types = types; 2258 2259 (void) zfs_iter_root(g_zfs, get_one_dataset, &cb); 2260 2261 *dslist = cb.cb_handles; 2262 *count = cb.cb_used; 2263 } 2264 2265 static int 2266 dataset_cmp(const void *a, const void *b) 2267 { 2268 zfs_handle_t **za = (zfs_handle_t **)a; 2269 zfs_handle_t **zb = (zfs_handle_t **)b; 2270 char mounta[MAXPATHLEN]; 2271 char mountb[MAXPATHLEN]; 2272 boolean_t gota, gotb; 2273 2274 if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 2275 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2276 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2277 if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 2278 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2279 sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2280 2281 if (gota && gotb) 2282 return (strcmp(mounta, mountb)); 2283 2284 if (gota) 2285 return (-1); 2286 if (gotb) 2287 return (1); 2288 2289 return (strcmp(zfs_get_name(a), zfs_get_name(b))); 2290 } 2291 2292 /* 2293 * Generic callback for sharing or mounting filesystems. Because the code is so 2294 * similar, we have a common function with an extra parameter to determine which 2295 * mode we are using. 2296 */ 2297 #define OP_SHARE 0x1 2298 #define OP_MOUNT 0x2 2299 2300 /* 2301 * Share or mount a dataset. 2302 */ 2303 static int 2304 share_mount_one(zfs_handle_t *zhp, int op, int flags, boolean_t explicit, 2305 const char *options) 2306 { 2307 char mountpoint[ZFS_MAXPROPLEN]; 2308 char shareopts[ZFS_MAXPROPLEN]; 2309 const char *cmdname = op == OP_SHARE ? "share" : "mount"; 2310 struct mnttab mnt; 2311 uint64_t zoned, canmount; 2312 zfs_type_t type = zfs_get_type(zhp); 2313 2314 assert(type & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)); 2315 2316 if (type == ZFS_TYPE_FILESYSTEM) { 2317 /* 2318 * Check to make sure we can mount/share this dataset. If we 2319 * are in the global zone and the filesystem is exported to a 2320 * local zone, or if we are in a local zone and the 2321 * filesystem is not exported, then it is an error. 2322 */ 2323 zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2324 2325 if (zoned && getzoneid() == GLOBAL_ZONEID) { 2326 if (!explicit) 2327 return (0); 2328 2329 (void) fprintf(stderr, gettext("cannot %s '%s': " 2330 "dataset is exported to a local zone\n"), cmdname, 2331 zfs_get_name(zhp)); 2332 return (1); 2333 2334 } else if (!zoned && getzoneid() != GLOBAL_ZONEID) { 2335 if (!explicit) 2336 return (0); 2337 2338 (void) fprintf(stderr, gettext("cannot %s '%s': " 2339 "permission denied\n"), cmdname, 2340 zfs_get_name(zhp)); 2341 return (1); 2342 } 2343 2344 /* 2345 * Ignore any filesystems which don't apply to us. This 2346 * includes those with a legacy mountpoint, or those with 2347 * legacy share options. 2348 */ 2349 verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 2350 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0); 2351 verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, 2352 sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); 2353 canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT); 2354 2355 if (op == OP_SHARE && strcmp(shareopts, "off") == 0) { 2356 if (!explicit) 2357 return (0); 2358 2359 (void) fprintf(stderr, gettext("cannot share '%s': " 2360 "legacy share\n"), zfs_get_name(zhp)); 2361 (void) fprintf(stderr, gettext("use share(1M) to " 2362 "share this filesystem\n")); 2363 return (1); 2364 } 2365 2366 /* 2367 * We cannot share or mount legacy filesystems. If the 2368 * shareopts is non-legacy but the mountpoint is legacy, we 2369 * treat it as a legacy share. 2370 */ 2371 if (strcmp(mountpoint, "legacy") == 0) { 2372 if (!explicit) 2373 return (0); 2374 2375 (void) fprintf(stderr, gettext("cannot %s '%s': " 2376 "legacy mountpoint\n"), cmdname, zfs_get_name(zhp)); 2377 (void) fprintf(stderr, gettext("use %s to " 2378 "%s this filesystem\n"), op == OP_SHARE ? 2379 "share(1M)" : "mount(1M)", cmdname); 2380 return (1); 2381 } 2382 2383 if (strcmp(mountpoint, "none") == 0) { 2384 if (!explicit) 2385 return (0); 2386 2387 (void) fprintf(stderr, gettext("cannot %s '%s': no " 2388 "mountpoint set\n"), cmdname, zfs_get_name(zhp)); 2389 return (1); 2390 } 2391 2392 if (!canmount) { 2393 if (!explicit) 2394 return (0); 2395 2396 (void) fprintf(stderr, gettext("cannot %s '%s': " 2397 "'canmount' property is set to 'off'\n"), cmdname, 2398 zfs_get_name(zhp)); 2399 return (1); 2400 } 2401 2402 /* 2403 * At this point, we have verified that the mountpoint and/or 2404 * shareopts are appropriate for auto management. If the 2405 * filesystem is already mounted or shared, return (failing 2406 * for explicit requests); otherwise mount or share the 2407 * filesystem. 2408 */ 2409 switch (op) { 2410 case OP_SHARE: 2411 if (zfs_is_shared_nfs(zhp, NULL)) { 2412 if (!explicit) 2413 return (0); 2414 2415 (void) fprintf(stderr, gettext("cannot share " 2416 "'%s': filesystem already shared\n"), 2417 zfs_get_name(zhp)); 2418 return (1); 2419 } 2420 2421 if (!zfs_is_mounted(zhp, NULL) && 2422 zfs_mount(zhp, NULL, 0) != 0) 2423 return (1); 2424 2425 if (zfs_share_nfs(zhp) != 0) 2426 return (1); 2427 break; 2428 2429 case OP_MOUNT: 2430 if (options == NULL) 2431 mnt.mnt_mntopts = ""; 2432 else 2433 mnt.mnt_mntopts = (char *)options; 2434 2435 if (!hasmntopt(&mnt, MNTOPT_REMOUNT) && 2436 zfs_is_mounted(zhp, NULL)) { 2437 if (!explicit) 2438 return (0); 2439 2440 (void) fprintf(stderr, gettext("cannot mount " 2441 "'%s': filesystem already mounted\n"), 2442 zfs_get_name(zhp)); 2443 return (1); 2444 } 2445 2446 if (zfs_mount(zhp, options, flags) != 0) 2447 return (1); 2448 break; 2449 } 2450 } else { 2451 assert(op == OP_SHARE); 2452 2453 /* 2454 * Ignore any volumes that aren't shared. 2455 */ 2456 verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 2457 sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); 2458 2459 if (strcmp(shareopts, "off") == 0) { 2460 if (!explicit) 2461 return (0); 2462 2463 (void) fprintf(stderr, gettext("cannot share '%s': " 2464 "'shareiscsi' property not set\n"), 2465 zfs_get_name(zhp)); 2466 (void) fprintf(stderr, gettext("set 'shareiscsi' " 2467 "property or use iscsitadm(1M) to share this " 2468 "volume\n")); 2469 return (1); 2470 } 2471 2472 if (zfs_is_shared_iscsi(zhp)) { 2473 if (!explicit) 2474 return (0); 2475 2476 (void) fprintf(stderr, gettext("cannot share " 2477 "'%s': volume already shared\n"), 2478 zfs_get_name(zhp)); 2479 return (1); 2480 } 2481 2482 if (zfs_share_iscsi(zhp) != 0) 2483 return (1); 2484 } 2485 2486 return (0); 2487 } 2488 2489 static int 2490 share_mount(int op, int argc, char **argv) 2491 { 2492 int do_all = 0; 2493 int c, ret = 0; 2494 const char *options = NULL; 2495 int types, flags = 0; 2496 2497 /* check options */ 2498 while ((c = getopt(argc, argv, op == OP_MOUNT ? ":ao:O" : "a")) 2499 != -1) { 2500 switch (c) { 2501 case 'a': 2502 do_all = 1; 2503 break; 2504 case 'o': 2505 options = optarg; 2506 break; 2507 case 'O': 2508 flags |= MS_OVERLAY; 2509 break; 2510 case ':': 2511 (void) fprintf(stderr, gettext("missing argument for " 2512 "'%c' option\n"), optopt); 2513 usage(B_FALSE); 2514 break; 2515 case '?': 2516 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2517 optopt); 2518 usage(B_FALSE); 2519 } 2520 } 2521 2522 argc -= optind; 2523 argv += optind; 2524 2525 /* check number of arguments */ 2526 if (do_all) { 2527 zfs_handle_t **dslist = NULL; 2528 size_t i, count = 0; 2529 2530 if (op == OP_MOUNT) { 2531 types = ZFS_TYPE_FILESYSTEM; 2532 } else if (argc > 0) { 2533 if (strcmp(argv[0], "nfs") == 0) { 2534 types = ZFS_TYPE_FILESYSTEM; 2535 } else if (strcmp(argv[0], "iscsi") == 0) { 2536 types = ZFS_TYPE_VOLUME; 2537 } else { 2538 (void) fprintf(stderr, gettext("share type " 2539 "must be 'nfs' or 'iscsi'\n")); 2540 usage(B_FALSE); 2541 } 2542 2543 argc--; 2544 argv++; 2545 } else { 2546 types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME; 2547 } 2548 2549 if (argc != 0) { 2550 (void) fprintf(stderr, gettext("too many arguments\n")); 2551 usage(B_FALSE); 2552 } 2553 2554 get_all_datasets(types, &dslist, &count); 2555 2556 if (count == 0) 2557 return (0); 2558 2559 qsort(dslist, count, sizeof (void *), dataset_cmp); 2560 2561 for (i = 0; i < count; i++) { 2562 if (share_mount_one(dslist[i], op, flags, B_FALSE, 2563 options) != 0) 2564 ret = 1; 2565 zfs_close(dslist[i]); 2566 } 2567 2568 free(dslist); 2569 } else if (argc == 0) { 2570 struct mnttab entry; 2571 2572 if (op == OP_SHARE) { 2573 (void) fprintf(stderr, gettext("missing filesystem " 2574 "argument\n")); 2575 usage(B_FALSE); 2576 } 2577 2578 /* 2579 * When mount is given no arguments, go through /etc/mnttab and 2580 * display any active ZFS mounts. We hide any snapshots, since 2581 * they are controlled automatically. 2582 */ 2583 rewind(mnttab_file); 2584 while (getmntent(mnttab_file, &entry) == 0) { 2585 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 || 2586 strchr(entry.mnt_special, '@') != NULL) 2587 continue; 2588 2589 (void) printf("%-30s %s\n", entry.mnt_special, 2590 entry.mnt_mountp); 2591 } 2592 2593 } else { 2594 zfs_handle_t *zhp; 2595 2596 types = ZFS_TYPE_FILESYSTEM; 2597 if (op == OP_SHARE) 2598 types |= ZFS_TYPE_VOLUME; 2599 2600 if (argc > 1) { 2601 (void) fprintf(stderr, 2602 gettext("too many arguments\n")); 2603 usage(B_FALSE); 2604 } 2605 2606 if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) { 2607 ret = 1; 2608 } else { 2609 ret = share_mount_one(zhp, op, flags, B_TRUE, 2610 options); 2611 zfs_close(zhp); 2612 } 2613 } 2614 2615 return (ret); 2616 } 2617 2618 /* 2619 * zfs mount -a [nfs | iscsi] 2620 * zfs mount filesystem 2621 * 2622 * Mount all filesystems, or mount the given filesystem. 2623 */ 2624 static int 2625 zfs_do_mount(int argc, char **argv) 2626 { 2627 return (share_mount(OP_MOUNT, argc, argv)); 2628 } 2629 2630 /* 2631 * zfs share -a [nfs | iscsi] 2632 * zfs share filesystem 2633 * 2634 * Share all filesystems, or share the given filesystem. 2635 */ 2636 static int 2637 zfs_do_share(int argc, char **argv) 2638 { 2639 return (share_mount(OP_SHARE, argc, argv)); 2640 } 2641 2642 typedef struct unshare_unmount_node { 2643 zfs_handle_t *un_zhp; 2644 char *un_mountp; 2645 uu_avl_node_t un_avlnode; 2646 } unshare_unmount_node_t; 2647 2648 /* ARGSUSED */ 2649 static int 2650 unshare_unmount_compare(const void *larg, const void *rarg, void *unused) 2651 { 2652 const unshare_unmount_node_t *l = larg; 2653 const unshare_unmount_node_t *r = rarg; 2654 2655 return (strcmp(l->un_mountp, r->un_mountp)); 2656 } 2657 2658 /* 2659 * Convenience routine used by zfs_do_umount() and manual_unmount(). Given an 2660 * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem, 2661 * and unmount it appropriately. 2662 */ 2663 static int 2664 unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) 2665 { 2666 zfs_handle_t *zhp; 2667 int ret; 2668 struct stat64 statbuf; 2669 struct extmnttab entry; 2670 const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount"; 2671 char property[ZFS_MAXPROPLEN]; 2672 2673 /* 2674 * Search for the path in /etc/mnttab. Rather than looking for the 2675 * specific path, which can be fooled by non-standard paths (i.e. ".." 2676 * or "//"), we stat() the path and search for the corresponding 2677 * (major,minor) device pair. 2678 */ 2679 if (stat64(path, &statbuf) != 0) { 2680 (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"), 2681 cmdname, path, strerror(errno)); 2682 return (1); 2683 } 2684 2685 /* 2686 * Search for the given (major,minor) pair in the mount table. 2687 */ 2688 rewind(mnttab_file); 2689 while ((ret = getextmntent(mnttab_file, &entry, 0)) == 0) { 2690 if (entry.mnt_major == major(statbuf.st_dev) && 2691 entry.mnt_minor == minor(statbuf.st_dev)) 2692 break; 2693 } 2694 if (ret != 0) { 2695 (void) fprintf(stderr, gettext("cannot %s '%s': not " 2696 "currently mounted\n"), cmdname, path); 2697 return (1); 2698 } 2699 2700 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) { 2701 (void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS " 2702 "filesystem\n"), cmdname, path); 2703 return (1); 2704 } 2705 2706 if ((zhp = zfs_open(g_zfs, entry.mnt_special, 2707 ZFS_TYPE_FILESYSTEM)) == NULL) 2708 return (1); 2709 2710 verify(zfs_prop_get(zhp, op == OP_SHARE ? 2711 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property, 2712 sizeof (property), NULL, NULL, 0, B_FALSE) == 0); 2713 2714 if (op == OP_SHARE) { 2715 if (strcmp(property, "off") == 0) { 2716 (void) fprintf(stderr, gettext("cannot unshare " 2717 "'%s': legacy share\n"), path); 2718 (void) fprintf(stderr, gettext("use " 2719 "unshare(1M) to unshare this filesystem\n")); 2720 ret = 1; 2721 } else if (!zfs_is_shared_nfs(zhp, NULL)) { 2722 (void) fprintf(stderr, gettext("cannot unshare '%s': " 2723 "not currently shared\n"), path); 2724 ret = 1; 2725 } else { 2726 ret = zfs_unshareall_nfs(zhp); 2727 } 2728 } else { 2729 if (is_manual) { 2730 ret = zfs_unmount(zhp, NULL, flags); 2731 } else if (strcmp(property, "legacy") == 0) { 2732 (void) fprintf(stderr, gettext("cannot unmount " 2733 "'%s': legacy mountpoint\n"), 2734 zfs_get_name(zhp)); 2735 (void) fprintf(stderr, gettext("use umount(1M) " 2736 "to unmount this filesystem\n")); 2737 ret = 1; 2738 } else { 2739 ret = zfs_unmountall(zhp, flags); 2740 } 2741 } 2742 2743 zfs_close(zhp); 2744 2745 return (ret != 0); 2746 } 2747 2748 /* 2749 * Generic callback for unsharing or unmounting a filesystem. 2750 */ 2751 static int 2752 unshare_unmount(int op, int argc, char **argv) 2753 { 2754 int do_all = 0; 2755 int flags = 0; 2756 int ret = 0; 2757 int types, c; 2758 zfs_handle_t *zhp; 2759 char property[ZFS_MAXPROPLEN]; 2760 2761 /* check options */ 2762 while ((c = getopt(argc, argv, op == OP_SHARE ? "a" : "af")) != -1) { 2763 switch (c) { 2764 case 'a': 2765 do_all = 1; 2766 break; 2767 case 'f': 2768 flags = MS_FORCE; 2769 break; 2770 case '?': 2771 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2772 optopt); 2773 usage(B_FALSE); 2774 } 2775 } 2776 2777 argc -= optind; 2778 argv += optind; 2779 2780 if (do_all) { 2781 /* 2782 * We could make use of zfs_for_each() to walk all datasets in 2783 * the system, but this would be very inefficient, especially 2784 * since we would have to linearly search /etc/mnttab for each 2785 * one. Instead, do one pass through /etc/mnttab looking for 2786 * zfs entries and call zfs_unmount() for each one. 2787 * 2788 * Things get a little tricky if the administrator has created 2789 * mountpoints beneath other ZFS filesystems. In this case, we 2790 * have to unmount the deepest filesystems first. To accomplish 2791 * this, we place all the mountpoints in an AVL tree sorted by 2792 * the special type (dataset name), and walk the result in 2793 * reverse to make sure to get any snapshots first. 2794 */ 2795 struct mnttab entry; 2796 uu_avl_pool_t *pool; 2797 uu_avl_t *tree; 2798 unshare_unmount_node_t *node; 2799 uu_avl_index_t idx; 2800 uu_avl_walk_t *walk; 2801 2802 if (argc != 0) { 2803 (void) fprintf(stderr, gettext("too many arguments\n")); 2804 usage(B_FALSE); 2805 } 2806 2807 if ((pool = uu_avl_pool_create("unmount_pool", 2808 sizeof (unshare_unmount_node_t), 2809 offsetof(unshare_unmount_node_t, un_avlnode), 2810 unshare_unmount_compare, 2811 UU_DEFAULT)) == NULL) { 2812 (void) fprintf(stderr, gettext("internal error: " 2813 "out of memory\n")); 2814 exit(1); 2815 } 2816 2817 if ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL) { 2818 (void) fprintf(stderr, gettext("internal error: " 2819 "out of memory\n")); 2820 exit(1); 2821 } 2822 2823 rewind(mnttab_file); 2824 while (getmntent(mnttab_file, &entry) == 0) { 2825 2826 /* ignore non-ZFS entries */ 2827 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 2828 continue; 2829 2830 /* ignore snapshots */ 2831 if (strchr(entry.mnt_special, '@') != NULL) 2832 continue; 2833 2834 if ((zhp = zfs_open(g_zfs, entry.mnt_special, 2835 ZFS_TYPE_FILESYSTEM)) == NULL) { 2836 ret = 1; 2837 continue; 2838 } 2839 2840 verify(zfs_prop_get(zhp, op == OP_SHARE ? 2841 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, 2842 property, sizeof (property), NULL, NULL, 2843 0, B_FALSE) == 0); 2844 2845 /* Ignore legacy mounts and shares */ 2846 if ((op == OP_SHARE && 2847 strcmp(property, "off") == 0) || 2848 (op == OP_MOUNT && 2849 strcmp(property, "legacy") == 0)) { 2850 zfs_close(zhp); 2851 continue; 2852 } 2853 2854 node = safe_malloc(sizeof (unshare_unmount_node_t)); 2855 node->un_zhp = zhp; 2856 2857 if ((node->un_mountp = strdup(entry.mnt_mountp)) == 2858 NULL) { 2859 (void) fprintf(stderr, gettext("internal error:" 2860 " out of memory\n")); 2861 exit(1); 2862 } 2863 2864 uu_avl_node_init(node, &node->un_avlnode, pool); 2865 2866 if (uu_avl_find(tree, node, NULL, &idx) == NULL) { 2867 uu_avl_insert(tree, node, idx); 2868 } else { 2869 zfs_close(node->un_zhp); 2870 free(node->un_mountp); 2871 free(node); 2872 } 2873 } 2874 2875 /* 2876 * Walk the AVL tree in reverse, unmounting each filesystem and 2877 * removing it from the AVL tree in the process. 2878 */ 2879 if ((walk = uu_avl_walk_start(tree, 2880 UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL) { 2881 (void) fprintf(stderr, 2882 gettext("internal error: out of memory")); 2883 exit(1); 2884 } 2885 2886 while ((node = uu_avl_walk_next(walk)) != NULL) { 2887 uu_avl_remove(tree, node); 2888 2889 switch (op) { 2890 case OP_SHARE: 2891 if (zfs_unshare_nfs(node->un_zhp, 2892 node->un_mountp) != 0) 2893 ret = 1; 2894 break; 2895 2896 case OP_MOUNT: 2897 if (zfs_unmount(node->un_zhp, 2898 node->un_mountp, flags) != 0) 2899 ret = 1; 2900 break; 2901 } 2902 2903 zfs_close(node->un_zhp); 2904 free(node->un_mountp); 2905 free(node); 2906 } 2907 2908 uu_avl_walk_end(walk); 2909 uu_avl_destroy(tree); 2910 uu_avl_pool_destroy(pool); 2911 2912 if (op == OP_SHARE) { 2913 /* 2914 * Finally, unshare any volumes shared via iSCSI. 2915 */ 2916 zfs_handle_t **dslist = NULL; 2917 size_t i, count = 0; 2918 2919 get_all_datasets(ZFS_TYPE_VOLUME, &dslist, &count); 2920 2921 if (count != 0) { 2922 qsort(dslist, count, sizeof (void *), 2923 dataset_cmp); 2924 2925 for (i = 0; i < count; i++) { 2926 if (zfs_unshare_iscsi(dslist[i]) != 0) 2927 ret = 1; 2928 zfs_close(dslist[i]); 2929 } 2930 2931 free(dslist); 2932 } 2933 } 2934 } else { 2935 if (argc != 1) { 2936 if (argc == 0) 2937 (void) fprintf(stderr, 2938 gettext("missing filesystem argument\n")); 2939 else 2940 (void) fprintf(stderr, 2941 gettext("too many arguments\n")); 2942 usage(B_FALSE); 2943 } 2944 2945 /* 2946 * We have an argument, but it may be a full path or a ZFS 2947 * filesystem. Pass full paths off to unmount_path() (shared by 2948 * manual_unmount), otherwise open the filesystem and pass to 2949 * zfs_unmount(). 2950 */ 2951 if (argv[0][0] == '/') 2952 return (unshare_unmount_path(op, argv[0], 2953 flags, B_FALSE)); 2954 2955 types = ZFS_TYPE_FILESYSTEM; 2956 if (op == OP_SHARE) 2957 types |= ZFS_TYPE_VOLUME; 2958 2959 if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) 2960 return (1); 2961 2962 if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { 2963 verify(zfs_prop_get(zhp, op == OP_SHARE ? 2964 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property, 2965 sizeof (property), NULL, NULL, 0, B_FALSE) == 0); 2966 2967 switch (op) { 2968 case OP_SHARE: 2969 if (strcmp(property, "off") == 0) { 2970 (void) fprintf(stderr, gettext("cannot " 2971 "unshare '%s': legacy share\n"), 2972 zfs_get_name(zhp)); 2973 (void) fprintf(stderr, gettext("use " 2974 "unshare(1M) to unshare this " 2975 "filesystem\n")); 2976 ret = 1; 2977 } else if (!zfs_is_shared_nfs(zhp, NULL)) { 2978 (void) fprintf(stderr, gettext("cannot " 2979 "unshare '%s': not currently " 2980 "shared\n"), zfs_get_name(zhp)); 2981 ret = 1; 2982 } else if (zfs_unshareall_nfs(zhp) != 0) { 2983 ret = 1; 2984 } 2985 break; 2986 2987 case OP_MOUNT: 2988 if (strcmp(property, "legacy") == 0) { 2989 (void) fprintf(stderr, gettext("cannot " 2990 "unmount '%s': legacy " 2991 "mountpoint\n"), zfs_get_name(zhp)); 2992 (void) fprintf(stderr, gettext("use " 2993 "umount(1M) to unmount this " 2994 "filesystem\n")); 2995 ret = 1; 2996 } else if (!zfs_is_mounted(zhp, NULL)) { 2997 (void) fprintf(stderr, gettext("cannot " 2998 "unmount '%s': not currently " 2999 "mounted\n"), 3000 zfs_get_name(zhp)); 3001 ret = 1; 3002 } else if (zfs_unmountall(zhp, flags) != 0) { 3003 ret = 1; 3004 } 3005 break; 3006 } 3007 } else { 3008 assert(op == OP_SHARE); 3009 3010 verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, property, 3011 sizeof (property), NULL, NULL, 0, B_FALSE) == 0); 3012 3013 if (strcmp(property, "off") == 0) { 3014 (void) fprintf(stderr, gettext("cannot unshare " 3015 "'%s': 'shareiscsi' property not set\n"), 3016 zfs_get_name(zhp)); 3017 (void) fprintf(stderr, gettext("set " 3018 "'shareiscsi' property or use " 3019 "iscsitadm(1M) to share this volume\n")); 3020 ret = 1; 3021 } else if (!zfs_is_shared_iscsi(zhp)) { 3022 (void) fprintf(stderr, gettext("cannot " 3023 "unshare '%s': not currently shared\n"), 3024 zfs_get_name(zhp)); 3025 ret = 1; 3026 } else if (zfs_unshare_iscsi(zhp) != 0) { 3027 ret = 1; 3028 } 3029 } 3030 3031 zfs_close(zhp); 3032 } 3033 3034 return (ret); 3035 } 3036 3037 /* 3038 * zfs unmount -a 3039 * zfs unmount filesystem 3040 * 3041 * Unmount all filesystems, or a specific ZFS filesystem. 3042 */ 3043 static int 3044 zfs_do_unmount(int argc, char **argv) 3045 { 3046 return (unshare_unmount(OP_MOUNT, argc, argv)); 3047 } 3048 3049 /* 3050 * zfs unshare -a 3051 * zfs unshare filesystem 3052 * 3053 * Unshare all filesystems, or a specific ZFS filesystem. 3054 */ 3055 static int 3056 zfs_do_unshare(int argc, char **argv) 3057 { 3058 return (unshare_unmount(OP_SHARE, argc, argv)); 3059 } 3060 3061 /* 3062 * Called when invoked as /etc/fs/zfs/mount. Do the mount if the mountpoint is 3063 * 'legacy'. Otherwise, complain that use should be using 'zfs mount'. 3064 */ 3065 static int 3066 manual_mount(int argc, char **argv) 3067 { 3068 zfs_handle_t *zhp; 3069 char mountpoint[ZFS_MAXPROPLEN]; 3070 char mntopts[MNT_LINE_MAX] = { '\0' }; 3071 int ret; 3072 int c; 3073 int flags = 0; 3074 char *dataset, *path; 3075 3076 /* check options */ 3077 while ((c = getopt(argc, argv, ":mo:O")) != -1) { 3078 switch (c) { 3079 case 'o': 3080 (void) strlcpy(mntopts, optarg, sizeof (mntopts)); 3081 break; 3082 case 'O': 3083 flags |= MS_OVERLAY; 3084 break; 3085 case 'm': 3086 flags |= MS_NOMNTTAB; 3087 break; 3088 case ':': 3089 (void) fprintf(stderr, gettext("missing argument for " 3090 "'%c' option\n"), optopt); 3091 usage(B_FALSE); 3092 break; 3093 case '?': 3094 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3095 optopt); 3096 (void) fprintf(stderr, gettext("usage: mount [-o opts] " 3097 "<path>\n")); 3098 return (2); 3099 } 3100 } 3101 3102 argc -= optind; 3103 argv += optind; 3104 3105 /* check that we only have two arguments */ 3106 if (argc != 2) { 3107 if (argc == 0) 3108 (void) fprintf(stderr, gettext("missing dataset " 3109 "argument\n")); 3110 else if (argc == 1) 3111 (void) fprintf(stderr, 3112 gettext("missing mountpoint argument\n")); 3113 else 3114 (void) fprintf(stderr, gettext("too many arguments\n")); 3115 (void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n"); 3116 return (2); 3117 } 3118 3119 dataset = argv[0]; 3120 path = argv[1]; 3121 3122 /* try to open the dataset */ 3123 if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) 3124 return (1); 3125 3126 (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 3127 sizeof (mountpoint), NULL, NULL, 0, B_FALSE); 3128 3129 /* check for legacy mountpoint and complain appropriately */ 3130 ret = 0; 3131 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 3132 if (mount(dataset, path, MS_OPTIONSTR | flags, MNTTYPE_ZFS, 3133 NULL, 0, mntopts, sizeof (mntopts)) != 0) { 3134 (void) fprintf(stderr, gettext("mount failed: %s\n"), 3135 strerror(errno)); 3136 ret = 1; 3137 } 3138 } else { 3139 (void) fprintf(stderr, gettext("filesystem '%s' cannot be " 3140 "mounted using 'mount -F zfs'\n"), dataset); 3141 (void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' " 3142 "instead.\n"), path); 3143 (void) fprintf(stderr, gettext("If you must use 'mount -F zfs' " 3144 "or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n")); 3145 (void) fprintf(stderr, gettext("See zfs(1M) for more " 3146 "information.\n")); 3147 ret = 1; 3148 } 3149 3150 return (ret); 3151 } 3152 3153 /* 3154 * Called when invoked as /etc/fs/zfs/umount. Unlike a manual mount, we allow 3155 * unmounts of non-legacy filesystems, as this is the dominant administrative 3156 * interface. 3157 */ 3158 static int 3159 manual_unmount(int argc, char **argv) 3160 { 3161 int flags = 0; 3162 int c; 3163 3164 /* check options */ 3165 while ((c = getopt(argc, argv, "f")) != -1) { 3166 switch (c) { 3167 case 'f': 3168 flags = MS_FORCE; 3169 break; 3170 case '?': 3171 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3172 optopt); 3173 (void) fprintf(stderr, gettext("usage: unmount [-f] " 3174 "<path>\n")); 3175 return (2); 3176 } 3177 } 3178 3179 argc -= optind; 3180 argv += optind; 3181 3182 /* check arguments */ 3183 if (argc != 1) { 3184 if (argc == 0) 3185 (void) fprintf(stderr, gettext("missing path " 3186 "argument\n")); 3187 else 3188 (void) fprintf(stderr, gettext("too many arguments\n")); 3189 (void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n")); 3190 return (2); 3191 } 3192 3193 return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE)); 3194 } 3195 3196 static int 3197 volcheck(zpool_handle_t *zhp, void *data) 3198 { 3199 boolean_t isinit = *((boolean_t *)data); 3200 3201 if (isinit) 3202 return (zpool_create_zvol_links(zhp)); 3203 else 3204 return (zpool_remove_zvol_links(zhp)); 3205 } 3206 3207 /* 3208 * Iterate over all pools in the system and either create or destroy /dev/zvol 3209 * links, depending on the value of 'isinit'. 3210 */ 3211 static int 3212 do_volcheck(boolean_t isinit) 3213 { 3214 return (zpool_iter(g_zfs, volcheck, &isinit) ? 1 : 0); 3215 } 3216 3217 int 3218 main(int argc, char **argv) 3219 { 3220 int ret; 3221 int i; 3222 char *progname; 3223 char *cmdname; 3224 3225 (void) setlocale(LC_ALL, ""); 3226 (void) textdomain(TEXT_DOMAIN); 3227 3228 opterr = 0; 3229 3230 if ((g_zfs = libzfs_init()) == NULL) { 3231 (void) fprintf(stderr, gettext("internal error: failed to " 3232 "initialize ZFS library\n")); 3233 return (1); 3234 } 3235 3236 libzfs_print_on_error(g_zfs, B_TRUE); 3237 3238 if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) { 3239 (void) fprintf(stderr, gettext("internal error: unable to " 3240 "open %s\n"), MNTTAB); 3241 return (1); 3242 } 3243 3244 /* 3245 * This command also doubles as the /etc/fs mount and unmount program. 3246 * Determine if we should take this behavior based on argv[0]. 3247 */ 3248 progname = basename(argv[0]); 3249 if (strcmp(progname, "mount") == 0) { 3250 ret = manual_mount(argc, argv); 3251 } else if (strcmp(progname, "umount") == 0) { 3252 ret = manual_unmount(argc, argv); 3253 } else { 3254 /* 3255 * Make sure the user has specified some command. 3256 */ 3257 if (argc < 2) { 3258 (void) fprintf(stderr, gettext("missing command\n")); 3259 usage(B_FALSE); 3260 } 3261 3262 cmdname = argv[1]; 3263 3264 /* 3265 * The 'umount' command is an alias for 'unmount' 3266 */ 3267 if (strcmp(cmdname, "umount") == 0) 3268 cmdname = "unmount"; 3269 3270 /* 3271 * The 'recv' command is an alias for 'receive' 3272 */ 3273 if (strcmp(cmdname, "recv") == 0) 3274 cmdname = "receive"; 3275 3276 /* 3277 * Special case '-?' 3278 */ 3279 if (strcmp(cmdname, "-?") == 0) 3280 usage(B_TRUE); 3281 3282 /* 3283 * 'volinit' and 'volfini' do not appear in the usage message, 3284 * so we have to special case them here. 3285 */ 3286 if (strcmp(cmdname, "volinit") == 0) 3287 return (do_volcheck(B_TRUE)); 3288 else if (strcmp(cmdname, "volfini") == 0) 3289 return (do_volcheck(B_FALSE)); 3290 3291 /* 3292 * Run the appropriate command. 3293 */ 3294 for (i = 0; i < NCOMMAND; i++) { 3295 if (command_table[i].name == NULL) 3296 continue; 3297 3298 if (strcmp(cmdname, command_table[i].name) == 0) { 3299 current_command = &command_table[i]; 3300 ret = command_table[i].func(argc - 1, argv + 1); 3301 break; 3302 } 3303 } 3304 3305 if (i == NCOMMAND) { 3306 (void) fprintf(stderr, gettext("unrecognized " 3307 "command '%s'\n"), cmdname); 3308 usage(B_FALSE); 3309 } 3310 } 3311 3312 (void) fclose(mnttab_file); 3313 3314 libzfs_fini(g_zfs); 3315 3316 /* 3317 * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3318 * for the purposes of running ::findleaks. 3319 */ 3320 if (getenv("ZFS_ABORT") != NULL) { 3321 (void) printf("dumping core by request\n"); 3322 abort(); 3323 } 3324 3325 return (ret); 3326 } 3327