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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 25 * Copyright (c) 2011 by Delphix. All rights reserved. 26 */ 27 28 #include <assert.h> 29 #include <ctype.h> 30 #include <errno.h> 31 #include <libgen.h> 32 #include <libintl.h> 33 #include <libuutil.h> 34 #include <libnvpair.h> 35 #include <locale.h> 36 #include <stddef.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <strings.h> 40 #include <unistd.h> 41 #include <fcntl.h> 42 #include <zone.h> 43 #include <grp.h> 44 #include <pwd.h> 45 #include <signal.h> 46 #include <sys/list.h> 47 #include <sys/mkdev.h> 48 #include <sys/mntent.h> 49 #include <sys/mnttab.h> 50 #include <sys/mount.h> 51 #include <sys/stat.h> 52 #include <sys/fs/zfs.h> 53 #include <sys/types.h> 54 #include <time.h> 55 56 #include <libzfs.h> 57 #include <zfs_prop.h> 58 #include <zfs_deleg.h> 59 #include <libuutil.h> 60 #include <aclutils.h> 61 #include <directory.h> 62 63 #include "zfs_iter.h" 64 #include "zfs_util.h" 65 #include "zfs_comutil.h" 66 67 libzfs_handle_t *g_zfs; 68 69 static FILE *mnttab_file; 70 static char history_str[HIS_MAX_RECORD_LEN]; 71 72 static int zfs_do_clone(int argc, char **argv); 73 static int zfs_do_create(int argc, char **argv); 74 static int zfs_do_destroy(int argc, char **argv); 75 static int zfs_do_get(int argc, char **argv); 76 static int zfs_do_inherit(int argc, char **argv); 77 static int zfs_do_list(int argc, char **argv); 78 static int zfs_do_mount(int argc, char **argv); 79 static int zfs_do_rename(int argc, char **argv); 80 static int zfs_do_rollback(int argc, char **argv); 81 static int zfs_do_set(int argc, char **argv); 82 static int zfs_do_upgrade(int argc, char **argv); 83 static int zfs_do_snapshot(int argc, char **argv); 84 static int zfs_do_unmount(int argc, char **argv); 85 static int zfs_do_share(int argc, char **argv); 86 static int zfs_do_unshare(int argc, char **argv); 87 static int zfs_do_send(int argc, char **argv); 88 static int zfs_do_receive(int argc, char **argv); 89 static int zfs_do_promote(int argc, char **argv); 90 static int zfs_do_userspace(int argc, char **argv); 91 static int zfs_do_allow(int argc, char **argv); 92 static int zfs_do_unallow(int argc, char **argv); 93 static int zfs_do_hold(int argc, char **argv); 94 static int zfs_do_holds(int argc, char **argv); 95 static int zfs_do_release(int argc, char **argv); 96 static int zfs_do_diff(int argc, char **argv); 97 98 /* 99 * Enable a reasonable set of defaults for libumem debugging on DEBUG builds. 100 */ 101 102 #ifdef DEBUG 103 const char * 104 _umem_debug_init(void) 105 { 106 return ("default,verbose"); /* $UMEM_DEBUG setting */ 107 } 108 109 const char * 110 _umem_logging_init(void) 111 { 112 return ("fail,contents"); /* $UMEM_LOGGING setting */ 113 } 114 #endif 115 116 typedef enum { 117 HELP_CLONE, 118 HELP_CREATE, 119 HELP_DESTROY, 120 HELP_GET, 121 HELP_INHERIT, 122 HELP_UPGRADE, 123 HELP_LIST, 124 HELP_MOUNT, 125 HELP_PROMOTE, 126 HELP_RECEIVE, 127 HELP_RENAME, 128 HELP_ROLLBACK, 129 HELP_SEND, 130 HELP_SET, 131 HELP_SHARE, 132 HELP_SNAPSHOT, 133 HELP_UNMOUNT, 134 HELP_UNSHARE, 135 HELP_ALLOW, 136 HELP_UNALLOW, 137 HELP_USERSPACE, 138 HELP_GROUPSPACE, 139 HELP_HOLD, 140 HELP_HOLDS, 141 HELP_RELEASE, 142 HELP_DIFF, 143 } zfs_help_t; 144 145 typedef struct zfs_command { 146 const char *name; 147 int (*func)(int argc, char **argv); 148 zfs_help_t usage; 149 } zfs_command_t; 150 151 /* 152 * Master command table. Each ZFS command has a name, associated function, and 153 * usage message. The usage messages need to be internationalized, so we have 154 * to have a function to return the usage message based on a command index. 155 * 156 * These commands are organized according to how they are displayed in the usage 157 * message. An empty command (one with a NULL name) indicates an empty line in 158 * the generic usage message. 159 */ 160 static zfs_command_t command_table[] = { 161 { "create", zfs_do_create, HELP_CREATE }, 162 { "destroy", zfs_do_destroy, HELP_DESTROY }, 163 { NULL }, 164 { "snapshot", zfs_do_snapshot, HELP_SNAPSHOT }, 165 { "rollback", zfs_do_rollback, HELP_ROLLBACK }, 166 { "clone", zfs_do_clone, HELP_CLONE }, 167 { "promote", zfs_do_promote, HELP_PROMOTE }, 168 { "rename", zfs_do_rename, HELP_RENAME }, 169 { NULL }, 170 { "list", zfs_do_list, HELP_LIST }, 171 { NULL }, 172 { "set", zfs_do_set, HELP_SET }, 173 { "get", zfs_do_get, HELP_GET }, 174 { "inherit", zfs_do_inherit, HELP_INHERIT }, 175 { "upgrade", zfs_do_upgrade, HELP_UPGRADE }, 176 { "userspace", zfs_do_userspace, HELP_USERSPACE }, 177 { "groupspace", zfs_do_userspace, HELP_GROUPSPACE }, 178 { NULL }, 179 { "mount", zfs_do_mount, HELP_MOUNT }, 180 { "unmount", zfs_do_unmount, HELP_UNMOUNT }, 181 { "share", zfs_do_share, HELP_SHARE }, 182 { "unshare", zfs_do_unshare, HELP_UNSHARE }, 183 { NULL }, 184 { "send", zfs_do_send, HELP_SEND }, 185 { "receive", zfs_do_receive, HELP_RECEIVE }, 186 { NULL }, 187 { "allow", zfs_do_allow, HELP_ALLOW }, 188 { NULL }, 189 { "unallow", zfs_do_unallow, HELP_UNALLOW }, 190 { NULL }, 191 { "hold", zfs_do_hold, HELP_HOLD }, 192 { "holds", zfs_do_holds, HELP_HOLDS }, 193 { "release", zfs_do_release, HELP_RELEASE }, 194 { "diff", zfs_do_diff, HELP_DIFF }, 195 }; 196 197 #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 198 199 zfs_command_t *current_command; 200 201 static const char * 202 get_usage(zfs_help_t idx) 203 { 204 switch (idx) { 205 case HELP_CLONE: 206 return (gettext("\tclone [-p] [-o property=value] ... " 207 "<snapshot> <filesystem|volume>\n")); 208 case HELP_CREATE: 209 return (gettext("\tcreate [-p] [-o property=value] ... " 210 "<filesystem>\n" 211 "\tcreate [-ps] [-b blocksize] [-o property=value] ... " 212 "-V <size> <volume>\n")); 213 case HELP_DESTROY: 214 return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n" 215 "\tdestroy [-dnpRrv] " 216 "<filesystem|volume>@<snap>[%<snap>][,...]\n")); 217 case HELP_GET: 218 return (gettext("\tget [-rHp] [-d max] " 219 "[-o \"all\" | field[,...]] [-s source[,...]]\n" 220 "\t <\"all\" | property[,...]> " 221 "[filesystem|volume|snapshot] ...\n")); 222 case HELP_INHERIT: 223 return (gettext("\tinherit [-rS] <property> " 224 "<filesystem|volume|snapshot> ...\n")); 225 case HELP_UPGRADE: 226 return (gettext("\tupgrade [-v]\n" 227 "\tupgrade [-r] [-V version] <-a | filesystem ...>\n")); 228 case HELP_LIST: 229 return (gettext("\tlist [-rH][-d max] " 230 "[-o property[,...]] [-t type[,...]] [-s property] ...\n" 231 "\t [-S property] ... " 232 "[filesystem|volume|snapshot] ...\n")); 233 case HELP_MOUNT: 234 return (gettext("\tmount\n" 235 "\tmount [-vO] [-o opts] <-a | filesystem>\n")); 236 case HELP_PROMOTE: 237 return (gettext("\tpromote <clone-filesystem>\n")); 238 case HELP_RECEIVE: 239 return (gettext("\treceive [-vnFu] <filesystem|volume|" 240 "snapshot>\n" 241 "\treceive [-vnFu] [-d | -e] <filesystem>\n")); 242 case HELP_RENAME: 243 return (gettext("\trename <filesystem|volume|snapshot> " 244 "<filesystem|volume|snapshot>\n" 245 "\trename -p <filesystem|volume> <filesystem|volume>\n" 246 "\trename -r <snapshot> <snapshot>")); 247 case HELP_ROLLBACK: 248 return (gettext("\trollback [-rRf] <snapshot>\n")); 249 case HELP_SEND: 250 return (gettext("\tsend [-DnPpRrv] [-[iI] snapshot] " 251 "<snapshot>\n")); 252 case HELP_SET: 253 return (gettext("\tset <property=value> " 254 "<filesystem|volume|snapshot> ...\n")); 255 case HELP_SHARE: 256 return (gettext("\tshare <-a | filesystem>\n")); 257 case HELP_SNAPSHOT: 258 return (gettext("\tsnapshot [-r] [-o property=value] ... " 259 "<filesystem@snapname|volume@snapname>\n")); 260 case HELP_UNMOUNT: 261 return (gettext("\tunmount [-f] " 262 "<-a | filesystem|mountpoint>\n")); 263 case HELP_UNSHARE: 264 return (gettext("\tunshare " 265 "<-a | filesystem|mountpoint>\n")); 266 case HELP_ALLOW: 267 return (gettext("\tallow <filesystem|volume>\n" 268 "\tallow [-ldug] " 269 "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n" 270 "\t <filesystem|volume>\n" 271 "\tallow [-ld] -e <perm|@setname>[,...] " 272 "<filesystem|volume>\n" 273 "\tallow -c <perm|@setname>[,...] <filesystem|volume>\n" 274 "\tallow -s @setname <perm|@setname>[,...] " 275 "<filesystem|volume>\n")); 276 case HELP_UNALLOW: 277 return (gettext("\tunallow [-rldug] " 278 "<\"everyone\"|user|group>[,...]\n" 279 "\t [<perm|@setname>[,...]] <filesystem|volume>\n" 280 "\tunallow [-rld] -e [<perm|@setname>[,...]] " 281 "<filesystem|volume>\n" 282 "\tunallow [-r] -c [<perm|@setname>[,...]] " 283 "<filesystem|volume>\n" 284 "\tunallow [-r] -s @setname [<perm|@setname>[,...]] " 285 "<filesystem|volume>\n")); 286 case HELP_USERSPACE: 287 return (gettext("\tuserspace [-hniHp] [-o field[,...]] " 288 "[-sS field] ... [-t type[,...]]\n" 289 "\t <filesystem|snapshot>\n")); 290 case HELP_GROUPSPACE: 291 return (gettext("\tgroupspace [-hniHpU] [-o field[,...]] " 292 "[-sS field] ... [-t type[,...]]\n" 293 "\t <filesystem|snapshot>\n")); 294 case HELP_HOLD: 295 return (gettext("\thold [-r] <tag> <snapshot> ...\n")); 296 case HELP_HOLDS: 297 return (gettext("\tholds [-r] <snapshot> ...\n")); 298 case HELP_RELEASE: 299 return (gettext("\trelease [-r] <tag> <snapshot> ...\n")); 300 case HELP_DIFF: 301 return (gettext("\tdiff [-FHt] <snapshot> " 302 "[snapshot|filesystem]\n")); 303 } 304 305 abort(); 306 /* NOTREACHED */ 307 } 308 309 void 310 nomem(void) 311 { 312 (void) fprintf(stderr, gettext("internal error: out of memory\n")); 313 exit(1); 314 } 315 316 /* 317 * Utility function to guarantee malloc() success. 318 */ 319 320 void * 321 safe_malloc(size_t size) 322 { 323 void *data; 324 325 if ((data = calloc(1, size)) == NULL) 326 nomem(); 327 328 return (data); 329 } 330 331 static char * 332 safe_strdup(char *str) 333 { 334 char *dupstr = strdup(str); 335 336 if (dupstr == NULL) 337 nomem(); 338 339 return (dupstr); 340 } 341 342 /* 343 * Callback routine that will print out information for each of 344 * the properties. 345 */ 346 static int 347 usage_prop_cb(int prop, void *cb) 348 { 349 FILE *fp = cb; 350 351 (void) fprintf(fp, "\t%-15s ", zfs_prop_to_name(prop)); 352 353 if (zfs_prop_readonly(prop)) 354 (void) fprintf(fp, " NO "); 355 else 356 (void) fprintf(fp, "YES "); 357 358 if (zfs_prop_inheritable(prop)) 359 (void) fprintf(fp, " YES "); 360 else 361 (void) fprintf(fp, " NO "); 362 363 if (zfs_prop_values(prop) == NULL) 364 (void) fprintf(fp, "-\n"); 365 else 366 (void) fprintf(fp, "%s\n", zfs_prop_values(prop)); 367 368 return (ZPROP_CONT); 369 } 370 371 /* 372 * Display usage message. If we're inside a command, display only the usage for 373 * that command. Otherwise, iterate over the entire command table and display 374 * a complete usage message. 375 */ 376 static void 377 usage(boolean_t requested) 378 { 379 int i; 380 boolean_t show_properties = B_FALSE; 381 FILE *fp = requested ? stdout : stderr; 382 383 if (current_command == NULL) { 384 385 (void) fprintf(fp, gettext("usage: zfs command args ...\n")); 386 (void) fprintf(fp, 387 gettext("where 'command' is one of the following:\n\n")); 388 389 for (i = 0; i < NCOMMAND; i++) { 390 if (command_table[i].name == NULL) 391 (void) fprintf(fp, "\n"); 392 else 393 (void) fprintf(fp, "%s", 394 get_usage(command_table[i].usage)); 395 } 396 397 (void) fprintf(fp, gettext("\nEach dataset is of the form: " 398 "pool/[dataset/]*dataset[@name]\n")); 399 } else { 400 (void) fprintf(fp, gettext("usage:\n")); 401 (void) fprintf(fp, "%s", get_usage(current_command->usage)); 402 } 403 404 if (current_command != NULL && 405 (strcmp(current_command->name, "set") == 0 || 406 strcmp(current_command->name, "get") == 0 || 407 strcmp(current_command->name, "inherit") == 0 || 408 strcmp(current_command->name, "list") == 0)) 409 show_properties = B_TRUE; 410 411 if (show_properties) { 412 (void) fprintf(fp, 413 gettext("\nThe following properties are supported:\n")); 414 415 (void) fprintf(fp, "\n\t%-14s %s %s %s\n\n", 416 "PROPERTY", "EDIT", "INHERIT", "VALUES"); 417 418 /* Iterate over all properties */ 419 (void) zprop_iter(usage_prop_cb, fp, B_FALSE, B_TRUE, 420 ZFS_TYPE_DATASET); 421 422 (void) fprintf(fp, "\t%-15s ", "userused@..."); 423 (void) fprintf(fp, " NO NO <size>\n"); 424 (void) fprintf(fp, "\t%-15s ", "groupused@..."); 425 (void) fprintf(fp, " NO NO <size>\n"); 426 (void) fprintf(fp, "\t%-15s ", "userquota@..."); 427 (void) fprintf(fp, "YES NO <size> | none\n"); 428 (void) fprintf(fp, "\t%-15s ", "groupquota@..."); 429 (void) fprintf(fp, "YES NO <size> | none\n"); 430 (void) fprintf(fp, "\t%-15s ", "written@<snap>"); 431 (void) fprintf(fp, " NO NO <size>\n"); 432 433 (void) fprintf(fp, gettext("\nSizes are specified in bytes " 434 "with standard units such as K, M, G, etc.\n")); 435 (void) fprintf(fp, gettext("\nUser-defined properties can " 436 "be specified by using a name containing a colon (:).\n")); 437 (void) fprintf(fp, gettext("\nThe {user|group}{used|quota}@ " 438 "properties must be appended with\n" 439 "a user or group specifier of one of these forms:\n" 440 " POSIX name (eg: \"matt\")\n" 441 " POSIX id (eg: \"126829\")\n" 442 " SMB name@domain (eg: \"matt@sun\")\n" 443 " SMB SID (eg: \"S-1-234-567-89\")\n")); 444 } else { 445 (void) fprintf(fp, 446 gettext("\nFor the property list, run: %s\n"), 447 "zfs set|get"); 448 (void) fprintf(fp, 449 gettext("\nFor the delegated permission list, run: %s\n"), 450 "zfs allow|unallow"); 451 } 452 453 /* 454 * See comments at end of main(). 455 */ 456 if (getenv("ZFS_ABORT") != NULL) { 457 (void) printf("dumping core by request\n"); 458 abort(); 459 } 460 461 exit(requested ? 0 : 2); 462 } 463 464 static int 465 parseprop(nvlist_t *props) 466 { 467 char *propname = optarg; 468 char *propval, *strval; 469 470 if ((propval = strchr(propname, '=')) == NULL) { 471 (void) fprintf(stderr, gettext("missing " 472 "'=' for -o option\n")); 473 return (-1); 474 } 475 *propval = '\0'; 476 propval++; 477 if (nvlist_lookup_string(props, propname, &strval) == 0) { 478 (void) fprintf(stderr, gettext("property '%s' " 479 "specified multiple times\n"), propname); 480 return (-1); 481 } 482 if (nvlist_add_string(props, propname, propval) != 0) 483 nomem(); 484 return (0); 485 } 486 487 static int 488 parse_depth(char *opt, int *flags) 489 { 490 char *tmp; 491 int depth; 492 493 depth = (int)strtol(opt, &tmp, 0); 494 if (*tmp) { 495 (void) fprintf(stderr, 496 gettext("%s is not an integer\n"), optarg); 497 usage(B_FALSE); 498 } 499 if (depth < 0) { 500 (void) fprintf(stderr, 501 gettext("Depth can not be negative.\n")); 502 usage(B_FALSE); 503 } 504 *flags |= (ZFS_ITER_DEPTH_LIMIT|ZFS_ITER_RECURSE); 505 return (depth); 506 } 507 508 #define PROGRESS_DELAY 2 /* seconds */ 509 510 static char *pt_reverse = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; 511 static time_t pt_begin; 512 static char *pt_header = NULL; 513 static boolean_t pt_shown; 514 515 static void 516 start_progress_timer(void) 517 { 518 pt_begin = time(NULL) + PROGRESS_DELAY; 519 pt_shown = B_FALSE; 520 } 521 522 static void 523 set_progress_header(char *header) 524 { 525 assert(pt_header == NULL); 526 pt_header = safe_strdup(header); 527 if (pt_shown) { 528 (void) printf("%s: ", header); 529 (void) fflush(stdout); 530 } 531 } 532 533 static void 534 update_progress(char *update) 535 { 536 if (!pt_shown && time(NULL) > pt_begin) { 537 int len = strlen(update); 538 539 (void) printf("%s: %s%*.*s", pt_header, update, len, len, 540 pt_reverse); 541 (void) fflush(stdout); 542 pt_shown = B_TRUE; 543 } else if (pt_shown) { 544 int len = strlen(update); 545 546 (void) printf("%s%*.*s", update, len, len, pt_reverse); 547 (void) fflush(stdout); 548 } 549 } 550 551 static void 552 finish_progress(char *done) 553 { 554 if (pt_shown) { 555 (void) printf("%s\n", done); 556 (void) fflush(stdout); 557 } 558 free(pt_header); 559 pt_header = NULL; 560 } 561 /* 562 * zfs clone [-p] [-o prop=value] ... <snap> <fs | vol> 563 * 564 * Given an existing dataset, create a writable copy whose initial contents 565 * are the same as the source. The newly created dataset maintains a 566 * dependency on the original; the original cannot be destroyed so long as 567 * the clone exists. 568 * 569 * The '-p' flag creates all the non-existing ancestors of the target first. 570 */ 571 static int 572 zfs_do_clone(int argc, char **argv) 573 { 574 zfs_handle_t *zhp = NULL; 575 boolean_t parents = B_FALSE; 576 nvlist_t *props; 577 int ret; 578 int c; 579 580 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) 581 nomem(); 582 583 /* check options */ 584 while ((c = getopt(argc, argv, "o:p")) != -1) { 585 switch (c) { 586 case 'o': 587 if (parseprop(props)) 588 return (1); 589 break; 590 case 'p': 591 parents = B_TRUE; 592 break; 593 case '?': 594 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 595 optopt); 596 goto usage; 597 } 598 } 599 600 argc -= optind; 601 argv += optind; 602 603 /* check number of arguments */ 604 if (argc < 1) { 605 (void) fprintf(stderr, gettext("missing source dataset " 606 "argument\n")); 607 goto usage; 608 } 609 if (argc < 2) { 610 (void) fprintf(stderr, gettext("missing target dataset " 611 "argument\n")); 612 goto usage; 613 } 614 if (argc > 2) { 615 (void) fprintf(stderr, gettext("too many arguments\n")); 616 goto usage; 617 } 618 619 /* open the source dataset */ 620 if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL) 621 return (1); 622 623 if (parents && zfs_name_valid(argv[1], ZFS_TYPE_FILESYSTEM | 624 ZFS_TYPE_VOLUME)) { 625 /* 626 * Now create the ancestors of the target dataset. If the 627 * target already exists and '-p' option was used we should not 628 * complain. 629 */ 630 if (zfs_dataset_exists(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | 631 ZFS_TYPE_VOLUME)) 632 return (0); 633 if (zfs_create_ancestors(g_zfs, argv[1]) != 0) 634 return (1); 635 } 636 637 /* pass to libzfs */ 638 ret = zfs_clone(zhp, argv[1], props); 639 640 /* create the mountpoint if necessary */ 641 if (ret == 0) { 642 zfs_handle_t *clone; 643 644 clone = zfs_open(g_zfs, argv[1], ZFS_TYPE_DATASET); 645 if (clone != NULL) { 646 if (zfs_get_type(clone) != ZFS_TYPE_VOLUME) 647 if ((ret = zfs_mount(clone, NULL, 0)) == 0) 648 ret = zfs_share(clone); 649 zfs_close(clone); 650 } 651 } 652 653 zfs_close(zhp); 654 nvlist_free(props); 655 656 return (!!ret); 657 658 usage: 659 if (zhp) 660 zfs_close(zhp); 661 nvlist_free(props); 662 usage(B_FALSE); 663 return (-1); 664 } 665 666 /* 667 * zfs create [-p] [-o prop=value] ... fs 668 * zfs create [-ps] [-b blocksize] [-o prop=value] ... -V vol size 669 * 670 * Create a new dataset. This command can be used to create filesystems 671 * and volumes. Snapshot creation is handled by 'zfs snapshot'. 672 * For volumes, the user must specify a size to be used. 673 * 674 * The '-s' flag applies only to volumes, and indicates that we should not try 675 * to set the reservation for this volume. By default we set a reservation 676 * equal to the size for any volume. For pools with SPA_VERSION >= 677 * SPA_VERSION_REFRESERVATION, we set a refreservation instead. 678 * 679 * The '-p' flag creates all the non-existing ancestors of the target first. 680 */ 681 static int 682 zfs_do_create(int argc, char **argv) 683 { 684 zfs_type_t type = ZFS_TYPE_FILESYSTEM; 685 zfs_handle_t *zhp = NULL; 686 uint64_t volsize; 687 int c; 688 boolean_t noreserve = B_FALSE; 689 boolean_t bflag = B_FALSE; 690 boolean_t parents = B_FALSE; 691 int ret = 1; 692 nvlist_t *props; 693 uint64_t intval; 694 int canmount = ZFS_CANMOUNT_OFF; 695 696 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) 697 nomem(); 698 699 /* check options */ 700 while ((c = getopt(argc, argv, ":V:b:so:p")) != -1) { 701 switch (c) { 702 case 'V': 703 type = ZFS_TYPE_VOLUME; 704 if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) { 705 (void) fprintf(stderr, gettext("bad volume " 706 "size '%s': %s\n"), optarg, 707 libzfs_error_description(g_zfs)); 708 goto error; 709 } 710 711 if (nvlist_add_uint64(props, 712 zfs_prop_to_name(ZFS_PROP_VOLSIZE), intval) != 0) 713 nomem(); 714 volsize = intval; 715 break; 716 case 'p': 717 parents = B_TRUE; 718 break; 719 case 'b': 720 bflag = B_TRUE; 721 if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) { 722 (void) fprintf(stderr, gettext("bad volume " 723 "block size '%s': %s\n"), optarg, 724 libzfs_error_description(g_zfs)); 725 goto error; 726 } 727 728 if (nvlist_add_uint64(props, 729 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 730 intval) != 0) 731 nomem(); 732 break; 733 case 'o': 734 if (parseprop(props)) 735 goto error; 736 break; 737 case 's': 738 noreserve = B_TRUE; 739 break; 740 case ':': 741 (void) fprintf(stderr, gettext("missing size " 742 "argument\n")); 743 goto badusage; 744 break; 745 case '?': 746 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 747 optopt); 748 goto badusage; 749 } 750 } 751 752 if ((bflag || noreserve) && type != ZFS_TYPE_VOLUME) { 753 (void) fprintf(stderr, gettext("'-s' and '-b' can only be " 754 "used when creating a volume\n")); 755 goto badusage; 756 } 757 758 argc -= optind; 759 argv += optind; 760 761 /* check number of arguments */ 762 if (argc == 0) { 763 (void) fprintf(stderr, gettext("missing %s argument\n"), 764 zfs_type_to_name(type)); 765 goto badusage; 766 } 767 if (argc > 1) { 768 (void) fprintf(stderr, gettext("too many arguments\n")); 769 goto badusage; 770 } 771 772 if (type == ZFS_TYPE_VOLUME && !noreserve) { 773 zpool_handle_t *zpool_handle; 774 uint64_t spa_version; 775 char *p; 776 zfs_prop_t resv_prop; 777 char *strval; 778 779 if (p = strchr(argv[0], '/')) 780 *p = '\0'; 781 zpool_handle = zpool_open(g_zfs, argv[0]); 782 if (p != NULL) 783 *p = '/'; 784 if (zpool_handle == NULL) 785 goto error; 786 spa_version = zpool_get_prop_int(zpool_handle, 787 ZPOOL_PROP_VERSION, NULL); 788 zpool_close(zpool_handle); 789 if (spa_version >= SPA_VERSION_REFRESERVATION) 790 resv_prop = ZFS_PROP_REFRESERVATION; 791 else 792 resv_prop = ZFS_PROP_RESERVATION; 793 volsize = zvol_volsize_to_reservation(volsize, props); 794 795 if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop), 796 &strval) != 0) { 797 if (nvlist_add_uint64(props, 798 zfs_prop_to_name(resv_prop), volsize) != 0) { 799 nvlist_free(props); 800 nomem(); 801 } 802 } 803 } 804 805 if (parents && zfs_name_valid(argv[0], type)) { 806 /* 807 * Now create the ancestors of target dataset. If the target 808 * already exists and '-p' option was used we should not 809 * complain. 810 */ 811 if (zfs_dataset_exists(g_zfs, argv[0], type)) { 812 ret = 0; 813 goto error; 814 } 815 if (zfs_create_ancestors(g_zfs, argv[0]) != 0) 816 goto error; 817 } 818 819 /* pass to libzfs */ 820 if (zfs_create(g_zfs, argv[0], type, props) != 0) 821 goto error; 822 823 if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL) 824 goto error; 825 826 ret = 0; 827 /* 828 * if the user doesn't want the dataset automatically mounted, 829 * then skip the mount/share step 830 */ 831 if (zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, type)) 832 canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT); 833 834 /* 835 * Mount and/or share the new filesystem as appropriate. We provide a 836 * verbose error message to let the user know that their filesystem was 837 * in fact created, even if we failed to mount or share it. 838 */ 839 if (canmount == ZFS_CANMOUNT_ON) { 840 if (zfs_mount(zhp, NULL, 0) != 0) { 841 (void) fprintf(stderr, gettext("filesystem " 842 "successfully created, but not mounted\n")); 843 ret = 1; 844 } else if (zfs_share(zhp) != 0) { 845 (void) fprintf(stderr, gettext("filesystem " 846 "successfully created, but not shared\n")); 847 ret = 1; 848 } 849 } 850 851 error: 852 if (zhp) 853 zfs_close(zhp); 854 nvlist_free(props); 855 return (ret); 856 badusage: 857 nvlist_free(props); 858 usage(B_FALSE); 859 return (2); 860 } 861 862 /* 863 * zfs destroy [-rRf] <fs, vol> 864 * zfs destroy [-rRd] <snap> 865 * 866 * -r Recursively destroy all children 867 * -R Recursively destroy all dependents, including clones 868 * -f Force unmounting of any dependents 869 * -d If we can't destroy now, mark for deferred destruction 870 * 871 * Destroys the given dataset. By default, it will unmount any filesystems, 872 * and refuse to destroy a dataset that has any dependents. A dependent can 873 * either be a child, or a clone of a child. 874 */ 875 typedef struct destroy_cbdata { 876 boolean_t cb_first; 877 boolean_t cb_force; 878 boolean_t cb_recurse; 879 boolean_t cb_error; 880 boolean_t cb_doclones; 881 zfs_handle_t *cb_target; 882 boolean_t cb_defer_destroy; 883 boolean_t cb_verbose; 884 boolean_t cb_parsable; 885 boolean_t cb_dryrun; 886 nvlist_t *cb_nvl; 887 888 /* first snap in contiguous run */ 889 zfs_handle_t *cb_firstsnap; 890 /* previous snap in contiguous run */ 891 zfs_handle_t *cb_prevsnap; 892 int64_t cb_snapused; 893 char *cb_snapspec; 894 } destroy_cbdata_t; 895 896 /* 897 * Check for any dependents based on the '-r' or '-R' flags. 898 */ 899 static int 900 destroy_check_dependent(zfs_handle_t *zhp, void *data) 901 { 902 destroy_cbdata_t *cbp = data; 903 const char *tname = zfs_get_name(cbp->cb_target); 904 const char *name = zfs_get_name(zhp); 905 906 if (strncmp(tname, name, strlen(tname)) == 0 && 907 (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) { 908 /* 909 * This is a direct descendant, not a clone somewhere else in 910 * the hierarchy. 911 */ 912 if (cbp->cb_recurse) 913 goto out; 914 915 if (cbp->cb_first) { 916 (void) fprintf(stderr, gettext("cannot destroy '%s': " 917 "%s has children\n"), 918 zfs_get_name(cbp->cb_target), 919 zfs_type_to_name(zfs_get_type(cbp->cb_target))); 920 (void) fprintf(stderr, gettext("use '-r' to destroy " 921 "the following datasets:\n")); 922 cbp->cb_first = B_FALSE; 923 cbp->cb_error = B_TRUE; 924 } 925 926 (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); 927 } else { 928 /* 929 * This is a clone. We only want to report this if the '-r' 930 * wasn't specified, or the target is a snapshot. 931 */ 932 if (!cbp->cb_recurse && 933 zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT) 934 goto out; 935 936 if (cbp->cb_first) { 937 (void) fprintf(stderr, gettext("cannot destroy '%s': " 938 "%s has dependent clones\n"), 939 zfs_get_name(cbp->cb_target), 940 zfs_type_to_name(zfs_get_type(cbp->cb_target))); 941 (void) fprintf(stderr, gettext("use '-R' to destroy " 942 "the following datasets:\n")); 943 cbp->cb_first = B_FALSE; 944 cbp->cb_error = B_TRUE; 945 cbp->cb_dryrun = B_TRUE; 946 } 947 948 (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); 949 } 950 951 out: 952 zfs_close(zhp); 953 return (0); 954 } 955 956 static int 957 destroy_callback(zfs_handle_t *zhp, void *data) 958 { 959 destroy_cbdata_t *cb = data; 960 const char *name = zfs_get_name(zhp); 961 962 if (cb->cb_verbose) { 963 if (cb->cb_parsable) { 964 (void) printf("destroy\t%s\n", name); 965 } else if (cb->cb_dryrun) { 966 (void) printf(gettext("would destroy %s\n"), 967 name); 968 } else { 969 (void) printf(gettext("will destroy %s\n"), 970 name); 971 } 972 } 973 974 /* 975 * Ignore pools (which we've already flagged as an error before getting 976 * here). 977 */ 978 if (strchr(zfs_get_name(zhp), '/') == NULL && 979 zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { 980 zfs_close(zhp); 981 return (0); 982 } 983 984 if (!cb->cb_dryrun) { 985 if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 || 986 zfs_destroy(zhp, cb->cb_defer_destroy) != 0) { 987 zfs_close(zhp); 988 return (-1); 989 } 990 } 991 992 zfs_close(zhp); 993 return (0); 994 } 995 996 static int 997 destroy_print_cb(zfs_handle_t *zhp, void *arg) 998 { 999 destroy_cbdata_t *cb = arg; 1000 const char *name = zfs_get_name(zhp); 1001 int err = 0; 1002 1003 if (nvlist_exists(cb->cb_nvl, name)) { 1004 if (cb->cb_firstsnap == NULL) 1005 cb->cb_firstsnap = zfs_handle_dup(zhp); 1006 if (cb->cb_prevsnap != NULL) 1007 zfs_close(cb->cb_prevsnap); 1008 /* this snap continues the current range */ 1009 cb->cb_prevsnap = zfs_handle_dup(zhp); 1010 if (cb->cb_verbose) { 1011 if (cb->cb_parsable) { 1012 (void) printf("destroy\t%s\n", name); 1013 } else if (cb->cb_dryrun) { 1014 (void) printf(gettext("would destroy %s\n"), 1015 name); 1016 } else { 1017 (void) printf(gettext("will destroy %s\n"), 1018 name); 1019 } 1020 } 1021 } else if (cb->cb_firstsnap != NULL) { 1022 /* end of this range */ 1023 uint64_t used = 0; 1024 err = zfs_get_snapused_int(cb->cb_firstsnap, 1025 cb->cb_prevsnap, &used); 1026 cb->cb_snapused += used; 1027 zfs_close(cb->cb_firstsnap); 1028 cb->cb_firstsnap = NULL; 1029 zfs_close(cb->cb_prevsnap); 1030 cb->cb_prevsnap = NULL; 1031 } 1032 zfs_close(zhp); 1033 return (err); 1034 } 1035 1036 static int 1037 destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb) 1038 { 1039 int err; 1040 assert(cb->cb_firstsnap == NULL); 1041 assert(cb->cb_prevsnap == NULL); 1042 err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb); 1043 if (cb->cb_firstsnap != NULL) { 1044 uint64_t used = 0; 1045 if (err == 0) { 1046 err = zfs_get_snapused_int(cb->cb_firstsnap, 1047 cb->cb_prevsnap, &used); 1048 } 1049 cb->cb_snapused += used; 1050 zfs_close(cb->cb_firstsnap); 1051 cb->cb_firstsnap = NULL; 1052 zfs_close(cb->cb_prevsnap); 1053 cb->cb_prevsnap = NULL; 1054 } 1055 return (err); 1056 } 1057 1058 static int 1059 snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg) 1060 { 1061 destroy_cbdata_t *cb = arg; 1062 int err = 0; 1063 1064 /* Check for clones. */ 1065 if (!cb->cb_doclones) { 1066 cb->cb_target = zhp; 1067 cb->cb_first = B_TRUE; 1068 err = zfs_iter_dependents(zhp, B_TRUE, 1069 destroy_check_dependent, cb); 1070 } 1071 1072 if (err == 0) { 1073 if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp))) 1074 nomem(); 1075 } 1076 zfs_close(zhp); 1077 return (err); 1078 } 1079 1080 static int 1081 gather_snapshots(zfs_handle_t *zhp, void *arg) 1082 { 1083 destroy_cbdata_t *cb = arg; 1084 int err = 0; 1085 1086 err = zfs_iter_snapspec(zhp, cb->cb_snapspec, snapshot_to_nvl_cb, cb); 1087 if (err == ENOENT) 1088 err = 0; 1089 if (err != 0) 1090 goto out; 1091 1092 if (cb->cb_verbose) { 1093 err = destroy_print_snapshots(zhp, cb); 1094 if (err != 0) 1095 goto out; 1096 } 1097 1098 if (cb->cb_recurse) 1099 err = zfs_iter_filesystems(zhp, gather_snapshots, cb); 1100 1101 out: 1102 zfs_close(zhp); 1103 return (err); 1104 } 1105 1106 static int 1107 destroy_clones(destroy_cbdata_t *cb) 1108 { 1109 nvpair_t *pair; 1110 for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL); 1111 pair != NULL; 1112 pair = nvlist_next_nvpair(cb->cb_nvl, pair)) { 1113 zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair), 1114 ZFS_TYPE_SNAPSHOT); 1115 if (zhp != NULL) { 1116 boolean_t defer = cb->cb_defer_destroy; 1117 int err; 1118 1119 /* 1120 * We can't defer destroy non-snapshots, so set it to 1121 * false while destroying the clones. 1122 */ 1123 cb->cb_defer_destroy = B_FALSE; 1124 err = zfs_iter_dependents(zhp, B_FALSE, 1125 destroy_callback, cb); 1126 cb->cb_defer_destroy = defer; 1127 zfs_close(zhp); 1128 if (err != 0) 1129 return (err); 1130 } 1131 } 1132 return (0); 1133 } 1134 1135 static int 1136 zfs_do_destroy(int argc, char **argv) 1137 { 1138 destroy_cbdata_t cb = { 0 }; 1139 int c; 1140 zfs_handle_t *zhp; 1141 char *at; 1142 zfs_type_t type = ZFS_TYPE_DATASET; 1143 1144 /* check options */ 1145 while ((c = getopt(argc, argv, "vpndfrR")) != -1) { 1146 switch (c) { 1147 case 'v': 1148 cb.cb_verbose = B_TRUE; 1149 break; 1150 case 'p': 1151 cb.cb_verbose = B_TRUE; 1152 cb.cb_parsable = B_TRUE; 1153 break; 1154 case 'n': 1155 cb.cb_dryrun = B_TRUE; 1156 break; 1157 case 'd': 1158 cb.cb_defer_destroy = B_TRUE; 1159 type = ZFS_TYPE_SNAPSHOT; 1160 break; 1161 case 'f': 1162 cb.cb_force = B_TRUE; 1163 break; 1164 case 'r': 1165 cb.cb_recurse = B_TRUE; 1166 break; 1167 case 'R': 1168 cb.cb_recurse = B_TRUE; 1169 cb.cb_doclones = B_TRUE; 1170 break; 1171 case '?': 1172 default: 1173 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1174 optopt); 1175 usage(B_FALSE); 1176 } 1177 } 1178 1179 argc -= optind; 1180 argv += optind; 1181 1182 /* check number of arguments */ 1183 if (argc == 0) { 1184 (void) fprintf(stderr, gettext("missing dataset argument\n")); 1185 usage(B_FALSE); 1186 } 1187 if (argc > 1) { 1188 (void) fprintf(stderr, gettext("too many arguments\n")); 1189 usage(B_FALSE); 1190 } 1191 1192 at = strchr(argv[0], '@'); 1193 if (at != NULL) { 1194 int err; 1195 1196 /* Build the list of snaps to destroy in cb_nvl. */ 1197 if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0) 1198 nomem(); 1199 1200 *at = '\0'; 1201 zhp = zfs_open(g_zfs, argv[0], 1202 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 1203 if (zhp == NULL) 1204 return (1); 1205 1206 cb.cb_snapspec = at + 1; 1207 if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 || 1208 cb.cb_error) { 1209 zfs_close(zhp); 1210 nvlist_free(cb.cb_nvl); 1211 return (1); 1212 } 1213 1214 if (nvlist_empty(cb.cb_nvl)) { 1215 (void) fprintf(stderr, gettext("could not find any " 1216 "snapshots to destroy; check snapshot names.\n")); 1217 zfs_close(zhp); 1218 nvlist_free(cb.cb_nvl); 1219 return (1); 1220 } 1221 1222 if (cb.cb_verbose) { 1223 char buf[16]; 1224 zfs_nicenum(cb.cb_snapused, buf, sizeof (buf)); 1225 if (cb.cb_parsable) { 1226 (void) printf("reclaim\t%llu\n", 1227 cb.cb_snapused); 1228 } else if (cb.cb_dryrun) { 1229 (void) printf(gettext("would reclaim %s\n"), 1230 buf); 1231 } else { 1232 (void) printf(gettext("will reclaim %s\n"), 1233 buf); 1234 } 1235 } 1236 1237 if (!cb.cb_dryrun) { 1238 if (cb.cb_doclones) 1239 err = destroy_clones(&cb); 1240 if (err == 0) { 1241 err = zfs_destroy_snaps_nvl(zhp, cb.cb_nvl, 1242 cb.cb_defer_destroy); 1243 } 1244 } 1245 1246 zfs_close(zhp); 1247 nvlist_free(cb.cb_nvl); 1248 if (err != 0) 1249 return (1); 1250 } else { 1251 /* Open the given dataset */ 1252 if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL) 1253 return (1); 1254 1255 cb.cb_target = zhp; 1256 1257 /* 1258 * Perform an explicit check for pools before going any further. 1259 */ 1260 if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL && 1261 zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { 1262 (void) fprintf(stderr, gettext("cannot destroy '%s': " 1263 "operation does not apply to pools\n"), 1264 zfs_get_name(zhp)); 1265 (void) fprintf(stderr, gettext("use 'zfs destroy -r " 1266 "%s' to destroy all datasets in the pool\n"), 1267 zfs_get_name(zhp)); 1268 (void) fprintf(stderr, gettext("use 'zpool destroy %s' " 1269 "to destroy the pool itself\n"), zfs_get_name(zhp)); 1270 zfs_close(zhp); 1271 return (1); 1272 } 1273 1274 /* 1275 * Check for any dependents and/or clones. 1276 */ 1277 cb.cb_first = B_TRUE; 1278 if (!cb.cb_doclones && 1279 zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent, 1280 &cb) != 0) { 1281 zfs_close(zhp); 1282 return (1); 1283 } 1284 1285 if (cb.cb_error) { 1286 zfs_close(zhp); 1287 return (1); 1288 } 1289 1290 if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback, 1291 &cb) != 0) { 1292 zfs_close(zhp); 1293 return (1); 1294 } 1295 1296 /* 1297 * Do the real thing. The callback will close the 1298 * handle regardless of whether it succeeds or not. 1299 */ 1300 if (destroy_callback(zhp, &cb) != 0) 1301 return (1); 1302 } 1303 1304 return (0); 1305 } 1306 1307 static boolean_t 1308 is_recvd_column(zprop_get_cbdata_t *cbp) 1309 { 1310 int i; 1311 zfs_get_column_t col; 1312 1313 for (i = 0; i < ZFS_GET_NCOLS && 1314 (col = cbp->cb_columns[i]) != GET_COL_NONE; i++) 1315 if (col == GET_COL_RECVD) 1316 return (B_TRUE); 1317 return (B_FALSE); 1318 } 1319 1320 /* 1321 * zfs get [-rHp] [-o all | field[,field]...] [-s source[,source]...] 1322 * < all | property[,property]... > < fs | snap | vol > ... 1323 * 1324 * -r recurse over any child datasets 1325 * -H scripted mode. Headers are stripped, and fields are separated 1326 * by tabs instead of spaces. 1327 * -o Set of fields to display. One of "name,property,value, 1328 * received,source". Default is "name,property,value,source". 1329 * "all" is an alias for all five. 1330 * -s Set of sources to allow. One of 1331 * "local,default,inherited,received,temporary,none". Default is 1332 * all six. 1333 * -p Display values in parsable (literal) format. 1334 * 1335 * Prints properties for the given datasets. The user can control which 1336 * columns to display as well as which property types to allow. 1337 */ 1338 1339 /* 1340 * Invoked to display the properties for a single dataset. 1341 */ 1342 static int 1343 get_callback(zfs_handle_t *zhp, void *data) 1344 { 1345 char buf[ZFS_MAXPROPLEN]; 1346 char rbuf[ZFS_MAXPROPLEN]; 1347 zprop_source_t sourcetype; 1348 char source[ZFS_MAXNAMELEN]; 1349 zprop_get_cbdata_t *cbp = data; 1350 nvlist_t *user_props = zfs_get_user_props(zhp); 1351 zprop_list_t *pl = cbp->cb_proplist; 1352 nvlist_t *propval; 1353 char *strval; 1354 char *sourceval; 1355 boolean_t received = is_recvd_column(cbp); 1356 1357 for (; pl != NULL; pl = pl->pl_next) { 1358 char *recvdval = NULL; 1359 /* 1360 * Skip the special fake placeholder. This will also skip over 1361 * the name property when 'all' is specified. 1362 */ 1363 if (pl->pl_prop == ZFS_PROP_NAME && 1364 pl == cbp->cb_proplist) 1365 continue; 1366 1367 if (pl->pl_prop != ZPROP_INVAL) { 1368 if (zfs_prop_get(zhp, pl->pl_prop, buf, 1369 sizeof (buf), &sourcetype, source, 1370 sizeof (source), 1371 cbp->cb_literal) != 0) { 1372 if (pl->pl_all) 1373 continue; 1374 if (!zfs_prop_valid_for_type(pl->pl_prop, 1375 ZFS_TYPE_DATASET)) { 1376 (void) fprintf(stderr, 1377 gettext("No such property '%s'\n"), 1378 zfs_prop_to_name(pl->pl_prop)); 1379 continue; 1380 } 1381 sourcetype = ZPROP_SRC_NONE; 1382 (void) strlcpy(buf, "-", sizeof (buf)); 1383 } 1384 1385 if (received && (zfs_prop_get_recvd(zhp, 1386 zfs_prop_to_name(pl->pl_prop), rbuf, sizeof (rbuf), 1387 cbp->cb_literal) == 0)) 1388 recvdval = rbuf; 1389 1390 zprop_print_one_property(zfs_get_name(zhp), cbp, 1391 zfs_prop_to_name(pl->pl_prop), 1392 buf, sourcetype, source, recvdval); 1393 } else if (zfs_prop_userquota(pl->pl_user_prop)) { 1394 sourcetype = ZPROP_SRC_LOCAL; 1395 1396 if (zfs_prop_get_userquota(zhp, pl->pl_user_prop, 1397 buf, sizeof (buf), cbp->cb_literal) != 0) { 1398 sourcetype = ZPROP_SRC_NONE; 1399 (void) strlcpy(buf, "-", sizeof (buf)); 1400 } 1401 1402 zprop_print_one_property(zfs_get_name(zhp), cbp, 1403 pl->pl_user_prop, buf, sourcetype, source, NULL); 1404 } else if (zfs_prop_written(pl->pl_user_prop)) { 1405 sourcetype = ZPROP_SRC_LOCAL; 1406 1407 if (zfs_prop_get_written(zhp, pl->pl_user_prop, 1408 buf, sizeof (buf), cbp->cb_literal) != 0) { 1409 sourcetype = ZPROP_SRC_NONE; 1410 (void) strlcpy(buf, "-", sizeof (buf)); 1411 } 1412 1413 zprop_print_one_property(zfs_get_name(zhp), cbp, 1414 pl->pl_user_prop, buf, sourcetype, source, NULL); 1415 } else { 1416 if (nvlist_lookup_nvlist(user_props, 1417 pl->pl_user_prop, &propval) != 0) { 1418 if (pl->pl_all) 1419 continue; 1420 sourcetype = ZPROP_SRC_NONE; 1421 strval = "-"; 1422 } else { 1423 verify(nvlist_lookup_string(propval, 1424 ZPROP_VALUE, &strval) == 0); 1425 verify(nvlist_lookup_string(propval, 1426 ZPROP_SOURCE, &sourceval) == 0); 1427 1428 if (strcmp(sourceval, 1429 zfs_get_name(zhp)) == 0) { 1430 sourcetype = ZPROP_SRC_LOCAL; 1431 } else if (strcmp(sourceval, 1432 ZPROP_SOURCE_VAL_RECVD) == 0) { 1433 sourcetype = ZPROP_SRC_RECEIVED; 1434 } else { 1435 sourcetype = ZPROP_SRC_INHERITED; 1436 (void) strlcpy(source, 1437 sourceval, sizeof (source)); 1438 } 1439 } 1440 1441 if (received && (zfs_prop_get_recvd(zhp, 1442 pl->pl_user_prop, rbuf, sizeof (rbuf), 1443 cbp->cb_literal) == 0)) 1444 recvdval = rbuf; 1445 1446 zprop_print_one_property(zfs_get_name(zhp), cbp, 1447 pl->pl_user_prop, strval, sourcetype, 1448 source, recvdval); 1449 } 1450 } 1451 1452 return (0); 1453 } 1454 1455 static int 1456 zfs_do_get(int argc, char **argv) 1457 { 1458 zprop_get_cbdata_t cb = { 0 }; 1459 int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS; 1460 char *value, *fields; 1461 int ret; 1462 int limit = 0; 1463 zprop_list_t fake_name = { 0 }; 1464 1465 /* 1466 * Set up default columns and sources. 1467 */ 1468 cb.cb_sources = ZPROP_SRC_ALL; 1469 cb.cb_columns[0] = GET_COL_NAME; 1470 cb.cb_columns[1] = GET_COL_PROPERTY; 1471 cb.cb_columns[2] = GET_COL_VALUE; 1472 cb.cb_columns[3] = GET_COL_SOURCE; 1473 cb.cb_type = ZFS_TYPE_DATASET; 1474 1475 /* check options */ 1476 while ((c = getopt(argc, argv, ":d:o:s:rHp")) != -1) { 1477 switch (c) { 1478 case 'p': 1479 cb.cb_literal = B_TRUE; 1480 break; 1481 case 'd': 1482 limit = parse_depth(optarg, &flags); 1483 break; 1484 case 'r': 1485 flags |= ZFS_ITER_RECURSE; 1486 break; 1487 case 'H': 1488 cb.cb_scripted = B_TRUE; 1489 break; 1490 case ':': 1491 (void) fprintf(stderr, gettext("missing argument for " 1492 "'%c' option\n"), optopt); 1493 usage(B_FALSE); 1494 break; 1495 case 'o': 1496 /* 1497 * Process the set of columns to display. We zero out 1498 * the structure to give us a blank slate. 1499 */ 1500 bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 1501 i = 0; 1502 while (*optarg != '\0') { 1503 static char *col_subopts[] = 1504 { "name", "property", "value", "received", 1505 "source", "all", NULL }; 1506 1507 if (i == ZFS_GET_NCOLS) { 1508 (void) fprintf(stderr, gettext("too " 1509 "many fields given to -o " 1510 "option\n")); 1511 usage(B_FALSE); 1512 } 1513 1514 switch (getsubopt(&optarg, col_subopts, 1515 &value)) { 1516 case 0: 1517 cb.cb_columns[i++] = GET_COL_NAME; 1518 break; 1519 case 1: 1520 cb.cb_columns[i++] = GET_COL_PROPERTY; 1521 break; 1522 case 2: 1523 cb.cb_columns[i++] = GET_COL_VALUE; 1524 break; 1525 case 3: 1526 cb.cb_columns[i++] = GET_COL_RECVD; 1527 flags |= ZFS_ITER_RECVD_PROPS; 1528 break; 1529 case 4: 1530 cb.cb_columns[i++] = GET_COL_SOURCE; 1531 break; 1532 case 5: 1533 if (i > 0) { 1534 (void) fprintf(stderr, 1535 gettext("\"all\" conflicts " 1536 "with specific fields " 1537 "given to -o option\n")); 1538 usage(B_FALSE); 1539 } 1540 cb.cb_columns[0] = GET_COL_NAME; 1541 cb.cb_columns[1] = GET_COL_PROPERTY; 1542 cb.cb_columns[2] = GET_COL_VALUE; 1543 cb.cb_columns[3] = GET_COL_RECVD; 1544 cb.cb_columns[4] = GET_COL_SOURCE; 1545 flags |= ZFS_ITER_RECVD_PROPS; 1546 i = ZFS_GET_NCOLS; 1547 break; 1548 default: 1549 (void) fprintf(stderr, 1550 gettext("invalid column name " 1551 "'%s'\n"), value); 1552 usage(B_FALSE); 1553 } 1554 } 1555 break; 1556 1557 case 's': 1558 cb.cb_sources = 0; 1559 while (*optarg != '\0') { 1560 static char *source_subopts[] = { 1561 "local", "default", "inherited", 1562 "received", "temporary", "none", 1563 NULL }; 1564 1565 switch (getsubopt(&optarg, source_subopts, 1566 &value)) { 1567 case 0: 1568 cb.cb_sources |= ZPROP_SRC_LOCAL; 1569 break; 1570 case 1: 1571 cb.cb_sources |= ZPROP_SRC_DEFAULT; 1572 break; 1573 case 2: 1574 cb.cb_sources |= ZPROP_SRC_INHERITED; 1575 break; 1576 case 3: 1577 cb.cb_sources |= ZPROP_SRC_RECEIVED; 1578 break; 1579 case 4: 1580 cb.cb_sources |= ZPROP_SRC_TEMPORARY; 1581 break; 1582 case 5: 1583 cb.cb_sources |= ZPROP_SRC_NONE; 1584 break; 1585 default: 1586 (void) fprintf(stderr, 1587 gettext("invalid source " 1588 "'%s'\n"), value); 1589 usage(B_FALSE); 1590 } 1591 } 1592 break; 1593 1594 case '?': 1595 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1596 optopt); 1597 usage(B_FALSE); 1598 } 1599 } 1600 1601 argc -= optind; 1602 argv += optind; 1603 1604 if (argc < 1) { 1605 (void) fprintf(stderr, gettext("missing property " 1606 "argument\n")); 1607 usage(B_FALSE); 1608 } 1609 1610 fields = argv[0]; 1611 1612 if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET) 1613 != 0) 1614 usage(B_FALSE); 1615 1616 argc--; 1617 argv++; 1618 1619 /* 1620 * As part of zfs_expand_proplist(), we keep track of the maximum column 1621 * width for each property. For the 'NAME' (and 'SOURCE') columns, we 1622 * need to know the maximum name length. However, the user likely did 1623 * not specify 'name' as one of the properties to fetch, so we need to 1624 * make sure we always include at least this property for 1625 * print_get_headers() to work properly. 1626 */ 1627 if (cb.cb_proplist != NULL) { 1628 fake_name.pl_prop = ZFS_PROP_NAME; 1629 fake_name.pl_width = strlen(gettext("NAME")); 1630 fake_name.pl_next = cb.cb_proplist; 1631 cb.cb_proplist = &fake_name; 1632 } 1633 1634 cb.cb_first = B_TRUE; 1635 1636 /* run for each object */ 1637 ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET, NULL, 1638 &cb.cb_proplist, limit, get_callback, &cb); 1639 1640 if (cb.cb_proplist == &fake_name) 1641 zprop_free_list(fake_name.pl_next); 1642 else 1643 zprop_free_list(cb.cb_proplist); 1644 1645 return (ret); 1646 } 1647 1648 /* 1649 * inherit [-rS] <property> <fs|vol> ... 1650 * 1651 * -r Recurse over all children 1652 * -S Revert to received value, if any 1653 * 1654 * For each dataset specified on the command line, inherit the given property 1655 * from its parent. Inheriting a property at the pool level will cause it to 1656 * use the default value. The '-r' flag will recurse over all children, and is 1657 * useful for setting a property on a hierarchy-wide basis, regardless of any 1658 * local modifications for each dataset. 1659 */ 1660 1661 typedef struct inherit_cbdata { 1662 const char *cb_propname; 1663 boolean_t cb_received; 1664 } inherit_cbdata_t; 1665 1666 static int 1667 inherit_recurse_cb(zfs_handle_t *zhp, void *data) 1668 { 1669 inherit_cbdata_t *cb = data; 1670 zfs_prop_t prop = zfs_name_to_prop(cb->cb_propname); 1671 1672 /* 1673 * If we're doing it recursively, then ignore properties that 1674 * are not valid for this type of dataset. 1675 */ 1676 if (prop != ZPROP_INVAL && 1677 !zfs_prop_valid_for_type(prop, zfs_get_type(zhp))) 1678 return (0); 1679 1680 return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0); 1681 } 1682 1683 static int 1684 inherit_cb(zfs_handle_t *zhp, void *data) 1685 { 1686 inherit_cbdata_t *cb = data; 1687 1688 return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0); 1689 } 1690 1691 static int 1692 zfs_do_inherit(int argc, char **argv) 1693 { 1694 int c; 1695 zfs_prop_t prop; 1696 inherit_cbdata_t cb = { 0 }; 1697 char *propname; 1698 int ret; 1699 int flags = 0; 1700 boolean_t received = B_FALSE; 1701 1702 /* check options */ 1703 while ((c = getopt(argc, argv, "rS")) != -1) { 1704 switch (c) { 1705 case 'r': 1706 flags |= ZFS_ITER_RECURSE; 1707 break; 1708 case 'S': 1709 received = B_TRUE; 1710 break; 1711 case '?': 1712 default: 1713 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1714 optopt); 1715 usage(B_FALSE); 1716 } 1717 } 1718 1719 argc -= optind; 1720 argv += optind; 1721 1722 /* check number of arguments */ 1723 if (argc < 1) { 1724 (void) fprintf(stderr, gettext("missing property argument\n")); 1725 usage(B_FALSE); 1726 } 1727 if (argc < 2) { 1728 (void) fprintf(stderr, gettext("missing dataset argument\n")); 1729 usage(B_FALSE); 1730 } 1731 1732 propname = argv[0]; 1733 argc--; 1734 argv++; 1735 1736 if ((prop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 1737 if (zfs_prop_readonly(prop)) { 1738 (void) fprintf(stderr, gettext( 1739 "%s property is read-only\n"), 1740 propname); 1741 return (1); 1742 } 1743 if (!zfs_prop_inheritable(prop) && !received) { 1744 (void) fprintf(stderr, gettext("'%s' property cannot " 1745 "be inherited\n"), propname); 1746 if (prop == ZFS_PROP_QUOTA || 1747 prop == ZFS_PROP_RESERVATION || 1748 prop == ZFS_PROP_REFQUOTA || 1749 prop == ZFS_PROP_REFRESERVATION) 1750 (void) fprintf(stderr, gettext("use 'zfs set " 1751 "%s=none' to clear\n"), propname); 1752 return (1); 1753 } 1754 if (received && (prop == ZFS_PROP_VOLSIZE || 1755 prop == ZFS_PROP_VERSION)) { 1756 (void) fprintf(stderr, gettext("'%s' property cannot " 1757 "be reverted to a received value\n"), propname); 1758 return (1); 1759 } 1760 } else if (!zfs_prop_user(propname)) { 1761 (void) fprintf(stderr, gettext("invalid property '%s'\n"), 1762 propname); 1763 usage(B_FALSE); 1764 } 1765 1766 cb.cb_propname = propname; 1767 cb.cb_received = received; 1768 1769 if (flags & ZFS_ITER_RECURSE) { 1770 ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET, 1771 NULL, NULL, 0, inherit_recurse_cb, &cb); 1772 } else { 1773 ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET, 1774 NULL, NULL, 0, inherit_cb, &cb); 1775 } 1776 1777 return (ret); 1778 } 1779 1780 typedef struct upgrade_cbdata { 1781 uint64_t cb_numupgraded; 1782 uint64_t cb_numsamegraded; 1783 uint64_t cb_numfailed; 1784 uint64_t cb_version; 1785 boolean_t cb_newer; 1786 boolean_t cb_foundone; 1787 char cb_lastfs[ZFS_MAXNAMELEN]; 1788 } upgrade_cbdata_t; 1789 1790 static int 1791 same_pool(zfs_handle_t *zhp, const char *name) 1792 { 1793 int len1 = strcspn(name, "/@"); 1794 const char *zhname = zfs_get_name(zhp); 1795 int len2 = strcspn(zhname, "/@"); 1796 1797 if (len1 != len2) 1798 return (B_FALSE); 1799 return (strncmp(name, zhname, len1) == 0); 1800 } 1801 1802 static int 1803 upgrade_list_callback(zfs_handle_t *zhp, void *data) 1804 { 1805 upgrade_cbdata_t *cb = data; 1806 int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 1807 1808 /* list if it's old/new */ 1809 if ((!cb->cb_newer && version < ZPL_VERSION) || 1810 (cb->cb_newer && version > ZPL_VERSION)) { 1811 char *str; 1812 if (cb->cb_newer) { 1813 str = gettext("The following filesystems are " 1814 "formatted using a newer software version and\n" 1815 "cannot be accessed on the current system.\n\n"); 1816 } else { 1817 str = gettext("The following filesystems are " 1818 "out of date, and can be upgraded. After being\n" 1819 "upgraded, these filesystems (and any 'zfs send' " 1820 "streams generated from\n" 1821 "subsequent snapshots) will no longer be " 1822 "accessible by older software versions.\n\n"); 1823 } 1824 1825 if (!cb->cb_foundone) { 1826 (void) puts(str); 1827 (void) printf(gettext("VER FILESYSTEM\n")); 1828 (void) printf(gettext("--- ------------\n")); 1829 cb->cb_foundone = B_TRUE; 1830 } 1831 1832 (void) printf("%2u %s\n", version, zfs_get_name(zhp)); 1833 } 1834 1835 return (0); 1836 } 1837 1838 static int 1839 upgrade_set_callback(zfs_handle_t *zhp, void *data) 1840 { 1841 upgrade_cbdata_t *cb = data; 1842 int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 1843 int needed_spa_version; 1844 int spa_version; 1845 1846 if (zfs_spa_version(zhp, &spa_version) < 0) 1847 return (-1); 1848 1849 needed_spa_version = zfs_spa_version_map(cb->cb_version); 1850 1851 if (needed_spa_version < 0) 1852 return (-1); 1853 1854 if (spa_version < needed_spa_version) { 1855 /* can't upgrade */ 1856 (void) printf(gettext("%s: can not be " 1857 "upgraded; the pool version needs to first " 1858 "be upgraded\nto version %d\n\n"), 1859 zfs_get_name(zhp), needed_spa_version); 1860 cb->cb_numfailed++; 1861 return (0); 1862 } 1863 1864 /* upgrade */ 1865 if (version < cb->cb_version) { 1866 char verstr[16]; 1867 (void) snprintf(verstr, sizeof (verstr), 1868 "%llu", cb->cb_version); 1869 if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) { 1870 /* 1871 * If they did "zfs upgrade -a", then we could 1872 * be doing ioctls to different pools. We need 1873 * to log this history once to each pool. 1874 */ 1875 verify(zpool_stage_history(g_zfs, history_str) == 0); 1876 } 1877 if (zfs_prop_set(zhp, "version", verstr) == 0) 1878 cb->cb_numupgraded++; 1879 else 1880 cb->cb_numfailed++; 1881 (void) strcpy(cb->cb_lastfs, zfs_get_name(zhp)); 1882 } else if (version > cb->cb_version) { 1883 /* can't downgrade */ 1884 (void) printf(gettext("%s: can not be downgraded; " 1885 "it is already at version %u\n"), 1886 zfs_get_name(zhp), version); 1887 cb->cb_numfailed++; 1888 } else { 1889 cb->cb_numsamegraded++; 1890 } 1891 return (0); 1892 } 1893 1894 /* 1895 * zfs upgrade 1896 * zfs upgrade -v 1897 * zfs upgrade [-r] [-V <version>] <-a | filesystem> 1898 */ 1899 static int 1900 zfs_do_upgrade(int argc, char **argv) 1901 { 1902 boolean_t all = B_FALSE; 1903 boolean_t showversions = B_FALSE; 1904 int ret; 1905 upgrade_cbdata_t cb = { 0 }; 1906 char c; 1907 int flags = ZFS_ITER_ARGS_CAN_BE_PATHS; 1908 1909 /* check options */ 1910 while ((c = getopt(argc, argv, "rvV:a")) != -1) { 1911 switch (c) { 1912 case 'r': 1913 flags |= ZFS_ITER_RECURSE; 1914 break; 1915 case 'v': 1916 showversions = B_TRUE; 1917 break; 1918 case 'V': 1919 if (zfs_prop_string_to_index(ZFS_PROP_VERSION, 1920 optarg, &cb.cb_version) != 0) { 1921 (void) fprintf(stderr, 1922 gettext("invalid version %s\n"), optarg); 1923 usage(B_FALSE); 1924 } 1925 break; 1926 case 'a': 1927 all = B_TRUE; 1928 break; 1929 case '?': 1930 default: 1931 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1932 optopt); 1933 usage(B_FALSE); 1934 } 1935 } 1936 1937 argc -= optind; 1938 argv += optind; 1939 1940 if ((!all && !argc) && ((flags & ZFS_ITER_RECURSE) | cb.cb_version)) 1941 usage(B_FALSE); 1942 if (showversions && (flags & ZFS_ITER_RECURSE || all || 1943 cb.cb_version || argc)) 1944 usage(B_FALSE); 1945 if ((all || argc) && (showversions)) 1946 usage(B_FALSE); 1947 if (all && argc) 1948 usage(B_FALSE); 1949 1950 if (showversions) { 1951 /* Show info on available versions. */ 1952 (void) printf(gettext("The following filesystem versions are " 1953 "supported:\n\n")); 1954 (void) printf(gettext("VER DESCRIPTION\n")); 1955 (void) printf("--- -----------------------------------------" 1956 "---------------\n"); 1957 (void) printf(gettext(" 1 Initial ZFS filesystem version\n")); 1958 (void) printf(gettext(" 2 Enhanced directory entries\n")); 1959 (void) printf(gettext(" 3 Case insensitive and filesystem " 1960 "user identifier (FUID)\n")); 1961 (void) printf(gettext(" 4 userquota, groupquota " 1962 "properties\n")); 1963 (void) printf(gettext(" 5 System attributes\n")); 1964 (void) printf(gettext("\nFor more information on a particular " 1965 "version, including supported releases,\n")); 1966 (void) printf("see the ZFS Administration Guide.\n\n"); 1967 ret = 0; 1968 } else if (argc || all) { 1969 /* Upgrade filesystems */ 1970 if (cb.cb_version == 0) 1971 cb.cb_version = ZPL_VERSION; 1972 ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_FILESYSTEM, 1973 NULL, NULL, 0, upgrade_set_callback, &cb); 1974 (void) printf(gettext("%llu filesystems upgraded\n"), 1975 cb.cb_numupgraded); 1976 if (cb.cb_numsamegraded) { 1977 (void) printf(gettext("%llu filesystems already at " 1978 "this version\n"), 1979 cb.cb_numsamegraded); 1980 } 1981 if (cb.cb_numfailed != 0) 1982 ret = 1; 1983 } else { 1984 /* List old-version filesytems */ 1985 boolean_t found; 1986 (void) printf(gettext("This system is currently running " 1987 "ZFS filesystem version %llu.\n\n"), ZPL_VERSION); 1988 1989 flags |= ZFS_ITER_RECURSE; 1990 ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM, 1991 NULL, NULL, 0, upgrade_list_callback, &cb); 1992 1993 found = cb.cb_foundone; 1994 cb.cb_foundone = B_FALSE; 1995 cb.cb_newer = B_TRUE; 1996 1997 ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM, 1998 NULL, NULL, 0, upgrade_list_callback, &cb); 1999 2000 if (!cb.cb_foundone && !found) { 2001 (void) printf(gettext("All filesystems are " 2002 "formatted with the current version.\n")); 2003 } 2004 } 2005 2006 return (ret); 2007 } 2008 2009 #define USTYPE_USR_BIT (0) 2010 #define USTYPE_GRP_BIT (1) 2011 #define USTYPE_PSX_BIT (2) 2012 #define USTYPE_SMB_BIT (3) 2013 2014 #define USTYPE_USR (1 << USTYPE_USR_BIT) 2015 #define USTYPE_GRP (1 << USTYPE_GRP_BIT) 2016 2017 #define USTYPE_PSX (1 << USTYPE_PSX_BIT) 2018 #define USTYPE_SMB (1 << USTYPE_SMB_BIT) 2019 2020 #define USTYPE_PSX_USR (USTYPE_PSX | USTYPE_USR) 2021 #define USTYPE_SMB_USR (USTYPE_SMB | USTYPE_USR) 2022 #define USTYPE_PSX_GRP (USTYPE_PSX | USTYPE_GRP) 2023 #define USTYPE_SMB_GRP (USTYPE_SMB | USTYPE_GRP) 2024 #define USTYPE_ALL (USTYPE_PSX_USR | USTYPE_SMB_USR \ 2025 | USTYPE_PSX_GRP | USTYPE_SMB_GRP) 2026 2027 2028 #define USPROP_USED_BIT (0) 2029 #define USPROP_QUOTA_BIT (1) 2030 2031 #define USPROP_USED (1 << USPROP_USED_BIT) 2032 #define USPROP_QUOTA (1 << USPROP_QUOTA_BIT) 2033 2034 typedef struct us_node { 2035 nvlist_t *usn_nvl; 2036 uu_avl_node_t usn_avlnode; 2037 uu_list_node_t usn_listnode; 2038 } us_node_t; 2039 2040 typedef struct us_cbdata { 2041 nvlist_t **cb_nvlp; 2042 uu_avl_pool_t *cb_avl_pool; 2043 uu_avl_t *cb_avl; 2044 boolean_t cb_numname; 2045 boolean_t cb_nicenum; 2046 boolean_t cb_sid2posix; 2047 zfs_userquota_prop_t cb_prop; 2048 zfs_sort_column_t *cb_sortcol; 2049 size_t cb_max_typelen; 2050 size_t cb_max_namelen; 2051 size_t cb_max_usedlen; 2052 size_t cb_max_quotalen; 2053 } us_cbdata_t; 2054 2055 typedef struct { 2056 zfs_sort_column_t *si_sortcol; 2057 boolean_t si_num_name; 2058 boolean_t si_parsable; 2059 } us_sort_info_t; 2060 2061 static int 2062 us_compare(const void *larg, const void *rarg, void *unused) 2063 { 2064 const us_node_t *l = larg; 2065 const us_node_t *r = rarg; 2066 int rc = 0; 2067 us_sort_info_t *si = (us_sort_info_t *)unused; 2068 zfs_sort_column_t *sortcol = si->si_sortcol; 2069 boolean_t num_name = si->si_num_name; 2070 nvlist_t *lnvl = l->usn_nvl; 2071 nvlist_t *rnvl = r->usn_nvl; 2072 2073 for (; sortcol != NULL; sortcol = sortcol->sc_next) { 2074 char *lvstr = ""; 2075 char *rvstr = ""; 2076 uint32_t lv32 = 0; 2077 uint32_t rv32 = 0; 2078 uint64_t lv64 = 0; 2079 uint64_t rv64 = 0; 2080 zfs_prop_t prop = sortcol->sc_prop; 2081 const char *propname = NULL; 2082 boolean_t reverse = sortcol->sc_reverse; 2083 2084 switch (prop) { 2085 case ZFS_PROP_TYPE: 2086 propname = "type"; 2087 (void) nvlist_lookup_uint32(lnvl, propname, &lv32); 2088 (void) nvlist_lookup_uint32(rnvl, propname, &rv32); 2089 if (rv32 != lv32) 2090 rc = (rv32 > lv32) ? 1 : -1; 2091 break; 2092 case ZFS_PROP_NAME: 2093 propname = "name"; 2094 if (num_name) { 2095 (void) nvlist_lookup_uint32(lnvl, propname, 2096 &lv32); 2097 (void) nvlist_lookup_uint32(rnvl, propname, 2098 &rv32); 2099 if (rv32 != lv32) 2100 rc = (rv32 > lv32) ? 1 : -1; 2101 } else { 2102 (void) nvlist_lookup_string(lnvl, propname, 2103 &lvstr); 2104 (void) nvlist_lookup_string(rnvl, propname, 2105 &rvstr); 2106 rc = strcmp(lvstr, rvstr); 2107 } 2108 break; 2109 2110 case ZFS_PROP_USED: 2111 case ZFS_PROP_QUOTA: 2112 if (ZFS_PROP_USED == prop) 2113 propname = "used"; 2114 else 2115 propname = "quota"; 2116 (void) nvlist_lookup_uint64(lnvl, propname, &lv64); 2117 (void) nvlist_lookup_uint64(rnvl, propname, &rv64); 2118 if (rv64 != lv64) 2119 rc = (rv64 > lv64) ? 1 : -1; 2120 } 2121 2122 if (rc) 2123 if (rc < 0) 2124 return (reverse ? 1 : -1); 2125 else 2126 return (reverse ? -1 : 1); 2127 } 2128 2129 return (rc); 2130 } 2131 2132 static inline const char * 2133 us_type2str(unsigned field_type) 2134 { 2135 switch (field_type) { 2136 case USTYPE_PSX_USR: 2137 return ("POSIX User"); 2138 case USTYPE_PSX_GRP: 2139 return ("POSIX Group"); 2140 case USTYPE_SMB_USR: 2141 return ("SMB User"); 2142 case USTYPE_SMB_GRP: 2143 return ("SMB Group"); 2144 default: 2145 return ("Undefined"); 2146 } 2147 } 2148 2149 /* 2150 * zfs userspace 2151 */ 2152 static int 2153 userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space) 2154 { 2155 us_cbdata_t *cb = (us_cbdata_t *)arg; 2156 zfs_userquota_prop_t prop = cb->cb_prop; 2157 char *name = NULL; 2158 char *propname; 2159 char namebuf[32]; 2160 char sizebuf[32]; 2161 us_node_t *node; 2162 uu_avl_pool_t *avl_pool = cb->cb_avl_pool; 2163 uu_avl_t *avl = cb->cb_avl; 2164 uu_avl_index_t idx; 2165 nvlist_t *props; 2166 us_node_t *n; 2167 zfs_sort_column_t *sortcol = cb->cb_sortcol; 2168 unsigned type; 2169 const char *typestr; 2170 size_t namelen; 2171 size_t typelen; 2172 size_t sizelen; 2173 us_sort_info_t sortinfo = { sortcol, cb->cb_numname }; 2174 2175 if (domain == NULL || domain[0] == '\0') { 2176 /* POSIX */ 2177 if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) { 2178 type = USTYPE_PSX_GRP; 2179 struct group *g = getgrgid(rid); 2180 if (g) 2181 name = g->gr_name; 2182 } else { 2183 type = USTYPE_PSX_USR; 2184 struct passwd *p = getpwuid(rid); 2185 if (p) 2186 name = p->pw_name; 2187 } 2188 } else { 2189 char sid[ZFS_MAXNAMELEN+32]; 2190 uid_t id; 2191 uint64_t classes; 2192 int err; 2193 directory_error_t e; 2194 2195 (void) snprintf(sid, sizeof (sid), "%s-%u", domain, rid); 2196 /* SMB */ 2197 if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) { 2198 type = USTYPE_SMB_GRP; 2199 err = sid_to_id(sid, B_FALSE, &id); 2200 } else { 2201 type = USTYPE_SMB_USR; 2202 err = sid_to_id(sid, B_TRUE, &id); 2203 } 2204 2205 if (err == 0) { 2206 rid = id; 2207 2208 e = directory_name_from_sid(NULL, sid, &name, &classes); 2209 if (e != NULL) { 2210 directory_error_free(e); 2211 return (NULL); 2212 } 2213 2214 if (name == NULL) 2215 name = sid; 2216 } 2217 } 2218 2219 /* 2220 * if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) 2221 * ug = "group"; 2222 * else 2223 * ug = "user"; 2224 */ 2225 2226 if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED) 2227 propname = "used"; 2228 else 2229 propname = "quota"; 2230 2231 (void) snprintf(namebuf, sizeof (namebuf), "%u", rid); 2232 if (name == NULL) 2233 name = namebuf; 2234 2235 if (cb->cb_nicenum) 2236 zfs_nicenum(space, sizebuf, sizeof (sizebuf)); 2237 else 2238 (void) sprintf(sizebuf, "%llu", space); 2239 2240 node = safe_malloc(sizeof (us_node_t)); 2241 uu_avl_node_init(node, &node->usn_avlnode, avl_pool); 2242 2243 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 2244 free(node); 2245 return (-1); 2246 } 2247 2248 if (nvlist_add_uint32(props, "type", type) != 0) 2249 nomem(); 2250 2251 if (cb->cb_numname) { 2252 if (nvlist_add_uint32(props, "name", rid) != 0) 2253 nomem(); 2254 namelen = strlen(namebuf); 2255 } else { 2256 if (nvlist_add_string(props, "name", name) != 0) 2257 nomem(); 2258 namelen = strlen(name); 2259 } 2260 2261 typestr = us_type2str(type); 2262 typelen = strlen(gettext(typestr)); 2263 if (typelen > cb->cb_max_typelen) 2264 cb->cb_max_typelen = typelen; 2265 2266 if (namelen > cb->cb_max_namelen) 2267 cb->cb_max_namelen = namelen; 2268 2269 sizelen = strlen(sizebuf); 2270 if (0 == strcmp(propname, "used")) { 2271 if (sizelen > cb->cb_max_usedlen) 2272 cb->cb_max_usedlen = sizelen; 2273 } else { 2274 if (sizelen > cb->cb_max_quotalen) 2275 cb->cb_max_quotalen = sizelen; 2276 } 2277 2278 node->usn_nvl = props; 2279 2280 n = uu_avl_find(avl, node, &sortinfo, &idx); 2281 if (n == NULL) 2282 uu_avl_insert(avl, node, idx); 2283 else { 2284 nvlist_free(props); 2285 free(node); 2286 node = n; 2287 props = node->usn_nvl; 2288 } 2289 2290 if (nvlist_add_uint64(props, propname, space) != 0) 2291 nomem(); 2292 2293 return (0); 2294 } 2295 2296 static inline boolean_t 2297 usprop_check(zfs_userquota_prop_t p, unsigned types, unsigned props) 2298 { 2299 unsigned type; 2300 unsigned prop; 2301 2302 switch (p) { 2303 case ZFS_PROP_USERUSED: 2304 type = USTYPE_USR; 2305 prop = USPROP_USED; 2306 break; 2307 case ZFS_PROP_USERQUOTA: 2308 type = USTYPE_USR; 2309 prop = USPROP_QUOTA; 2310 break; 2311 case ZFS_PROP_GROUPUSED: 2312 type = USTYPE_GRP; 2313 prop = USPROP_USED; 2314 break; 2315 case ZFS_PROP_GROUPQUOTA: 2316 type = USTYPE_GRP; 2317 prop = USPROP_QUOTA; 2318 break; 2319 default: /* ALL */ 2320 return (B_TRUE); 2321 }; 2322 2323 return (type & types && prop & props); 2324 } 2325 2326 #define USFIELD_TYPE (1 << 0) 2327 #define USFIELD_NAME (1 << 1) 2328 #define USFIELD_USED (1 << 2) 2329 #define USFIELD_QUOTA (1 << 3) 2330 #define USFIELD_ALL (USFIELD_TYPE | USFIELD_NAME | USFIELD_USED | USFIELD_QUOTA) 2331 2332 static int 2333 parsefields(unsigned *fieldsp, char **names, unsigned *bits, size_t len) 2334 { 2335 char *field = optarg; 2336 char *delim; 2337 2338 do { 2339 int i; 2340 boolean_t found = B_FALSE; 2341 delim = strchr(field, ','); 2342 if (delim != NULL) 2343 *delim = '\0'; 2344 2345 for (i = 0; i < len; i++) 2346 if (0 == strcmp(field, names[i])) { 2347 found = B_TRUE; 2348 *fieldsp |= bits[i]; 2349 break; 2350 } 2351 2352 if (!found) { 2353 (void) fprintf(stderr, gettext("invalid type '%s'" 2354 "for -t option\n"), field); 2355 return (-1); 2356 } 2357 2358 field = delim + 1; 2359 } while (delim); 2360 2361 return (0); 2362 } 2363 2364 2365 static char *type_names[] = { "posixuser", "smbuser", "posixgroup", "smbgroup", 2366 "all" }; 2367 static unsigned type_bits[] = { 2368 USTYPE_PSX_USR, 2369 USTYPE_SMB_USR, 2370 USTYPE_PSX_GRP, 2371 USTYPE_SMB_GRP, 2372 USTYPE_ALL 2373 }; 2374 2375 static char *us_field_names[] = { "type", "name", "used", "quota" }; 2376 static unsigned us_field_bits[] = { 2377 USFIELD_TYPE, 2378 USFIELD_NAME, 2379 USFIELD_USED, 2380 USFIELD_QUOTA 2381 }; 2382 2383 static void 2384 print_us_node(boolean_t scripted, boolean_t parseable, unsigned fields, 2385 size_t type_width, size_t name_width, size_t used_width, 2386 size_t quota_width, us_node_t *node) 2387 { 2388 nvlist_t *nvl = node->usn_nvl; 2389 nvpair_t *nvp = NULL; 2390 char valstr[ZFS_MAXNAMELEN]; 2391 boolean_t first = B_TRUE; 2392 boolean_t quota_found = B_FALSE; 2393 2394 if (fields & USFIELD_QUOTA && !nvlist_exists(nvl, "quota")) 2395 if (nvlist_add_string(nvl, "quota", "none") != 0) 2396 nomem(); 2397 2398 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 2399 char *pname = nvpair_name(nvp); 2400 data_type_t type = nvpair_type(nvp); 2401 uint32_t val32 = 0; 2402 uint64_t val64 = 0; 2403 char *strval = NULL; 2404 unsigned field = 0; 2405 unsigned width = 0; 2406 int i; 2407 for (i = 0; i < 4; i++) { 2408 if (0 == strcmp(pname, us_field_names[i])) { 2409 field = us_field_bits[i]; 2410 break; 2411 } 2412 } 2413 2414 if (!(field & fields)) 2415 continue; 2416 2417 switch (type) { 2418 case DATA_TYPE_UINT32: 2419 (void) nvpair_value_uint32(nvp, &val32); 2420 break; 2421 case DATA_TYPE_UINT64: 2422 (void) nvpair_value_uint64(nvp, &val64); 2423 break; 2424 case DATA_TYPE_STRING: 2425 (void) nvpair_value_string(nvp, &strval); 2426 break; 2427 default: 2428 (void) fprintf(stderr, "Invalid data type\n"); 2429 } 2430 2431 if (!first) 2432 if (scripted) 2433 (void) printf("\t"); 2434 else 2435 (void) printf(" "); 2436 2437 switch (field) { 2438 case USFIELD_TYPE: 2439 strval = (char *)us_type2str(val32); 2440 width = type_width; 2441 break; 2442 case USFIELD_NAME: 2443 if (type == DATA_TYPE_UINT64) { 2444 (void) sprintf(valstr, "%llu", val64); 2445 strval = valstr; 2446 } 2447 width = name_width; 2448 break; 2449 case USFIELD_USED: 2450 case USFIELD_QUOTA: 2451 if (type == DATA_TYPE_UINT64) { 2452 (void) nvpair_value_uint64(nvp, &val64); 2453 if (parseable) 2454 (void) sprintf(valstr, "%llu", val64); 2455 else 2456 zfs_nicenum(val64, valstr, 2457 sizeof (valstr)); 2458 strval = valstr; 2459 } 2460 2461 if (field == USFIELD_USED) 2462 width = used_width; 2463 else { 2464 quota_found = B_FALSE; 2465 width = quota_width; 2466 } 2467 2468 break; 2469 } 2470 2471 if (field == USFIELD_QUOTA && !quota_found) 2472 (void) printf("%*s", width, strval); 2473 else { 2474 if (type == DATA_TYPE_STRING) 2475 (void) printf("%-*s", width, strval); 2476 else 2477 (void) printf("%*s", width, strval); 2478 } 2479 2480 first = B_FALSE; 2481 2482 } 2483 2484 (void) printf("\n"); 2485 } 2486 2487 static void 2488 print_us(boolean_t scripted, boolean_t parsable, unsigned fields, 2489 unsigned type_width, unsigned name_width, unsigned used_width, 2490 unsigned quota_width, boolean_t rmnode, uu_avl_t *avl) 2491 { 2492 static char *us_field_hdr[] = { "TYPE", "NAME", "USED", "QUOTA" }; 2493 us_node_t *node; 2494 const char *col; 2495 int i; 2496 size_t width[4] = { type_width, name_width, used_width, quota_width }; 2497 2498 if (!scripted) { 2499 boolean_t first = B_TRUE; 2500 for (i = 0; i < 4; i++) { 2501 unsigned field = us_field_bits[i]; 2502 if (!(field & fields)) 2503 continue; 2504 2505 col = gettext(us_field_hdr[i]); 2506 if (field == USFIELD_TYPE || field == USFIELD_NAME) 2507 (void) printf(first?"%-*s":" %-*s", width[i], 2508 col); 2509 else 2510 (void) printf(first?"%*s":" %*s", width[i], 2511 col); 2512 first = B_FALSE; 2513 } 2514 (void) printf("\n"); 2515 } 2516 2517 for (node = uu_avl_first(avl); node != NULL; 2518 node = uu_avl_next(avl, node)) { 2519 print_us_node(scripted, parsable, fields, type_width, 2520 name_width, used_width, used_width, node); 2521 if (rmnode) 2522 nvlist_free(node->usn_nvl); 2523 } 2524 } 2525 2526 static int 2527 zfs_do_userspace(int argc, char **argv) 2528 { 2529 zfs_handle_t *zhp; 2530 zfs_userquota_prop_t p; 2531 uu_avl_pool_t *avl_pool; 2532 uu_avl_t *avl_tree; 2533 uu_avl_walk_t *walk; 2534 2535 char *cmd; 2536 boolean_t scripted = B_FALSE; 2537 boolean_t prtnum = B_FALSE; 2538 boolean_t parseable = B_FALSE; 2539 boolean_t sid2posix = B_FALSE; 2540 int error; 2541 int c; 2542 zfs_sort_column_t *default_sortcol = NULL; 2543 zfs_sort_column_t *sortcol = NULL; 2544 unsigned types = USTYPE_PSX_USR | USTYPE_SMB_USR; 2545 unsigned fields = 0; 2546 unsigned props = USPROP_USED | USPROP_QUOTA; 2547 us_cbdata_t cb; 2548 us_node_t *node; 2549 boolean_t resort_avl = B_FALSE; 2550 2551 if (argc < 2) 2552 usage(B_FALSE); 2553 2554 cmd = argv[0]; 2555 if (0 == strcmp(cmd, "groupspace")) 2556 /* toggle default group types */ 2557 types = USTYPE_PSX_GRP | USTYPE_SMB_GRP; 2558 2559 /* check options */ 2560 while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) { 2561 switch (c) { 2562 case 'n': 2563 prtnum = B_TRUE; 2564 break; 2565 case 'H': 2566 scripted = B_TRUE; 2567 break; 2568 case 'p': 2569 parseable = B_TRUE; 2570 break; 2571 case 'o': 2572 if (parsefields(&fields, us_field_names, us_field_bits, 2573 4) != 0) 2574 return (1); 2575 break; 2576 case 's': 2577 if (zfs_add_sort_column(&sortcol, optarg, 2578 B_FALSE) != 0) { 2579 (void) fprintf(stderr, 2580 gettext("invalid property '%s'\n"), optarg); 2581 usage(B_FALSE); 2582 } 2583 break; 2584 case 'S': 2585 if (zfs_add_sort_column(&sortcol, optarg, 2586 B_TRUE) != 0) { 2587 (void) fprintf(stderr, 2588 gettext("invalid property '%s'\n"), optarg); 2589 usage(B_FALSE); 2590 } 2591 break; 2592 case 't': 2593 if (parsefields(&types, type_names, type_bits, 5)) 2594 return (1); 2595 break; 2596 case 'i': 2597 sid2posix = B_TRUE; 2598 break; 2599 case ':': 2600 (void) fprintf(stderr, gettext("missing argument for " 2601 "'%c' option\n"), optopt); 2602 usage(B_FALSE); 2603 break; 2604 case '?': 2605 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2606 optopt); 2607 usage(B_FALSE); 2608 } 2609 } 2610 2611 argc -= optind; 2612 argv += optind; 2613 2614 /* ok, now we have sorted by default colums (type,name) avl tree */ 2615 if (sortcol) { 2616 zfs_sort_column_t *sc; 2617 for (sc = sortcol; sc; sc = sc->sc_next) { 2618 if (sc->sc_prop == ZFS_PROP_QUOTA) { 2619 resort_avl = B_TRUE; 2620 break; 2621 } 2622 } 2623 } 2624 2625 if (!fields) 2626 fields = USFIELD_ALL; 2627 2628 if ((zhp = zfs_open(g_zfs, argv[argc-1], ZFS_TYPE_DATASET)) == NULL) 2629 return (1); 2630 2631 if ((avl_pool = uu_avl_pool_create("us_avl_pool", sizeof (us_node_t), 2632 offsetof(us_node_t, usn_avlnode), 2633 us_compare, UU_DEFAULT)) == NULL) 2634 nomem(); 2635 if ((avl_tree = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) 2636 nomem(); 2637 2638 if (sortcol && !resort_avl) 2639 cb.cb_sortcol = sortcol; 2640 else { 2641 (void) zfs_add_sort_column(&default_sortcol, "type", B_FALSE); 2642 (void) zfs_add_sort_column(&default_sortcol, "name", B_FALSE); 2643 cb.cb_sortcol = default_sortcol; 2644 } 2645 cb.cb_numname = prtnum; 2646 cb.cb_nicenum = !parseable; 2647 cb.cb_avl_pool = avl_pool; 2648 cb.cb_avl = avl_tree; 2649 cb.cb_sid2posix = sid2posix; 2650 cb.cb_max_typelen = strlen(gettext("TYPE")); 2651 cb.cb_max_namelen = strlen(gettext("NAME")); 2652 cb.cb_max_usedlen = strlen(gettext("USED")); 2653 cb.cb_max_quotalen = strlen(gettext("QUOTA")); 2654 2655 for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) { 2656 if (!usprop_check(p, types, props)) 2657 continue; 2658 2659 cb.cb_prop = p; 2660 error = zfs_userspace(zhp, p, userspace_cb, &cb); 2661 if (error) 2662 break; 2663 } 2664 2665 2666 if (resort_avl) { 2667 us_node_t *node; 2668 us_node_t *rmnode; 2669 uu_list_pool_t *listpool; 2670 uu_list_t *list; 2671 uu_avl_index_t idx = 0; 2672 uu_list_index_t idx2 = 0; 2673 listpool = uu_list_pool_create("tmplist", sizeof (us_node_t), 2674 offsetof(us_node_t, usn_listnode), NULL, 2675 UU_DEFAULT); 2676 list = uu_list_create(listpool, NULL, UU_DEFAULT); 2677 2678 node = uu_avl_first(avl_tree); 2679 uu_list_node_init(node, &node->usn_listnode, listpool); 2680 while (node != NULL) { 2681 rmnode = node; 2682 node = uu_avl_next(avl_tree, node); 2683 uu_avl_remove(avl_tree, rmnode); 2684 if (uu_list_find(list, rmnode, NULL, &idx2) == NULL) { 2685 uu_list_insert(list, rmnode, idx2); 2686 } 2687 } 2688 2689 for (node = uu_list_first(list); node != NULL; 2690 node = uu_list_next(list, node)) { 2691 us_sort_info_t sortinfo = { sortcol, cb.cb_numname }; 2692 if (uu_avl_find(avl_tree, node, &sortinfo, &idx) == 2693 NULL) 2694 uu_avl_insert(avl_tree, node, idx); 2695 } 2696 2697 uu_list_destroy(list); 2698 } 2699 2700 /* print & free node`s nvlist memory */ 2701 print_us(scripted, parseable, fields, cb.cb_max_typelen, 2702 cb.cb_max_namelen, cb.cb_max_usedlen, 2703 cb.cb_max_quotalen, B_TRUE, cb.cb_avl); 2704 2705 if (sortcol) 2706 zfs_free_sort_columns(sortcol); 2707 zfs_free_sort_columns(default_sortcol); 2708 2709 /* 2710 * Finally, clean up the AVL tree. 2711 */ 2712 if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL) 2713 nomem(); 2714 2715 while ((node = uu_avl_walk_next(walk)) != NULL) { 2716 uu_avl_remove(cb.cb_avl, node); 2717 free(node); 2718 } 2719 2720 uu_avl_walk_end(walk); 2721 uu_avl_destroy(avl_tree); 2722 uu_avl_pool_destroy(avl_pool); 2723 2724 return (error); 2725 } 2726 2727 /* 2728 * list [-r][-d max] [-H] [-o property[,property]...] [-t type[,type]...] 2729 * [-s property [-s property]...] [-S property [-S property]...] 2730 * <dataset> ... 2731 * 2732 * -r Recurse over all children 2733 * -d Limit recursion by depth. 2734 * -H Scripted mode; elide headers and separate columns by tabs 2735 * -o Control which fields to display. 2736 * -t Control which object types to display. 2737 * -s Specify sort columns, descending order. 2738 * -S Specify sort columns, ascending order. 2739 * 2740 * When given no arguments, lists all filesystems in the system. 2741 * Otherwise, list the specified datasets, optionally recursing down them if 2742 * '-r' is specified. 2743 */ 2744 typedef struct list_cbdata { 2745 boolean_t cb_first; 2746 boolean_t cb_scripted; 2747 zprop_list_t *cb_proplist; 2748 } list_cbdata_t; 2749 2750 /* 2751 * Given a list of columns to display, output appropriate headers for each one. 2752 */ 2753 static void 2754 print_header(zprop_list_t *pl) 2755 { 2756 char headerbuf[ZFS_MAXPROPLEN]; 2757 const char *header; 2758 int i; 2759 boolean_t first = B_TRUE; 2760 boolean_t right_justify; 2761 2762 for (; pl != NULL; pl = pl->pl_next) { 2763 if (!first) { 2764 (void) printf(" "); 2765 } else { 2766 first = B_FALSE; 2767 } 2768 2769 right_justify = B_FALSE; 2770 if (pl->pl_prop != ZPROP_INVAL) { 2771 header = zfs_prop_column_name(pl->pl_prop); 2772 right_justify = zfs_prop_align_right(pl->pl_prop); 2773 } else { 2774 for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2775 headerbuf[i] = toupper(pl->pl_user_prop[i]); 2776 headerbuf[i] = '\0'; 2777 header = headerbuf; 2778 } 2779 2780 if (pl->pl_next == NULL && !right_justify) 2781 (void) printf("%s", header); 2782 else if (right_justify) 2783 (void) printf("%*s", pl->pl_width, header); 2784 else 2785 (void) printf("%-*s", pl->pl_width, header); 2786 } 2787 2788 (void) printf("\n"); 2789 } 2790 2791 /* 2792 * Given a dataset and a list of fields, print out all the properties according 2793 * to the described layout. 2794 */ 2795 static void 2796 print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted) 2797 { 2798 boolean_t first = B_TRUE; 2799 char property[ZFS_MAXPROPLEN]; 2800 nvlist_t *userprops = zfs_get_user_props(zhp); 2801 nvlist_t *propval; 2802 char *propstr; 2803 boolean_t right_justify; 2804 int width; 2805 2806 for (; pl != NULL; pl = pl->pl_next) { 2807 if (!first) { 2808 if (scripted) 2809 (void) printf("\t"); 2810 else 2811 (void) printf(" "); 2812 } else { 2813 first = B_FALSE; 2814 } 2815 2816 if (pl->pl_prop != ZPROP_INVAL) { 2817 if (zfs_prop_get(zhp, pl->pl_prop, property, 2818 sizeof (property), NULL, NULL, 0, B_FALSE) != 0) 2819 propstr = "-"; 2820 else 2821 propstr = property; 2822 2823 right_justify = zfs_prop_align_right(pl->pl_prop); 2824 } else if (zfs_prop_userquota(pl->pl_user_prop)) { 2825 if (zfs_prop_get_userquota(zhp, pl->pl_user_prop, 2826 property, sizeof (property), B_FALSE) != 0) 2827 propstr = "-"; 2828 else 2829 propstr = property; 2830 right_justify = B_TRUE; 2831 } else if (zfs_prop_written(pl->pl_user_prop)) { 2832 if (zfs_prop_get_written(zhp, pl->pl_user_prop, 2833 property, sizeof (property), B_FALSE) != 0) 2834 propstr = "-"; 2835 else 2836 propstr = property; 2837 right_justify = B_TRUE; 2838 } else { 2839 if (nvlist_lookup_nvlist(userprops, 2840 pl->pl_user_prop, &propval) != 0) 2841 propstr = "-"; 2842 else 2843 verify(nvlist_lookup_string(propval, 2844 ZPROP_VALUE, &propstr) == 0); 2845 right_justify = B_FALSE; 2846 } 2847 2848 width = pl->pl_width; 2849 2850 /* 2851 * If this is being called in scripted mode, or if this is the 2852 * last column and it is left-justified, don't include a width 2853 * format specifier. 2854 */ 2855 if (scripted || (pl->pl_next == NULL && !right_justify)) 2856 (void) printf("%s", propstr); 2857 else if (right_justify) 2858 (void) printf("%*s", width, propstr); 2859 else 2860 (void) printf("%-*s", width, propstr); 2861 } 2862 2863 (void) printf("\n"); 2864 } 2865 2866 /* 2867 * Generic callback function to list a dataset or snapshot. 2868 */ 2869 static int 2870 list_callback(zfs_handle_t *zhp, void *data) 2871 { 2872 list_cbdata_t *cbp = data; 2873 2874 if (cbp->cb_first) { 2875 if (!cbp->cb_scripted) 2876 print_header(cbp->cb_proplist); 2877 cbp->cb_first = B_FALSE; 2878 } 2879 2880 print_dataset(zhp, cbp->cb_proplist, cbp->cb_scripted); 2881 2882 return (0); 2883 } 2884 2885 static int 2886 zfs_do_list(int argc, char **argv) 2887 { 2888 int c; 2889 boolean_t scripted = B_FALSE; 2890 static char default_fields[] = 2891 "name,used,available,referenced,mountpoint"; 2892 int types = ZFS_TYPE_DATASET; 2893 boolean_t types_specified = B_FALSE; 2894 char *fields = NULL; 2895 list_cbdata_t cb = { 0 }; 2896 char *value; 2897 int limit = 0; 2898 int ret; 2899 zfs_sort_column_t *sortcol = NULL; 2900 int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS; 2901 2902 /* check options */ 2903 while ((c = getopt(argc, argv, ":d:o:rt:Hs:S:")) != -1) { 2904 switch (c) { 2905 case 'o': 2906 fields = optarg; 2907 break; 2908 case 'd': 2909 limit = parse_depth(optarg, &flags); 2910 break; 2911 case 'r': 2912 flags |= ZFS_ITER_RECURSE; 2913 break; 2914 case 'H': 2915 scripted = B_TRUE; 2916 break; 2917 case 's': 2918 if (zfs_add_sort_column(&sortcol, optarg, 2919 B_FALSE) != 0) { 2920 (void) fprintf(stderr, 2921 gettext("invalid property '%s'\n"), optarg); 2922 usage(B_FALSE); 2923 } 2924 break; 2925 case 'S': 2926 if (zfs_add_sort_column(&sortcol, optarg, 2927 B_TRUE) != 0) { 2928 (void) fprintf(stderr, 2929 gettext("invalid property '%s'\n"), optarg); 2930 usage(B_FALSE); 2931 } 2932 break; 2933 case 't': 2934 types = 0; 2935 types_specified = B_TRUE; 2936 flags &= ~ZFS_ITER_PROP_LISTSNAPS; 2937 while (*optarg != '\0') { 2938 static char *type_subopts[] = { "filesystem", 2939 "volume", "snapshot", "all", NULL }; 2940 2941 switch (getsubopt(&optarg, type_subopts, 2942 &value)) { 2943 case 0: 2944 types |= ZFS_TYPE_FILESYSTEM; 2945 break; 2946 case 1: 2947 types |= ZFS_TYPE_VOLUME; 2948 break; 2949 case 2: 2950 types |= ZFS_TYPE_SNAPSHOT; 2951 break; 2952 case 3: 2953 types = ZFS_TYPE_DATASET; 2954 break; 2955 2956 default: 2957 (void) fprintf(stderr, 2958 gettext("invalid type '%s'\n"), 2959 value); 2960 usage(B_FALSE); 2961 } 2962 } 2963 break; 2964 case ':': 2965 (void) fprintf(stderr, gettext("missing argument for " 2966 "'%c' option\n"), optopt); 2967 usage(B_FALSE); 2968 break; 2969 case '?': 2970 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2971 optopt); 2972 usage(B_FALSE); 2973 } 2974 } 2975 2976 argc -= optind; 2977 argv += optind; 2978 2979 if (fields == NULL) 2980 fields = default_fields; 2981 2982 /* 2983 * If "-o space" and no types were specified, don't display snapshots. 2984 */ 2985 if (strcmp(fields, "space") == 0 && types_specified == B_FALSE) 2986 types &= ~ZFS_TYPE_SNAPSHOT; 2987 2988 /* 2989 * If the user specifies '-o all', the zprop_get_list() doesn't 2990 * normally include the name of the dataset. For 'zfs list', we always 2991 * want this property to be first. 2992 */ 2993 if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET) 2994 != 0) 2995 usage(B_FALSE); 2996 2997 cb.cb_scripted = scripted; 2998 cb.cb_first = B_TRUE; 2999 3000 ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist, 3001 limit, list_callback, &cb); 3002 3003 zprop_free_list(cb.cb_proplist); 3004 zfs_free_sort_columns(sortcol); 3005 3006 if (ret == 0 && cb.cb_first && !cb.cb_scripted) 3007 (void) printf(gettext("no datasets available\n")); 3008 3009 return (ret); 3010 } 3011 3012 /* 3013 * zfs rename <fs | snap | vol> <fs | snap | vol> 3014 * zfs rename -p <fs | vol> <fs | vol> 3015 * zfs rename -r <snap> <snap> 3016 * 3017 * Renames the given dataset to another of the same type. 3018 * 3019 * The '-p' flag creates all the non-existing ancestors of the target first. 3020 */ 3021 /* ARGSUSED */ 3022 static int 3023 zfs_do_rename(int argc, char **argv) 3024 { 3025 zfs_handle_t *zhp; 3026 int c; 3027 int ret; 3028 boolean_t recurse = B_FALSE; 3029 boolean_t parents = B_FALSE; 3030 3031 /* check options */ 3032 while ((c = getopt(argc, argv, "pr")) != -1) { 3033 switch (c) { 3034 case 'p': 3035 parents = B_TRUE; 3036 break; 3037 case 'r': 3038 recurse = B_TRUE; 3039 break; 3040 case '?': 3041 default: 3042 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3043 optopt); 3044 usage(B_FALSE); 3045 } 3046 } 3047 3048 argc -= optind; 3049 argv += optind; 3050 3051 /* check number of arguments */ 3052 if (argc < 1) { 3053 (void) fprintf(stderr, gettext("missing source dataset " 3054 "argument\n")); 3055 usage(B_FALSE); 3056 } 3057 if (argc < 2) { 3058 (void) fprintf(stderr, gettext("missing target dataset " 3059 "argument\n")); 3060 usage(B_FALSE); 3061 } 3062 if (argc > 2) { 3063 (void) fprintf(stderr, gettext("too many arguments\n")); 3064 usage(B_FALSE); 3065 } 3066 3067 if (recurse && parents) { 3068 (void) fprintf(stderr, gettext("-p and -r options are mutually " 3069 "exclusive\n")); 3070 usage(B_FALSE); 3071 } 3072 3073 if (recurse && strchr(argv[0], '@') == 0) { 3074 (void) fprintf(stderr, gettext("source dataset for recursive " 3075 "rename must be a snapshot\n")); 3076 usage(B_FALSE); 3077 } 3078 3079 if ((zhp = zfs_open(g_zfs, argv[0], parents ? ZFS_TYPE_FILESYSTEM | 3080 ZFS_TYPE_VOLUME : ZFS_TYPE_DATASET)) == NULL) 3081 return (1); 3082 3083 /* If we were asked and the name looks good, try to create ancestors. */ 3084 if (parents && zfs_name_valid(argv[1], zfs_get_type(zhp)) && 3085 zfs_create_ancestors(g_zfs, argv[1]) != 0) { 3086 zfs_close(zhp); 3087 return (1); 3088 } 3089 3090 ret = (zfs_rename(zhp, argv[1], recurse) != 0); 3091 3092 zfs_close(zhp); 3093 return (ret); 3094 } 3095 3096 /* 3097 * zfs promote <fs> 3098 * 3099 * Promotes the given clone fs to be the parent 3100 */ 3101 /* ARGSUSED */ 3102 static int 3103 zfs_do_promote(int argc, char **argv) 3104 { 3105 zfs_handle_t *zhp; 3106 int ret; 3107 3108 /* check options */ 3109 if (argc > 1 && argv[1][0] == '-') { 3110 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3111 argv[1][1]); 3112 usage(B_FALSE); 3113 } 3114 3115 /* check number of arguments */ 3116 if (argc < 2) { 3117 (void) fprintf(stderr, gettext("missing clone filesystem" 3118 " argument\n")); 3119 usage(B_FALSE); 3120 } 3121 if (argc > 2) { 3122 (void) fprintf(stderr, gettext("too many arguments\n")); 3123 usage(B_FALSE); 3124 } 3125 3126 zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 3127 if (zhp == NULL) 3128 return (1); 3129 3130 ret = (zfs_promote(zhp) != 0); 3131 3132 3133 zfs_close(zhp); 3134 return (ret); 3135 } 3136 3137 /* 3138 * zfs rollback [-rRf] <snapshot> 3139 * 3140 * -r Delete any intervening snapshots before doing rollback 3141 * -R Delete any snapshots and their clones 3142 * -f ignored for backwards compatability 3143 * 3144 * Given a filesystem, rollback to a specific snapshot, discarding any changes 3145 * since then and making it the active dataset. If more recent snapshots exist, 3146 * the command will complain unless the '-r' flag is given. 3147 */ 3148 typedef struct rollback_cbdata { 3149 uint64_t cb_create; 3150 boolean_t cb_first; 3151 int cb_doclones; 3152 char *cb_target; 3153 int cb_error; 3154 boolean_t cb_recurse; 3155 boolean_t cb_dependent; 3156 } rollback_cbdata_t; 3157 3158 /* 3159 * Report any snapshots more recent than the one specified. Used when '-r' is 3160 * not specified. We reuse this same callback for the snapshot dependents - if 3161 * 'cb_dependent' is set, then this is a dependent and we should report it 3162 * without checking the transaction group. 3163 */ 3164 static int 3165 rollback_check(zfs_handle_t *zhp, void *data) 3166 { 3167 rollback_cbdata_t *cbp = data; 3168 3169 if (cbp->cb_doclones) { 3170 zfs_close(zhp); 3171 return (0); 3172 } 3173 3174 if (!cbp->cb_dependent) { 3175 if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 && 3176 zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3177 zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3178 cbp->cb_create) { 3179 3180 if (cbp->cb_first && !cbp->cb_recurse) { 3181 (void) fprintf(stderr, gettext("cannot " 3182 "rollback to '%s': more recent snapshots " 3183 "exist\n"), 3184 cbp->cb_target); 3185 (void) fprintf(stderr, gettext("use '-r' to " 3186 "force deletion of the following " 3187 "snapshots:\n")); 3188 cbp->cb_first = 0; 3189 cbp->cb_error = 1; 3190 } 3191 3192 if (cbp->cb_recurse) { 3193 cbp->cb_dependent = B_TRUE; 3194 if (zfs_iter_dependents(zhp, B_TRUE, 3195 rollback_check, cbp) != 0) { 3196 zfs_close(zhp); 3197 return (-1); 3198 } 3199 cbp->cb_dependent = B_FALSE; 3200 } else { 3201 (void) fprintf(stderr, "%s\n", 3202 zfs_get_name(zhp)); 3203 } 3204 } 3205 } else { 3206 if (cbp->cb_first && cbp->cb_recurse) { 3207 (void) fprintf(stderr, gettext("cannot rollback to " 3208 "'%s': clones of previous snapshots exist\n"), 3209 cbp->cb_target); 3210 (void) fprintf(stderr, gettext("use '-R' to " 3211 "force deletion of the following clones and " 3212 "dependents:\n")); 3213 cbp->cb_first = 0; 3214 cbp->cb_error = 1; 3215 } 3216 3217 (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); 3218 } 3219 3220 zfs_close(zhp); 3221 return (0); 3222 } 3223 3224 static int 3225 zfs_do_rollback(int argc, char **argv) 3226 { 3227 int ret; 3228 int c; 3229 boolean_t force = B_FALSE; 3230 rollback_cbdata_t cb = { 0 }; 3231 zfs_handle_t *zhp, *snap; 3232 char parentname[ZFS_MAXNAMELEN]; 3233 char *delim; 3234 3235 /* check options */ 3236 while ((c = getopt(argc, argv, "rRf")) != -1) { 3237 switch (c) { 3238 case 'r': 3239 cb.cb_recurse = 1; 3240 break; 3241 case 'R': 3242 cb.cb_recurse = 1; 3243 cb.cb_doclones = 1; 3244 break; 3245 case 'f': 3246 force = B_TRUE; 3247 break; 3248 case '?': 3249 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3250 optopt); 3251 usage(B_FALSE); 3252 } 3253 } 3254 3255 argc -= optind; 3256 argv += optind; 3257 3258 /* check number of arguments */ 3259 if (argc < 1) { 3260 (void) fprintf(stderr, gettext("missing dataset argument\n")); 3261 usage(B_FALSE); 3262 } 3263 if (argc > 1) { 3264 (void) fprintf(stderr, gettext("too many arguments\n")); 3265 usage(B_FALSE); 3266 } 3267 3268 /* open the snapshot */ 3269 if ((snap = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL) 3270 return (1); 3271 3272 /* open the parent dataset */ 3273 (void) strlcpy(parentname, argv[0], sizeof (parentname)); 3274 verify((delim = strrchr(parentname, '@')) != NULL); 3275 *delim = '\0'; 3276 if ((zhp = zfs_open(g_zfs, parentname, ZFS_TYPE_DATASET)) == NULL) { 3277 zfs_close(snap); 3278 return (1); 3279 } 3280 3281 /* 3282 * Check for more recent snapshots and/or clones based on the presence 3283 * of '-r' and '-R'. 3284 */ 3285 cb.cb_target = argv[0]; 3286 cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 3287 cb.cb_first = B_TRUE; 3288 cb.cb_error = 0; 3289 if ((ret = zfs_iter_children(zhp, rollback_check, &cb)) != 0) 3290 goto out; 3291 3292 if ((ret = cb.cb_error) != 0) 3293 goto out; 3294 3295 /* 3296 * Rollback parent to the given snapshot. 3297 */ 3298 ret = zfs_rollback(zhp, snap, force); 3299 3300 out: 3301 zfs_close(snap); 3302 zfs_close(zhp); 3303 3304 if (ret == 0) 3305 return (0); 3306 else 3307 return (1); 3308 } 3309 3310 /* 3311 * zfs set property=value { fs | snap | vol } ... 3312 * 3313 * Sets the given property for all datasets specified on the command line. 3314 */ 3315 typedef struct set_cbdata { 3316 char *cb_propname; 3317 char *cb_value; 3318 } set_cbdata_t; 3319 3320 static int 3321 set_callback(zfs_handle_t *zhp, void *data) 3322 { 3323 set_cbdata_t *cbp = data; 3324 3325 if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) { 3326 switch (libzfs_errno(g_zfs)) { 3327 case EZFS_MOUNTFAILED: 3328 (void) fprintf(stderr, gettext("property may be set " 3329 "but unable to remount filesystem\n")); 3330 break; 3331 case EZFS_SHARENFSFAILED: 3332 (void) fprintf(stderr, gettext("property may be set " 3333 "but unable to reshare filesystem\n")); 3334 break; 3335 } 3336 return (1); 3337 } 3338 return (0); 3339 } 3340 3341 static int 3342 zfs_do_set(int argc, char **argv) 3343 { 3344 set_cbdata_t cb; 3345 int ret; 3346 3347 /* check for options */ 3348 if (argc > 1 && argv[1][0] == '-') { 3349 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3350 argv[1][1]); 3351 usage(B_FALSE); 3352 } 3353 3354 /* check number of arguments */ 3355 if (argc < 2) { 3356 (void) fprintf(stderr, gettext("missing property=value " 3357 "argument\n")); 3358 usage(B_FALSE); 3359 } 3360 if (argc < 3) { 3361 (void) fprintf(stderr, gettext("missing dataset name\n")); 3362 usage(B_FALSE); 3363 } 3364 3365 /* validate property=value argument */ 3366 cb.cb_propname = argv[1]; 3367 if (((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) || 3368 (cb.cb_value[1] == '\0')) { 3369 (void) fprintf(stderr, gettext("missing value in " 3370 "property=value argument\n")); 3371 usage(B_FALSE); 3372 } 3373 3374 *cb.cb_value = '\0'; 3375 cb.cb_value++; 3376 3377 if (*cb.cb_propname == '\0') { 3378 (void) fprintf(stderr, 3379 gettext("missing property in property=value argument\n")); 3380 usage(B_FALSE); 3381 } 3382 3383 ret = zfs_for_each(argc - 2, argv + 2, NULL, 3384 ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb); 3385 3386 return (ret); 3387 } 3388 3389 /* 3390 * zfs snapshot [-r] [-o prop=value] ... <fs@snap> 3391 * 3392 * Creates a snapshot with the given name. While functionally equivalent to 3393 * 'zfs create', it is a separate command to differentiate intent. 3394 */ 3395 static int 3396 zfs_do_snapshot(int argc, char **argv) 3397 { 3398 boolean_t recursive = B_FALSE; 3399 int ret; 3400 char c; 3401 nvlist_t *props; 3402 3403 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) 3404 nomem(); 3405 3406 /* check options */ 3407 while ((c = getopt(argc, argv, "ro:")) != -1) { 3408 switch (c) { 3409 case 'o': 3410 if (parseprop(props)) 3411 return (1); 3412 break; 3413 case 'r': 3414 recursive = B_TRUE; 3415 break; 3416 case '?': 3417 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3418 optopt); 3419 goto usage; 3420 } 3421 } 3422 3423 argc -= optind; 3424 argv += optind; 3425 3426 /* check number of arguments */ 3427 if (argc < 1) { 3428 (void) fprintf(stderr, gettext("missing snapshot argument\n")); 3429 goto usage; 3430 } 3431 if (argc > 1) { 3432 (void) fprintf(stderr, gettext("too many arguments\n")); 3433 goto usage; 3434 } 3435 3436 ret = zfs_snapshot(g_zfs, argv[0], recursive, props); 3437 nvlist_free(props); 3438 if (ret && recursive) 3439 (void) fprintf(stderr, gettext("no snapshots were created\n")); 3440 return (ret != 0); 3441 3442 usage: 3443 nvlist_free(props); 3444 usage(B_FALSE); 3445 return (-1); 3446 } 3447 3448 /* 3449 * Send a backup stream to stdout. 3450 */ 3451 static int 3452 zfs_do_send(int argc, char **argv) 3453 { 3454 char *fromname = NULL; 3455 char *toname = NULL; 3456 char *cp; 3457 zfs_handle_t *zhp; 3458 sendflags_t flags = { 0 }; 3459 int c, err; 3460 nvlist_t *dbgnv = NULL; 3461 boolean_t extraverbose = B_FALSE; 3462 3463 /* check options */ 3464 while ((c = getopt(argc, argv, ":i:I:RDpvnP")) != -1) { 3465 switch (c) { 3466 case 'i': 3467 if (fromname) 3468 usage(B_FALSE); 3469 fromname = optarg; 3470 break; 3471 case 'I': 3472 if (fromname) 3473 usage(B_FALSE); 3474 fromname = optarg; 3475 flags.doall = B_TRUE; 3476 break; 3477 case 'R': 3478 flags.replicate = B_TRUE; 3479 break; 3480 case 'p': 3481 flags.props = B_TRUE; 3482 break; 3483 case 'P': 3484 flags.parsable = B_TRUE; 3485 flags.verbose = B_TRUE; 3486 break; 3487 case 'v': 3488 if (flags.verbose) 3489 extraverbose = B_TRUE; 3490 flags.verbose = B_TRUE; 3491 break; 3492 case 'D': 3493 flags.dedup = B_TRUE; 3494 break; 3495 case 'n': 3496 flags.dryrun = B_TRUE; 3497 break; 3498 case ':': 3499 (void) fprintf(stderr, gettext("missing argument for " 3500 "'%c' option\n"), optopt); 3501 usage(B_FALSE); 3502 break; 3503 case '?': 3504 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3505 optopt); 3506 usage(B_FALSE); 3507 } 3508 } 3509 3510 argc -= optind; 3511 argv += optind; 3512 3513 /* check number of arguments */ 3514 if (argc < 1) { 3515 (void) fprintf(stderr, gettext("missing snapshot argument\n")); 3516 usage(B_FALSE); 3517 } 3518 if (argc > 1) { 3519 (void) fprintf(stderr, gettext("too many arguments\n")); 3520 usage(B_FALSE); 3521 } 3522 3523 if (!flags.dryrun && isatty(STDOUT_FILENO)) { 3524 (void) fprintf(stderr, 3525 gettext("Error: Stream can not be written to a terminal.\n" 3526 "You must redirect standard output.\n")); 3527 return (1); 3528 } 3529 3530 cp = strchr(argv[0], '@'); 3531 if (cp == NULL) { 3532 (void) fprintf(stderr, 3533 gettext("argument must be a snapshot\n")); 3534 usage(B_FALSE); 3535 } 3536 *cp = '\0'; 3537 toname = cp + 1; 3538 zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 3539 if (zhp == NULL) 3540 return (1); 3541 3542 /* 3543 * If they specified the full path to the snapshot, chop off 3544 * everything except the short name of the snapshot, but special 3545 * case if they specify the origin. 3546 */ 3547 if (fromname && (cp = strchr(fromname, '@')) != NULL) { 3548 char origin[ZFS_MAXNAMELEN]; 3549 zprop_source_t src; 3550 3551 (void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN, 3552 origin, sizeof (origin), &src, NULL, 0, B_FALSE); 3553 3554 if (strcmp(origin, fromname) == 0) { 3555 fromname = NULL; 3556 flags.fromorigin = B_TRUE; 3557 } else { 3558 *cp = '\0'; 3559 if (cp != fromname && strcmp(argv[0], fromname)) { 3560 (void) fprintf(stderr, 3561 gettext("incremental source must be " 3562 "in same filesystem\n")); 3563 usage(B_FALSE); 3564 } 3565 fromname = cp + 1; 3566 if (strchr(fromname, '@') || strchr(fromname, '/')) { 3567 (void) fprintf(stderr, 3568 gettext("invalid incremental source\n")); 3569 usage(B_FALSE); 3570 } 3571 } 3572 } 3573 3574 if (flags.replicate && fromname == NULL) 3575 flags.doall = B_TRUE; 3576 3577 err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO, NULL, 0, 3578 extraverbose ? &dbgnv : NULL); 3579 3580 if (extraverbose && dbgnv != NULL) { 3581 /* 3582 * dump_nvlist prints to stdout, but that's been 3583 * redirected to a file. Make it print to stderr 3584 * instead. 3585 */ 3586 (void) dup2(STDERR_FILENO, STDOUT_FILENO); 3587 dump_nvlist(dbgnv, 0); 3588 nvlist_free(dbgnv); 3589 } 3590 zfs_close(zhp); 3591 3592 return (err != 0); 3593 } 3594 3595 /* 3596 * zfs receive [-vnFu] [-d | -e] <fs@snap> 3597 * 3598 * Restore a backup stream from stdin. 3599 */ 3600 static int 3601 zfs_do_receive(int argc, char **argv) 3602 { 3603 int c, err; 3604 recvflags_t flags = { 0 }; 3605 3606 /* check options */ 3607 while ((c = getopt(argc, argv, ":denuvF")) != -1) { 3608 switch (c) { 3609 case 'd': 3610 flags.isprefix = B_TRUE; 3611 break; 3612 case 'e': 3613 flags.isprefix = B_TRUE; 3614 flags.istail = B_TRUE; 3615 break; 3616 case 'n': 3617 flags.dryrun = B_TRUE; 3618 break; 3619 case 'u': 3620 flags.nomount = B_TRUE; 3621 break; 3622 case 'v': 3623 flags.verbose = B_TRUE; 3624 break; 3625 case 'F': 3626 flags.force = B_TRUE; 3627 break; 3628 case ':': 3629 (void) fprintf(stderr, gettext("missing argument for " 3630 "'%c' option\n"), optopt); 3631 usage(B_FALSE); 3632 break; 3633 case '?': 3634 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3635 optopt); 3636 usage(B_FALSE); 3637 } 3638 } 3639 3640 argc -= optind; 3641 argv += optind; 3642 3643 /* check number of arguments */ 3644 if (argc < 1) { 3645 (void) fprintf(stderr, gettext("missing snapshot argument\n")); 3646 usage(B_FALSE); 3647 } 3648 if (argc > 1) { 3649 (void) fprintf(stderr, gettext("too many arguments\n")); 3650 usage(B_FALSE); 3651 } 3652 3653 if (isatty(STDIN_FILENO)) { 3654 (void) fprintf(stderr, 3655 gettext("Error: Backup stream can not be read " 3656 "from a terminal.\n" 3657 "You must redirect standard input.\n")); 3658 return (1); 3659 } 3660 3661 err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, NULL); 3662 3663 return (err != 0); 3664 } 3665 3666 /* 3667 * allow/unallow stuff 3668 */ 3669 /* copied from zfs/sys/dsl_deleg.h */ 3670 #define ZFS_DELEG_PERM_CREATE "create" 3671 #define ZFS_DELEG_PERM_DESTROY "destroy" 3672 #define ZFS_DELEG_PERM_SNAPSHOT "snapshot" 3673 #define ZFS_DELEG_PERM_ROLLBACK "rollback" 3674 #define ZFS_DELEG_PERM_CLONE "clone" 3675 #define ZFS_DELEG_PERM_PROMOTE "promote" 3676 #define ZFS_DELEG_PERM_RENAME "rename" 3677 #define ZFS_DELEG_PERM_MOUNT "mount" 3678 #define ZFS_DELEG_PERM_SHARE "share" 3679 #define ZFS_DELEG_PERM_SEND "send" 3680 #define ZFS_DELEG_PERM_RECEIVE "receive" 3681 #define ZFS_DELEG_PERM_ALLOW "allow" 3682 #define ZFS_DELEG_PERM_USERPROP "userprop" 3683 #define ZFS_DELEG_PERM_VSCAN "vscan" /* ??? */ 3684 #define ZFS_DELEG_PERM_USERQUOTA "userquota" 3685 #define ZFS_DELEG_PERM_GROUPQUOTA "groupquota" 3686 #define ZFS_DELEG_PERM_USERUSED "userused" 3687 #define ZFS_DELEG_PERM_GROUPUSED "groupused" 3688 #define ZFS_DELEG_PERM_HOLD "hold" 3689 #define ZFS_DELEG_PERM_RELEASE "release" 3690 #define ZFS_DELEG_PERM_DIFF "diff" 3691 3692 #define ZFS_NUM_DELEG_NOTES ZFS_DELEG_NOTE_NONE 3693 3694 static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = { 3695 { ZFS_DELEG_PERM_ALLOW, ZFS_DELEG_NOTE_ALLOW }, 3696 { ZFS_DELEG_PERM_CLONE, ZFS_DELEG_NOTE_CLONE }, 3697 { ZFS_DELEG_PERM_CREATE, ZFS_DELEG_NOTE_CREATE }, 3698 { ZFS_DELEG_PERM_DESTROY, ZFS_DELEG_NOTE_DESTROY }, 3699 { ZFS_DELEG_PERM_DIFF, ZFS_DELEG_NOTE_DIFF}, 3700 { ZFS_DELEG_PERM_HOLD, ZFS_DELEG_NOTE_HOLD }, 3701 { ZFS_DELEG_PERM_MOUNT, ZFS_DELEG_NOTE_MOUNT }, 3702 { ZFS_DELEG_PERM_PROMOTE, ZFS_DELEG_NOTE_PROMOTE }, 3703 { ZFS_DELEG_PERM_RECEIVE, ZFS_DELEG_NOTE_RECEIVE }, 3704 { ZFS_DELEG_PERM_RELEASE, ZFS_DELEG_NOTE_RELEASE }, 3705 { ZFS_DELEG_PERM_RENAME, ZFS_DELEG_NOTE_RENAME }, 3706 { ZFS_DELEG_PERM_ROLLBACK, ZFS_DELEG_NOTE_ROLLBACK }, 3707 { ZFS_DELEG_PERM_SEND, ZFS_DELEG_NOTE_SEND }, 3708 { ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE }, 3709 { ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT }, 3710 3711 { ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA }, 3712 { ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED }, 3713 { ZFS_DELEG_PERM_USERPROP, ZFS_DELEG_NOTE_USERPROP }, 3714 { ZFS_DELEG_PERM_USERQUOTA, ZFS_DELEG_NOTE_USERQUOTA }, 3715 { ZFS_DELEG_PERM_USERUSED, ZFS_DELEG_NOTE_USERUSED }, 3716 { NULL, ZFS_DELEG_NOTE_NONE } 3717 }; 3718 3719 /* permission structure */ 3720 typedef struct deleg_perm { 3721 zfs_deleg_who_type_t dp_who_type; 3722 const char *dp_name; 3723 boolean_t dp_local; 3724 boolean_t dp_descend; 3725 } deleg_perm_t; 3726 3727 /* */ 3728 typedef struct deleg_perm_node { 3729 deleg_perm_t dpn_perm; 3730 3731 uu_avl_node_t dpn_avl_node; 3732 } deleg_perm_node_t; 3733 3734 typedef struct fs_perm fs_perm_t; 3735 3736 /* permissions set */ 3737 typedef struct who_perm { 3738 zfs_deleg_who_type_t who_type; 3739 const char *who_name; /* id */ 3740 char who_ug_name[256]; /* user/group name */ 3741 fs_perm_t *who_fsperm; /* uplink */ 3742 3743 uu_avl_t *who_deleg_perm_avl; /* permissions */ 3744 } who_perm_t; 3745 3746 /* */ 3747 typedef struct who_perm_node { 3748 who_perm_t who_perm; 3749 uu_avl_node_t who_avl_node; 3750 } who_perm_node_t; 3751 3752 typedef struct fs_perm_set fs_perm_set_t; 3753 /* fs permissions */ 3754 struct fs_perm { 3755 const char *fsp_name; 3756 3757 uu_avl_t *fsp_sc_avl; /* sets,create */ 3758 uu_avl_t *fsp_uge_avl; /* user,group,everyone */ 3759 3760 fs_perm_set_t *fsp_set; /* uplink */ 3761 }; 3762 3763 /* */ 3764 typedef struct fs_perm_node { 3765 fs_perm_t fspn_fsperm; 3766 uu_avl_t *fspn_avl; 3767 3768 uu_list_node_t fspn_list_node; 3769 } fs_perm_node_t; 3770 3771 /* top level structure */ 3772 struct fs_perm_set { 3773 uu_list_pool_t *fsps_list_pool; 3774 uu_list_t *fsps_list; /* list of fs_perms */ 3775 3776 uu_avl_pool_t *fsps_named_set_avl_pool; 3777 uu_avl_pool_t *fsps_who_perm_avl_pool; 3778 uu_avl_pool_t *fsps_deleg_perm_avl_pool; 3779 }; 3780 3781 static inline const char * 3782 deleg_perm_type(zfs_deleg_note_t note) 3783 { 3784 /* subcommands */ 3785 switch (note) { 3786 /* SUBCOMMANDS */ 3787 /* OTHER */ 3788 case ZFS_DELEG_NOTE_GROUPQUOTA: 3789 case ZFS_DELEG_NOTE_GROUPUSED: 3790 case ZFS_DELEG_NOTE_USERPROP: 3791 case ZFS_DELEG_NOTE_USERQUOTA: 3792 case ZFS_DELEG_NOTE_USERUSED: 3793 /* other */ 3794 return (gettext("other")); 3795 default: 3796 return (gettext("subcommand")); 3797 } 3798 } 3799 3800 static int inline 3801 who_type2weight(zfs_deleg_who_type_t who_type) 3802 { 3803 int res; 3804 switch (who_type) { 3805 case ZFS_DELEG_NAMED_SET_SETS: 3806 case ZFS_DELEG_NAMED_SET: 3807 res = 0; 3808 break; 3809 case ZFS_DELEG_CREATE_SETS: 3810 case ZFS_DELEG_CREATE: 3811 res = 1; 3812 break; 3813 case ZFS_DELEG_USER_SETS: 3814 case ZFS_DELEG_USER: 3815 res = 2; 3816 break; 3817 case ZFS_DELEG_GROUP_SETS: 3818 case ZFS_DELEG_GROUP: 3819 res = 3; 3820 break; 3821 case ZFS_DELEG_EVERYONE_SETS: 3822 case ZFS_DELEG_EVERYONE: 3823 res = 4; 3824 break; 3825 default: 3826 res = -1; 3827 } 3828 3829 return (res); 3830 } 3831 3832 /* ARGSUSED */ 3833 static int 3834 who_perm_compare(const void *larg, const void *rarg, void *unused) 3835 { 3836 const who_perm_node_t *l = larg; 3837 const who_perm_node_t *r = rarg; 3838 zfs_deleg_who_type_t ltype = l->who_perm.who_type; 3839 zfs_deleg_who_type_t rtype = r->who_perm.who_type; 3840 int lweight = who_type2weight(ltype); 3841 int rweight = who_type2weight(rtype); 3842 int res = lweight - rweight; 3843 if (res == 0) 3844 res = strncmp(l->who_perm.who_name, r->who_perm.who_name, 3845 ZFS_MAX_DELEG_NAME-1); 3846 3847 if (res == 0) 3848 return (0); 3849 if (res > 0) 3850 return (1); 3851 else 3852 return (-1); 3853 } 3854 3855 /* ARGSUSED */ 3856 static int 3857 deleg_perm_compare(const void *larg, const void *rarg, void *unused) 3858 { 3859 const deleg_perm_node_t *l = larg; 3860 const deleg_perm_node_t *r = rarg; 3861 int res = strncmp(l->dpn_perm.dp_name, r->dpn_perm.dp_name, 3862 ZFS_MAX_DELEG_NAME-1); 3863 3864 if (res == 0) 3865 return (0); 3866 3867 if (res > 0) 3868 return (1); 3869 else 3870 return (-1); 3871 } 3872 3873 static inline void 3874 fs_perm_set_init(fs_perm_set_t *fspset) 3875 { 3876 bzero(fspset, sizeof (fs_perm_set_t)); 3877 3878 if ((fspset->fsps_list_pool = uu_list_pool_create("fsps_list_pool", 3879 sizeof (fs_perm_node_t), offsetof(fs_perm_node_t, fspn_list_node), 3880 NULL, UU_DEFAULT)) == NULL) 3881 nomem(); 3882 if ((fspset->fsps_list = uu_list_create(fspset->fsps_list_pool, NULL, 3883 UU_DEFAULT)) == NULL) 3884 nomem(); 3885 3886 if ((fspset->fsps_named_set_avl_pool = uu_avl_pool_create( 3887 "named_set_avl_pool", sizeof (who_perm_node_t), offsetof( 3888 who_perm_node_t, who_avl_node), who_perm_compare, 3889 UU_DEFAULT)) == NULL) 3890 nomem(); 3891 3892 if ((fspset->fsps_who_perm_avl_pool = uu_avl_pool_create( 3893 "who_perm_avl_pool", sizeof (who_perm_node_t), offsetof( 3894 who_perm_node_t, who_avl_node), who_perm_compare, 3895 UU_DEFAULT)) == NULL) 3896 nomem(); 3897 3898 if ((fspset->fsps_deleg_perm_avl_pool = uu_avl_pool_create( 3899 "deleg_perm_avl_pool", sizeof (deleg_perm_node_t), offsetof( 3900 deleg_perm_node_t, dpn_avl_node), deleg_perm_compare, UU_DEFAULT)) 3901 == NULL) 3902 nomem(); 3903 } 3904 3905 static inline void fs_perm_fini(fs_perm_t *); 3906 static inline void who_perm_fini(who_perm_t *); 3907 3908 static inline void 3909 fs_perm_set_fini(fs_perm_set_t *fspset) 3910 { 3911 fs_perm_node_t *node = uu_list_first(fspset->fsps_list); 3912 3913 while (node != NULL) { 3914 fs_perm_node_t *next_node = 3915 uu_list_next(fspset->fsps_list, node); 3916 fs_perm_t *fsperm = &node->fspn_fsperm; 3917 fs_perm_fini(fsperm); 3918 uu_list_remove(fspset->fsps_list, node); 3919 free(node); 3920 node = next_node; 3921 } 3922 3923 uu_avl_pool_destroy(fspset->fsps_named_set_avl_pool); 3924 uu_avl_pool_destroy(fspset->fsps_who_perm_avl_pool); 3925 uu_avl_pool_destroy(fspset->fsps_deleg_perm_avl_pool); 3926 } 3927 3928 static inline void 3929 deleg_perm_init(deleg_perm_t *deleg_perm, zfs_deleg_who_type_t type, 3930 const char *name) 3931 { 3932 deleg_perm->dp_who_type = type; 3933 deleg_perm->dp_name = name; 3934 } 3935 3936 static inline void 3937 who_perm_init(who_perm_t *who_perm, fs_perm_t *fsperm, 3938 zfs_deleg_who_type_t type, const char *name) 3939 { 3940 uu_avl_pool_t *pool; 3941 pool = fsperm->fsp_set->fsps_deleg_perm_avl_pool; 3942 3943 bzero(who_perm, sizeof (who_perm_t)); 3944 3945 if ((who_perm->who_deleg_perm_avl = uu_avl_create(pool, NULL, 3946 UU_DEFAULT)) == NULL) 3947 nomem(); 3948 3949 who_perm->who_type = type; 3950 who_perm->who_name = name; 3951 who_perm->who_fsperm = fsperm; 3952 } 3953 3954 static inline void 3955 who_perm_fini(who_perm_t *who_perm) 3956 { 3957 deleg_perm_node_t *node = uu_avl_first(who_perm->who_deleg_perm_avl); 3958 3959 while (node != NULL) { 3960 deleg_perm_node_t *next_node = 3961 uu_avl_next(who_perm->who_deleg_perm_avl, node); 3962 3963 uu_avl_remove(who_perm->who_deleg_perm_avl, node); 3964 free(node); 3965 node = next_node; 3966 } 3967 3968 uu_avl_destroy(who_perm->who_deleg_perm_avl); 3969 } 3970 3971 static inline void 3972 fs_perm_init(fs_perm_t *fsperm, fs_perm_set_t *fspset, const char *fsname) 3973 { 3974 uu_avl_pool_t *nset_pool = fspset->fsps_named_set_avl_pool; 3975 uu_avl_pool_t *who_pool = fspset->fsps_who_perm_avl_pool; 3976 3977 bzero(fsperm, sizeof (fs_perm_t)); 3978 3979 if ((fsperm->fsp_sc_avl = uu_avl_create(nset_pool, NULL, UU_DEFAULT)) 3980 == NULL) 3981 nomem(); 3982 3983 if ((fsperm->fsp_uge_avl = uu_avl_create(who_pool, NULL, UU_DEFAULT)) 3984 == NULL) 3985 nomem(); 3986 3987 fsperm->fsp_set = fspset; 3988 fsperm->fsp_name = fsname; 3989 } 3990 3991 static inline void 3992 fs_perm_fini(fs_perm_t *fsperm) 3993 { 3994 who_perm_node_t *node = uu_avl_first(fsperm->fsp_sc_avl); 3995 while (node != NULL) { 3996 who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_sc_avl, 3997 node); 3998 who_perm_t *who_perm = &node->who_perm; 3999 who_perm_fini(who_perm); 4000 uu_avl_remove(fsperm->fsp_sc_avl, node); 4001 free(node); 4002 node = next_node; 4003 } 4004 4005 node = uu_avl_first(fsperm->fsp_uge_avl); 4006 while (node != NULL) { 4007 who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_uge_avl, 4008 node); 4009 who_perm_t *who_perm = &node->who_perm; 4010 who_perm_fini(who_perm); 4011 uu_avl_remove(fsperm->fsp_uge_avl, node); 4012 free(node); 4013 node = next_node; 4014 } 4015 4016 uu_avl_destroy(fsperm->fsp_sc_avl); 4017 uu_avl_destroy(fsperm->fsp_uge_avl); 4018 } 4019 4020 static void inline 4021 set_deleg_perm_node(uu_avl_t *avl, deleg_perm_node_t *node, 4022 zfs_deleg_who_type_t who_type, const char *name, char locality) 4023 { 4024 uu_avl_index_t idx = 0; 4025 4026 deleg_perm_node_t *found_node = NULL; 4027 deleg_perm_t *deleg_perm = &node->dpn_perm; 4028 4029 deleg_perm_init(deleg_perm, who_type, name); 4030 4031 if ((found_node = uu_avl_find(avl, node, NULL, &idx)) 4032 == NULL) 4033 uu_avl_insert(avl, node, idx); 4034 else { 4035 node = found_node; 4036 deleg_perm = &node->dpn_perm; 4037 } 4038 4039 4040 switch (locality) { 4041 case ZFS_DELEG_LOCAL: 4042 deleg_perm->dp_local = B_TRUE; 4043 break; 4044 case ZFS_DELEG_DESCENDENT: 4045 deleg_perm->dp_descend = B_TRUE; 4046 break; 4047 case ZFS_DELEG_NA: 4048 break; 4049 default: 4050 assert(B_FALSE); /* invalid locality */ 4051 } 4052 } 4053 4054 static inline int 4055 parse_who_perm(who_perm_t *who_perm, nvlist_t *nvl, char locality) 4056 { 4057 nvpair_t *nvp = NULL; 4058 fs_perm_set_t *fspset = who_perm->who_fsperm->fsp_set; 4059 uu_avl_t *avl = who_perm->who_deleg_perm_avl; 4060 zfs_deleg_who_type_t who_type = who_perm->who_type; 4061 4062 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 4063 const char *name = nvpair_name(nvp); 4064 data_type_t type = nvpair_type(nvp); 4065 uu_avl_pool_t *avl_pool = fspset->fsps_deleg_perm_avl_pool; 4066 deleg_perm_node_t *node = 4067 safe_malloc(sizeof (deleg_perm_node_t)); 4068 4069 assert(type == DATA_TYPE_BOOLEAN); 4070 4071 uu_avl_node_init(node, &node->dpn_avl_node, avl_pool); 4072 set_deleg_perm_node(avl, node, who_type, name, locality); 4073 } 4074 4075 return (0); 4076 } 4077 4078 static inline int 4079 parse_fs_perm(fs_perm_t *fsperm, nvlist_t *nvl) 4080 { 4081 nvpair_t *nvp = NULL; 4082 fs_perm_set_t *fspset = fsperm->fsp_set; 4083 4084 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 4085 nvlist_t *nvl2 = NULL; 4086 const char *name = nvpair_name(nvp); 4087 uu_avl_t *avl = NULL; 4088 uu_avl_pool_t *avl_pool; 4089 zfs_deleg_who_type_t perm_type = name[0]; 4090 char perm_locality = name[1]; 4091 const char *perm_name = name + 3; 4092 boolean_t is_set = B_TRUE; 4093 who_perm_t *who_perm = NULL; 4094 4095 assert('$' == name[2]); 4096 4097 if (nvpair_value_nvlist(nvp, &nvl2) != 0) 4098 return (-1); 4099 4100 switch (perm_type) { 4101 case ZFS_DELEG_CREATE: 4102 case ZFS_DELEG_CREATE_SETS: 4103 case ZFS_DELEG_NAMED_SET: 4104 case ZFS_DELEG_NAMED_SET_SETS: 4105 avl_pool = fspset->fsps_named_set_avl_pool; 4106 avl = fsperm->fsp_sc_avl; 4107 break; 4108 case ZFS_DELEG_USER: 4109 case ZFS_DELEG_USER_SETS: 4110 case ZFS_DELEG_GROUP: 4111 case ZFS_DELEG_GROUP_SETS: 4112 case ZFS_DELEG_EVERYONE: 4113 case ZFS_DELEG_EVERYONE_SETS: 4114 avl_pool = fspset->fsps_who_perm_avl_pool; 4115 avl = fsperm->fsp_uge_avl; 4116 break; 4117 } 4118 4119 if (is_set) { 4120 who_perm_node_t *found_node = NULL; 4121 who_perm_node_t *node = safe_malloc( 4122 sizeof (who_perm_node_t)); 4123 who_perm = &node->who_perm; 4124 uu_avl_index_t idx = 0; 4125 4126 uu_avl_node_init(node, &node->who_avl_node, avl_pool); 4127 who_perm_init(who_perm, fsperm, perm_type, perm_name); 4128 4129 if ((found_node = uu_avl_find(avl, node, NULL, &idx)) 4130 == NULL) { 4131 if (avl == fsperm->fsp_uge_avl) { 4132 uid_t rid = 0; 4133 struct passwd *p = NULL; 4134 struct group *g = NULL; 4135 const char *nice_name = NULL; 4136 4137 switch (perm_type) { 4138 case ZFS_DELEG_USER_SETS: 4139 case ZFS_DELEG_USER: 4140 rid = atoi(perm_name); 4141 p = getpwuid(rid); 4142 if (p) 4143 nice_name = p->pw_name; 4144 break; 4145 case ZFS_DELEG_GROUP_SETS: 4146 case ZFS_DELEG_GROUP: 4147 rid = atoi(perm_name); 4148 g = getgrgid(rid); 4149 if (g) 4150 nice_name = g->gr_name; 4151 break; 4152 } 4153 4154 if (nice_name != NULL) 4155 (void) strlcpy( 4156 node->who_perm.who_ug_name, 4157 nice_name, 256); 4158 } 4159 4160 uu_avl_insert(avl, node, idx); 4161 } else { 4162 node = found_node; 4163 who_perm = &node->who_perm; 4164 } 4165 } 4166 4167 (void) parse_who_perm(who_perm, nvl2, perm_locality); 4168 } 4169 4170 return (0); 4171 } 4172 4173 static inline int 4174 parse_fs_perm_set(fs_perm_set_t *fspset, nvlist_t *nvl) 4175 { 4176 nvpair_t *nvp = NULL; 4177 uu_avl_index_t idx = 0; 4178 4179 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 4180 nvlist_t *nvl2 = NULL; 4181 const char *fsname = nvpair_name(nvp); 4182 data_type_t type = nvpair_type(nvp); 4183 fs_perm_t *fsperm = NULL; 4184 fs_perm_node_t *node = safe_malloc(sizeof (fs_perm_node_t)); 4185 if (node == NULL) 4186 nomem(); 4187 4188 fsperm = &node->fspn_fsperm; 4189 4190 assert(DATA_TYPE_NVLIST == type); 4191 4192 uu_list_node_init(node, &node->fspn_list_node, 4193 fspset->fsps_list_pool); 4194 4195 idx = uu_list_numnodes(fspset->fsps_list); 4196 fs_perm_init(fsperm, fspset, fsname); 4197 4198 if (nvpair_value_nvlist(nvp, &nvl2) != 0) 4199 return (-1); 4200 4201 (void) parse_fs_perm(fsperm, nvl2); 4202 4203 uu_list_insert(fspset->fsps_list, node, idx); 4204 } 4205 4206 return (0); 4207 } 4208 4209 static inline const char * 4210 deleg_perm_comment(zfs_deleg_note_t note) 4211 { 4212 const char *str = ""; 4213 4214 /* subcommands */ 4215 switch (note) { 4216 /* SUBCOMMANDS */ 4217 case ZFS_DELEG_NOTE_ALLOW: 4218 str = gettext("Must also have the permission that is being" 4219 "\n\t\t\t\tallowed"); 4220 break; 4221 case ZFS_DELEG_NOTE_CLONE: 4222 str = gettext("Must also have the 'create' ability and 'mount'" 4223 "\n\t\t\t\tability in the origin file system"); 4224 break; 4225 case ZFS_DELEG_NOTE_CREATE: 4226 str = gettext("Must also have the 'mount' ability"); 4227 break; 4228 case ZFS_DELEG_NOTE_DESTROY: 4229 str = gettext("Must also have the 'mount' ability"); 4230 break; 4231 case ZFS_DELEG_NOTE_DIFF: 4232 str = gettext("Allows lookup of paths within a dataset;" 4233 "\n\t\t\t\tgiven an object number. Ordinary users need this" 4234 "\n\t\t\t\tin order to use zfs diff"); 4235 break; 4236 case ZFS_DELEG_NOTE_HOLD: 4237 str = gettext("Allows adding a user hold to a snapshot"); 4238 break; 4239 case ZFS_DELEG_NOTE_MOUNT: 4240 str = gettext("Allows mount/umount of ZFS datasets"); 4241 break; 4242 case ZFS_DELEG_NOTE_PROMOTE: 4243 str = gettext("Must also have the 'mount'\n\t\t\t\tand" 4244 " 'promote' ability in the origin file system"); 4245 break; 4246 case ZFS_DELEG_NOTE_RECEIVE: 4247 str = gettext("Must also have the 'mount' and 'create'" 4248 " ability"); 4249 break; 4250 case ZFS_DELEG_NOTE_RELEASE: 4251 str = gettext("Allows releasing a user hold which\n\t\t\t\t" 4252 "might destroy the snapshot"); 4253 break; 4254 case ZFS_DELEG_NOTE_RENAME: 4255 str = gettext("Must also have the 'mount' and 'create'" 4256 "\n\t\t\t\tability in the new parent"); 4257 break; 4258 case ZFS_DELEG_NOTE_ROLLBACK: 4259 str = gettext(""); 4260 break; 4261 case ZFS_DELEG_NOTE_SEND: 4262 str = gettext(""); 4263 break; 4264 case ZFS_DELEG_NOTE_SHARE: 4265 str = gettext("Allows sharing file systems over NFS or SMB" 4266 "\n\t\t\t\tprotocols"); 4267 break; 4268 case ZFS_DELEG_NOTE_SNAPSHOT: 4269 str = gettext(""); 4270 break; 4271 /* 4272 * case ZFS_DELEG_NOTE_VSCAN: 4273 * str = gettext(""); 4274 * break; 4275 */ 4276 /* OTHER */ 4277 case ZFS_DELEG_NOTE_GROUPQUOTA: 4278 str = gettext("Allows accessing any groupquota@... property"); 4279 break; 4280 case ZFS_DELEG_NOTE_GROUPUSED: 4281 str = gettext("Allows reading any groupused@... property"); 4282 break; 4283 case ZFS_DELEG_NOTE_USERPROP: 4284 str = gettext("Allows changing any user property"); 4285 break; 4286 case ZFS_DELEG_NOTE_USERQUOTA: 4287 str = gettext("Allows accessing any userquota@... property"); 4288 break; 4289 case ZFS_DELEG_NOTE_USERUSED: 4290 str = gettext("Allows reading any userused@... property"); 4291 break; 4292 /* other */ 4293 default: 4294 str = ""; 4295 } 4296 4297 return (str); 4298 } 4299 4300 struct allow_opts { 4301 boolean_t local; 4302 boolean_t descend; 4303 boolean_t user; 4304 boolean_t group; 4305 boolean_t everyone; 4306 boolean_t create; 4307 boolean_t set; 4308 boolean_t recursive; /* unallow only */ 4309 boolean_t prt_usage; 4310 4311 boolean_t prt_perms; 4312 char *who; 4313 char *perms; 4314 const char *dataset; 4315 }; 4316 4317 static inline int 4318 prop_cmp(const void *a, const void *b) 4319 { 4320 const char *str1 = *(const char **)a; 4321 const char *str2 = *(const char **)b; 4322 return (strcmp(str1, str2)); 4323 } 4324 4325 static void 4326 allow_usage(boolean_t un, boolean_t requested, const char *msg) 4327 { 4328 const char *opt_desc[] = { 4329 "-h", gettext("show this help message and exit"), 4330 "-l", gettext("set permission locally"), 4331 "-d", gettext("set permission for descents"), 4332 "-u", gettext("set permission for user"), 4333 "-g", gettext("set permission for group"), 4334 "-e", gettext("set permission for everyone"), 4335 "-c", gettext("set create time permission"), 4336 "-s", gettext("define permission set"), 4337 /* unallow only */ 4338 "-r", gettext("remove permissions recursively"), 4339 }; 4340 size_t unallow_size = sizeof (opt_desc) / sizeof (char *); 4341 size_t allow_size = unallow_size - 2; 4342 const char *props[ZFS_NUM_PROPS]; 4343 int i; 4344 size_t count = 0; 4345 FILE *fp = requested ? stdout : stderr; 4346 zprop_desc_t *pdtbl = zfs_prop_get_table(); 4347 const char *fmt = gettext("%-16s %-14s\t%s\n"); 4348 4349 (void) fprintf(fp, gettext("Usage: %s\n"), get_usage(un ? HELP_UNALLOW : 4350 HELP_ALLOW)); 4351 (void) fprintf(fp, gettext("Options:\n")); 4352 for (int i = 0; i < (un ? unallow_size : allow_size); i++) { 4353 const char *opt = opt_desc[i++]; 4354 const char *optdsc = opt_desc[i]; 4355 (void) fprintf(fp, gettext(" %-10s %s\n"), opt, optdsc); 4356 } 4357 4358 (void) fprintf(fp, gettext("\nThe following permissions are " 4359 "supported:\n\n")); 4360 (void) fprintf(fp, fmt, gettext("NAME"), gettext("TYPE"), 4361 gettext("NOTES")); 4362 for (i = 0; i < ZFS_NUM_DELEG_NOTES; i++) { 4363 const char *perm_name = zfs_deleg_perm_tbl[i].z_perm; 4364 zfs_deleg_note_t perm_note = zfs_deleg_perm_tbl[i].z_note; 4365 const char *perm_type = deleg_perm_type(perm_note); 4366 const char *perm_comment = deleg_perm_comment(perm_note); 4367 (void) fprintf(fp, fmt, perm_name, perm_type, perm_comment); 4368 } 4369 4370 for (i = 0; i < ZFS_NUM_PROPS; i++) { 4371 zprop_desc_t *pd = &pdtbl[i]; 4372 if (pd->pd_visible != B_TRUE) 4373 continue; 4374 4375 if (pd->pd_attr == PROP_READONLY) 4376 continue; 4377 4378 props[count++] = pd->pd_name; 4379 } 4380 props[count] = NULL; 4381 4382 qsort(props, count, sizeof (char *), prop_cmp); 4383 4384 for (i = 0; i < count; i++) 4385 (void) fprintf(fp, fmt, props[i], gettext("property"), ""); 4386 4387 if (msg != NULL) 4388 (void) fprintf(fp, gettext("\nzfs: error: %s"), msg); 4389 4390 exit(requested ? 0 : 2); 4391 } 4392 4393 static inline const char * 4394 munge_args(int argc, char **argv, boolean_t un, size_t expected_argc, 4395 char **permsp) 4396 { 4397 if (un && argc == expected_argc - 1) 4398 *permsp = NULL; 4399 else if (argc == expected_argc) 4400 *permsp = argv[argc - 2]; 4401 else 4402 allow_usage(un, B_FALSE, 4403 gettext("wrong number of parameters\n")); 4404 4405 return (argv[argc - 1]); 4406 } 4407 4408 static void 4409 parse_allow_args(int argc, char **argv, boolean_t un, struct allow_opts *opts) 4410 { 4411 int uge_sum = opts->user + opts->group + opts->everyone; 4412 int csuge_sum = opts->create + opts->set + uge_sum; 4413 int ldcsuge_sum = csuge_sum + opts->local + opts->descend; 4414 int all_sum = un ? ldcsuge_sum + opts->recursive : ldcsuge_sum; 4415 4416 if (uge_sum > 1) 4417 allow_usage(un, B_FALSE, 4418 gettext("-u, -g, and -e are mutually exclusive\n")); 4419 4420 if (opts->prt_usage) 4421 if (argc == 0 && all_sum == 0) 4422 allow_usage(un, B_TRUE, NULL); 4423 else 4424 usage(B_FALSE); 4425 4426 if (opts->set) { 4427 if (csuge_sum > 1) 4428 allow_usage(un, B_FALSE, 4429 gettext("invalid options combined with -s\n")); 4430 4431 opts->dataset = munge_args(argc, argv, un, 3, &opts->perms); 4432 if (argv[0][0] != '@') 4433 allow_usage(un, B_FALSE, 4434 gettext("invalid set name: missing '@' prefix\n")); 4435 opts->who = argv[0]; 4436 } else if (opts->create) { 4437 if (ldcsuge_sum > 1) 4438 allow_usage(un, B_FALSE, 4439 gettext("invalid options combined with -c\n")); 4440 opts->dataset = munge_args(argc, argv, un, 2, &opts->perms); 4441 } else if (opts->everyone) { 4442 if (csuge_sum > 1) 4443 allow_usage(un, B_FALSE, 4444 gettext("invalid options combined with -e\n")); 4445 opts->dataset = munge_args(argc, argv, un, 2, &opts->perms); 4446 } else if (uge_sum == 0 && argc > 0 && strcmp(argv[0], "everyone") 4447 == 0) { 4448 opts->everyone = B_TRUE; 4449 argc--; 4450 argv++; 4451 opts->dataset = munge_args(argc, argv, un, 2, &opts->perms); 4452 } else if (argc == 1) { 4453 opts->prt_perms = B_TRUE; 4454 opts->dataset = argv[argc-1]; 4455 } else { 4456 opts->dataset = munge_args(argc, argv, un, 3, &opts->perms); 4457 opts->who = argv[0]; 4458 } 4459 4460 if (!opts->local && !opts->descend) { 4461 opts->local = B_TRUE; 4462 opts->descend = B_TRUE; 4463 } 4464 } 4465 4466 static void 4467 store_allow_perm(zfs_deleg_who_type_t type, boolean_t local, boolean_t descend, 4468 const char *who, char *perms, nvlist_t *top_nvl) 4469 { 4470 int i; 4471 char ld[2] = { '\0', '\0' }; 4472 char who_buf[ZFS_MAXNAMELEN+32]; 4473 char base_type; 4474 char set_type; 4475 nvlist_t *base_nvl = NULL; 4476 nvlist_t *set_nvl = NULL; 4477 nvlist_t *nvl; 4478 4479 if (nvlist_alloc(&base_nvl, NV_UNIQUE_NAME, 0) != 0) 4480 nomem(); 4481 if (nvlist_alloc(&set_nvl, NV_UNIQUE_NAME, 0) != 0) 4482 nomem(); 4483 4484 switch (type) { 4485 case ZFS_DELEG_NAMED_SET_SETS: 4486 case ZFS_DELEG_NAMED_SET: 4487 set_type = ZFS_DELEG_NAMED_SET_SETS; 4488 base_type = ZFS_DELEG_NAMED_SET; 4489 ld[0] = ZFS_DELEG_NA; 4490 break; 4491 case ZFS_DELEG_CREATE_SETS: 4492 case ZFS_DELEG_CREATE: 4493 set_type = ZFS_DELEG_CREATE_SETS; 4494 base_type = ZFS_DELEG_CREATE; 4495 ld[0] = ZFS_DELEG_NA; 4496 break; 4497 case ZFS_DELEG_USER_SETS: 4498 case ZFS_DELEG_USER: 4499 set_type = ZFS_DELEG_USER_SETS; 4500 base_type = ZFS_DELEG_USER; 4501 if (local) 4502 ld[0] = ZFS_DELEG_LOCAL; 4503 if (descend) 4504 ld[1] = ZFS_DELEG_DESCENDENT; 4505 break; 4506 case ZFS_DELEG_GROUP_SETS: 4507 case ZFS_DELEG_GROUP: 4508 set_type = ZFS_DELEG_GROUP_SETS; 4509 base_type = ZFS_DELEG_GROUP; 4510 if (local) 4511 ld[0] = ZFS_DELEG_LOCAL; 4512 if (descend) 4513 ld[1] = ZFS_DELEG_DESCENDENT; 4514 break; 4515 case ZFS_DELEG_EVERYONE_SETS: 4516 case ZFS_DELEG_EVERYONE: 4517 set_type = ZFS_DELEG_EVERYONE_SETS; 4518 base_type = ZFS_DELEG_EVERYONE; 4519 if (local) 4520 ld[0] = ZFS_DELEG_LOCAL; 4521 if (descend) 4522 ld[1] = ZFS_DELEG_DESCENDENT; 4523 } 4524 4525 if (perms != NULL) { 4526 char *curr = perms; 4527 char *end = curr + strlen(perms); 4528 4529 while (curr < end) { 4530 char *delim = strchr(curr, ','); 4531 if (delim == NULL) 4532 delim = end; 4533 else 4534 *delim = '\0'; 4535 4536 if (curr[0] == '@') 4537 nvl = set_nvl; 4538 else 4539 nvl = base_nvl; 4540 4541 (void) nvlist_add_boolean(nvl, curr); 4542 if (delim != end) 4543 *delim = ','; 4544 curr = delim + 1; 4545 } 4546 4547 for (i = 0; i < 2; i++) { 4548 char locality = ld[i]; 4549 if (locality == 0) 4550 continue; 4551 4552 if (!nvlist_empty(base_nvl)) { 4553 if (who != NULL) 4554 (void) snprintf(who_buf, 4555 sizeof (who_buf), "%c%c$%s", 4556 base_type, locality, who); 4557 else 4558 (void) snprintf(who_buf, 4559 sizeof (who_buf), "%c%c$", 4560 base_type, locality); 4561 4562 (void) nvlist_add_nvlist(top_nvl, who_buf, 4563 base_nvl); 4564 } 4565 4566 4567 if (!nvlist_empty(set_nvl)) { 4568 if (who != NULL) 4569 (void) snprintf(who_buf, 4570 sizeof (who_buf), "%c%c$%s", 4571 set_type, locality, who); 4572 else 4573 (void) snprintf(who_buf, 4574 sizeof (who_buf), "%c%c$", 4575 set_type, locality); 4576 4577 (void) nvlist_add_nvlist(top_nvl, who_buf, 4578 set_nvl); 4579 } 4580 } 4581 } else { 4582 for (i = 0; i < 2; i++) { 4583 char locality = ld[i]; 4584 if (locality == 0) 4585 continue; 4586 4587 if (who != NULL) 4588 (void) snprintf(who_buf, sizeof (who_buf), 4589 "%c%c$%s", base_type, locality, who); 4590 else 4591 (void) snprintf(who_buf, sizeof (who_buf), 4592 "%c%c$", base_type, locality); 4593 (void) nvlist_add_boolean(top_nvl, who_buf); 4594 4595 if (who != NULL) 4596 (void) snprintf(who_buf, sizeof (who_buf), 4597 "%c%c$%s", set_type, locality, who); 4598 else 4599 (void) snprintf(who_buf, sizeof (who_buf), 4600 "%c%c$", set_type, locality); 4601 (void) nvlist_add_boolean(top_nvl, who_buf); 4602 } 4603 } 4604 } 4605 4606 static int 4607 construct_fsacl_list(boolean_t un, struct allow_opts *opts, nvlist_t **nvlp) 4608 { 4609 if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) 4610 nomem(); 4611 4612 if (opts->set) { 4613 store_allow_perm(ZFS_DELEG_NAMED_SET, opts->local, 4614 opts->descend, opts->who, opts->perms, *nvlp); 4615 } else if (opts->create) { 4616 store_allow_perm(ZFS_DELEG_CREATE, opts->local, 4617 opts->descend, NULL, opts->perms, *nvlp); 4618 } else if (opts->everyone) { 4619 store_allow_perm(ZFS_DELEG_EVERYONE, opts->local, 4620 opts->descend, NULL, opts->perms, *nvlp); 4621 } else { 4622 char *curr = opts->who; 4623 char *end = curr + strlen(curr); 4624 4625 while (curr < end) { 4626 const char *who; 4627 zfs_deleg_who_type_t who_type; 4628 char *endch; 4629 char *delim = strchr(curr, ','); 4630 char errbuf[256]; 4631 char id[64]; 4632 struct passwd *p = NULL; 4633 struct group *g = NULL; 4634 4635 uid_t rid; 4636 if (delim == NULL) 4637 delim = end; 4638 else 4639 *delim = '\0'; 4640 4641 rid = (uid_t)strtol(curr, &endch, 0); 4642 if (opts->user) { 4643 who_type = ZFS_DELEG_USER; 4644 if (*endch != '\0') 4645 p = getpwnam(curr); 4646 else 4647 p = getpwuid(rid); 4648 4649 if (p != NULL) 4650 rid = p->pw_uid; 4651 else { 4652 (void) snprintf(errbuf, 256, gettext( 4653 "invalid user %s"), curr); 4654 allow_usage(un, B_TRUE, errbuf); 4655 } 4656 } else if (opts->group) { 4657 who_type = ZFS_DELEG_GROUP; 4658 if (*endch != '\0') 4659 g = getgrnam(curr); 4660 else 4661 g = getgrgid(rid); 4662 4663 if (g != NULL) 4664 rid = g->gr_gid; 4665 else { 4666 (void) snprintf(errbuf, 256, gettext( 4667 "invalid group %s"), curr); 4668 allow_usage(un, B_TRUE, errbuf); 4669 } 4670 } else { 4671 if (*endch != '\0') { 4672 p = getpwnam(curr); 4673 } else { 4674 p = getpwuid(rid); 4675 } 4676 4677 if (p == NULL) 4678 if (*endch != '\0') { 4679 g = getgrnam(curr); 4680 } else { 4681 g = getgrgid(rid); 4682 } 4683 4684 if (p != NULL) { 4685 who_type = ZFS_DELEG_USER; 4686 rid = p->pw_uid; 4687 } else if (g != NULL) { 4688 who_type = ZFS_DELEG_GROUP; 4689 rid = g->gr_gid; 4690 } else { 4691 (void) snprintf(errbuf, 256, gettext( 4692 "invalid user/group %s"), curr); 4693 allow_usage(un, B_TRUE, errbuf); 4694 } 4695 } 4696 4697 (void) sprintf(id, "%u", rid); 4698 who = id; 4699 4700 store_allow_perm(who_type, opts->local, 4701 opts->descend, who, opts->perms, *nvlp); 4702 curr = delim + 1; 4703 } 4704 } 4705 4706 return (0); 4707 } 4708 4709 static void 4710 print_set_creat_perms(uu_avl_t *who_avl) 4711 { 4712 const char *sc_title[] = { 4713 gettext("Permission sets:\n"), 4714 gettext("Create time permissions:\n"), 4715 NULL 4716 }; 4717 const char **title_ptr = sc_title; 4718 who_perm_node_t *who_node = NULL; 4719 int prev_weight = -1; 4720 4721 for (who_node = uu_avl_first(who_avl); who_node != NULL; 4722 who_node = uu_avl_next(who_avl, who_node)) { 4723 uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl; 4724 zfs_deleg_who_type_t who_type = who_node->who_perm.who_type; 4725 const char *who_name = who_node->who_perm.who_name; 4726 int weight = who_type2weight(who_type); 4727 boolean_t first = B_TRUE; 4728 deleg_perm_node_t *deleg_node; 4729 4730 if (prev_weight != weight) { 4731 (void) printf(*title_ptr++); 4732 prev_weight = weight; 4733 } 4734 4735 if (who_name == NULL || strnlen(who_name, 1) == 0) 4736 (void) printf("\t"); 4737 else 4738 (void) printf("\t%s ", who_name); 4739 4740 for (deleg_node = uu_avl_first(avl); deleg_node != NULL; 4741 deleg_node = uu_avl_next(avl, deleg_node)) { 4742 if (first) { 4743 (void) printf("%s", 4744 deleg_node->dpn_perm.dp_name); 4745 first = B_FALSE; 4746 } else 4747 (void) printf(",%s", 4748 deleg_node->dpn_perm.dp_name); 4749 } 4750 4751 (void) printf("\n"); 4752 } 4753 } 4754 4755 static void inline 4756 print_uge_deleg_perms(uu_avl_t *who_avl, boolean_t local, boolean_t descend, 4757 const char *title) 4758 { 4759 who_perm_node_t *who_node = NULL; 4760 boolean_t prt_title = B_TRUE; 4761 uu_avl_walk_t *walk; 4762 4763 if ((walk = uu_avl_walk_start(who_avl, UU_WALK_ROBUST)) == NULL) 4764 nomem(); 4765 4766 while ((who_node = uu_avl_walk_next(walk)) != NULL) { 4767 const char *who_name = who_node->who_perm.who_name; 4768 const char *nice_who_name = who_node->who_perm.who_ug_name; 4769 uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl; 4770 zfs_deleg_who_type_t who_type = who_node->who_perm.who_type; 4771 char delim = ' '; 4772 deleg_perm_node_t *deleg_node; 4773 boolean_t prt_who = B_TRUE; 4774 4775 for (deleg_node = uu_avl_first(avl); 4776 deleg_node != NULL; 4777 deleg_node = uu_avl_next(avl, deleg_node)) { 4778 if (local != deleg_node->dpn_perm.dp_local || 4779 descend != deleg_node->dpn_perm.dp_descend) 4780 continue; 4781 4782 if (prt_who) { 4783 const char *who = NULL; 4784 if (prt_title) { 4785 prt_title = B_FALSE; 4786 (void) printf(title); 4787 } 4788 4789 switch (who_type) { 4790 case ZFS_DELEG_USER_SETS: 4791 case ZFS_DELEG_USER: 4792 who = gettext("user"); 4793 if (nice_who_name) 4794 who_name = nice_who_name; 4795 break; 4796 case ZFS_DELEG_GROUP_SETS: 4797 case ZFS_DELEG_GROUP: 4798 who = gettext("group"); 4799 if (nice_who_name) 4800 who_name = nice_who_name; 4801 break; 4802 case ZFS_DELEG_EVERYONE_SETS: 4803 case ZFS_DELEG_EVERYONE: 4804 who = gettext("everyone"); 4805 who_name = NULL; 4806 } 4807 4808 prt_who = B_FALSE; 4809 if (who_name == NULL) 4810 (void) printf("\t%s", who); 4811 else 4812 (void) printf("\t%s %s", who, who_name); 4813 } 4814 4815 (void) printf("%c%s", delim, 4816 deleg_node->dpn_perm.dp_name); 4817 delim = ','; 4818 } 4819 4820 if (!prt_who) 4821 (void) printf("\n"); 4822 } 4823 4824 uu_avl_walk_end(walk); 4825 } 4826 4827 static void 4828 print_fs_perms(fs_perm_set_t *fspset) 4829 { 4830 fs_perm_node_t *node = NULL; 4831 char buf[ZFS_MAXNAMELEN+32]; 4832 const char *dsname = buf; 4833 4834 for (node = uu_list_first(fspset->fsps_list); node != NULL; 4835 node = uu_list_next(fspset->fsps_list, node)) { 4836 uu_avl_t *sc_avl = node->fspn_fsperm.fsp_sc_avl; 4837 uu_avl_t *uge_avl = node->fspn_fsperm.fsp_uge_avl; 4838 int left = 0; 4839 4840 (void) snprintf(buf, ZFS_MAXNAMELEN+32, 4841 gettext("---- Permissions on %s "), 4842 node->fspn_fsperm.fsp_name); 4843 (void) printf(dsname); 4844 left = 70 - strlen(buf); 4845 while (left-- > 0) 4846 (void) printf("-"); 4847 (void) printf("\n"); 4848 4849 print_set_creat_perms(sc_avl); 4850 print_uge_deleg_perms(uge_avl, B_TRUE, B_FALSE, 4851 gettext("Local permissions:\n")); 4852 print_uge_deleg_perms(uge_avl, B_FALSE, B_TRUE, 4853 gettext("Descendent permissions:\n")); 4854 print_uge_deleg_perms(uge_avl, B_TRUE, B_TRUE, 4855 gettext("Local+Descendent permissions:\n")); 4856 } 4857 } 4858 4859 static fs_perm_set_t fs_perm_set = { NULL, NULL, NULL, NULL }; 4860 4861 struct deleg_perms { 4862 boolean_t un; 4863 nvlist_t *nvl; 4864 }; 4865 4866 static int 4867 set_deleg_perms(zfs_handle_t *zhp, void *data) 4868 { 4869 struct deleg_perms *perms = (struct deleg_perms *)data; 4870 zfs_type_t zfs_type = zfs_get_type(zhp); 4871 4872 if (zfs_type != ZFS_TYPE_FILESYSTEM && zfs_type != ZFS_TYPE_VOLUME) 4873 return (0); 4874 4875 return (zfs_set_fsacl(zhp, perms->un, perms->nvl)); 4876 } 4877 4878 static int 4879 zfs_do_allow_unallow_impl(int argc, char **argv, boolean_t un) 4880 { 4881 zfs_handle_t *zhp; 4882 nvlist_t *perm_nvl = NULL; 4883 nvlist_t *update_perm_nvl = NULL; 4884 int error = 1; 4885 int c; 4886 struct allow_opts opts = { 0 }; 4887 4888 const char *optstr = un ? "ldugecsrh" : "ldugecsh"; 4889 4890 /* check opts */ 4891 while ((c = getopt(argc, argv, optstr)) != -1) { 4892 switch (c) { 4893 case 'l': 4894 opts.local = B_TRUE; 4895 break; 4896 case 'd': 4897 opts.descend = B_TRUE; 4898 break; 4899 case 'u': 4900 opts.user = B_TRUE; 4901 break; 4902 case 'g': 4903 opts.group = B_TRUE; 4904 break; 4905 case 'e': 4906 opts.everyone = B_TRUE; 4907 break; 4908 case 's': 4909 opts.set = B_TRUE; 4910 break; 4911 case 'c': 4912 opts.create = B_TRUE; 4913 break; 4914 case 'r': 4915 opts.recursive = B_TRUE; 4916 break; 4917 case ':': 4918 (void) fprintf(stderr, gettext("missing argument for " 4919 "'%c' option\n"), optopt); 4920 usage(B_FALSE); 4921 break; 4922 case 'h': 4923 opts.prt_usage = B_TRUE; 4924 break; 4925 case '?': 4926 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4927 optopt); 4928 usage(B_FALSE); 4929 } 4930 } 4931 4932 argc -= optind; 4933 argv += optind; 4934 4935 /* check arguments */ 4936 parse_allow_args(argc, argv, un, &opts); 4937 4938 /* try to open the dataset */ 4939 if ((zhp = zfs_open(g_zfs, opts.dataset, ZFS_TYPE_FILESYSTEM)) 4940 == NULL) { 4941 (void) fprintf(stderr, "Failed to open Dataset *%s*\n", 4942 opts.dataset); 4943 return (-1); 4944 } 4945 4946 if (zfs_get_fsacl(zhp, &perm_nvl) != 0) 4947 goto cleanup2; 4948 4949 fs_perm_set_init(&fs_perm_set); 4950 if (parse_fs_perm_set(&fs_perm_set, perm_nvl) != 0) { 4951 (void) fprintf(stderr, "Failed to parse fsacl permissionsn"); 4952 goto cleanup1; 4953 } 4954 4955 if (opts.prt_perms) 4956 print_fs_perms(&fs_perm_set); 4957 else { 4958 (void) construct_fsacl_list(un, &opts, &update_perm_nvl); 4959 if (zfs_set_fsacl(zhp, un, update_perm_nvl) != 0) 4960 goto cleanup0; 4961 4962 if (un && opts.recursive) { 4963 struct deleg_perms data = { un, update_perm_nvl }; 4964 if (zfs_iter_filesystems(zhp, set_deleg_perms, 4965 &data) != 0) 4966 goto cleanup0; 4967 } 4968 } 4969 4970 error = 0; 4971 4972 cleanup0: 4973 nvlist_free(perm_nvl); 4974 if (update_perm_nvl != NULL) 4975 nvlist_free(update_perm_nvl); 4976 cleanup1: 4977 fs_perm_set_fini(&fs_perm_set); 4978 cleanup2: 4979 zfs_close(zhp); 4980 4981 return (error); 4982 } 4983 4984 /* 4985 * zfs allow [-r] [-t] <tag> <snap> ... 4986 * 4987 * -r Recursively hold 4988 * -t Temporary hold (hidden option) 4989 * 4990 * Apply a user-hold with the given tag to the list of snapshots. 4991 */ 4992 static int 4993 zfs_do_allow(int argc, char **argv) 4994 { 4995 return (zfs_do_allow_unallow_impl(argc, argv, B_FALSE)); 4996 } 4997 4998 /* 4999 * zfs unallow [-r] [-t] <tag> <snap> ... 5000 * 5001 * -r Recursively hold 5002 * -t Temporary hold (hidden option) 5003 * 5004 * Apply a user-hold with the given tag to the list of snapshots. 5005 */ 5006 static int 5007 zfs_do_unallow(int argc, char **argv) 5008 { 5009 return (zfs_do_allow_unallow_impl(argc, argv, B_TRUE)); 5010 } 5011 5012 static int 5013 zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding) 5014 { 5015 int errors = 0; 5016 int i; 5017 const char *tag; 5018 boolean_t recursive = B_FALSE; 5019 boolean_t temphold = B_FALSE; 5020 const char *opts = holding ? "rt" : "r"; 5021 int c; 5022 5023 /* check options */ 5024 while ((c = getopt(argc, argv, opts)) != -1) { 5025 switch (c) { 5026 case 'r': 5027 recursive = B_TRUE; 5028 break; 5029 case 't': 5030 temphold = B_TRUE; 5031 break; 5032 case '?': 5033 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5034 optopt); 5035 usage(B_FALSE); 5036 } 5037 } 5038 5039 argc -= optind; 5040 argv += optind; 5041 5042 /* check number of arguments */ 5043 if (argc < 2) 5044 usage(B_FALSE); 5045 5046 tag = argv[0]; 5047 --argc; 5048 ++argv; 5049 5050 if (holding && tag[0] == '.') { 5051 /* tags starting with '.' are reserved for libzfs */ 5052 (void) fprintf(stderr, gettext("tag may not start with '.'\n")); 5053 usage(B_FALSE); 5054 } 5055 5056 for (i = 0; i < argc; ++i) { 5057 zfs_handle_t *zhp; 5058 char parent[ZFS_MAXNAMELEN]; 5059 const char *delim; 5060 char *path = argv[i]; 5061 5062 delim = strchr(path, '@'); 5063 if (delim == NULL) { 5064 (void) fprintf(stderr, 5065 gettext("'%s' is not a snapshot\n"), path); 5066 ++errors; 5067 continue; 5068 } 5069 (void) strncpy(parent, path, delim - path); 5070 parent[delim - path] = '\0'; 5071 5072 zhp = zfs_open(g_zfs, parent, 5073 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 5074 if (zhp == NULL) { 5075 ++errors; 5076 continue; 5077 } 5078 if (holding) { 5079 if (zfs_hold(zhp, delim+1, tag, recursive, 5080 temphold, B_FALSE, -1, 0, 0) != 0) 5081 ++errors; 5082 } else { 5083 if (zfs_release(zhp, delim+1, tag, recursive) != 0) 5084 ++errors; 5085 } 5086 zfs_close(zhp); 5087 } 5088 5089 return (errors != 0); 5090 } 5091 5092 /* 5093 * zfs hold [-r] [-t] <tag> <snap> ... 5094 * 5095 * -r Recursively hold 5096 * -t Temporary hold (hidden option) 5097 * 5098 * Apply a user-hold with the given tag to the list of snapshots. 5099 */ 5100 static int 5101 zfs_do_hold(int argc, char **argv) 5102 { 5103 return (zfs_do_hold_rele_impl(argc, argv, B_TRUE)); 5104 } 5105 5106 /* 5107 * zfs release [-r] <tag> <snap> ... 5108 * 5109 * -r Recursively release 5110 * 5111 * Release a user-hold with the given tag from the list of snapshots. 5112 */ 5113 static int 5114 zfs_do_release(int argc, char **argv) 5115 { 5116 return (zfs_do_hold_rele_impl(argc, argv, B_FALSE)); 5117 } 5118 5119 typedef struct holds_cbdata { 5120 boolean_t cb_recursive; 5121 const char *cb_snapname; 5122 nvlist_t **cb_nvlp; 5123 size_t cb_max_namelen; 5124 size_t cb_max_taglen; 5125 } holds_cbdata_t; 5126 5127 #define STRFTIME_FMT_STR "%a %b %e %k:%M %Y" 5128 #define DATETIME_BUF_LEN (32) 5129 /* 5130 * 5131 */ 5132 static void 5133 print_holds(boolean_t scripted, size_t nwidth, size_t tagwidth, nvlist_t *nvl) 5134 { 5135 int i; 5136 nvpair_t *nvp = NULL; 5137 char *hdr_cols[] = { "NAME", "TAG", "TIMESTAMP" }; 5138 const char *col; 5139 5140 if (!scripted) { 5141 for (i = 0; i < 3; i++) { 5142 col = gettext(hdr_cols[i]); 5143 if (i < 2) 5144 (void) printf("%-*s ", i ? tagwidth : nwidth, 5145 col); 5146 else 5147 (void) printf("%s\n", col); 5148 } 5149 } 5150 5151 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 5152 char *zname = nvpair_name(nvp); 5153 nvlist_t *nvl2; 5154 nvpair_t *nvp2 = NULL; 5155 (void) nvpair_value_nvlist(nvp, &nvl2); 5156 while ((nvp2 = nvlist_next_nvpair(nvl2, nvp2)) != NULL) { 5157 char tsbuf[DATETIME_BUF_LEN]; 5158 char *tagname = nvpair_name(nvp2); 5159 uint64_t val = 0; 5160 time_t time; 5161 struct tm t; 5162 char sep = scripted ? '\t' : ' '; 5163 size_t sepnum = scripted ? 1 : 2; 5164 5165 (void) nvpair_value_uint64(nvp2, &val); 5166 time = (time_t)val; 5167 (void) localtime_r(&time, &t); 5168 (void) strftime(tsbuf, DATETIME_BUF_LEN, 5169 gettext(STRFTIME_FMT_STR), &t); 5170 5171 (void) printf("%-*s%*c%-*s%*c%s\n", nwidth, zname, 5172 sepnum, sep, tagwidth, tagname, sepnum, sep, tsbuf); 5173 } 5174 } 5175 } 5176 5177 /* 5178 * Generic callback function to list a dataset or snapshot. 5179 */ 5180 static int 5181 holds_callback(zfs_handle_t *zhp, void *data) 5182 { 5183 holds_cbdata_t *cbp = data; 5184 nvlist_t *top_nvl = *cbp->cb_nvlp; 5185 nvlist_t *nvl = NULL; 5186 nvpair_t *nvp = NULL; 5187 const char *zname = zfs_get_name(zhp); 5188 size_t znamelen = strnlen(zname, ZFS_MAXNAMELEN); 5189 5190 if (cbp->cb_recursive) { 5191 const char *snapname; 5192 char *delim = strchr(zname, '@'); 5193 if (delim == NULL) 5194 return (0); 5195 5196 snapname = delim + 1; 5197 if (strcmp(cbp->cb_snapname, snapname)) 5198 return (0); 5199 } 5200 5201 if (zfs_get_holds(zhp, &nvl) != 0) 5202 return (-1); 5203 5204 if (znamelen > cbp->cb_max_namelen) 5205 cbp->cb_max_namelen = znamelen; 5206 5207 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 5208 const char *tag = nvpair_name(nvp); 5209 size_t taglen = strnlen(tag, MAXNAMELEN); 5210 if (taglen > cbp->cb_max_taglen) 5211 cbp->cb_max_taglen = taglen; 5212 } 5213 5214 return (nvlist_add_nvlist(top_nvl, zname, nvl)); 5215 } 5216 5217 /* 5218 * zfs holds [-r] <snap> ... 5219 * 5220 * -r Recursively hold 5221 */ 5222 static int 5223 zfs_do_holds(int argc, char **argv) 5224 { 5225 int errors = 0; 5226 int c; 5227 int i; 5228 boolean_t scripted = B_FALSE; 5229 boolean_t recursive = B_FALSE; 5230 const char *opts = "rH"; 5231 nvlist_t *nvl; 5232 5233 int types = ZFS_TYPE_SNAPSHOT; 5234 holds_cbdata_t cb = { 0 }; 5235 5236 int limit = 0; 5237 int ret; 5238 int flags = 0; 5239 5240 /* check options */ 5241 while ((c = getopt(argc, argv, opts)) != -1) { 5242 switch (c) { 5243 case 'r': 5244 recursive = B_TRUE; 5245 break; 5246 case 'H': 5247 scripted = B_TRUE; 5248 break; 5249 case '?': 5250 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5251 optopt); 5252 usage(B_FALSE); 5253 } 5254 } 5255 5256 if (recursive) { 5257 types |= ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME; 5258 flags |= ZFS_ITER_RECURSE; 5259 } 5260 5261 argc -= optind; 5262 argv += optind; 5263 5264 /* check number of arguments */ 5265 if (argc < 1) 5266 usage(B_FALSE); 5267 5268 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 5269 nomem(); 5270 5271 for (i = 0; i < argc; ++i) { 5272 char *snapshot = argv[i]; 5273 const char *delim; 5274 const char *snapname; 5275 5276 delim = strchr(snapshot, '@'); 5277 if (delim == NULL) { 5278 (void) fprintf(stderr, 5279 gettext("'%s' is not a snapshot\n"), snapshot); 5280 ++errors; 5281 continue; 5282 } 5283 snapname = delim + 1; 5284 if (recursive) 5285 snapshot[delim - snapshot] = '\0'; 5286 5287 cb.cb_recursive = recursive; 5288 cb.cb_snapname = snapname; 5289 cb.cb_nvlp = &nvl; 5290 5291 /* 5292 * 1. collect holds data, set format options 5293 */ 5294 ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit, 5295 holds_callback, &cb); 5296 if (ret != 0) 5297 ++errors; 5298 } 5299 5300 /* 5301 * 2. print holds data 5302 */ 5303 print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl); 5304 5305 if (nvlist_empty(nvl)) 5306 (void) printf(gettext("no datasets available\n")); 5307 5308 nvlist_free(nvl); 5309 5310 return (0 != errors); 5311 } 5312 5313 #define CHECK_SPINNER 30 5314 #define SPINNER_TIME 3 /* seconds */ 5315 #define MOUNT_TIME 5 /* seconds */ 5316 5317 static int 5318 get_one_dataset(zfs_handle_t *zhp, void *data) 5319 { 5320 static char *spin[] = { "-", "\\", "|", "/" }; 5321 static int spinval = 0; 5322 static int spincheck = 0; 5323 static time_t last_spin_time = (time_t)0; 5324 get_all_cb_t *cbp = data; 5325 zfs_type_t type = zfs_get_type(zhp); 5326 5327 if (cbp->cb_verbose) { 5328 if (--spincheck < 0) { 5329 time_t now = time(NULL); 5330 if (last_spin_time + SPINNER_TIME < now) { 5331 update_progress(spin[spinval++ % 4]); 5332 last_spin_time = now; 5333 } 5334 spincheck = CHECK_SPINNER; 5335 } 5336 } 5337 5338 /* 5339 * Interate over any nested datasets. 5340 */ 5341 if (zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) { 5342 zfs_close(zhp); 5343 return (1); 5344 } 5345 5346 /* 5347 * Skip any datasets whose type does not match. 5348 */ 5349 if ((type & ZFS_TYPE_FILESYSTEM) == 0) { 5350 zfs_close(zhp); 5351 return (0); 5352 } 5353 libzfs_add_handle(cbp, zhp); 5354 assert(cbp->cb_used <= cbp->cb_alloc); 5355 5356 return (0); 5357 } 5358 5359 static void 5360 get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose) 5361 { 5362 get_all_cb_t cb = { 0 }; 5363 cb.cb_verbose = verbose; 5364 cb.cb_getone = get_one_dataset; 5365 5366 if (verbose) 5367 set_progress_header(gettext("Reading ZFS config")); 5368 (void) zfs_iter_root(g_zfs, get_one_dataset, &cb); 5369 5370 *dslist = cb.cb_handles; 5371 *count = cb.cb_used; 5372 5373 if (verbose) 5374 finish_progress(gettext("done.")); 5375 } 5376 5377 /* 5378 * Generic callback for sharing or mounting filesystems. Because the code is so 5379 * similar, we have a common function with an extra parameter to determine which 5380 * mode we are using. 5381 */ 5382 #define OP_SHARE 0x1 5383 #define OP_MOUNT 0x2 5384 5385 /* 5386 * Share or mount a dataset. 5387 */ 5388 static int 5389 share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol, 5390 boolean_t explicit, const char *options) 5391 { 5392 char mountpoint[ZFS_MAXPROPLEN]; 5393 char shareopts[ZFS_MAXPROPLEN]; 5394 char smbshareopts[ZFS_MAXPROPLEN]; 5395 const char *cmdname = op == OP_SHARE ? "share" : "mount"; 5396 struct mnttab mnt; 5397 uint64_t zoned, canmount; 5398 boolean_t shared_nfs, shared_smb; 5399 5400 assert(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM); 5401 5402 /* 5403 * Check to make sure we can mount/share this dataset. If we 5404 * are in the global zone and the filesystem is exported to a 5405 * local zone, or if we are in a local zone and the 5406 * filesystem is not exported, then it is an error. 5407 */ 5408 zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 5409 5410 if (zoned && getzoneid() == GLOBAL_ZONEID) { 5411 if (!explicit) 5412 return (0); 5413 5414 (void) fprintf(stderr, gettext("cannot %s '%s': " 5415 "dataset is exported to a local zone\n"), cmdname, 5416 zfs_get_name(zhp)); 5417 return (1); 5418 5419 } else if (!zoned && getzoneid() != GLOBAL_ZONEID) { 5420 if (!explicit) 5421 return (0); 5422 5423 (void) fprintf(stderr, gettext("cannot %s '%s': " 5424 "permission denied\n"), cmdname, 5425 zfs_get_name(zhp)); 5426 return (1); 5427 } 5428 5429 /* 5430 * Ignore any filesystems which don't apply to us. This 5431 * includes those with a legacy mountpoint, or those with 5432 * legacy share options. 5433 */ 5434 verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 5435 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0); 5436 verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, 5437 sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); 5438 verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts, 5439 sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0); 5440 5441 if (op == OP_SHARE && strcmp(shareopts, "off") == 0 && 5442 strcmp(smbshareopts, "off") == 0) { 5443 if (!explicit) 5444 return (0); 5445 5446 (void) fprintf(stderr, gettext("cannot share '%s': " 5447 "legacy share\n"), zfs_get_name(zhp)); 5448 (void) fprintf(stderr, gettext("use share(1M) to " 5449 "share this filesystem, or set " 5450 "sharenfs property on\n")); 5451 return (1); 5452 } 5453 5454 /* 5455 * We cannot share or mount legacy filesystems. If the 5456 * shareopts is non-legacy but the mountpoint is legacy, we 5457 * treat it as a legacy share. 5458 */ 5459 if (strcmp(mountpoint, "legacy") == 0) { 5460 if (!explicit) 5461 return (0); 5462 5463 (void) fprintf(stderr, gettext("cannot %s '%s': " 5464 "legacy mountpoint\n"), cmdname, zfs_get_name(zhp)); 5465 (void) fprintf(stderr, gettext("use %s(1M) to " 5466 "%s this filesystem\n"), cmdname, cmdname); 5467 return (1); 5468 } 5469 5470 if (strcmp(mountpoint, "none") == 0) { 5471 if (!explicit) 5472 return (0); 5473 5474 (void) fprintf(stderr, gettext("cannot %s '%s': no " 5475 "mountpoint set\n"), cmdname, zfs_get_name(zhp)); 5476 return (1); 5477 } 5478 5479 /* 5480 * canmount explicit outcome 5481 * on no pass through 5482 * on yes pass through 5483 * off no return 0 5484 * off yes display error, return 1 5485 * noauto no return 0 5486 * noauto yes pass through 5487 */ 5488 canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT); 5489 if (canmount == ZFS_CANMOUNT_OFF) { 5490 if (!explicit) 5491 return (0); 5492 5493 (void) fprintf(stderr, gettext("cannot %s '%s': " 5494 "'canmount' property is set to 'off'\n"), cmdname, 5495 zfs_get_name(zhp)); 5496 return (1); 5497 } else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) { 5498 return (0); 5499 } 5500 5501 /* 5502 * At this point, we have verified that the mountpoint and/or 5503 * shareopts are appropriate for auto management. If the 5504 * filesystem is already mounted or shared, return (failing 5505 * for explicit requests); otherwise mount or share the 5506 * filesystem. 5507 */ 5508 switch (op) { 5509 case OP_SHARE: 5510 5511 shared_nfs = zfs_is_shared_nfs(zhp, NULL); 5512 shared_smb = zfs_is_shared_smb(zhp, NULL); 5513 5514 if (shared_nfs && shared_smb || 5515 (shared_nfs && strcmp(shareopts, "on") == 0 && 5516 strcmp(smbshareopts, "off") == 0) || 5517 (shared_smb && strcmp(smbshareopts, "on") == 0 && 5518 strcmp(shareopts, "off") == 0)) { 5519 if (!explicit) 5520 return (0); 5521 5522 (void) fprintf(stderr, gettext("cannot share " 5523 "'%s': filesystem already shared\n"), 5524 zfs_get_name(zhp)); 5525 return (1); 5526 } 5527 5528 if (!zfs_is_mounted(zhp, NULL) && 5529 zfs_mount(zhp, NULL, 0) != 0) 5530 return (1); 5531 5532 if (protocol == NULL) { 5533 if (zfs_shareall(zhp) != 0) 5534 return (1); 5535 } else if (strcmp(protocol, "nfs") == 0) { 5536 if (zfs_share_nfs(zhp)) 5537 return (1); 5538 } else if (strcmp(protocol, "smb") == 0) { 5539 if (zfs_share_smb(zhp)) 5540 return (1); 5541 } else { 5542 (void) fprintf(stderr, gettext("cannot share " 5543 "'%s': invalid share type '%s' " 5544 "specified\n"), 5545 zfs_get_name(zhp), protocol); 5546 return (1); 5547 } 5548 5549 break; 5550 5551 case OP_MOUNT: 5552 if (options == NULL) 5553 mnt.mnt_mntopts = ""; 5554 else 5555 mnt.mnt_mntopts = (char *)options; 5556 5557 if (!hasmntopt(&mnt, MNTOPT_REMOUNT) && 5558 zfs_is_mounted(zhp, NULL)) { 5559 if (!explicit) 5560 return (0); 5561 5562 (void) fprintf(stderr, gettext("cannot mount " 5563 "'%s': filesystem already mounted\n"), 5564 zfs_get_name(zhp)); 5565 return (1); 5566 } 5567 5568 if (zfs_mount(zhp, options, flags) != 0) 5569 return (1); 5570 break; 5571 } 5572 5573 return (0); 5574 } 5575 5576 /* 5577 * Reports progress in the form "(current/total)". Not thread-safe. 5578 */ 5579 static void 5580 report_mount_progress(int current, int total) 5581 { 5582 static time_t last_progress_time = 0; 5583 time_t now = time(NULL); 5584 char info[32]; 5585 5586 /* report 1..n instead of 0..n-1 */ 5587 ++current; 5588 5589 /* display header if we're here for the first time */ 5590 if (current == 1) { 5591 set_progress_header(gettext("Mounting ZFS filesystems")); 5592 } else if (current != total && last_progress_time + MOUNT_TIME >= now) { 5593 /* too soon to report again */ 5594 return; 5595 } 5596 5597 last_progress_time = now; 5598 5599 (void) sprintf(info, "(%d/%d)", current, total); 5600 5601 if (current == total) 5602 finish_progress(info); 5603 else 5604 update_progress(info); 5605 } 5606 5607 static void 5608 append_options(char *mntopts, char *newopts) 5609 { 5610 int len = strlen(mntopts); 5611 5612 /* original length plus new string to append plus 1 for the comma */ 5613 if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) { 5614 (void) fprintf(stderr, gettext("the opts argument for " 5615 "'%c' option is too long (more than %d chars)\n"), 5616 "-o", MNT_LINE_MAX); 5617 usage(B_FALSE); 5618 } 5619 5620 if (*mntopts) 5621 mntopts[len++] = ','; 5622 5623 (void) strcpy(&mntopts[len], newopts); 5624 } 5625 5626 static int 5627 share_mount(int op, int argc, char **argv) 5628 { 5629 int do_all = 0; 5630 boolean_t verbose = B_FALSE; 5631 int c, ret = 0; 5632 char *options = NULL; 5633 int flags = 0; 5634 5635 /* check options */ 5636 while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:O" : "a")) 5637 != -1) { 5638 switch (c) { 5639 case 'a': 5640 do_all = 1; 5641 break; 5642 case 'v': 5643 verbose = B_TRUE; 5644 break; 5645 case 'o': 5646 if (*optarg == '\0') { 5647 (void) fprintf(stderr, gettext("empty mount " 5648 "options (-o) specified\n")); 5649 usage(B_FALSE); 5650 } 5651 5652 if (options == NULL) 5653 options = safe_malloc(MNT_LINE_MAX + 1); 5654 5655 /* option validation is done later */ 5656 append_options(options, optarg); 5657 break; 5658 5659 case 'O': 5660 flags |= MS_OVERLAY; 5661 break; 5662 case ':': 5663 (void) fprintf(stderr, gettext("missing argument for " 5664 "'%c' option\n"), optopt); 5665 usage(B_FALSE); 5666 break; 5667 case '?': 5668 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5669 optopt); 5670 usage(B_FALSE); 5671 } 5672 } 5673 5674 argc -= optind; 5675 argv += optind; 5676 5677 /* check number of arguments */ 5678 if (do_all) { 5679 zfs_handle_t **dslist = NULL; 5680 size_t i, count = 0; 5681 char *protocol = NULL; 5682 5683 if (op == OP_SHARE && argc > 0) { 5684 if (strcmp(argv[0], "nfs") != 0 && 5685 strcmp(argv[0], "smb") != 0) { 5686 (void) fprintf(stderr, gettext("share type " 5687 "must be 'nfs' or 'smb'\n")); 5688 usage(B_FALSE); 5689 } 5690 protocol = argv[0]; 5691 argc--; 5692 argv++; 5693 } 5694 5695 if (argc != 0) { 5696 (void) fprintf(stderr, gettext("too many arguments\n")); 5697 usage(B_FALSE); 5698 } 5699 5700 start_progress_timer(); 5701 get_all_datasets(&dslist, &count, verbose); 5702 5703 if (count == 0) 5704 return (0); 5705 5706 qsort(dslist, count, sizeof (void *), libzfs_dataset_cmp); 5707 5708 for (i = 0; i < count; i++) { 5709 if (verbose) 5710 report_mount_progress(i, count); 5711 5712 if (share_mount_one(dslist[i], op, flags, protocol, 5713 B_FALSE, options) != 0) 5714 ret = 1; 5715 zfs_close(dslist[i]); 5716 } 5717 5718 free(dslist); 5719 } else if (argc == 0) { 5720 struct mnttab entry; 5721 5722 if ((op == OP_SHARE) || (options != NULL)) { 5723 (void) fprintf(stderr, gettext("missing filesystem " 5724 "argument (specify -a for all)\n")); 5725 usage(B_FALSE); 5726 } 5727 5728 /* 5729 * When mount is given no arguments, go through /etc/mnttab and 5730 * display any active ZFS mounts. We hide any snapshots, since 5731 * they are controlled automatically. 5732 */ 5733 rewind(mnttab_file); 5734 while (getmntent(mnttab_file, &entry) == 0) { 5735 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 || 5736 strchr(entry.mnt_special, '@') != NULL) 5737 continue; 5738 5739 (void) printf("%-30s %s\n", entry.mnt_special, 5740 entry.mnt_mountp); 5741 } 5742 5743 } else { 5744 zfs_handle_t *zhp; 5745 5746 if (argc > 1) { 5747 (void) fprintf(stderr, 5748 gettext("too many arguments\n")); 5749 usage(B_FALSE); 5750 } 5751 5752 if ((zhp = zfs_open(g_zfs, argv[0], 5753 ZFS_TYPE_FILESYSTEM)) == NULL) { 5754 ret = 1; 5755 } else { 5756 ret = share_mount_one(zhp, op, flags, NULL, B_TRUE, 5757 options); 5758 zfs_close(zhp); 5759 } 5760 } 5761 5762 return (ret); 5763 } 5764 5765 /* 5766 * zfs mount -a [nfs] 5767 * zfs mount filesystem 5768 * 5769 * Mount all filesystems, or mount the given filesystem. 5770 */ 5771 static int 5772 zfs_do_mount(int argc, char **argv) 5773 { 5774 return (share_mount(OP_MOUNT, argc, argv)); 5775 } 5776 5777 /* 5778 * zfs share -a [nfs | smb] 5779 * zfs share filesystem 5780 * 5781 * Share all filesystems, or share the given filesystem. 5782 */ 5783 static int 5784 zfs_do_share(int argc, char **argv) 5785 { 5786 return (share_mount(OP_SHARE, argc, argv)); 5787 } 5788 5789 typedef struct unshare_unmount_node { 5790 zfs_handle_t *un_zhp; 5791 char *un_mountp; 5792 uu_avl_node_t un_avlnode; 5793 } unshare_unmount_node_t; 5794 5795 /* ARGSUSED */ 5796 static int 5797 unshare_unmount_compare(const void *larg, const void *rarg, void *unused) 5798 { 5799 const unshare_unmount_node_t *l = larg; 5800 const unshare_unmount_node_t *r = rarg; 5801 5802 return (strcmp(l->un_mountp, r->un_mountp)); 5803 } 5804 5805 /* 5806 * Convenience routine used by zfs_do_umount() and manual_unmount(). Given an 5807 * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem, 5808 * and unmount it appropriately. 5809 */ 5810 static int 5811 unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) 5812 { 5813 zfs_handle_t *zhp; 5814 int ret; 5815 struct stat64 statbuf; 5816 struct extmnttab entry; 5817 const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount"; 5818 ino_t path_inode; 5819 5820 /* 5821 * Search for the path in /etc/mnttab. Rather than looking for the 5822 * specific path, which can be fooled by non-standard paths (i.e. ".." 5823 * or "//"), we stat() the path and search for the corresponding 5824 * (major,minor) device pair. 5825 */ 5826 if (stat64(path, &statbuf) != 0) { 5827 (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"), 5828 cmdname, path, strerror(errno)); 5829 return (1); 5830 } 5831 path_inode = statbuf.st_ino; 5832 5833 /* 5834 * Search for the given (major,minor) pair in the mount table. 5835 */ 5836 rewind(mnttab_file); 5837 while ((ret = getextmntent(mnttab_file, &entry, 0)) == 0) { 5838 if (entry.mnt_major == major(statbuf.st_dev) && 5839 entry.mnt_minor == minor(statbuf.st_dev)) 5840 break; 5841 } 5842 if (ret != 0) { 5843 if (op == OP_SHARE) { 5844 (void) fprintf(stderr, gettext("cannot %s '%s': not " 5845 "currently mounted\n"), cmdname, path); 5846 return (1); 5847 } 5848 (void) fprintf(stderr, gettext("warning: %s not in mnttab\n"), 5849 path); 5850 if ((ret = umount2(path, flags)) != 0) 5851 (void) fprintf(stderr, gettext("%s: %s\n"), path, 5852 strerror(errno)); 5853 return (ret != 0); 5854 } 5855 5856 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) { 5857 (void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS " 5858 "filesystem\n"), cmdname, path); 5859 return (1); 5860 } 5861 5862 if ((zhp = zfs_open(g_zfs, entry.mnt_special, 5863 ZFS_TYPE_FILESYSTEM)) == NULL) 5864 return (1); 5865 5866 ret = 1; 5867 if (stat64(entry.mnt_mountp, &statbuf) != 0) { 5868 (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"), 5869 cmdname, path, strerror(errno)); 5870 goto out; 5871 } else if (statbuf.st_ino != path_inode) { 5872 (void) fprintf(stderr, gettext("cannot " 5873 "%s '%s': not a mountpoint\n"), cmdname, path); 5874 goto out; 5875 } 5876 5877 if (op == OP_SHARE) { 5878 char nfs_mnt_prop[ZFS_MAXPROPLEN]; 5879 char smbshare_prop[ZFS_MAXPROPLEN]; 5880 5881 verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, nfs_mnt_prop, 5882 sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0); 5883 verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshare_prop, 5884 sizeof (smbshare_prop), NULL, NULL, 0, B_FALSE) == 0); 5885 5886 if (strcmp(nfs_mnt_prop, "off") == 0 && 5887 strcmp(smbshare_prop, "off") == 0) { 5888 (void) fprintf(stderr, gettext("cannot unshare " 5889 "'%s': legacy share\n"), path); 5890 (void) fprintf(stderr, gettext("use " 5891 "unshare(1M) to unshare this filesystem\n")); 5892 } else if (!zfs_is_shared(zhp)) { 5893 (void) fprintf(stderr, gettext("cannot unshare '%s': " 5894 "not currently shared\n"), path); 5895 } else { 5896 ret = zfs_unshareall_bypath(zhp, path); 5897 } 5898 } else { 5899 char mtpt_prop[ZFS_MAXPROPLEN]; 5900 5901 verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mtpt_prop, 5902 sizeof (mtpt_prop), NULL, NULL, 0, B_FALSE) == 0); 5903 5904 if (is_manual) { 5905 ret = zfs_unmount(zhp, NULL, flags); 5906 } else if (strcmp(mtpt_prop, "legacy") == 0) { 5907 (void) fprintf(stderr, gettext("cannot unmount " 5908 "'%s': legacy mountpoint\n"), 5909 zfs_get_name(zhp)); 5910 (void) fprintf(stderr, gettext("use umount(1M) " 5911 "to unmount this filesystem\n")); 5912 } else { 5913 ret = zfs_unmountall(zhp, flags); 5914 } 5915 } 5916 5917 out: 5918 zfs_close(zhp); 5919 5920 return (ret != 0); 5921 } 5922 5923 /* 5924 * Generic callback for unsharing or unmounting a filesystem. 5925 */ 5926 static int 5927 unshare_unmount(int op, int argc, char **argv) 5928 { 5929 int do_all = 0; 5930 int flags = 0; 5931 int ret = 0; 5932 int c; 5933 zfs_handle_t *zhp; 5934 char nfs_mnt_prop[ZFS_MAXPROPLEN]; 5935 char sharesmb[ZFS_MAXPROPLEN]; 5936 5937 /* check options */ 5938 while ((c = getopt(argc, argv, op == OP_SHARE ? "a" : "af")) != -1) { 5939 switch (c) { 5940 case 'a': 5941 do_all = 1; 5942 break; 5943 case 'f': 5944 flags = MS_FORCE; 5945 break; 5946 case '?': 5947 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5948 optopt); 5949 usage(B_FALSE); 5950 } 5951 } 5952 5953 argc -= optind; 5954 argv += optind; 5955 5956 if (do_all) { 5957 /* 5958 * We could make use of zfs_for_each() to walk all datasets in 5959 * the system, but this would be very inefficient, especially 5960 * since we would have to linearly search /etc/mnttab for each 5961 * one. Instead, do one pass through /etc/mnttab looking for 5962 * zfs entries and call zfs_unmount() for each one. 5963 * 5964 * Things get a little tricky if the administrator has created 5965 * mountpoints beneath other ZFS filesystems. In this case, we 5966 * have to unmount the deepest filesystems first. To accomplish 5967 * this, we place all the mountpoints in an AVL tree sorted by 5968 * the special type (dataset name), and walk the result in 5969 * reverse to make sure to get any snapshots first. 5970 */ 5971 struct mnttab entry; 5972 uu_avl_pool_t *pool; 5973 uu_avl_t *tree; 5974 unshare_unmount_node_t *node; 5975 uu_avl_index_t idx; 5976 uu_avl_walk_t *walk; 5977 5978 if (argc != 0) { 5979 (void) fprintf(stderr, gettext("too many arguments\n")); 5980 usage(B_FALSE); 5981 } 5982 5983 if (((pool = uu_avl_pool_create("unmount_pool", 5984 sizeof (unshare_unmount_node_t), 5985 offsetof(unshare_unmount_node_t, un_avlnode), 5986 unshare_unmount_compare, UU_DEFAULT)) == NULL) || 5987 ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL)) 5988 nomem(); 5989 5990 rewind(mnttab_file); 5991 while (getmntent(mnttab_file, &entry) == 0) { 5992 5993 /* ignore non-ZFS entries */ 5994 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 5995 continue; 5996 5997 /* ignore snapshots */ 5998 if (strchr(entry.mnt_special, '@') != NULL) 5999 continue; 6000 6001 if ((zhp = zfs_open(g_zfs, entry.mnt_special, 6002 ZFS_TYPE_FILESYSTEM)) == NULL) { 6003 ret = 1; 6004 continue; 6005 } 6006 6007 switch (op) { 6008 case OP_SHARE: 6009 verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, 6010 nfs_mnt_prop, 6011 sizeof (nfs_mnt_prop), 6012 NULL, NULL, 0, B_FALSE) == 0); 6013 if (strcmp(nfs_mnt_prop, "off") != 0) 6014 break; 6015 verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, 6016 nfs_mnt_prop, 6017 sizeof (nfs_mnt_prop), 6018 NULL, NULL, 0, B_FALSE) == 0); 6019 if (strcmp(nfs_mnt_prop, "off") == 0) 6020 continue; 6021 break; 6022 case OP_MOUNT: 6023 /* Ignore legacy mounts */ 6024 verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, 6025 nfs_mnt_prop, 6026 sizeof (nfs_mnt_prop), 6027 NULL, NULL, 0, B_FALSE) == 0); 6028 if (strcmp(nfs_mnt_prop, "legacy") == 0) 6029 continue; 6030 /* Ignore canmount=noauto mounts */ 6031 if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == 6032 ZFS_CANMOUNT_NOAUTO) 6033 continue; 6034 default: 6035 break; 6036 } 6037 6038 node = safe_malloc(sizeof (unshare_unmount_node_t)); 6039 node->un_zhp = zhp; 6040 node->un_mountp = safe_strdup(entry.mnt_mountp); 6041 6042 uu_avl_node_init(node, &node->un_avlnode, pool); 6043 6044 if (uu_avl_find(tree, node, NULL, &idx) == NULL) { 6045 uu_avl_insert(tree, node, idx); 6046 } else { 6047 zfs_close(node->un_zhp); 6048 free(node->un_mountp); 6049 free(node); 6050 } 6051 } 6052 6053 /* 6054 * Walk the AVL tree in reverse, unmounting each filesystem and 6055 * removing it from the AVL tree in the process. 6056 */ 6057 if ((walk = uu_avl_walk_start(tree, 6058 UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL) 6059 nomem(); 6060 6061 while ((node = uu_avl_walk_next(walk)) != NULL) { 6062 uu_avl_remove(tree, node); 6063 6064 switch (op) { 6065 case OP_SHARE: 6066 if (zfs_unshareall_bypath(node->un_zhp, 6067 node->un_mountp) != 0) 6068 ret = 1; 6069 break; 6070 6071 case OP_MOUNT: 6072 if (zfs_unmount(node->un_zhp, 6073 node->un_mountp, flags) != 0) 6074 ret = 1; 6075 break; 6076 } 6077 6078 zfs_close(node->un_zhp); 6079 free(node->un_mountp); 6080 free(node); 6081 } 6082 6083 uu_avl_walk_end(walk); 6084 uu_avl_destroy(tree); 6085 uu_avl_pool_destroy(pool); 6086 6087 } else { 6088 if (argc != 1) { 6089 if (argc == 0) 6090 (void) fprintf(stderr, 6091 gettext("missing filesystem argument\n")); 6092 else 6093 (void) fprintf(stderr, 6094 gettext("too many arguments\n")); 6095 usage(B_FALSE); 6096 } 6097 6098 /* 6099 * We have an argument, but it may be a full path or a ZFS 6100 * filesystem. Pass full paths off to unmount_path() (shared by 6101 * manual_unmount), otherwise open the filesystem and pass to 6102 * zfs_unmount(). 6103 */ 6104 if (argv[0][0] == '/') 6105 return (unshare_unmount_path(op, argv[0], 6106 flags, B_FALSE)); 6107 6108 if ((zhp = zfs_open(g_zfs, argv[0], 6109 ZFS_TYPE_FILESYSTEM)) == NULL) 6110 return (1); 6111 6112 verify(zfs_prop_get(zhp, op == OP_SHARE ? 6113 ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, 6114 nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL, 6115 NULL, 0, B_FALSE) == 0); 6116 6117 switch (op) { 6118 case OP_SHARE: 6119 verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, 6120 nfs_mnt_prop, 6121 sizeof (nfs_mnt_prop), 6122 NULL, NULL, 0, B_FALSE) == 0); 6123 verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, 6124 sharesmb, sizeof (sharesmb), NULL, NULL, 6125 0, B_FALSE) == 0); 6126 6127 if (strcmp(nfs_mnt_prop, "off") == 0 && 6128 strcmp(sharesmb, "off") == 0) { 6129 (void) fprintf(stderr, gettext("cannot " 6130 "unshare '%s': legacy share\n"), 6131 zfs_get_name(zhp)); 6132 (void) fprintf(stderr, gettext("use " 6133 "unshare(1M) to unshare this " 6134 "filesystem\n")); 6135 ret = 1; 6136 } else if (!zfs_is_shared(zhp)) { 6137 (void) fprintf(stderr, gettext("cannot " 6138 "unshare '%s': not currently " 6139 "shared\n"), zfs_get_name(zhp)); 6140 ret = 1; 6141 } else if (zfs_unshareall(zhp) != 0) { 6142 ret = 1; 6143 } 6144 break; 6145 6146 case OP_MOUNT: 6147 if (strcmp(nfs_mnt_prop, "legacy") == 0) { 6148 (void) fprintf(stderr, gettext("cannot " 6149 "unmount '%s': legacy " 6150 "mountpoint\n"), zfs_get_name(zhp)); 6151 (void) fprintf(stderr, gettext("use " 6152 "umount(1M) to unmount this " 6153 "filesystem\n")); 6154 ret = 1; 6155 } else if (!zfs_is_mounted(zhp, NULL)) { 6156 (void) fprintf(stderr, gettext("cannot " 6157 "unmount '%s': not currently " 6158 "mounted\n"), 6159 zfs_get_name(zhp)); 6160 ret = 1; 6161 } else if (zfs_unmountall(zhp, flags) != 0) { 6162 ret = 1; 6163 } 6164 break; 6165 } 6166 6167 zfs_close(zhp); 6168 } 6169 6170 return (ret); 6171 } 6172 6173 /* 6174 * zfs unmount -a 6175 * zfs unmount filesystem 6176 * 6177 * Unmount all filesystems, or a specific ZFS filesystem. 6178 */ 6179 static int 6180 zfs_do_unmount(int argc, char **argv) 6181 { 6182 return (unshare_unmount(OP_MOUNT, argc, argv)); 6183 } 6184 6185 /* 6186 * zfs unshare -a 6187 * zfs unshare filesystem 6188 * 6189 * Unshare all filesystems, or a specific ZFS filesystem. 6190 */ 6191 static int 6192 zfs_do_unshare(int argc, char **argv) 6193 { 6194 return (unshare_unmount(OP_SHARE, argc, argv)); 6195 } 6196 6197 /* 6198 * Called when invoked as /etc/fs/zfs/mount. Do the mount if the mountpoint is 6199 * 'legacy'. Otherwise, complain that use should be using 'zfs mount'. 6200 */ 6201 static int 6202 manual_mount(int argc, char **argv) 6203 { 6204 zfs_handle_t *zhp; 6205 char mountpoint[ZFS_MAXPROPLEN]; 6206 char mntopts[MNT_LINE_MAX] = { '\0' }; 6207 int ret; 6208 int c; 6209 int flags = 0; 6210 char *dataset, *path; 6211 6212 /* check options */ 6213 while ((c = getopt(argc, argv, ":mo:O")) != -1) { 6214 switch (c) { 6215 case 'o': 6216 (void) strlcpy(mntopts, optarg, sizeof (mntopts)); 6217 break; 6218 case 'O': 6219 flags |= MS_OVERLAY; 6220 break; 6221 case 'm': 6222 flags |= MS_NOMNTTAB; 6223 break; 6224 case ':': 6225 (void) fprintf(stderr, gettext("missing argument for " 6226 "'%c' option\n"), optopt); 6227 usage(B_FALSE); 6228 break; 6229 case '?': 6230 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 6231 optopt); 6232 (void) fprintf(stderr, gettext("usage: mount [-o opts] " 6233 "<path>\n")); 6234 return (2); 6235 } 6236 } 6237 6238 argc -= optind; 6239 argv += optind; 6240 6241 /* check that we only have two arguments */ 6242 if (argc != 2) { 6243 if (argc == 0) 6244 (void) fprintf(stderr, gettext("missing dataset " 6245 "argument\n")); 6246 else if (argc == 1) 6247 (void) fprintf(stderr, 6248 gettext("missing mountpoint argument\n")); 6249 else 6250 (void) fprintf(stderr, gettext("too many arguments\n")); 6251 (void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n"); 6252 return (2); 6253 } 6254 6255 dataset = argv[0]; 6256 path = argv[1]; 6257 6258 /* try to open the dataset */ 6259 if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) 6260 return (1); 6261 6262 (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 6263 sizeof (mountpoint), NULL, NULL, 0, B_FALSE); 6264 6265 /* check for legacy mountpoint and complain appropriately */ 6266 ret = 0; 6267 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 6268 if (mount(dataset, path, MS_OPTIONSTR | flags, MNTTYPE_ZFS, 6269 NULL, 0, mntopts, sizeof (mntopts)) != 0) { 6270 (void) fprintf(stderr, gettext("mount failed: %s\n"), 6271 strerror(errno)); 6272 ret = 1; 6273 } 6274 } else { 6275 (void) fprintf(stderr, gettext("filesystem '%s' cannot be " 6276 "mounted using 'mount -F zfs'\n"), dataset); 6277 (void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' " 6278 "instead.\n"), path); 6279 (void) fprintf(stderr, gettext("If you must use 'mount -F zfs' " 6280 "or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n")); 6281 (void) fprintf(stderr, gettext("See zfs(1M) for more " 6282 "information.\n")); 6283 ret = 1; 6284 } 6285 6286 return (ret); 6287 } 6288 6289 /* 6290 * Called when invoked as /etc/fs/zfs/umount. Unlike a manual mount, we allow 6291 * unmounts of non-legacy filesystems, as this is the dominant administrative 6292 * interface. 6293 */ 6294 static int 6295 manual_unmount(int argc, char **argv) 6296 { 6297 int flags = 0; 6298 int c; 6299 6300 /* check options */ 6301 while ((c = getopt(argc, argv, "f")) != -1) { 6302 switch (c) { 6303 case 'f': 6304 flags = MS_FORCE; 6305 break; 6306 case '?': 6307 (void) fprintf(stderr, gettext("invalid option '%c'\n"), 6308 optopt); 6309 (void) fprintf(stderr, gettext("usage: unmount [-f] " 6310 "<path>\n")); 6311 return (2); 6312 } 6313 } 6314 6315 argc -= optind; 6316 argv += optind; 6317 6318 /* check arguments */ 6319 if (argc != 1) { 6320 if (argc == 0) 6321 (void) fprintf(stderr, gettext("missing path " 6322 "argument\n")); 6323 else 6324 (void) fprintf(stderr, gettext("too many arguments\n")); 6325 (void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n")); 6326 return (2); 6327 } 6328 6329 return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE)); 6330 } 6331 6332 static int 6333 find_command_idx(char *command, int *idx) 6334 { 6335 int i; 6336 6337 for (i = 0; i < NCOMMAND; i++) { 6338 if (command_table[i].name == NULL) 6339 continue; 6340 6341 if (strcmp(command, command_table[i].name) == 0) { 6342 *idx = i; 6343 return (0); 6344 } 6345 } 6346 return (1); 6347 } 6348 6349 static int 6350 zfs_do_diff(int argc, char **argv) 6351 { 6352 zfs_handle_t *zhp; 6353 int flags = 0; 6354 char *tosnap = NULL; 6355 char *fromsnap = NULL; 6356 char *atp, *copy; 6357 int err; 6358 int c; 6359 6360 while ((c = getopt(argc, argv, "FHt")) != -1) { 6361 switch (c) { 6362 case 'F': 6363 flags |= ZFS_DIFF_CLASSIFY; 6364 break; 6365 case 'H': 6366 flags |= ZFS_DIFF_PARSEABLE; 6367 break; 6368 case 't': 6369 flags |= ZFS_DIFF_TIMESTAMP; 6370 break; 6371 default: 6372 (void) fprintf(stderr, 6373 gettext("invalid option '%c'\n"), optopt); 6374 usage(B_FALSE); 6375 } 6376 } 6377 6378 argc -= optind; 6379 argv += optind; 6380 6381 if (argc < 1) { 6382 (void) fprintf(stderr, 6383 gettext("must provide at least one snapshot name\n")); 6384 usage(B_FALSE); 6385 } 6386 6387 if (argc > 2) { 6388 (void) fprintf(stderr, gettext("too many arguments\n")); 6389 usage(B_FALSE); 6390 } 6391 6392 fromsnap = argv[0]; 6393 tosnap = (argc == 2) ? argv[1] : NULL; 6394 6395 copy = NULL; 6396 if (*fromsnap != '@') 6397 copy = strdup(fromsnap); 6398 else if (tosnap) 6399 copy = strdup(tosnap); 6400 if (copy == NULL) 6401 usage(B_FALSE); 6402 6403 if (atp = strchr(copy, '@')) 6404 *atp = '\0'; 6405 6406 if ((zhp = zfs_open(g_zfs, copy, ZFS_TYPE_FILESYSTEM)) == NULL) 6407 return (1); 6408 6409 free(copy); 6410 6411 /* 6412 * Ignore SIGPIPE so that the library can give us 6413 * information on any failure 6414 */ 6415 (void) sigignore(SIGPIPE); 6416 6417 err = zfs_show_diffs(zhp, STDOUT_FILENO, fromsnap, tosnap, flags); 6418 6419 zfs_close(zhp); 6420 6421 return (err != 0); 6422 } 6423 6424 int 6425 main(int argc, char **argv) 6426 { 6427 int ret; 6428 int i; 6429 char *progname; 6430 char *cmdname; 6431 6432 (void) setlocale(LC_ALL, ""); 6433 (void) textdomain(TEXT_DOMAIN); 6434 6435 opterr = 0; 6436 6437 if ((g_zfs = libzfs_init()) == NULL) { 6438 (void) fprintf(stderr, gettext("internal error: failed to " 6439 "initialize ZFS library\n")); 6440 return (1); 6441 } 6442 6443 zpool_set_history_str("zfs", argc, argv, history_str); 6444 verify(zpool_stage_history(g_zfs, history_str) == 0); 6445 6446 libzfs_print_on_error(g_zfs, B_TRUE); 6447 6448 if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) { 6449 (void) fprintf(stderr, gettext("internal error: unable to " 6450 "open %s\n"), MNTTAB); 6451 return (1); 6452 } 6453 6454 /* 6455 * This command also doubles as the /etc/fs mount and unmount program. 6456 * Determine if we should take this behavior based on argv[0]. 6457 */ 6458 progname = basename(argv[0]); 6459 if (strcmp(progname, "mount") == 0) { 6460 ret = manual_mount(argc, argv); 6461 } else if (strcmp(progname, "umount") == 0) { 6462 ret = manual_unmount(argc, argv); 6463 } else { 6464 /* 6465 * Make sure the user has specified some command. 6466 */ 6467 if (argc < 2) { 6468 (void) fprintf(stderr, gettext("missing command\n")); 6469 usage(B_FALSE); 6470 } 6471 6472 cmdname = argv[1]; 6473 6474 /* 6475 * The 'umount' command is an alias for 'unmount' 6476 */ 6477 if (strcmp(cmdname, "umount") == 0) 6478 cmdname = "unmount"; 6479 6480 /* 6481 * The 'recv' command is an alias for 'receive' 6482 */ 6483 if (strcmp(cmdname, "recv") == 0) 6484 cmdname = "receive"; 6485 6486 /* 6487 * Special case '-?' 6488 */ 6489 if (strcmp(cmdname, "-?") == 0) 6490 usage(B_TRUE); 6491 6492 /* 6493 * Run the appropriate command. 6494 */ 6495 libzfs_mnttab_cache(g_zfs, B_TRUE); 6496 if (find_command_idx(cmdname, &i) == 0) { 6497 current_command = &command_table[i]; 6498 ret = command_table[i].func(argc - 1, argv + 1); 6499 } else if (strchr(cmdname, '=') != NULL) { 6500 verify(find_command_idx("set", &i) == 0); 6501 current_command = &command_table[i]; 6502 ret = command_table[i].func(argc, argv); 6503 } else { 6504 (void) fprintf(stderr, gettext("unrecognized " 6505 "command '%s'\n"), cmdname); 6506 usage(B_FALSE); 6507 } 6508 libzfs_mnttab_cache(g_zfs, B_FALSE); 6509 } 6510 6511 (void) fclose(mnttab_file); 6512 6513 libzfs_fini(g_zfs); 6514 6515 /* 6516 * The 'ZFS_ABORT' environment variable causes us to dump core on exit 6517 * for the purposes of running ::findleaks. 6518 */ 6519 if (getenv("ZFS_ABORT") != NULL) { 6520 (void) printf("dumping core by request\n"); 6521 abort(); 6522 } 6523 6524 return (ret); 6525 } 6526