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