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