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