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