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 2005 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 <filesystems|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_force; 1288 int cb_doclones; 1289 char *cb_target; 1290 int cb_error; 1291 int cb_recurse; 1292 int cb_dependent; 1293 } rollback_cbdata_t; 1294 1295 /* 1296 * Report any snapshots more recent than the one specified. Used when '-r' is 1297 * not specified. We reuse this same callback for the snapshot dependents - if 1298 * 'cb_dependent' is set, then this is a dependent and we should report it 1299 * without checking the transaction group. 1300 */ 1301 static int 1302 rollback_check(zfs_handle_t *zhp, void *data) 1303 { 1304 rollback_cbdata_t *cbp = data; 1305 1306 if (cbp->cb_doclones) 1307 return (0); 1308 1309 if (!cbp->cb_dependent) { 1310 if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 && 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 /* 1356 * Unmount any filesystems or snapshots that will need to be destroyed as part 1357 * of the rollback process. 1358 */ 1359 static int 1360 rollback_unmount(zfs_handle_t *zhp, void *data) 1361 { 1362 rollback_cbdata_t *cbp = data; 1363 1364 if (!cbp->cb_dependent) { 1365 if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 && 1366 zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 1367 cbp->cb_create) { 1368 1369 cbp->cb_dependent = TRUE; 1370 (void) zfs_iter_dependents(zhp, rollback_unmount, cbp); 1371 cbp->cb_dependent = FALSE; 1372 1373 if (zfs_unmount(zhp, NULL, 1374 cbp->cb_force ? MS_FORCE: 0) != 0) 1375 cbp->cb_error = 1; 1376 } 1377 } else if (zfs_unmount(zhp, NULL, cbp->cb_force ? MS_FORCE : 0) != 0) { 1378 cbp->cb_error = 1; 1379 } 1380 1381 zfs_close(zhp); 1382 return (0); 1383 } 1384 1385 /* 1386 * Destroy any more recent snapshots. We invoke this callback on any dependents 1387 * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 1388 * is a dependent and we should just destroy it without checking the transaction 1389 * group. 1390 */ 1391 static int 1392 rollback_destroy(zfs_handle_t *zhp, void *data) 1393 { 1394 rollback_cbdata_t *cbp = data; 1395 1396 if (!cbp->cb_dependent) { 1397 if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 && 1398 zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 1399 cbp->cb_create) { 1400 1401 cbp->cb_dependent = TRUE; 1402 (void) zfs_iter_dependents(zhp, rollback_destroy, cbp); 1403 cbp->cb_dependent = FALSE; 1404 1405 if (zfs_destroy(zhp) != 0) 1406 cbp->cb_error = 1; 1407 } 1408 } else if (zfs_destroy(zhp) != 0) { 1409 cbp->cb_error = 1; 1410 } 1411 1412 zfs_close(zhp); 1413 return (0); 1414 } 1415 1416 static int 1417 zfs_do_rollback(int argc, char **argv) 1418 { 1419 int ret; 1420 int c; 1421 rollback_cbdata_t cb = { 0 }; 1422 int was_mounted; 1423 zfs_handle_t *zhp, *snap; 1424 char parentname[ZFS_MAXNAMELEN]; 1425 char *delim; 1426 1427 /* check options */ 1428 while ((c = getopt(argc, argv, "rfR")) != -1) { 1429 switch (c) { 1430 case 'f': 1431 cb.cb_force = TRUE; 1432 break; 1433 case 'r': 1434 cb.cb_recurse = 1; 1435 break; 1436 case 'R': 1437 cb.cb_recurse = 1; 1438 cb.cb_doclones = 1; 1439 break; 1440 case '?': 1441 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1442 optopt); 1443 usage(FALSE); 1444 } 1445 } 1446 1447 argc -= optind; 1448 argv += optind; 1449 1450 /* check number of arguments */ 1451 if (argc < 1) { 1452 (void) fprintf(stderr, gettext("missing dataset argument\n")); 1453 usage(FALSE); 1454 } 1455 if (argc > 1) { 1456 (void) fprintf(stderr, gettext("too many arguments\n")); 1457 usage(FALSE); 1458 } 1459 1460 cb.cb_target = argv[0]; 1461 1462 /* open the snapshot */ 1463 if ((snap = zfs_open(cb.cb_target, ZFS_TYPE_SNAPSHOT)) == NULL) 1464 return (1); 1465 1466 (void) strlcpy(parentname, cb.cb_target, sizeof (parentname)); 1467 verify((delim = strrchr(parentname, '@')) != NULL); 1468 *delim = '\0'; 1469 if ((zhp = zfs_open(parentname, ZFS_TYPE_ANY)) == NULL) { 1470 zfs_close(snap); 1471 return (1); 1472 } 1473 1474 /* See if this dataset is mounted */ 1475 was_mounted = zfs_is_mounted(zhp, NULL); 1476 1477 cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 1478 1479 /* 1480 * Check for more recent snapshots and/or clones based on the presence 1481 * of '-r' and '-R'. 1482 */ 1483 cb.cb_first = 1; 1484 cb.cb_error = 0; 1485 (void) zfs_iter_children(zhp, rollback_check, &cb); 1486 1487 if ((ret = cb.cb_error) != 0) 1488 goto out; 1489 1490 cb.cb_error = 0; 1491 1492 /* 1493 * Unmount any snapshots as well as the dataset itself. 1494 */ 1495 if ((ret = zfs_iter_children(zhp, rollback_unmount, 1496 &cb)) != 0 || (ret = zfs_unmount(zhp, NULL, 1497 cb.cb_force ? MS_FORCE : 0)) != 0) 1498 goto out; 1499 1500 (void) zfs_iter_children(zhp, rollback_destroy, &cb); 1501 1502 if ((ret = cb.cb_error) != 0) 1503 goto out; 1504 1505 /* 1506 * Now that we have verified that the snapshot is the latest, rollback 1507 * to the given snapshot. 1508 */ 1509 ret = zfs_rollback(zhp); 1510 1511 /* 1512 * We only want to re-mount the filesystem if it was mounted in the 1513 * first place. 1514 */ 1515 if (was_mounted) 1516 (void) zfs_mount(zhp, NULL, 0); 1517 1518 out: 1519 zfs_close(snap); 1520 zfs_close(zhp); 1521 1522 if (ret == 0) 1523 return (0); 1524 else 1525 return (1); 1526 } 1527 1528 /* 1529 * zfs set property=value { fs | snap | vol } ... 1530 * 1531 * Sets the given property for all datasets specified on the command line. 1532 */ 1533 typedef struct set_cbdata { 1534 char *cb_propname; 1535 char *cb_value; 1536 zfs_prop_t cb_prop; 1537 } set_cbdata_t; 1538 1539 static int 1540 set_callback(zfs_handle_t *zhp, void *data) 1541 { 1542 set_cbdata_t *cbp = data; 1543 int ret = 1; 1544 1545 /* don't allow setting of properties for snapshots */ 1546 if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) { 1547 (void) fprintf(stderr, gettext("cannot set %s property for " 1548 "'%s': snapshot properties cannot be modified\n"), 1549 cbp->cb_propname, zfs_get_name(zhp)); 1550 return (1); 1551 } 1552 1553 /* 1554 * If we're changing the volsize, and the volsize and reservation are 1555 * the same, then change the reservation as well. 1556 */ 1557 if (cbp->cb_prop == ZFS_PROP_VOLSIZE && 1558 zfs_get_type(zhp) == ZFS_TYPE_VOLUME && 1559 zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE) == 1560 zfs_prop_get_int(zhp, ZFS_PROP_RESERVATION)) { 1561 uint64_t volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1562 uint64_t avail = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE); 1563 uint64_t value; 1564 1565 verify(zfs_nicestrtonum(cbp->cb_value, &value) == 0); 1566 1567 /* 1568 * Warn about raising the volume size greater than the amount of 1569 * available space. 1570 */ 1571 if (value > volsize && (value - volsize) > avail) { 1572 (void) fprintf(stderr, gettext("cannot set " 1573 "%s property for '%s': volume size exceeds " 1574 "amount of available space\n"), 1575 cbp->cb_propname, zfs_get_name(zhp)); 1576 return (1); 1577 } 1578 1579 if (zfs_prop_set(zhp, ZFS_PROP_RESERVATION, 1580 cbp->cb_value) != 0) { 1581 (void) fprintf(stderr, gettext("volsize and " 1582 "reservation must remain equal\n")); 1583 return (1); 1584 } 1585 } 1586 1587 /* 1588 * Do not allow the reservation to be set above the volume size. We do 1589 * this here instead of inside libzfs because libzfs violates this rule 1590 * internally. 1591 */ 1592 if (cbp->cb_prop == ZFS_PROP_RESERVATION && 1593 zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 1594 uint64_t value; 1595 uint64_t volsize; 1596 1597 volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 1598 if (strcmp(cbp->cb_value, "none") == 0) 1599 value = 0; 1600 else 1601 verify(zfs_nicestrtonum(cbp->cb_value, &value) == 0); 1602 1603 if (value > volsize) { 1604 (void) fprintf(stderr, gettext("cannot set %s " 1605 "for '%s': size is greater than current " 1606 "volume size\n"), cbp->cb_propname, 1607 zfs_get_name(zhp)); 1608 return (-1); 1609 } 1610 } 1611 1612 if (zfs_prop_set(zhp, cbp->cb_prop, cbp->cb_value) != 0) 1613 return (1); 1614 1615 ret = 0; 1616 error: 1617 return (ret); 1618 } 1619 1620 static int 1621 zfs_do_set(int argc, char **argv) 1622 { 1623 set_cbdata_t cb; 1624 1625 /* check for options */ 1626 if (argc > 1 && argv[1][0] == '-') { 1627 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1628 argv[1][1]); 1629 usage(FALSE); 1630 } 1631 1632 /* check number of arguments */ 1633 if (argc < 2) { 1634 (void) fprintf(stderr, gettext("missing property=value " 1635 "argument\n")); 1636 usage(FALSE); 1637 } 1638 if (argc < 3) { 1639 (void) fprintf(stderr, gettext("missing dataset name\n")); 1640 usage(FALSE); 1641 } 1642 1643 /* validate property=value argument */ 1644 cb.cb_propname = argv[1]; 1645 if ((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) { 1646 (void) fprintf(stderr, gettext("missing value in " 1647 "property=value argument\n")); 1648 usage(FALSE); 1649 } 1650 1651 *cb.cb_value = '\0'; 1652 cb.cb_value++; 1653 1654 if (*cb.cb_propname == '\0') { 1655 (void) fprintf(stderr, 1656 gettext("missing property in property=value argument\n")); 1657 usage(FALSE); 1658 } 1659 if (*cb.cb_value == '\0') { 1660 (void) fprintf(stderr, 1661 gettext("missing value in property=value argument\n")); 1662 usage(FALSE); 1663 } 1664 1665 /* get the property type */ 1666 if ((cb.cb_prop = zfs_name_to_prop(cb.cb_propname)) == 1667 ZFS_PROP_INVAL) { 1668 (void) fprintf(stderr, 1669 gettext("invalid property '%s'\n"), cb.cb_propname); 1670 usage(FALSE); 1671 } 1672 1673 /* 1674 * Validate that the value is appropriate for this property. We do this 1675 * once now so we don't generate multiple errors each time we try to 1676 * apply it to a dataset. 1677 */ 1678 if (zfs_prop_validate(cb.cb_prop, cb.cb_value, NULL) != 0) 1679 return (1); 1680 1681 return (zfs_for_each(argc - 2, argv + 2, FALSE, 1682 ZFS_TYPE_ANY, set_callback, &cb)); 1683 } 1684 1685 /* 1686 * zfs snapshot <fs@snap> 1687 * 1688 * Creates a snapshot with the given name. While functionally equivalent to 1689 * 'zfs create', it is a separate command to diffferentiate intent. 1690 */ 1691 static int 1692 zfs_do_snapshot(int argc, char **argv) 1693 { 1694 /* check options */ 1695 if (argc > 1 && argv[1][0] == '-') { 1696 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1697 argv[1][1]); 1698 usage(FALSE); 1699 } 1700 1701 /* check number of arguments */ 1702 if (argc < 2) { 1703 (void) fprintf(stderr, gettext("missing snapshot argument\n")); 1704 usage(FALSE); 1705 } 1706 if (argc > 2) { 1707 (void) fprintf(stderr, gettext("too many arguments\n")); 1708 usage(FALSE); 1709 } 1710 1711 return (zfs_snapshot(argv[1]) != 0); 1712 } 1713 1714 /* 1715 * zfs backup [-i <fs@snap>] <fs@snap> 1716 * 1717 * Send a backup stream to stdout. 1718 */ 1719 static int 1720 zfs_do_backup(int argc, char **argv) 1721 { 1722 char *fromname = NULL; 1723 zfs_handle_t *zhp_from = NULL, *zhp_to; 1724 int c, err; 1725 1726 /* check options */ 1727 while ((c = getopt(argc, argv, ":i:")) != -1) { 1728 switch (c) { 1729 case 'i': 1730 fromname = optarg; 1731 break; 1732 case ':': 1733 (void) fprintf(stderr, gettext("missing argument for " 1734 "'%c' option\n"), optopt); 1735 usage(FALSE); 1736 break; 1737 case '?': 1738 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1739 optopt); 1740 usage(FALSE); 1741 } 1742 } 1743 1744 argc -= optind; 1745 argv += optind; 1746 1747 /* check number of arguments */ 1748 if (argc < 1) { 1749 (void) fprintf(stderr, gettext("missing snapshot argument\n")); 1750 usage(FALSE); 1751 } 1752 if (argc > 1) { 1753 (void) fprintf(stderr, gettext("too many arguments\n")); 1754 usage(FALSE); 1755 } 1756 1757 if (isatty(STDOUT_FILENO)) { 1758 (void) fprintf(stderr, 1759 gettext("Error: Backup stream can not be written " 1760 "to a terminal.\n" 1761 "You must redirect standard output.\n")); 1762 return (1); 1763 } 1764 1765 if (fromname) { 1766 if ((zhp_from = zfs_open(fromname, ZFS_TYPE_SNAPSHOT)) == NULL) 1767 return (1); 1768 } 1769 if ((zhp_to = zfs_open(argv[0], ZFS_TYPE_SNAPSHOT)) == NULL) 1770 return (1); 1771 1772 err = zfs_backup(zhp_to, zhp_from); 1773 1774 if (zhp_from) 1775 zfs_close(zhp_from); 1776 zfs_close(zhp_to); 1777 1778 return (err != 0); 1779 } 1780 1781 /* 1782 * zfs restore <fs@snap> 1783 * 1784 * Restore a backup stream from stdin. 1785 */ 1786 static int 1787 zfs_do_restore(int argc, char **argv) 1788 { 1789 int c, err; 1790 int isprefix = FALSE; 1791 int dryrun = FALSE; 1792 int verbose = FALSE; 1793 1794 /* check options */ 1795 while ((c = getopt(argc, argv, ":dnv")) != -1) { 1796 switch (c) { 1797 case 'd': 1798 isprefix = TRUE; 1799 break; 1800 case 'n': 1801 dryrun = TRUE; 1802 break; 1803 case 'v': 1804 verbose = TRUE; 1805 break; 1806 case ':': 1807 (void) fprintf(stderr, gettext("missing argument for " 1808 "'%c' option\n"), optopt); 1809 usage(FALSE); 1810 break; 1811 case '?': 1812 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1813 optopt); 1814 usage(FALSE); 1815 } 1816 } 1817 1818 argc -= optind; 1819 argv += optind; 1820 1821 /* check number of arguments */ 1822 if (argc < 1) { 1823 (void) fprintf(stderr, gettext("missing snapshot argument\n")); 1824 usage(FALSE); 1825 } 1826 if (argc > 1) { 1827 (void) fprintf(stderr, gettext("too many arguments\n")); 1828 usage(FALSE); 1829 } 1830 1831 if (isatty(STDIN_FILENO)) { 1832 (void) fprintf(stderr, 1833 gettext("Error: Backup stream can not be read " 1834 "from a terminal.\n" 1835 "You must redirect standard input.\n")); 1836 return (1); 1837 } 1838 1839 err = zfs_restore(argv[0], isprefix, verbose, dryrun); 1840 return (err != 0); 1841 } 1842 1843 1844 /* 1845 * Generic callback for sharing or mounting filesystems. Because the code is so 1846 * similar, we have a common function with an extra parameter to determine which 1847 * mode we are using. 1848 */ 1849 #define OP_SHARE 0x1 1850 #define OP_MOUNT 0x2 1851 1852 typedef struct share_mount_cbdata { 1853 int cb_type; 1854 int cb_explicit; 1855 int cb_flags; 1856 const char *cb_options; 1857 } share_mount_cbdata_t; 1858 1859 /* 1860 * Share or mount the filesystem. 1861 */ 1862 static int 1863 share_mount_callback(zfs_handle_t *zhp, void *data) 1864 { 1865 char mountpoint[ZFS_MAXPROPLEN]; 1866 char shareopts[ZFS_MAXPROPLEN]; 1867 share_mount_cbdata_t *cbp = data; 1868 const char *cmdname = cbp->cb_type == OP_SHARE ? "share" : "mount"; 1869 struct mnttab mnt; 1870 uint64_t zoned; 1871 1872 if (cbp->cb_options == NULL) 1873 mnt.mnt_mntopts = ""; 1874 else 1875 mnt.mnt_mntopts = (char *)cbp->cb_options; 1876 1877 /* 1878 * Check to make sure we can mount/share this dataset. If we are in the 1879 * global zone and the filesystem is exported to a local zone, or if we 1880 * are in a local zone and the filesystem is not exported, then it is an 1881 * error. 1882 */ 1883 zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 1884 1885 if (zoned && getzoneid() == GLOBAL_ZONEID) { 1886 if (!cbp->cb_explicit) 1887 return (0); 1888 1889 (void) fprintf(stderr, gettext("cannot %s '%s': dataset is " 1890 "exported to a local zone\n"), cmdname, zfs_get_name(zhp)); 1891 return (1); 1892 1893 } else if (!zoned && getzoneid() != GLOBAL_ZONEID) { 1894 if (!cbp->cb_explicit) 1895 return (0); 1896 1897 (void) fprintf(stderr, gettext("cannot %s '%s': permission " 1898 "denied\n"), cmdname, zfs_get_name(zhp)); 1899 return (1); 1900 } 1901 1902 /* 1903 * Inore any filesystems which don't apply to us. This includes those 1904 * with a legacy mountpoint, or those with legacy share options. 1905 */ 1906 verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 1907 sizeof (mountpoint), NULL, NULL, 0, FALSE) == 0); 1908 verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, 1909 sizeof (shareopts), NULL, NULL, 0, FALSE) == 0); 1910 1911 if (cbp->cb_type == OP_SHARE) { 1912 if (strcmp(shareopts, "off") == 0) { 1913 if (!cbp->cb_explicit) 1914 return (0); 1915 1916 (void) fprintf(stderr, gettext("cannot share '%s': " 1917 "legacy share\n"), zfs_get_name(zhp)); 1918 (void) fprintf(stderr, gettext("use share(1M) to " 1919 "share this filesystem\n")); 1920 return (1); 1921 } 1922 } 1923 1924 /* 1925 * We cannot share or mount legacy filesystems. If the shareopts is 1926 * non-legacy but the mountpoint is legacy, we treat it as a legacy 1927 * share. 1928 */ 1929 if (strcmp(mountpoint, "legacy") == 0) { 1930 if (!cbp->cb_explicit) 1931 return (0); 1932 1933 (void) fprintf(stderr, gettext("cannot %s '%s': " 1934 "legacy mountpoint\n"), cmdname, zfs_get_name(zhp)); 1935 (void) fprintf(stderr, gettext("use %s to " 1936 "%s this filesystem\n"), cbp->cb_type == OP_SHARE ? 1937 "share(1M)" : "mount(1M)", cmdname); 1938 return (1); 1939 } 1940 1941 if (strcmp(mountpoint, "none") == 0) { 1942 if (!cbp->cb_explicit) 1943 return (0); 1944 1945 (void) fprintf(stderr, gettext("cannot %s '%s': no " 1946 "mountpoint set\n"), cmdname, zfs_get_name(zhp)); 1947 return (1); 1948 } 1949 1950 /* 1951 * At this point, we have verified that the mountpoint and/or shareopts 1952 * are appropriate for auto management. Determine if the filesystem is 1953 * currently mounted or shared, and abort if this is an explicit 1954 * request. 1955 */ 1956 switch (cbp->cb_type) { 1957 case OP_SHARE: 1958 if (zfs_is_shared(zhp, NULL)) { 1959 if (cbp->cb_explicit) { 1960 (void) fprintf(stderr, gettext("cannot share " 1961 "'%s': filesystem already shared\n"), 1962 zfs_get_name(zhp)); 1963 return (1); 1964 } else { 1965 return (0); 1966 } 1967 } 1968 break; 1969 1970 case OP_MOUNT: 1971 if (!hasmntopt(&mnt, MNTOPT_REMOUNT) && 1972 zfs_is_mounted(zhp, NULL)) { 1973 if (cbp->cb_explicit) { 1974 (void) fprintf(stderr, gettext("cannot mount " 1975 "'%s': filesystem already mounted\n"), 1976 zfs_get_name(zhp)); 1977 return (1); 1978 } else { 1979 return (0); 1980 } 1981 } 1982 break; 1983 } 1984 1985 /* 1986 * Mount and optionally share the filesystem. 1987 */ 1988 switch (cbp->cb_type) { 1989 case OP_SHARE: 1990 { 1991 if (!zfs_is_mounted(zhp, NULL) && 1992 zfs_mount(zhp, NULL, 0) != 0) 1993 return (1); 1994 1995 if (zfs_share(zhp) != 0) 1996 return (1); 1997 } 1998 break; 1999 2000 case OP_MOUNT: 2001 if (zfs_mount(zhp, cbp->cb_options, cbp->cb_flags) != 0) 2002 return (1); 2003 break; 2004 } 2005 2006 return (0); 2007 } 2008 2009 static int 2010 share_or_mount(int type, int argc, char **argv) 2011 { 2012 int do_all = 0; 2013 int c, ret; 2014 share_mount_cbdata_t cb = { 0 }; 2015 2016 cb.cb_type = type; 2017 2018 /* check options */ 2019 while ((c = getopt(argc, argv, type == OP_MOUNT ? ":ao:O" : "a")) 2020 != -1) { 2021 switch (c) { 2022 case 'a': 2023 do_all = 1; 2024 break; 2025 case 'o': 2026 cb.cb_options = optarg; 2027 break; 2028 case 'O': 2029 cb.cb_flags |= MS_OVERLAY; 2030 break; 2031 case ':': 2032 (void) fprintf(stderr, gettext("missing argument for " 2033 "'%c' option\n"), optopt); 2034 usage(FALSE); 2035 break; 2036 case '?': 2037 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2038 optopt); 2039 usage(FALSE); 2040 } 2041 } 2042 2043 argc -= optind; 2044 argv += optind; 2045 2046 /* check number of arguments */ 2047 if (do_all) { 2048 if (argc != 0) { 2049 (void) fprintf(stderr, gettext("too many arguments\n")); 2050 usage(FALSE); 2051 } 2052 2053 ret = zfs_for_each(argc, argv, TRUE, 2054 ZFS_TYPE_FILESYSTEM, share_mount_callback, &cb); 2055 } else if (argc == 0) { 2056 struct mnttab entry; 2057 2058 if (type == OP_SHARE) { 2059 (void) fprintf(stderr, gettext("missing filesystem " 2060 "argument\n")); 2061 usage(FALSE); 2062 } 2063 2064 /* 2065 * When mount is given no arguments, go through /etc/mnttab and 2066 * display any active ZFS mounts. We hide any snapshots, since 2067 * they are controlled automatically. 2068 */ 2069 rewind(mnttab_file); 2070 while (getmntent(mnttab_file, &entry) == 0) { 2071 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 || 2072 strchr(entry.mnt_special, '@') != NULL) 2073 continue; 2074 2075 (void) printf("%-30s %s\n", entry.mnt_special, 2076 entry.mnt_mountp); 2077 } 2078 2079 ret = 0; 2080 } else { 2081 zfs_handle_t *zhp; 2082 2083 if (argc > 1) { 2084 (void) fprintf(stderr, 2085 gettext("too many arguments\n")); 2086 usage(FALSE); 2087 } 2088 2089 if ((zhp = zfs_open(argv[0], ZFS_TYPE_FILESYSTEM)) == NULL) 2090 ret = 1; 2091 else { 2092 cb.cb_explicit = TRUE; 2093 ret = share_mount_callback(zhp, &cb); 2094 zfs_close(zhp); 2095 } 2096 } 2097 2098 return (ret); 2099 } 2100 2101 /* 2102 * zfs mount -a 2103 * zfs mount filesystem 2104 * 2105 * Mount all filesystems, or mount the given filesystem. 2106 */ 2107 static int 2108 zfs_do_mount(int argc, char **argv) 2109 { 2110 return (share_or_mount(OP_MOUNT, argc, argv)); 2111 } 2112 2113 /* 2114 * zfs share -a 2115 * zfs share filesystem 2116 * 2117 * Share all filesystems, or share the given filesystem. 2118 */ 2119 static int 2120 zfs_do_share(int argc, char **argv) 2121 { 2122 return (share_or_mount(OP_SHARE, argc, argv)); 2123 } 2124 2125 typedef struct unshare_unmount_node { 2126 zfs_handle_t *un_zhp; 2127 char *un_mountp; 2128 uu_avl_node_t un_avlnode; 2129 } unshare_unmount_node_t; 2130 2131 /* ARGSUSED */ 2132 static int 2133 unshare_unmount_compare(const void *larg, const void *rarg, void *unused) 2134 { 2135 const unshare_unmount_node_t *l = larg; 2136 const unshare_unmount_node_t *r = rarg; 2137 2138 return (strcmp(l->un_mountp, r->un_mountp)); 2139 } 2140 2141 /* 2142 * Convenience routine used by zfs_do_umount() and manual_unmount(). Given an 2143 * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem, 2144 * and unmount it appropriately. 2145 */ 2146 static int 2147 unshare_unmount_path(int type, char *path, int flags, int is_manual) 2148 { 2149 zfs_handle_t *zhp; 2150 int ret; 2151 struct stat64 statbuf; 2152 struct extmnttab entry; 2153 const char *cmdname = (type == OP_SHARE) ? "unshare" : "unmount"; 2154 char property[ZFS_MAXPROPLEN]; 2155 2156 /* 2157 * Search for the path in /etc/mnttab. Rather than looking for the 2158 * specific path, which can be fooled by non-standard paths (i.e. ".." 2159 * or "//"), we stat() the path and search for the corresponding 2160 * (major,minor) device pair. 2161 */ 2162 if (stat64(path, &statbuf) != 0) { 2163 (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"), 2164 cmdname, path, strerror(errno)); 2165 return (1); 2166 } 2167 2168 /* 2169 * Search for the given (major,minor) pair in the mount table. 2170 */ 2171 rewind(mnttab_file); 2172 while ((ret = getextmntent(mnttab_file, &entry, 0)) == 0) { 2173 if (entry.mnt_major == major(statbuf.st_dev) && 2174 entry.mnt_minor == minor(statbuf.st_dev)) 2175 break; 2176 } 2177 if (ret != 0) { 2178 (void) fprintf(stderr, gettext("cannot %s '%s': not " 2179 "currently mounted\n"), cmdname, path); 2180 return (1); 2181 } 2182 2183 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) { 2184 (void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS " 2185 "filesystem\n"), cmdname, path); 2186 return (1); 2187 } 2188 2189 if ((zhp = zfs_open(entry.mnt_special, ZFS_TYPE_FILESYSTEM)) == NULL) 2190 return (1); 2191 2192 verify(zfs_prop_get(zhp, type == OP_SHARE ? 2193 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property, 2194 sizeof (property), NULL, NULL, 0, FALSE) == 0); 2195 2196 if (type == OP_SHARE) { 2197 if (strcmp(property, "off") == 0) { 2198 (void) fprintf(stderr, gettext("cannot unshare " 2199 "'%s': legacy share\n"), path); 2200 (void) fprintf(stderr, gettext("use " 2201 "unshare(1M) to unshare this filesystem\n")); 2202 ret = 1; 2203 } else if (!zfs_is_shared(zhp, NULL)) { 2204 (void) fprintf(stderr, gettext("cannot unshare '%s': " 2205 "not currently shared\n"), path); 2206 ret = 1; 2207 } else { 2208 ret = zfs_unshareall(zhp); 2209 } 2210 } else { 2211 if (strcmp(property, "legacy") == 0 && !is_manual) { 2212 (void) fprintf(stderr, gettext("cannot unmount " 2213 "'%s': legacy mountpoint\n"), 2214 zfs_get_name(zhp)); 2215 (void) fprintf(stderr, gettext("use umount(1M) " 2216 "to unmount this filesystem\n")); 2217 ret = 1; 2218 } else { 2219 ret = zfs_unmountall(zhp, flags); 2220 } 2221 } 2222 2223 zfs_close(zhp); 2224 2225 return (ret != 0); 2226 } 2227 2228 /* 2229 * Generic callback for unsharing or unmounting a filesystem. 2230 */ 2231 static int 2232 unshare_unmount(int type, int argc, char **argv) 2233 { 2234 int do_all = 0; 2235 int flags = 0; 2236 int ret = 0; 2237 int c; 2238 zfs_handle_t *zhp; 2239 char property[ZFS_MAXPROPLEN]; 2240 2241 /* check options */ 2242 while ((c = getopt(argc, argv, type == OP_SHARE ? "a" : "af")) != -1) { 2243 switch (c) { 2244 case 'a': 2245 do_all = 1; 2246 break; 2247 case 'f': 2248 flags = MS_FORCE; 2249 break; 2250 case '?': 2251 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2252 optopt); 2253 usage(FALSE); 2254 } 2255 } 2256 2257 argc -= optind; 2258 argv += optind; 2259 2260 /* ensure correct number of arguments */ 2261 if (do_all) { 2262 if (argc != 0) { 2263 (void) fprintf(stderr, gettext("too many arguments\n")); 2264 usage(FALSE); 2265 } 2266 } else if (argc != 1) { 2267 if (argc == 0) 2268 (void) fprintf(stderr, 2269 gettext("missing filesystem argument\n")); 2270 else 2271 (void) fprintf(stderr, 2272 gettext("too many arguments\n")); 2273 usage(FALSE); 2274 } 2275 2276 if (do_all) { 2277 /* 2278 * We could make use of zfs_for_each() to walk all datasets in 2279 * the system, but this would be very inefficient, especially 2280 * since we would have to linearly search /etc/mnttab for each 2281 * one. Instead, do one pass through /etc/mnttab looking for 2282 * zfs entries and call zfs_unmount() for each one. 2283 * 2284 * Things get a little tricky if the administrator has created 2285 * mountpoints beneath other ZFS filesystems. In this case, we 2286 * have to unmount the deepest filesystems first. To accomplish 2287 * this, we place all the mountpoints in an AVL tree sorted by 2288 * the special type (dataset name), and walk the result in 2289 * reverse to make sure to get any snapshots first. 2290 */ 2291 struct mnttab entry; 2292 uu_avl_pool_t *pool; 2293 uu_avl_t *tree; 2294 unshare_unmount_node_t *node; 2295 uu_avl_index_t idx; 2296 uu_avl_walk_t *walk; 2297 2298 if ((pool = uu_avl_pool_create("unmount_pool", 2299 sizeof (unshare_unmount_node_t), 2300 offsetof(unshare_unmount_node_t, un_avlnode), 2301 unshare_unmount_compare, 2302 UU_DEFAULT)) == NULL) { 2303 (void) fprintf(stderr, gettext("internal error: " 2304 "out of memory\n")); 2305 exit(1); 2306 } 2307 2308 if ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL) { 2309 (void) fprintf(stderr, gettext("internal error: " 2310 "out of memory\n")); 2311 exit(1); 2312 } 2313 2314 rewind(mnttab_file); 2315 while (getmntent(mnttab_file, &entry) == 0) { 2316 2317 /* ignore non-ZFS entries */ 2318 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 2319 continue; 2320 2321 /* ignore snapshots */ 2322 if (strchr(entry.mnt_special, '@') != NULL) 2323 continue; 2324 2325 if ((zhp = zfs_open(entry.mnt_special, 2326 ZFS_TYPE_FILESYSTEM)) == NULL) { 2327 ret = 1; 2328 continue; 2329 } 2330 2331 verify(zfs_prop_get(zhp, type == OP_SHARE ? 2332 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, 2333 property, sizeof (property), NULL, NULL, 2334 0, FALSE) == 0); 2335 2336 /* Ignore legacy mounts and shares */ 2337 if ((type == OP_SHARE && 2338 strcmp(property, "off") == 0) || 2339 (type == OP_MOUNT && 2340 strcmp(property, "legacy") == 0)) { 2341 zfs_close(zhp); 2342 continue; 2343 } 2344 2345 node = safe_malloc(sizeof (unshare_unmount_node_t)); 2346 node->un_zhp = zhp; 2347 2348 if ((node->un_mountp = strdup(entry.mnt_mountp)) == 2349 NULL) { 2350 (void) fprintf(stderr, gettext("internal error:" 2351 " out of memory\n")); 2352 exit(1); 2353 } 2354 2355 uu_avl_node_init(node, &node->un_avlnode, pool); 2356 2357 if (uu_avl_find(tree, node, NULL, &idx) == NULL) { 2358 uu_avl_insert(tree, node, idx); 2359 } else { 2360 zfs_close(node->un_zhp); 2361 free(node->un_mountp); 2362 free(node); 2363 } 2364 } 2365 2366 /* 2367 * Walk the AVL tree in reverse, unmounting each filesystem and 2368 * removing it from the AVL tree in the process. 2369 */ 2370 if ((walk = uu_avl_walk_start(tree, 2371 UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL) { 2372 (void) fprintf(stderr, 2373 gettext("internal error: out of memory")); 2374 exit(1); 2375 } 2376 2377 while ((node = uu_avl_walk_next(walk)) != NULL) { 2378 uu_avl_remove(tree, node); 2379 2380 switch (type) { 2381 case OP_SHARE: 2382 if (zfs_unshare(node->un_zhp, 2383 node->un_mountp) != 0) 2384 ret = 1; 2385 break; 2386 2387 case OP_MOUNT: 2388 if (zfs_unmount(node->un_zhp, 2389 node->un_mountp, flags) != 0) 2390 ret = 1; 2391 break; 2392 } 2393 2394 zfs_close(node->un_zhp); 2395 free(node->un_mountp); 2396 free(node); 2397 } 2398 2399 uu_avl_walk_end(walk); 2400 uu_avl_destroy(tree); 2401 uu_avl_pool_destroy(pool); 2402 } else { 2403 /* 2404 * We have an argument, but it may be a full path or a ZFS 2405 * filesystem. Pass full paths off to unmount_path() (shared by 2406 * manual_unmount), otherwise open the filesystem and pass to 2407 * zfs_unmount(). 2408 */ 2409 if (argv[0][0] == '/') 2410 return (unshare_unmount_path(type, argv[0], 2411 flags, FALSE)); 2412 2413 if ((zhp = zfs_open(argv[0], ZFS_TYPE_FILESYSTEM)) == NULL) 2414 return (1); 2415 2416 verify(zfs_prop_get(zhp, type == OP_SHARE ? 2417 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property, 2418 sizeof (property), NULL, NULL, 0, FALSE) == 0); 2419 2420 switch (type) { 2421 case OP_SHARE: 2422 if (strcmp(property, "off") == 0) { 2423 (void) fprintf(stderr, gettext("cannot unshare " 2424 "'%s': legacy share\n"), zfs_get_name(zhp)); 2425 (void) fprintf(stderr, gettext("use unshare(1M)" 2426 " to unshare this filesystem\n")); 2427 ret = 1; 2428 } else if (!zfs_is_shared(zhp, NULL)) { 2429 (void) fprintf(stderr, gettext("cannot unshare " 2430 "'%s': not currently shared\n"), 2431 zfs_get_name(zhp)); 2432 ret = 1; 2433 } else if (zfs_unshareall(zhp) != 0) { 2434 ret = 1; 2435 } 2436 break; 2437 2438 case OP_MOUNT: 2439 if (strcmp(property, "legacy") == 0) { 2440 (void) fprintf(stderr, gettext("cannot unmount " 2441 "'%s': legacy mountpoint\n"), 2442 zfs_get_name(zhp)); 2443 (void) fprintf(stderr, gettext("use umount(1M) " 2444 "to unmount this filesystem\n")); 2445 ret = 1; 2446 } else if (!zfs_is_mounted(zhp, NULL)) { 2447 (void) fprintf(stderr, gettext("cannot unmount " 2448 "'%s': not currently mounted\n"), 2449 zfs_get_name(zhp)); 2450 ret = 1; 2451 } else if (zfs_unmountall(zhp, flags) != 0) { 2452 ret = 1; 2453 } 2454 } 2455 2456 zfs_close(zhp); 2457 } 2458 2459 return (ret); 2460 } 2461 2462 /* 2463 * zfs unmount -a 2464 * zfs unmount filesystem 2465 * 2466 * Unmount all filesystems, or a specific ZFS filesystem. 2467 */ 2468 static int 2469 zfs_do_unmount(int argc, char **argv) 2470 { 2471 return (unshare_unmount(OP_MOUNT, argc, argv)); 2472 } 2473 2474 /* 2475 * zfs unshare -a 2476 * zfs unshare filesystem 2477 * 2478 * Unshare all filesystems, or a specific ZFS filesystem. 2479 */ 2480 static int 2481 zfs_do_unshare(int argc, char **argv) 2482 { 2483 return (unshare_unmount(OP_SHARE, argc, argv)); 2484 } 2485 2486 /* 2487 * Called when invoked as /etc/fs/zfs/mount. Do the mount if the mountpoint is 2488 * 'legacy'. Otherwise, complain that use should be using 'zfs mount'. 2489 */ 2490 static int 2491 manual_mount(int argc, char **argv) 2492 { 2493 zfs_handle_t *zhp; 2494 char mountpoint[ZFS_MAXPROPLEN]; 2495 char mntopts[MNT_LINE_MAX] = { '\0' }; 2496 int ret; 2497 int c; 2498 int flags = 0; 2499 char *dataset, *path; 2500 2501 /* check options */ 2502 while ((c = getopt(argc, argv, ":o:O")) != -1) { 2503 switch (c) { 2504 case 'o': 2505 (void) strlcpy(mntopts, optarg, sizeof (mntopts)); 2506 break; 2507 case 'O': 2508 flags |= MS_OVERLAY; 2509 break; 2510 case ':': 2511 (void) fprintf(stderr, gettext("missing argument for " 2512 "'%c' option\n"), optopt); 2513 usage(FALSE); 2514 break; 2515 case '?': 2516 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2517 optopt); 2518 (void) fprintf(stderr, gettext("usage: mount [-o opts] " 2519 "<path>\n")); 2520 return (2); 2521 } 2522 } 2523 2524 argc -= optind; 2525 argv += optind; 2526 2527 /* check that we only have two arguments */ 2528 if (argc != 2) { 2529 if (argc == 0) 2530 (void) fprintf(stderr, gettext("missing dataset " 2531 "argument\n")); 2532 else if (argc == 1) 2533 (void) fprintf(stderr, 2534 gettext("missing mountpoint argument\n")); 2535 else 2536 (void) fprintf(stderr, gettext("too many arguments\n")); 2537 (void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n"); 2538 return (2); 2539 } 2540 2541 dataset = argv[0]; 2542 path = argv[1]; 2543 2544 /* try to open the dataset */ 2545 if ((zhp = zfs_open(dataset, ZFS_TYPE_FILESYSTEM)) == NULL) 2546 return (1); 2547 2548 (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 2549 sizeof (mountpoint), NULL, NULL, 0, FALSE); 2550 2551 /* check for legacy mountpoint and complain appropriately */ 2552 ret = 0; 2553 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 2554 if (mount(dataset, path, MS_OPTIONSTR | flags, MNTTYPE_ZFS, 2555 NULL, 0, mntopts, sizeof (mntopts)) != 0) { 2556 (void) fprintf(stderr, gettext("mount failed: %s\n"), 2557 strerror(errno)); 2558 ret = 1; 2559 } 2560 } else { 2561 (void) fprintf(stderr, gettext("filesystem '%s' cannot be " 2562 "mounted using 'mount -F zfs'\n"), dataset); 2563 (void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' " 2564 "instead.\n"), path); 2565 (void) fprintf(stderr, gettext("If you must use 'mount -F zfs' " 2566 "or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n")); 2567 (void) fprintf(stderr, gettext("See zfs(1M) for more " 2568 "information.\n")); 2569 ret = 1; 2570 } 2571 2572 return (ret); 2573 } 2574 2575 /* 2576 * Called when invoked as /etc/fs/zfs/umount. Unlike a manual mount, we allow 2577 * unmounts of non-legacy filesystems, as this is the dominant administrative 2578 * interface. 2579 */ 2580 static int 2581 manual_unmount(int argc, char **argv) 2582 { 2583 int flags = 0; 2584 int c; 2585 2586 /* check options */ 2587 while ((c = getopt(argc, argv, "f")) != -1) { 2588 switch (c) { 2589 case 'f': 2590 flags = MS_FORCE; 2591 break; 2592 case '?': 2593 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2594 optopt); 2595 (void) fprintf(stderr, gettext("usage: unmount [-f] " 2596 "<path>\n")); 2597 return (2); 2598 } 2599 } 2600 2601 argc -= optind; 2602 argv += optind; 2603 2604 /* check arguments */ 2605 if (argc != 1) { 2606 if (argc == 0) 2607 (void) fprintf(stderr, gettext("missing path " 2608 "argument\n")); 2609 else 2610 (void) fprintf(stderr, gettext("too many arguments\n")); 2611 (void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n")); 2612 return (2); 2613 } 2614 2615 return (unshare_unmount_path(OP_MOUNT, argv[0], flags, TRUE)); 2616 } 2617 2618 static int 2619 volcheck(zpool_handle_t *zhp, void *data) 2620 { 2621 int isinit = (int)data; 2622 2623 if (isinit) 2624 return (zpool_create_zvol_links(zhp)); 2625 else 2626 return (zpool_remove_zvol_links(zhp)); 2627 } 2628 2629 /* 2630 * Iterate over all pools in the system and either create or destroy /dev/zvol 2631 * links, depending on the value of 'isinit'. 2632 */ 2633 static int 2634 do_volcheck(int isinit) 2635 { 2636 return (zpool_iter(volcheck, (void *)isinit) ? 1 : 0); 2637 } 2638 2639 int 2640 main(int argc, char **argv) 2641 { 2642 int ret; 2643 int i; 2644 char *progname; 2645 char *cmdname; 2646 2647 (void) setlocale(LC_ALL, ""); 2648 (void) textdomain(TEXT_DOMAIN); 2649 2650 opterr = 0; 2651 2652 if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) { 2653 (void) fprintf(stderr, gettext("internal error: unable to " 2654 "open %s\n"), MNTTAB); 2655 return (1); 2656 } 2657 2658 /* 2659 * This command also doubles as the /etc/fs mount and unmount program. 2660 * Determine if we should take this behavior based on argv[0]. 2661 */ 2662 progname = basename(argv[0]); 2663 if (strcmp(progname, "mount") == 0) { 2664 ret = manual_mount(argc, argv); 2665 } else if (strcmp(progname, "umount") == 0) { 2666 ret = manual_unmount(argc, argv); 2667 } else { 2668 /* 2669 * Make sure the user has specified some command. 2670 */ 2671 if (argc < 2) { 2672 (void) fprintf(stderr, gettext("missing command\n")); 2673 usage(FALSE); 2674 } 2675 2676 cmdname = argv[1]; 2677 2678 /* 2679 * The 'umount' command is an alias for 'unmount' 2680 */ 2681 if (strcmp(cmdname, "umount") == 0) 2682 cmdname = "unmount"; 2683 2684 /* 2685 * Special case '-?' 2686 */ 2687 if (strcmp(cmdname, "-?") == 0) 2688 usage(TRUE); 2689 2690 /* 2691 * 'volinit' and 'volfini' do not appear in the usage message, 2692 * so we have to special case them here. 2693 */ 2694 if (strcmp(cmdname, "volinit") == 0) 2695 return (do_volcheck(TRUE)); 2696 else if (strcmp(cmdname, "volfini") == 0) 2697 return (do_volcheck(FALSE)); 2698 2699 /* 2700 * Run the appropriate command. 2701 */ 2702 for (i = 0; i < NCOMMAND; i++) { 2703 if (command_table[i].name == NULL) 2704 continue; 2705 2706 if (strcmp(cmdname, command_table[i].name) == 0) { 2707 current_command = &command_table[i]; 2708 ret = command_table[i].func(argc - 1, argv + 1); 2709 break; 2710 } 2711 } 2712 2713 if (i == NCOMMAND) { 2714 (void) fprintf(stderr, gettext("unrecognized " 2715 "command '%s'\n"), cmdname); 2716 usage(FALSE); 2717 } 2718 } 2719 2720 (void) fclose(mnttab_file); 2721 2722 /* 2723 * The 'ZFS_ABORT' environment variable causes us to dump core on exit 2724 * for the purposes of running ::findleaks. 2725 */ 2726 if (getenv("ZFS_ABORT") != NULL) { 2727 (void) printf("dumping core by request\n"); 2728 abort(); 2729 } 2730 2731 return (ret); 2732 } 2733