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