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