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