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