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