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