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