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