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