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