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