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