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