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] [-vO] -a\n" 211 "\tmount [-o opts] [-vO] <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); 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 boolean_t cb_verbose; 2722 } get_all_cbdata_t; 2723 2724 #define CHECK_SPINNER 30 2725 #define SPINNER_TIME 3 /* seconds */ 2726 #define MOUNT_TIME 5 /* seconds */ 2727 2728 static int 2729 get_one_dataset(zfs_handle_t *zhp, void *data) 2730 { 2731 static char spin[] = { '-', '\\', '|', '/' }; 2732 static int spinval = 0; 2733 static int spincheck = 0; 2734 static time_t last_spin_time = (time_t)0; 2735 get_all_cbdata_t *cbp = data; 2736 zfs_type_t type = zfs_get_type(zhp); 2737 2738 if (cbp->cb_verbose) { 2739 if (--spincheck < 0) { 2740 time_t now = time(NULL); 2741 if (last_spin_time + SPINNER_TIME < now) { 2742 (void) printf("\b%c", spin[spinval++ % 4]); 2743 (void) fflush(stdout); 2744 last_spin_time = now; 2745 } 2746 spincheck = CHECK_SPINNER; 2747 } 2748 } 2749 2750 /* 2751 * Interate over any nested datasets. 2752 */ 2753 if (type == ZFS_TYPE_FILESYSTEM && 2754 zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) { 2755 zfs_close(zhp); 2756 return (1); 2757 } 2758 2759 /* 2760 * Skip any datasets whose type does not match. 2761 */ 2762 if ((type & cbp->cb_types) == 0) { 2763 zfs_close(zhp); 2764 return (0); 2765 } 2766 2767 if (cbp->cb_alloc == cbp->cb_used) { 2768 zfs_handle_t **handles; 2769 2770 if (cbp->cb_alloc == 0) 2771 cbp->cb_alloc = 64; 2772 else 2773 cbp->cb_alloc *= 2; 2774 2775 handles = safe_malloc(cbp->cb_alloc * sizeof (void *)); 2776 2777 if (cbp->cb_handles) { 2778 bcopy(cbp->cb_handles, handles, 2779 cbp->cb_used * sizeof (void *)); 2780 free(cbp->cb_handles); 2781 } 2782 2783 cbp->cb_handles = handles; 2784 } 2785 2786 cbp->cb_handles[cbp->cb_used++] = zhp; 2787 2788 return (0); 2789 } 2790 2791 static void 2792 get_all_datasets(uint_t types, zfs_handle_t ***dslist, size_t *count, 2793 boolean_t verbose) 2794 { 2795 get_all_cbdata_t cb = { 0 }; 2796 cb.cb_types = types; 2797 cb.cb_verbose = verbose; 2798 2799 if (verbose) { 2800 (void) printf("%s: *", gettext("Reading ZFS config")); 2801 (void) fflush(stdout); 2802 } 2803 2804 (void) zfs_iter_root(g_zfs, get_one_dataset, &cb); 2805 2806 *dslist = cb.cb_handles; 2807 *count = cb.cb_used; 2808 2809 if (verbose) { 2810 (void) printf("\b%s\n", gettext("done.")); 2811 } 2812 } 2813 2814 static int 2815 dataset_cmp(const void *a, const void *b) 2816 { 2817 zfs_handle_t **za = (zfs_handle_t **)a; 2818 zfs_handle_t **zb = (zfs_handle_t **)b; 2819 char mounta[MAXPATHLEN]; 2820 char mountb[MAXPATHLEN]; 2821 boolean_t gota, gotb; 2822 2823 if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 2824 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2825 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2826 if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 2827 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2828 sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2829 2830 if (gota && gotb) 2831 return (strcmp(mounta, mountb)); 2832 2833 if (gota) 2834 return (-1); 2835 if (gotb) 2836 return (1); 2837 2838 return (strcmp(zfs_get_name(a), zfs_get_name(b))); 2839 } 2840 2841 /* 2842 * Generic callback for sharing or mounting filesystems. Because the code is so 2843 * similar, we have a common function with an extra parameter to determine which 2844 * mode we are using. 2845 */ 2846 #define OP_SHARE 0x1 2847 #define OP_MOUNT 0x2 2848 2849 /* 2850 * Share or mount a dataset. 2851 */ 2852 static int 2853 share_mount_one(zfs_handle_t *zhp, int op, int flags, boolean_t explicit, 2854 const char *options) 2855 { 2856 char mountpoint[ZFS_MAXPROPLEN]; 2857 char shareopts[ZFS_MAXPROPLEN]; 2858 const char *cmdname = op == OP_SHARE ? "share" : "mount"; 2859 struct mnttab mnt; 2860 uint64_t zoned, canmount; 2861 zfs_type_t type = zfs_get_type(zhp); 2862 2863 assert(type & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)); 2864 2865 if (type == ZFS_TYPE_FILESYSTEM) { 2866 /* 2867 * Check to make sure we can mount/share this dataset. If we 2868 * are in the global zone and the filesystem is exported to a 2869 * local zone, or if we are in a local zone and the 2870 * filesystem is not exported, then it is an error. 2871 */ 2872 zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2873 2874 if (zoned && getzoneid() == GLOBAL_ZONEID) { 2875 if (!explicit) 2876 return (0); 2877 2878 (void) fprintf(stderr, gettext("cannot %s '%s': " 2879 "dataset is exported to a local zone\n"), cmdname, 2880 zfs_get_name(zhp)); 2881 return (1); 2882 2883 } else if (!zoned && getzoneid() != GLOBAL_ZONEID) { 2884 if (!explicit) 2885 return (0); 2886 2887 (void) fprintf(stderr, gettext("cannot %s '%s': " 2888 "permission denied\n"), cmdname, 2889 zfs_get_name(zhp)); 2890 return (1); 2891 } 2892 2893 /* 2894 * Ignore any filesystems which don't apply to us. This 2895 * includes those with a legacy mountpoint, or those with 2896 * legacy share options. 2897 */ 2898 verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 2899 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0); 2900 verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, 2901 sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); 2902 canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT); 2903 2904 if (op == OP_SHARE && strcmp(shareopts, "off") == 0) { 2905 if (!explicit) 2906 return (0); 2907 2908 (void) fprintf(stderr, gettext("cannot share '%s': " 2909 "legacy share\n"), zfs_get_name(zhp)); 2910 (void) fprintf(stderr, gettext("use share(1M) to " 2911 "share this filesystem\n")); 2912 return (1); 2913 } 2914 2915 /* 2916 * We cannot share or mount legacy filesystems. If the 2917 * shareopts is non-legacy but the mountpoint is legacy, we 2918 * treat it as a legacy share. 2919 */ 2920 if (strcmp(mountpoint, "legacy") == 0) { 2921 if (!explicit) 2922 return (0); 2923 2924 (void) fprintf(stderr, gettext("cannot %s '%s': " 2925 "legacy mountpoint\n"), cmdname, zfs_get_name(zhp)); 2926 (void) fprintf(stderr, gettext("use %s to " 2927 "%s this filesystem\n"), op == OP_SHARE ? 2928 "share(1M)" : "mount(1M)", cmdname); 2929 return (1); 2930 } 2931 2932 if (strcmp(mountpoint, "none") == 0) { 2933 if (!explicit) 2934 return (0); 2935 2936 (void) fprintf(stderr, gettext("cannot %s '%s': no " 2937 "mountpoint set\n"), cmdname, zfs_get_name(zhp)); 2938 return (1); 2939 } 2940 2941 if (!canmount) { 2942 if (!explicit) 2943 return (0); 2944 2945 (void) fprintf(stderr, gettext("cannot %s '%s': " 2946 "'canmount' property is set to 'off'\n"), cmdname, 2947 zfs_get_name(zhp)); 2948 return (1); 2949 } 2950 2951 /* 2952 * At this point, we have verified that the mountpoint and/or 2953 * shareopts are appropriate for auto management. If the 2954 * filesystem is already mounted or shared, return (failing 2955 * for explicit requests); otherwise mount or share the 2956 * filesystem. 2957 */ 2958 switch (op) { 2959 case OP_SHARE: 2960 if (zfs_is_shared_nfs(zhp, NULL)) { 2961 if (!explicit) 2962 return (0); 2963 2964 (void) fprintf(stderr, gettext("cannot share " 2965 "'%s': filesystem already shared\n"), 2966 zfs_get_name(zhp)); 2967 return (1); 2968 } 2969 2970 if (!zfs_is_mounted(zhp, NULL) && 2971 zfs_mount(zhp, NULL, 0) != 0) 2972 return (1); 2973 2974 if (zfs_share_nfs(zhp) != 0) 2975 return (1); 2976 break; 2977 2978 case OP_MOUNT: 2979 if (options == NULL) 2980 mnt.mnt_mntopts = ""; 2981 else 2982 mnt.mnt_mntopts = (char *)options; 2983 2984 if (!hasmntopt(&mnt, MNTOPT_REMOUNT) && 2985 zfs_is_mounted(zhp, NULL)) { 2986 if (!explicit) 2987 return (0); 2988 2989 (void) fprintf(stderr, gettext("cannot mount " 2990 "'%s': filesystem already mounted\n"), 2991 zfs_get_name(zhp)); 2992 return (1); 2993 } 2994 2995 if (zfs_mount(zhp, options, flags) != 0) 2996 return (1); 2997 break; 2998 } 2999 } else { 3000 assert(op == OP_SHARE); 3001 3002 /* 3003 * Ignore any volumes that aren't shared. 3004 */ 3005 verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 3006 sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); 3007 3008 if (strcmp(shareopts, "off") == 0) { 3009 if (!explicit) 3010 return (0); 3011 3012 (void) fprintf(stderr, gettext("cannot share '%s': " 3013 "'shareiscsi' property not set\n"), 3014 zfs_get_name(zhp)); 3015 (void) fprintf(stderr, gettext("set 'shareiscsi' " 3016 "property or use iscsitadm(1M) to share this " 3017 "volume\n")); 3018 return (1); 3019 } 3020 3021 if (zfs_is_shared_iscsi(zhp)) { 3022 if (!explicit) 3023 return (0); 3024 3025 (void) fprintf(stderr, gettext("cannot share " 3026 "'%s': volume already shared\n"), 3027 zfs_get_name(zhp)); 3028 return (1); 3029 } 3030 3031 if (zfs_share_iscsi(zhp) != 0) 3032 return (1); 3033 } 3034 3035 return (0); 3036 } 3037 3038 /* 3039 * Reports progress in the form "(current/total)". Not thread-safe. 3040 */ 3041 static void 3042 report_mount_progress(int current, int total) 3043 { 3044 static int len; 3045 static char *reverse = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" 3046 "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; 3047 static time_t last_progress_time; 3048 time_t now = time(NULL); 3049 3050 /* report 1..n instead of 0..n-1 */ 3051 ++current; 3052 3053 /* display header if we're here for the first time */ 3054 if (current == 1) { 3055 (void) printf(gettext("Mounting ZFS filesystems: ")); 3056 len = 0; 3057 } else if (current != total && last_progress_time + MOUNT_TIME >= now) 3058 return; /* too soon to report again */ 3059 3060 last_progress_time = now; 3061 3062 /* back up to prepare for overwriting */ 3063 if (len) 3064 (void) printf("%*.*s", len, len, reverse); 3065 3066 /* We put a newline at the end if this is the last one. */ 3067 len = printf("(%d/%d)%s", current, total, current == total ? "\n" : ""); 3068 (void) fflush(stdout); 3069 } 3070 3071 static int 3072 share_mount(int op, int argc, char **argv) 3073 { 3074 int do_all = 0; 3075 boolean_t verbose = B_FALSE; 3076 int c, ret = 0; 3077 const char *options = NULL; 3078 int types, flags = 0; 3079 3080 /* check options */ 3081 while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:O" : "a")) 3082 != -1) { 3083 switch (c) { 3084 case 'a': 3085 do_all = 1; 3086 break; 3087 case 'v': 3088 verbose = B_TRUE; 3089 break; 3090 case 'o': 3091 if (strlen(optarg) <= MNT_LINE_MAX) { 3092 options = optarg; 3093 break; 3094 } 3095 (void) fprintf(stderr, gettext("the opts argument for " 3096 "'%c' option is too long (more than %d chars)\n"), 3097 optopt, MNT_LINE_MAX); 3098 usage(B_FALSE); 3099 break; 3100 3101 case 'O': 3102 flags |= MS_OVERLAY; 3103 break; 3104 case ':': 3105 (void) fprintf(stderr, gettext("missing argument for " 3106 "'%c' option\n"), optopt); 3107 usage(B_FALSE); 3108 break; 3109 case '?': 3110 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3111 optopt); 3112 usage(B_FALSE); 3113 } 3114 } 3115 3116 argc -= optind; 3117 argv += optind; 3118 3119 /* check number of arguments */ 3120 if (do_all) { 3121 zfs_handle_t **dslist = NULL; 3122 size_t i, count = 0; 3123 3124 if (op == OP_MOUNT) { 3125 types = ZFS_TYPE_FILESYSTEM; 3126 } else if (argc > 0) { 3127 if (strcmp(argv[0], "nfs") == 0) { 3128 types = ZFS_TYPE_FILESYSTEM; 3129 } else if (strcmp(argv[0], "iscsi") == 0) { 3130 types = ZFS_TYPE_VOLUME; 3131 } else { 3132 (void) fprintf(stderr, gettext("share type " 3133 "must be 'nfs' or 'iscsi'\n")); 3134 usage(B_FALSE); 3135 } 3136 3137 argc--; 3138 argv++; 3139 } else { 3140 types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME; 3141 } 3142 3143 if (argc != 0) { 3144 (void) fprintf(stderr, gettext("too many arguments\n")); 3145 usage(B_FALSE); 3146 } 3147 3148 get_all_datasets(types, &dslist, &count, verbose); 3149 3150 if (count == 0) 3151 return (0); 3152 3153 qsort(dslist, count, sizeof (void *), dataset_cmp); 3154 3155 for (i = 0; i < count; i++) { 3156 if (verbose) 3157 report_mount_progress(i, count); 3158 3159 if (share_mount_one(dslist[i], op, flags, B_FALSE, 3160 options) != 0) 3161 ret = 1; 3162 zfs_close(dslist[i]); 3163 } 3164 3165 free(dslist); 3166 } else if (argc == 0) { 3167 struct mnttab entry; 3168 3169 if ((op == OP_SHARE) || (options != NULL)) { 3170 (void) fprintf(stderr, gettext("missing filesystem " 3171 "argument (specify -a for all)\n")); 3172 usage(B_FALSE); 3173 } 3174 3175 /* 3176 * When mount is given no arguments, go through /etc/mnttab and 3177 * display any active ZFS mounts. We hide any snapshots, since 3178 * they are controlled automatically. 3179 */ 3180 rewind(mnttab_file); 3181 while (getmntent(mnttab_file, &entry) == 0) { 3182 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 || 3183 strchr(entry.mnt_special, '@') != NULL) 3184 continue; 3185 3186 (void) printf("%-30s %s\n", entry.mnt_special, 3187 entry.mnt_mountp); 3188 } 3189 3190 } else { 3191 zfs_handle_t *zhp; 3192 3193 types = ZFS_TYPE_FILESYSTEM; 3194 if (op == OP_SHARE) 3195 types |= ZFS_TYPE_VOLUME; 3196 3197 if (argc > 1) { 3198 (void) fprintf(stderr, 3199 gettext("too many arguments\n")); 3200 usage(B_FALSE); 3201 } 3202 3203 if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) { 3204 ret = 1; 3205 } else { 3206 ret = share_mount_one(zhp, op, flags, B_TRUE, 3207 options); 3208 zfs_close(zhp); 3209 } 3210 } 3211 3212 return (ret); 3213 } 3214 3215 /* 3216 * zfs mount -a [nfs | iscsi] 3217 * zfs mount filesystem 3218 * 3219 * Mount all filesystems, or mount the given filesystem. 3220 */ 3221 static int 3222 zfs_do_mount(int argc, char **argv) 3223 { 3224 return (share_mount(OP_MOUNT, argc, argv)); 3225 } 3226 3227 /* 3228 * zfs share -a [nfs | iscsi] 3229 * zfs share filesystem 3230 * 3231 * Share all filesystems, or share the given filesystem. 3232 */ 3233 static int 3234 zfs_do_share(int argc, char **argv) 3235 { 3236 return (share_mount(OP_SHARE, argc, argv)); 3237 } 3238 3239 typedef struct unshare_unmount_node { 3240 zfs_handle_t *un_zhp; 3241 char *un_mountp; 3242 uu_avl_node_t un_avlnode; 3243 } unshare_unmount_node_t; 3244 3245 /* ARGSUSED */ 3246 static int 3247 unshare_unmount_compare(const void *larg, const void *rarg, void *unused) 3248 { 3249 const unshare_unmount_node_t *l = larg; 3250 const unshare_unmount_node_t *r = rarg; 3251 3252 return (strcmp(l->un_mountp, r->un_mountp)); 3253 } 3254 3255 /* 3256 * Convenience routine used by zfs_do_umount() and manual_unmount(). Given an 3257 * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem, 3258 * and unmount it appropriately. 3259 */ 3260 static int 3261 unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) 3262 { 3263 zfs_handle_t *zhp; 3264 int ret; 3265 struct stat64 statbuf; 3266 struct extmnttab entry; 3267 const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount"; 3268 char property[ZFS_MAXPROPLEN]; 3269 3270 /* 3271 * Search for the path in /etc/mnttab. Rather than looking for the 3272 * specific path, which can be fooled by non-standard paths (i.e. ".." 3273 * or "//"), we stat() the path and search for the corresponding 3274 * (major,minor) device pair. 3275 */ 3276 if (stat64(path, &statbuf) != 0) { 3277 (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"), 3278 cmdname, path, strerror(errno)); 3279 return (1); 3280 } 3281 3282 /* 3283 * Search for the given (major,minor) pair in the mount table. 3284 */ 3285 rewind(mnttab_file); 3286 while ((ret = getextmntent(mnttab_file, &entry, 0)) == 0) { 3287 if (entry.mnt_major == major(statbuf.st_dev) && 3288 entry.mnt_minor == minor(statbuf.st_dev)) 3289 break; 3290 } 3291 if (ret != 0) { 3292 (void) fprintf(stderr, gettext("cannot %s '%s': not " 3293 "currently mounted\n"), cmdname, path); 3294 return (1); 3295 } 3296 3297 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) { 3298 (void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS " 3299 "filesystem\n"), cmdname, path); 3300 return (1); 3301 } 3302 3303 if ((zhp = zfs_open(g_zfs, entry.mnt_special, 3304 ZFS_TYPE_FILESYSTEM)) == NULL) 3305 return (1); 3306 3307 verify(zfs_prop_get(zhp, op == OP_SHARE ? 3308 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property, 3309 sizeof (property), NULL, NULL, 0, B_FALSE) == 0); 3310 3311 if (op == OP_SHARE) { 3312 if (strcmp(property, "off") == 0) { 3313 (void) fprintf(stderr, gettext("cannot unshare " 3314 "'%s': legacy share\n"), path); 3315 (void) fprintf(stderr, gettext("use " 3316 "unshare(1M) to unshare this filesystem\n")); 3317 ret = 1; 3318 } else if (!zfs_is_shared_nfs(zhp, NULL)) { 3319 (void) fprintf(stderr, gettext("cannot unshare '%s': " 3320 "not currently shared\n"), path); 3321 ret = 1; 3322 } else { 3323 ret = zfs_unshareall_nfs(zhp); 3324 } 3325 } else { 3326 if (is_manual) { 3327 ret = zfs_unmount(zhp, NULL, flags); 3328 } else if (strcmp(property, "legacy") == 0) { 3329 (void) fprintf(stderr, gettext("cannot unmount " 3330 "'%s': legacy mountpoint\n"), 3331 zfs_get_name(zhp)); 3332 (void) fprintf(stderr, gettext("use umount(1M) " 3333 "to unmount this filesystem\n")); 3334 ret = 1; 3335 } else { 3336 ret = zfs_unmountall(zhp, flags); 3337 } 3338 } 3339 3340 zfs_close(zhp); 3341 3342 return (ret != 0); 3343 } 3344 3345 /* 3346 * Generic callback for unsharing or unmounting a filesystem. 3347 */ 3348 static int 3349 unshare_unmount(int op, int argc, char **argv) 3350 { 3351 int do_all = 0; 3352 int flags = 0; 3353 int ret = 0; 3354 int types, c; 3355 zfs_handle_t *zhp; 3356 char property[ZFS_MAXPROPLEN]; 3357 3358 /* check options */ 3359 while ((c = getopt(argc, argv, op == OP_SHARE ? "a" : "af")) != -1) { 3360 switch (c) { 3361 case 'a': 3362 do_all = 1; 3363 break; 3364 case 'f': 3365 flags = MS_FORCE; 3366 break; 3367 case '?': 3368 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3369 optopt); 3370 usage(B_FALSE); 3371 } 3372 } 3373 3374 argc -= optind; 3375 argv += optind; 3376 3377 if (do_all) { 3378 /* 3379 * We could make use of zfs_for_each() to walk all datasets in 3380 * the system, but this would be very inefficient, especially 3381 * since we would have to linearly search /etc/mnttab for each 3382 * one. Instead, do one pass through /etc/mnttab looking for 3383 * zfs entries and call zfs_unmount() for each one. 3384 * 3385 * Things get a little tricky if the administrator has created 3386 * mountpoints beneath other ZFS filesystems. In this case, we 3387 * have to unmount the deepest filesystems first. To accomplish 3388 * this, we place all the mountpoints in an AVL tree sorted by 3389 * the special type (dataset name), and walk the result in 3390 * reverse to make sure to get any snapshots first. 3391 */ 3392 struct mnttab entry; 3393 uu_avl_pool_t *pool; 3394 uu_avl_t *tree; 3395 unshare_unmount_node_t *node; 3396 uu_avl_index_t idx; 3397 uu_avl_walk_t *walk; 3398 3399 if (argc != 0) { 3400 (void) fprintf(stderr, gettext("too many arguments\n")); 3401 usage(B_FALSE); 3402 } 3403 3404 if ((pool = uu_avl_pool_create("unmount_pool", 3405 sizeof (unshare_unmount_node_t), 3406 offsetof(unshare_unmount_node_t, un_avlnode), 3407 unshare_unmount_compare, 3408 UU_DEFAULT)) == NULL) { 3409 (void) fprintf(stderr, gettext("internal error: " 3410 "out of memory\n")); 3411 exit(1); 3412 } 3413 3414 if ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL) { 3415 (void) fprintf(stderr, gettext("internal error: " 3416 "out of memory\n")); 3417 exit(1); 3418 } 3419 3420 rewind(mnttab_file); 3421 while (getmntent(mnttab_file, &entry) == 0) { 3422 3423 /* ignore non-ZFS entries */ 3424 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 3425 continue; 3426 3427 /* ignore snapshots */ 3428 if (strchr(entry.mnt_special, '@') != NULL) 3429 continue; 3430 3431 if ((zhp = zfs_open(g_zfs, entry.mnt_special, 3432 ZFS_TYPE_FILESYSTEM)) == NULL) { 3433 ret = 1; 3434 continue; 3435 } 3436 3437 verify(zfs_prop_get(zhp, op == OP_SHARE ? 3438 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, 3439 property, sizeof (property), NULL, NULL, 3440 0, B_FALSE) == 0); 3441 3442 /* Ignore legacy mounts and shares */ 3443 if ((op == OP_SHARE && 3444 strcmp(property, "off") == 0) || 3445 (op == OP_MOUNT && 3446 strcmp(property, "legacy") == 0)) { 3447 zfs_close(zhp); 3448 continue; 3449 } 3450 3451 node = safe_malloc(sizeof (unshare_unmount_node_t)); 3452 node->un_zhp = zhp; 3453 3454 if ((node->un_mountp = strdup(entry.mnt_mountp)) == 3455 NULL) { 3456 (void) fprintf(stderr, gettext("internal error:" 3457 " out of memory\n")); 3458 exit(1); 3459 } 3460 3461 uu_avl_node_init(node, &node->un_avlnode, pool); 3462 3463 if (uu_avl_find(tree, node, NULL, &idx) == NULL) { 3464 uu_avl_insert(tree, node, idx); 3465 } else { 3466 zfs_close(node->un_zhp); 3467 free(node->un_mountp); 3468 free(node); 3469 } 3470 } 3471 3472 /* 3473 * Walk the AVL tree in reverse, unmounting each filesystem and 3474 * removing it from the AVL tree in the process. 3475 */ 3476 if ((walk = uu_avl_walk_start(tree, 3477 UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL) { 3478 (void) fprintf(stderr, 3479 gettext("internal error: out of memory")); 3480 exit(1); 3481 } 3482 3483 while ((node = uu_avl_walk_next(walk)) != NULL) { 3484 uu_avl_remove(tree, node); 3485 3486 switch (op) { 3487 case OP_SHARE: 3488 if (zfs_unshare_nfs(node->un_zhp, 3489 node->un_mountp) != 0) 3490 ret = 1; 3491 break; 3492 3493 case OP_MOUNT: 3494 if (zfs_unmount(node->un_zhp, 3495 node->un_mountp, flags) != 0) 3496 ret = 1; 3497 break; 3498 } 3499 3500 zfs_close(node->un_zhp); 3501 free(node->un_mountp); 3502 free(node); 3503 } 3504 3505 uu_avl_walk_end(walk); 3506 uu_avl_destroy(tree); 3507 uu_avl_pool_destroy(pool); 3508 3509 if (op == OP_SHARE) { 3510 /* 3511 * Finally, unshare any volumes shared via iSCSI. 3512 */ 3513 zfs_handle_t **dslist = NULL; 3514 size_t i, count = 0; 3515 3516 get_all_datasets(ZFS_TYPE_VOLUME, &dslist, &count, 3517 B_FALSE); 3518 3519 if (count != 0) { 3520 qsort(dslist, count, sizeof (void *), 3521 dataset_cmp); 3522 3523 for (i = 0; i < count; i++) { 3524 if (zfs_unshare_iscsi(dslist[i]) != 0) 3525 ret = 1; 3526 zfs_close(dslist[i]); 3527 } 3528 3529 free(dslist); 3530 } 3531 } 3532 } else { 3533 if (argc != 1) { 3534 if (argc == 0) 3535 (void) fprintf(stderr, 3536 gettext("missing filesystem argument\n")); 3537 else 3538 (void) fprintf(stderr, 3539 gettext("too many arguments\n")); 3540 usage(B_FALSE); 3541 } 3542 3543 /* 3544 * We have an argument, but it may be a full path or a ZFS 3545 * filesystem. Pass full paths off to unmount_path() (shared by 3546 * manual_unmount), otherwise open the filesystem and pass to 3547 * zfs_unmount(). 3548 */ 3549 if (argv[0][0] == '/') 3550 return (unshare_unmount_path(op, argv[0], 3551 flags, B_FALSE)); 3552 3553 types = ZFS_TYPE_FILESYSTEM; 3554 if (op == OP_SHARE) 3555 types |= ZFS_TYPE_VOLUME; 3556 3557 if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) 3558 return (1); 3559 3560 if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { 3561 verify(zfs_prop_get(zhp, op == OP_SHARE ? 3562 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property, 3563 sizeof (property), NULL, NULL, 0, B_FALSE) == 0); 3564 3565 switch (op) { 3566 case OP_SHARE: 3567 if (strcmp(property, "off") == 0) { 3568 (void) fprintf(stderr, gettext("cannot " 3569 "unshare '%s': legacy share\n"), 3570 zfs_get_name(zhp)); 3571 (void) fprintf(stderr, gettext("use " 3572 "unshare(1M) to unshare this " 3573 "filesystem\n")); 3574 ret = 1; 3575 } else if (!zfs_is_shared_nfs(zhp, NULL)) { 3576 (void) fprintf(stderr, gettext("cannot " 3577 "unshare '%s': not currently " 3578 "shared\n"), zfs_get_name(zhp)); 3579 ret = 1; 3580 } else if (zfs_unshareall_nfs(zhp) != 0) { 3581 ret = 1; 3582 } 3583 break; 3584 3585 case OP_MOUNT: 3586 if (strcmp(property, "legacy") == 0) { 3587 (void) fprintf(stderr, gettext("cannot " 3588 "unmount '%s': legacy " 3589 "mountpoint\n"), zfs_get_name(zhp)); 3590 (void) fprintf(stderr, gettext("use " 3591 "umount(1M) to unmount this " 3592 "filesystem\n")); 3593 ret = 1; 3594 } else if (!zfs_is_mounted(zhp, NULL)) { 3595 (void) fprintf(stderr, gettext("cannot " 3596 "unmount '%s': not currently " 3597 "mounted\n"), 3598 zfs_get_name(zhp)); 3599 ret = 1; 3600 } else if (zfs_unmountall(zhp, flags) != 0) { 3601 ret = 1; 3602 } 3603 break; 3604 } 3605 } else { 3606 assert(op == OP_SHARE); 3607 3608 verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, property, 3609 sizeof (property), NULL, NULL, 0, B_FALSE) == 0); 3610 3611 if (strcmp(property, "off") == 0) { 3612 (void) fprintf(stderr, gettext("cannot unshare " 3613 "'%s': 'shareiscsi' property not set\n"), 3614 zfs_get_name(zhp)); 3615 (void) fprintf(stderr, gettext("set " 3616 "'shareiscsi' property or use " 3617 "iscsitadm(1M) to share this volume\n")); 3618 ret = 1; 3619 } else if (!zfs_is_shared_iscsi(zhp)) { 3620 (void) fprintf(stderr, gettext("cannot " 3621 "unshare '%s': not currently shared\n"), 3622 zfs_get_name(zhp)); 3623 ret = 1; 3624 } else if (zfs_unshare_iscsi(zhp) != 0) { 3625 ret = 1; 3626 } 3627 } 3628 3629 zfs_close(zhp); 3630 } 3631 3632 return (ret); 3633 } 3634 3635 /* 3636 * zfs unmount -a 3637 * zfs unmount filesystem 3638 * 3639 * Unmount all filesystems, or a specific ZFS filesystem. 3640 */ 3641 static int 3642 zfs_do_unmount(int argc, char **argv) 3643 { 3644 return (unshare_unmount(OP_MOUNT, argc, argv)); 3645 } 3646 3647 /* 3648 * zfs unshare -a 3649 * zfs unshare filesystem 3650 * 3651 * Unshare all filesystems, or a specific ZFS filesystem. 3652 */ 3653 static int 3654 zfs_do_unshare(int argc, char **argv) 3655 { 3656 return (unshare_unmount(OP_SHARE, argc, argv)); 3657 } 3658 3659 /* 3660 * Called when invoked as /etc/fs/zfs/mount. Do the mount if the mountpoint is 3661 * 'legacy'. Otherwise, complain that use should be using 'zfs mount'. 3662 */ 3663 static int 3664 manual_mount(int argc, char **argv) 3665 { 3666 zfs_handle_t *zhp; 3667 char mountpoint[ZFS_MAXPROPLEN]; 3668 char mntopts[MNT_LINE_MAX] = { '\0' }; 3669 int ret; 3670 int c; 3671 int flags = 0; 3672 char *dataset, *path; 3673 3674 /* check options */ 3675 while ((c = getopt(argc, argv, ":mo:O")) != -1) { 3676 switch (c) { 3677 case 'o': 3678 (void) strlcpy(mntopts, optarg, sizeof (mntopts)); 3679 break; 3680 case 'O': 3681 flags |= MS_OVERLAY; 3682 break; 3683 case 'm': 3684 flags |= MS_NOMNTTAB; 3685 break; 3686 case ':': 3687 (void) fprintf(stderr, gettext("missing argument for " 3688 "'%c' option\n"), optopt); 3689 usage(B_FALSE); 3690 break; 3691 case '?': 3692 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3693 optopt); 3694 (void) fprintf(stderr, gettext("usage: mount [-o opts] " 3695 "<path>\n")); 3696 return (2); 3697 } 3698 } 3699 3700 argc -= optind; 3701 argv += optind; 3702 3703 /* check that we only have two arguments */ 3704 if (argc != 2) { 3705 if (argc == 0) 3706 (void) fprintf(stderr, gettext("missing dataset " 3707 "argument\n")); 3708 else if (argc == 1) 3709 (void) fprintf(stderr, 3710 gettext("missing mountpoint argument\n")); 3711 else 3712 (void) fprintf(stderr, gettext("too many arguments\n")); 3713 (void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n"); 3714 return (2); 3715 } 3716 3717 dataset = argv[0]; 3718 path = argv[1]; 3719 3720 /* try to open the dataset */ 3721 if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) 3722 return (1); 3723 3724 (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 3725 sizeof (mountpoint), NULL, NULL, 0, B_FALSE); 3726 3727 /* check for legacy mountpoint and complain appropriately */ 3728 ret = 0; 3729 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 3730 if (mount(dataset, path, MS_OPTIONSTR | flags, MNTTYPE_ZFS, 3731 NULL, 0, mntopts, sizeof (mntopts)) != 0) { 3732 (void) fprintf(stderr, gettext("mount failed: %s\n"), 3733 strerror(errno)); 3734 ret = 1; 3735 } 3736 } else { 3737 (void) fprintf(stderr, gettext("filesystem '%s' cannot be " 3738 "mounted using 'mount -F zfs'\n"), dataset); 3739 (void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' " 3740 "instead.\n"), path); 3741 (void) fprintf(stderr, gettext("If you must use 'mount -F zfs' " 3742 "or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n")); 3743 (void) fprintf(stderr, gettext("See zfs(1M) for more " 3744 "information.\n")); 3745 ret = 1; 3746 } 3747 3748 return (ret); 3749 } 3750 3751 /* 3752 * Called when invoked as /etc/fs/zfs/umount. Unlike a manual mount, we allow 3753 * unmounts of non-legacy filesystems, as this is the dominant administrative 3754 * interface. 3755 */ 3756 static int 3757 manual_unmount(int argc, char **argv) 3758 { 3759 int flags = 0; 3760 int c; 3761 3762 /* check options */ 3763 while ((c = getopt(argc, argv, "f")) != -1) { 3764 switch (c) { 3765 case 'f': 3766 flags = MS_FORCE; 3767 break; 3768 case '?': 3769 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3770 optopt); 3771 (void) fprintf(stderr, gettext("usage: unmount [-f] " 3772 "<path>\n")); 3773 return (2); 3774 } 3775 } 3776 3777 argc -= optind; 3778 argv += optind; 3779 3780 /* check arguments */ 3781 if (argc != 1) { 3782 if (argc == 0) 3783 (void) fprintf(stderr, gettext("missing path " 3784 "argument\n")); 3785 else 3786 (void) fprintf(stderr, gettext("too many arguments\n")); 3787 (void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n")); 3788 return (2); 3789 } 3790 3791 return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE)); 3792 } 3793 3794 static int 3795 volcheck(zpool_handle_t *zhp, void *data) 3796 { 3797 boolean_t isinit = *((boolean_t *)data); 3798 3799 if (isinit) 3800 return (zpool_create_zvol_links(zhp)); 3801 else 3802 return (zpool_remove_zvol_links(zhp)); 3803 } 3804 3805 /* 3806 * Iterate over all pools in the system and either create or destroy /dev/zvol 3807 * links, depending on the value of 'isinit'. 3808 */ 3809 static int 3810 do_volcheck(boolean_t isinit) 3811 { 3812 return (zpool_iter(g_zfs, volcheck, &isinit) ? 1 : 0); 3813 } 3814 3815 static int 3816 find_command_idx(char *command, int *idx) 3817 { 3818 int i; 3819 3820 for (i = 0; i < NCOMMAND; i++) { 3821 if (command_table[i].name == NULL) 3822 continue; 3823 3824 if (strcmp(command, command_table[i].name) == 0) { 3825 *idx = i; 3826 return (0); 3827 } 3828 } 3829 return (1); 3830 } 3831 3832 zfs_prop_t 3833 propset_cb(zfs_prop_t prop, void *data) 3834 { 3835 char *cmdname = (char *)data; 3836 3837 if (strcmp(cmdname, zfs_prop_to_name(prop)) == 0) 3838 return (prop); 3839 3840 return (ZFS_PROP_CONT); 3841 } 3842 3843 int 3844 main(int argc, char **argv) 3845 { 3846 int ret; 3847 int i; 3848 char *progname; 3849 char *cmdname; 3850 char *str; 3851 boolean_t found = B_FALSE; 3852 3853 (void) setlocale(LC_ALL, ""); 3854 (void) textdomain(TEXT_DOMAIN); 3855 3856 opterr = 0; 3857 3858 first_argc = argc; 3859 first_argv = argv; 3860 3861 if ((g_zfs = libzfs_init()) == NULL) { 3862 (void) fprintf(stderr, gettext("internal error: failed to " 3863 "initialize ZFS library\n")); 3864 return (1); 3865 } 3866 3867 zpool_stage_history(g_zfs, argc, argv, B_TRUE); 3868 3869 libzfs_print_on_error(g_zfs, B_TRUE); 3870 3871 if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) { 3872 (void) fprintf(stderr, gettext("internal error: unable to " 3873 "open %s\n"), MNTTAB); 3874 return (1); 3875 } 3876 3877 /* 3878 * This command also doubles as the /etc/fs mount and unmount program. 3879 * Determine if we should take this behavior based on argv[0]. 3880 */ 3881 progname = basename(argv[0]); 3882 if (strcmp(progname, "mount") == 0) { 3883 ret = manual_mount(argc, argv); 3884 } else if (strcmp(progname, "umount") == 0) { 3885 ret = manual_unmount(argc, argv); 3886 } else { 3887 /* 3888 * Make sure the user has specified some command. 3889 */ 3890 if (argc < 2) { 3891 (void) fprintf(stderr, gettext("missing command\n")); 3892 usage(B_FALSE); 3893 } 3894 3895 cmdname = argv[1]; 3896 3897 /* 3898 * The 'umount' command is an alias for 'unmount' 3899 */ 3900 if (strcmp(cmdname, "umount") == 0) 3901 cmdname = "unmount"; 3902 3903 /* 3904 * The 'recv' command is an alias for 'receive' 3905 */ 3906 if (strcmp(cmdname, "recv") == 0) 3907 cmdname = "receive"; 3908 3909 /* 3910 * Special case '-?' 3911 */ 3912 if (strcmp(cmdname, "-?") == 0) 3913 usage(B_TRUE); 3914 3915 /* 3916 * 'volinit' and 'volfini' do not appear in the usage message, 3917 * so we have to special case them here. 3918 */ 3919 if (strcmp(cmdname, "volinit") == 0) 3920 return (do_volcheck(B_TRUE)); 3921 else if (strcmp(cmdname, "volfini") == 0) 3922 return (do_volcheck(B_FALSE)); 3923 3924 /* 3925 * Run the appropriate command. 3926 */ 3927 if (find_command_idx(cmdname, &i) == 0) { 3928 current_command = &command_table[i]; 3929 ret = command_table[i].func(argc - 1, argv + 1); 3930 found = B_TRUE; 3931 } 3932 3933 /* 3934 * Check and see if they are doing property=value 3935 */ 3936 if (found == B_FALSE && 3937 ((str = strchr(cmdname, '=')) != NULL)) { 3938 *str = '\0'; 3939 if (zfs_prop_iter(propset_cb, cmdname, 3940 B_FALSE) != ZFS_PROP_INVAL) 3941 found = B_TRUE; 3942 3943 if (found == B_FALSE && zfs_prop_user(cmdname)) 3944 found = B_TRUE; 3945 3946 if (found == B_TRUE && 3947 find_command_idx("set", &i) == 0) { 3948 *str = '='; 3949 current_command = &command_table[i]; 3950 ret = command_table[i].func(argc, argv); 3951 } else { 3952 (void) fprintf(stderr, 3953 gettext("invalid property '%s'\n"), 3954 cmdname); 3955 found = B_TRUE; 3956 ret = 1; 3957 } 3958 3959 } 3960 3961 if (found == B_FALSE) { 3962 (void) fprintf(stderr, gettext("unrecognized " 3963 "command '%s'\n"), cmdname); 3964 usage(B_FALSE); 3965 } 3966 } 3967 3968 (void) fclose(mnttab_file); 3969 3970 libzfs_fini(g_zfs); 3971 3972 /* 3973 * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3974 * for the purposes of running ::findleaks. 3975 */ 3976 if (getenv("ZFS_ABORT") != NULL) { 3977 (void) printf("dumping core by request\n"); 3978 abort(); 3979 } 3980 3981 return (ret); 3982 } 3983