1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 221204Slling * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <assert.h> 29*2676Seschrock #include <ctype.h> 30789Sahrens #include <errno.h> 31789Sahrens #include <libgen.h> 32789Sahrens #include <libintl.h> 33789Sahrens #include <libuutil.h> 34789Sahrens #include <locale.h> 35789Sahrens #include <stddef.h> 36789Sahrens #include <stdio.h> 37789Sahrens #include <stdlib.h> 38789Sahrens #include <strings.h> 39789Sahrens #include <unistd.h> 40789Sahrens #include <fcntl.h> 41789Sahrens #include <zone.h> 42789Sahrens #include <sys/mkdev.h> 43789Sahrens #include <sys/mntent.h> 44789Sahrens #include <sys/mnttab.h> 45789Sahrens #include <sys/mount.h> 46789Sahrens #include <sys/stat.h> 47789Sahrens 48789Sahrens #include <libzfs.h> 49789Sahrens 50789Sahrens #include "zfs_iter.h" 512082Seschrock #include "zfs_util.h" 522082Seschrock 532082Seschrock libzfs_handle_t *g_zfs; 54789Sahrens 55789Sahrens static FILE *mnttab_file; 56789Sahrens 57789Sahrens static int zfs_do_clone(int argc, char **argv); 58789Sahrens static int zfs_do_create(int argc, char **argv); 59789Sahrens static int zfs_do_destroy(int argc, char **argv); 60789Sahrens static int zfs_do_get(int argc, char **argv); 61789Sahrens static int zfs_do_inherit(int argc, char **argv); 62789Sahrens static int zfs_do_list(int argc, char **argv); 63789Sahrens static int zfs_do_mount(int argc, char **argv); 64789Sahrens static int zfs_do_rename(int argc, char **argv); 65789Sahrens static int zfs_do_rollback(int argc, char **argv); 66789Sahrens static int zfs_do_set(int argc, char **argv); 67789Sahrens static int zfs_do_snapshot(int argc, char **argv); 68789Sahrens static int zfs_do_unmount(int argc, char **argv); 69789Sahrens static int zfs_do_share(int argc, char **argv); 70789Sahrens static int zfs_do_unshare(int argc, char **argv); 711749Sahrens static int zfs_do_send(int argc, char **argv); 721749Sahrens static int zfs_do_receive(int argc, char **argv); 732082Seschrock static int zfs_do_promote(int argc, char **argv); 74789Sahrens 75789Sahrens /* 76789Sahrens * These libumem hooks provide a reasonable set of defaults for the allocator's 77789Sahrens * debugging facilities. 78789Sahrens */ 79789Sahrens const char * 80789Sahrens _umem_debug_init() 81789Sahrens { 82789Sahrens return ("default,verbose"); /* $UMEM_DEBUG setting */ 83789Sahrens } 84789Sahrens 85789Sahrens const char * 86789Sahrens _umem_logging_init(void) 87789Sahrens { 88789Sahrens return ("fail,contents"); /* $UMEM_LOGGING setting */ 89789Sahrens } 90789Sahrens 911387Seschrock typedef enum { 921387Seschrock HELP_CLONE, 931387Seschrock HELP_CREATE, 941387Seschrock HELP_DESTROY, 951387Seschrock HELP_GET, 961387Seschrock HELP_INHERIT, 971387Seschrock HELP_LIST, 981387Seschrock HELP_MOUNT, 992082Seschrock HELP_PROMOTE, 1001749Sahrens HELP_RECEIVE, 1011387Seschrock HELP_RENAME, 1021387Seschrock HELP_ROLLBACK, 1031749Sahrens HELP_SEND, 1041387Seschrock HELP_SET, 1051387Seschrock HELP_SHARE, 1061387Seschrock HELP_SNAPSHOT, 1071387Seschrock HELP_UNMOUNT, 1081387Seschrock HELP_UNSHARE 1091387Seschrock } zfs_help_t; 1101387Seschrock 111789Sahrens typedef struct zfs_command { 112789Sahrens const char *name; 113789Sahrens int (*func)(int argc, char **argv); 1141387Seschrock zfs_help_t usage; 115789Sahrens } zfs_command_t; 116789Sahrens 117789Sahrens /* 118789Sahrens * Master command table. Each ZFS command has a name, associated function, and 1191544Seschrock * usage message. The usage messages need to be internationalized, so we have 1201544Seschrock * to have a function to return the usage message based on a command index. 1211387Seschrock * 1221387Seschrock * These commands are organized according to how they are displayed in the usage 1231387Seschrock * message. An empty command (one with a NULL name) indicates an empty line in 1241387Seschrock * the generic usage message. 125789Sahrens */ 126789Sahrens static zfs_command_t command_table[] = { 1271387Seschrock { "create", zfs_do_create, HELP_CREATE }, 1281387Seschrock { "destroy", zfs_do_destroy, HELP_DESTROY }, 129789Sahrens { NULL }, 1301387Seschrock { "snapshot", zfs_do_snapshot, HELP_SNAPSHOT }, 1311387Seschrock { "rollback", zfs_do_rollback, HELP_ROLLBACK }, 1321387Seschrock { "clone", zfs_do_clone, HELP_CLONE }, 1332082Seschrock { "promote", zfs_do_promote, HELP_PROMOTE }, 1341387Seschrock { "rename", zfs_do_rename, HELP_RENAME }, 135789Sahrens { NULL }, 1361387Seschrock { "list", zfs_do_list, HELP_LIST }, 137789Sahrens { NULL }, 1381387Seschrock { "set", zfs_do_set, HELP_SET }, 1391387Seschrock { "get", zfs_do_get, HELP_GET }, 1401387Seschrock { "inherit", zfs_do_inherit, HELP_INHERIT }, 141789Sahrens { NULL }, 1421387Seschrock { "mount", zfs_do_mount, HELP_MOUNT }, 143789Sahrens { NULL }, 1441387Seschrock { "unmount", zfs_do_unmount, HELP_UNMOUNT }, 145789Sahrens { NULL }, 1461387Seschrock { "share", zfs_do_share, HELP_SHARE }, 147789Sahrens { NULL }, 1481387Seschrock { "unshare", zfs_do_unshare, HELP_UNSHARE }, 149789Sahrens { NULL }, 1501749Sahrens { "send", zfs_do_send, HELP_SEND }, 1511749Sahrens { "receive", zfs_do_receive, HELP_RECEIVE }, 152789Sahrens }; 153789Sahrens 154789Sahrens #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 155789Sahrens 156789Sahrens zfs_command_t *current_command; 157789Sahrens 1581387Seschrock static const char * 1591387Seschrock get_usage(zfs_help_t idx) 1601387Seschrock { 1611387Seschrock switch (idx) { 1621387Seschrock case HELP_CLONE: 1631387Seschrock return (gettext("\tclone <snapshot> <filesystem|volume>\n")); 1641387Seschrock case HELP_CREATE: 165*2676Seschrock return (gettext("\tcreate [[-o property=value] ... ] " 166*2676Seschrock "<filesystem>\n" 167*2676Seschrock "\tcreate [-s] [-b blocksize] [[-o property=value] ...]\n" 168*2676Seschrock "\t -V <size> <volume>\n")); 1691387Seschrock case HELP_DESTROY: 1701387Seschrock return (gettext("\tdestroy [-rRf] " 1711387Seschrock "<filesystem|volume|snapshot>\n")); 1721387Seschrock case HELP_GET: 1731387Seschrock return (gettext("\tget [-rHp] [-o field[,field]...] " 1741387Seschrock "[-s source[,source]...]\n" 1751387Seschrock "\t <all | property[,property]...> " 176*2676Seschrock "[filesystem|volume|snapshot] ...\n")); 1771387Seschrock case HELP_INHERIT: 1781387Seschrock return (gettext("\tinherit [-r] <property> " 1791387Seschrock "<filesystem|volume> ...\n")); 1801387Seschrock case HELP_LIST: 1811387Seschrock return (gettext("\tlist [-rH] [-o property[,property]...] " 1821387Seschrock "[-t type[,type]...]\n" 1832379Ssjelinek "\t [-s property [-s property]...]" 1842379Ssjelinek " [-S property [-S property]...]\n" 1851387Seschrock "\t [filesystem|volume|snapshot] ...\n")); 1861387Seschrock case HELP_MOUNT: 1871387Seschrock return (gettext("\tmount\n" 1881387Seschrock "\tmount [-o opts] [-O] -a\n" 1891387Seschrock "\tmount [-o opts] [-O] <filesystem>\n")); 1902082Seschrock case HELP_PROMOTE: 1912082Seschrock return (gettext("\tpromote <clone filesystem>\n")); 1921749Sahrens case HELP_RECEIVE: 1932665Snd150628 return (gettext("\treceive [-vnF] <filesystem|volume|" 1942665Snd150628 "snapshot>\n" 1952665Snd150628 "\treceive [-vnF] -d <filesystem>\n")); 1961387Seschrock case HELP_RENAME: 1971387Seschrock return (gettext("\trename <filesystem|volume|snapshot> " 1981387Seschrock "<filesystem|volume|snapshot>\n")); 1991387Seschrock case HELP_ROLLBACK: 2001387Seschrock return (gettext("\trollback [-rRf] <snapshot>\n")); 2011749Sahrens case HELP_SEND: 2021749Sahrens return (gettext("\tsend [-i <snapshot>] <snapshot>\n")); 2031387Seschrock case HELP_SET: 2041387Seschrock return (gettext("\tset <property=value> " 2051387Seschrock "<filesystem|volume> ...\n")); 2061387Seschrock case HELP_SHARE: 2071387Seschrock return (gettext("\tshare -a\n" 2081387Seschrock "\tshare <filesystem>\n")); 2091387Seschrock case HELP_SNAPSHOT: 2102199Sahrens return (gettext("\tsnapshot [-r] " 2112199Sahrens "<filesystem@name|volume@name>\n")); 2121387Seschrock case HELP_UNMOUNT: 2131387Seschrock return (gettext("\tunmount [-f] -a\n" 2141387Seschrock "\tunmount [-f] <filesystem|mountpoint>\n")); 2151387Seschrock case HELP_UNSHARE: 2161387Seschrock return (gettext("\tunshare [-f] -a\n" 2171387Seschrock "\tunshare [-f] <filesystem|mountpoint>\n")); 2181387Seschrock } 2191387Seschrock 2201387Seschrock abort(); 2211387Seschrock /* NOTREACHED */ 2221387Seschrock } 2231387Seschrock 224789Sahrens /* 225789Sahrens * Utility function to guarantee malloc() success. 226789Sahrens */ 227789Sahrens void * 228789Sahrens safe_malloc(size_t size) 229789Sahrens { 230789Sahrens void *data; 231789Sahrens 232789Sahrens if ((data = calloc(1, size)) == NULL) { 233789Sahrens (void) fprintf(stderr, "internal error: out of memory\n"); 234789Sahrens exit(1); 235789Sahrens } 236789Sahrens 237789Sahrens return (data); 238789Sahrens } 239789Sahrens 240789Sahrens /* 241789Sahrens * Display usage message. If we're inside a command, display only the usage for 242789Sahrens * that command. Otherwise, iterate over the entire command table and display 243789Sahrens * a complete usage message. 244789Sahrens */ 245789Sahrens static void 2462082Seschrock usage(boolean_t requested) 247789Sahrens { 248789Sahrens int i; 2492082Seschrock boolean_t show_properties = B_FALSE; 250789Sahrens FILE *fp = requested ? stdout : stderr; 251789Sahrens 252789Sahrens if (current_command == NULL) { 253789Sahrens 254789Sahrens (void) fprintf(fp, gettext("usage: zfs command args ...\n")); 255789Sahrens (void) fprintf(fp, 256789Sahrens gettext("where 'command' is one of the following:\n\n")); 257789Sahrens 258789Sahrens for (i = 0; i < NCOMMAND; i++) { 259789Sahrens if (command_table[i].name == NULL) 260789Sahrens (void) fprintf(fp, "\n"); 261789Sahrens else 262789Sahrens (void) fprintf(fp, "%s", 2631387Seschrock get_usage(command_table[i].usage)); 264789Sahrens } 265789Sahrens 266789Sahrens (void) fprintf(fp, gettext("\nEach dataset is of the form: " 267789Sahrens "pool/[dataset/]*dataset[@name]\n")); 268789Sahrens } else { 269789Sahrens (void) fprintf(fp, gettext("usage:\n")); 2701387Seschrock (void) fprintf(fp, "%s", get_usage(current_command->usage)); 271789Sahrens } 272789Sahrens 2732190Sdarrenm if (current_command != NULL && 2742190Sdarrenm (strcmp(current_command->name, "set") == 0 || 275789Sahrens strcmp(current_command->name, "get") == 0 || 276789Sahrens strcmp(current_command->name, "inherit") == 0 || 2772190Sdarrenm strcmp(current_command->name, "list") == 0)) 2782082Seschrock show_properties = B_TRUE; 279789Sahrens 280789Sahrens if (show_properties) { 281789Sahrens 282789Sahrens (void) fprintf(fp, 283789Sahrens gettext("\nThe following properties are supported:\n")); 284789Sahrens 285789Sahrens (void) fprintf(fp, "\n\t%-13s %s %s %s\n\n", 286789Sahrens "PROPERTY", "EDIT", "INHERIT", "VALUES"); 287789Sahrens 288789Sahrens for (i = 0; i < ZFS_NPROP_VISIBLE; i++) { 289789Sahrens (void) fprintf(fp, "\t%-13s ", zfs_prop_to_name(i)); 290789Sahrens 291789Sahrens if (zfs_prop_readonly(i)) 292789Sahrens (void) fprintf(fp, " NO "); 293789Sahrens else 294789Sahrens (void) fprintf(fp, " YES "); 295789Sahrens 296789Sahrens if (zfs_prop_inheritable(i)) 297789Sahrens (void) fprintf(fp, " YES "); 298789Sahrens else 299789Sahrens (void) fprintf(fp, " NO "); 300789Sahrens 301789Sahrens if (zfs_prop_values(i) == NULL) 302789Sahrens (void) fprintf(fp, "-\n"); 303789Sahrens else 304789Sahrens (void) fprintf(fp, "%s\n", zfs_prop_values(i)); 305789Sahrens } 306789Sahrens (void) fprintf(fp, gettext("\nSizes are specified in bytes " 307789Sahrens "with standard units such as K, M, G, etc.\n")); 308*2676Seschrock (void) fprintf(fp, gettext("\n\nUser-defined properties can " 309*2676Seschrock "be specified by using a name containing a colon (:).\n")); 3102190Sdarrenm } else { 3112190Sdarrenm /* 3122190Sdarrenm * TRANSLATION NOTE: 3132190Sdarrenm * "zfs set|get" must not be localised this is the 3142190Sdarrenm * command name and arguments. 3152190Sdarrenm */ 3162190Sdarrenm (void) fprintf(fp, 3172190Sdarrenm gettext("\nFor the property list, run: zfs set|get\n")); 318789Sahrens } 319789Sahrens 320*2676Seschrock /* 321*2676Seschrock * See comments at end of main(). 322*2676Seschrock */ 323*2676Seschrock if (getenv("ZFS_ABORT") != NULL) { 324*2676Seschrock (void) printf("dumping core by request\n"); 325*2676Seschrock abort(); 326*2676Seschrock } 327*2676Seschrock 328789Sahrens exit(requested ? 0 : 2); 329789Sahrens } 330789Sahrens 331789Sahrens /* 332789Sahrens * zfs clone <fs, snap, vol> fs 333789Sahrens * 334789Sahrens * Given an existing dataset, create a writable copy whose initial contents 335789Sahrens * are the same as the source. The newly created dataset maintains a 336789Sahrens * dependency on the original; the original cannot be destroyed so long as 337789Sahrens * the clone exists. 338789Sahrens */ 339789Sahrens static int 340789Sahrens zfs_do_clone(int argc, char **argv) 341789Sahrens { 342789Sahrens zfs_handle_t *zhp; 343789Sahrens int ret; 344789Sahrens 345789Sahrens /* check options */ 346789Sahrens if (argc > 1 && argv[1][0] == '-') { 347789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 348789Sahrens argv[1][1]); 3492082Seschrock usage(B_FALSE); 350789Sahrens } 351789Sahrens 352789Sahrens /* check number of arguments */ 353789Sahrens if (argc < 2) { 354789Sahrens (void) fprintf(stderr, gettext("missing source dataset " 355789Sahrens "argument\n")); 3562082Seschrock usage(B_FALSE); 357789Sahrens } 358789Sahrens if (argc < 3) { 359789Sahrens (void) fprintf(stderr, gettext("missing target dataset " 360789Sahrens "argument\n")); 3612082Seschrock usage(B_FALSE); 362789Sahrens } 363789Sahrens if (argc > 3) { 364789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 3652082Seschrock usage(B_FALSE); 366789Sahrens } 367789Sahrens 368789Sahrens /* open the source dataset */ 3692082Seschrock if ((zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_SNAPSHOT)) == NULL) 370789Sahrens return (1); 371789Sahrens 372789Sahrens /* pass to libzfs */ 373*2676Seschrock ret = zfs_clone(zhp, argv[2], NULL); 374789Sahrens 375789Sahrens /* create the mountpoint if necessary */ 376789Sahrens if (ret == 0) { 3772082Seschrock zfs_handle_t *clone = zfs_open(g_zfs, argv[2], ZFS_TYPE_ANY); 378789Sahrens if (clone != NULL) { 379789Sahrens if ((ret = zfs_mount(clone, NULL, 0)) == 0) 380789Sahrens ret = zfs_share(clone); 381789Sahrens zfs_close(clone); 382789Sahrens } 383789Sahrens } 384789Sahrens 385789Sahrens zfs_close(zhp); 386789Sahrens 387789Sahrens return (ret == 0 ? 0 : 1); 388789Sahrens } 389789Sahrens 390789Sahrens /* 391*2676Seschrock * zfs create [-o prop=value] ... fs 392*2676Seschrock * zfs create [-s] [-b blocksize] [-o prop=value] ... -V vol size 393789Sahrens * 394789Sahrens * Create a new dataset. This command can be used to create filesystems 395789Sahrens * and volumes. Snapshot creation is handled by 'zfs snapshot'. 396789Sahrens * For volumes, the user must specify a size to be used. 397789Sahrens * 398789Sahrens * The '-s' flag applies only to volumes, and indicates that we should not try 399789Sahrens * to set the reservation for this volume. By default we set a reservation 400789Sahrens * equal to the size for any volume. 401789Sahrens */ 402789Sahrens static int 403789Sahrens zfs_do_create(int argc, char **argv) 404789Sahrens { 405789Sahrens zfs_type_t type = ZFS_TYPE_FILESYSTEM; 406*2676Seschrock zfs_handle_t *zhp = NULL; 407*2676Seschrock uint64_t volsize; 408789Sahrens int c; 4092082Seschrock boolean_t noreserve = B_FALSE; 410*2676Seschrock int ret = 1; 411*2676Seschrock nvlist_t *props = NULL; 412*2676Seschrock uint64_t intval; 413*2676Seschrock char *propname; 414*2676Seschrock char *propval, *strval; 415*2676Seschrock 416*2676Seschrock if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 417*2676Seschrock (void) fprintf(stderr, gettext("internal error: " 418*2676Seschrock "out of memory\n")); 419*2676Seschrock return (1); 420*2676Seschrock } 421789Sahrens 422789Sahrens /* check options */ 423*2676Seschrock while ((c = getopt(argc, argv, ":V:b:so:")) != -1) { 424789Sahrens switch (c) { 425789Sahrens case 'V': 426789Sahrens type = ZFS_TYPE_VOLUME; 427*2676Seschrock if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) { 428*2676Seschrock (void) fprintf(stderr, gettext("bad volume " 429*2676Seschrock "size '%s': %s\n"), optarg, 430*2676Seschrock libzfs_error_description(g_zfs)); 431*2676Seschrock goto error; 432*2676Seschrock } 433*2676Seschrock 434*2676Seschrock if (nvlist_add_uint64(props, 435*2676Seschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), 436*2676Seschrock intval) != 0) { 437*2676Seschrock (void) fprintf(stderr, gettext("internal " 438*2676Seschrock "error: out of memory\n")); 439*2676Seschrock goto error; 440*2676Seschrock } 441*2676Seschrock volsize = intval; 442789Sahrens break; 443789Sahrens case 'b': 444*2676Seschrock if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) { 445*2676Seschrock (void) fprintf(stderr, gettext("bad volume " 446*2676Seschrock "block size '%s': %s\n"), optarg, 447*2676Seschrock libzfs_error_description(g_zfs)); 448*2676Seschrock goto error; 449*2676Seschrock } 450*2676Seschrock 451*2676Seschrock if (nvlist_add_uint64(props, 452*2676Seschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 453*2676Seschrock intval) != 0) { 454*2676Seschrock (void) fprintf(stderr, gettext("internal " 455*2676Seschrock "error: out of memory\n")); 456*2676Seschrock goto error; 457*2676Seschrock } 458*2676Seschrock break; 459*2676Seschrock case 'o': 460*2676Seschrock propname = optarg; 461*2676Seschrock if ((propval = strchr(propname, '=')) == NULL) { 462*2676Seschrock (void) fprintf(stderr, gettext("missing " 463*2676Seschrock "'=' for -o option\n")); 464*2676Seschrock goto error; 465*2676Seschrock } 466*2676Seschrock *propval = '\0'; 467*2676Seschrock propval++; 468*2676Seschrock if (nvlist_lookup_string(props, propname, 469*2676Seschrock &strval) == 0) { 470*2676Seschrock (void) fprintf(stderr, gettext("property '%s' " 471*2676Seschrock "specified multiple times\n"), propname); 472*2676Seschrock goto error; 473*2676Seschrock } 474*2676Seschrock if (nvlist_add_string(props, propname, propval) != 0) { 475*2676Seschrock (void) fprintf(stderr, gettext("internal " 476*2676Seschrock "error: out of memory\n")); 477*2676Seschrock goto error; 478*2676Seschrock } 479789Sahrens break; 480789Sahrens case 's': 4812082Seschrock noreserve = B_TRUE; 482789Sahrens break; 483789Sahrens case ':': 484789Sahrens (void) fprintf(stderr, gettext("missing size " 485789Sahrens "argument\n")); 486*2676Seschrock goto badusage; 487789Sahrens break; 488789Sahrens case '?': 489789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 490789Sahrens optopt); 491*2676Seschrock goto badusage; 492789Sahrens } 493789Sahrens } 494789Sahrens 495789Sahrens if (noreserve && type != ZFS_TYPE_VOLUME) { 496789Sahrens (void) fprintf(stderr, gettext("'-s' can only be used when " 497789Sahrens "creating a volume\n")); 498*2676Seschrock goto badusage; 499789Sahrens } 500789Sahrens 501789Sahrens argc -= optind; 502789Sahrens argv += optind; 503789Sahrens 504789Sahrens /* check number of arguments */ 505789Sahrens if (argc == 0) { 506789Sahrens (void) fprintf(stderr, gettext("missing %s argument\n"), 507789Sahrens zfs_type_to_name(type)); 508*2676Seschrock goto badusage; 509789Sahrens } 510789Sahrens if (argc > 1) { 511789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 512*2676Seschrock goto badusage; 513*2676Seschrock } 514*2676Seschrock 515*2676Seschrock if (type == ZFS_TYPE_VOLUME && !noreserve && 516*2676Seschrock nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_RESERVATION), 517*2676Seschrock &strval) != 0) { 518*2676Seschrock if (nvlist_add_uint64(props, 519*2676Seschrock zfs_prop_to_name(ZFS_PROP_RESERVATION), 520*2676Seschrock volsize) != 0) { 521*2676Seschrock (void) fprintf(stderr, gettext("internal " 522*2676Seschrock "error: out of memory\n")); 523*2676Seschrock nvlist_free(props); 524*2676Seschrock return (1); 525*2676Seschrock } 526789Sahrens } 527789Sahrens 528789Sahrens /* pass to libzfs */ 529*2676Seschrock if (zfs_create(g_zfs, argv[0], type, props) != 0) 530*2676Seschrock goto error; 531789Sahrens 5322082Seschrock if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_ANY)) == NULL) 533*2676Seschrock goto error; 534789Sahrens 535789Sahrens /* 536789Sahrens * Mount and/or share the new filesystem as appropriate. We provide a 537789Sahrens * verbose error message to let the user know that their filesystem was 538789Sahrens * in fact created, even if we failed to mount or share it. 539789Sahrens */ 540789Sahrens if (zfs_mount(zhp, NULL, 0) != 0) { 541789Sahrens (void) fprintf(stderr, gettext("filesystem successfully " 542789Sahrens "created, but not mounted\n")); 543789Sahrens ret = 1; 544789Sahrens } else if (zfs_share(zhp) != 0) { 545789Sahrens (void) fprintf(stderr, gettext("filesystem successfully " 546789Sahrens "created, but not shared\n")); 547789Sahrens ret = 1; 548789Sahrens } else { 549789Sahrens ret = 0; 550789Sahrens } 551789Sahrens 552*2676Seschrock error: 553*2676Seschrock if (zhp) 554*2676Seschrock zfs_close(zhp); 555*2676Seschrock nvlist_free(props); 556789Sahrens return (ret); 557*2676Seschrock badusage: 558*2676Seschrock nvlist_free(props); 559*2676Seschrock usage(B_FALSE); 560*2676Seschrock return (2); 561789Sahrens } 562789Sahrens 563789Sahrens /* 564789Sahrens * zfs destroy [-rf] <fs, snap, vol> 565789Sahrens * 566789Sahrens * -r Recursively destroy all children 567789Sahrens * -R Recursively destroy all dependents, including clones 568789Sahrens * -f Force unmounting of any dependents 569789Sahrens * 570789Sahrens * Destroys the given dataset. By default, it will unmount any filesystems, 571789Sahrens * and refuse to destroy a dataset that has any dependents. A dependent can 572789Sahrens * either be a child, or a clone of a child. 573789Sahrens */ 574789Sahrens typedef struct destroy_cbdata { 5752082Seschrock boolean_t cb_first; 576789Sahrens int cb_force; 577789Sahrens int cb_recurse; 578789Sahrens int cb_error; 579789Sahrens int cb_needforce; 580789Sahrens int cb_doclones; 581789Sahrens zfs_handle_t *cb_target; 5822199Sahrens char *cb_snapname; 583789Sahrens } destroy_cbdata_t; 584789Sahrens 585789Sahrens /* 586789Sahrens * Check for any dependents based on the '-r' or '-R' flags. 587789Sahrens */ 588789Sahrens static int 589789Sahrens destroy_check_dependent(zfs_handle_t *zhp, void *data) 590789Sahrens { 591789Sahrens destroy_cbdata_t *cbp = data; 592789Sahrens const char *tname = zfs_get_name(cbp->cb_target); 593789Sahrens const char *name = zfs_get_name(zhp); 594789Sahrens 595789Sahrens if (strncmp(tname, name, strlen(tname)) == 0 && 596789Sahrens (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) { 597789Sahrens /* 598789Sahrens * This is a direct descendant, not a clone somewhere else in 599789Sahrens * the hierarchy. 600789Sahrens */ 601789Sahrens if (cbp->cb_recurse) 602789Sahrens goto out; 603789Sahrens 604789Sahrens if (cbp->cb_first) { 605789Sahrens (void) fprintf(stderr, gettext("cannot destroy '%s': " 606789Sahrens "%s has children\n"), 607789Sahrens zfs_get_name(cbp->cb_target), 608789Sahrens zfs_type_to_name(zfs_get_type(cbp->cb_target))); 609789Sahrens (void) fprintf(stderr, gettext("use '-r' to destroy " 610789Sahrens "the following datasets:\n")); 6112082Seschrock cbp->cb_first = B_FALSE; 612789Sahrens cbp->cb_error = 1; 613789Sahrens } 614789Sahrens 615789Sahrens (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); 616789Sahrens } else { 617789Sahrens /* 618789Sahrens * This is a clone. We only want to report this if the '-r' 619789Sahrens * wasn't specified, or the target is a snapshot. 620789Sahrens */ 621789Sahrens if (!cbp->cb_recurse && 622789Sahrens zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT) 623789Sahrens goto out; 624789Sahrens 625789Sahrens if (cbp->cb_first) { 626789Sahrens (void) fprintf(stderr, gettext("cannot destroy '%s': " 627789Sahrens "%s has dependent clones\n"), 628789Sahrens zfs_get_name(cbp->cb_target), 629789Sahrens zfs_type_to_name(zfs_get_type(cbp->cb_target))); 630789Sahrens (void) fprintf(stderr, gettext("use '-R' to destroy " 631789Sahrens "the following datasets:\n")); 6322082Seschrock cbp->cb_first = B_FALSE; 633789Sahrens cbp->cb_error = 1; 634789Sahrens } 635789Sahrens 636789Sahrens (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); 637789Sahrens } 638789Sahrens 639789Sahrens out: 640789Sahrens zfs_close(zhp); 641789Sahrens return (0); 642789Sahrens } 643789Sahrens 644789Sahrens static int 645789Sahrens destroy_callback(zfs_handle_t *zhp, void *data) 646789Sahrens { 647789Sahrens destroy_cbdata_t *cbp = data; 648789Sahrens 649789Sahrens /* 650789Sahrens * Ignore pools (which we've already flagged as an error before getting 651789Sahrens * here. 652789Sahrens */ 653789Sahrens if (strchr(zfs_get_name(zhp), '/') == NULL && 654789Sahrens zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { 655789Sahrens zfs_close(zhp); 656789Sahrens return (0); 657789Sahrens } 658789Sahrens 659789Sahrens /* 660789Sahrens * Bail out on the first error. 661789Sahrens */ 662789Sahrens if (zfs_unmount(zhp, NULL, cbp->cb_force ? MS_FORCE : 0) != 0 || 663789Sahrens zfs_destroy(zhp) != 0) { 664789Sahrens zfs_close(zhp); 665789Sahrens return (-1); 666789Sahrens } 667789Sahrens 668789Sahrens zfs_close(zhp); 669789Sahrens return (0); 670789Sahrens } 671789Sahrens 6722199Sahrens static int 6732199Sahrens destroy_snap_clones(zfs_handle_t *zhp, void *arg) 6742199Sahrens { 6752199Sahrens destroy_cbdata_t *cbp = arg; 6762199Sahrens char thissnap[MAXPATHLEN]; 6772199Sahrens zfs_handle_t *szhp; 6782199Sahrens 6792199Sahrens (void) snprintf(thissnap, sizeof (thissnap), 6802199Sahrens "%s@%s", zfs_get_name(zhp), cbp->cb_snapname); 6812199Sahrens 6822199Sahrens libzfs_print_on_error(g_zfs, B_FALSE); 6832199Sahrens szhp = zfs_open(g_zfs, thissnap, ZFS_TYPE_SNAPSHOT); 6842199Sahrens libzfs_print_on_error(g_zfs, B_TRUE); 6852199Sahrens if (szhp) { 6862199Sahrens /* 6872199Sahrens * Destroy any clones of this snapshot 6882199Sahrens */ 6892474Seschrock if (zfs_iter_dependents(szhp, B_FALSE, destroy_callback, 6902474Seschrock cbp) != 0) { 6912474Seschrock zfs_close(szhp); 6922474Seschrock return (-1); 6932474Seschrock } 6942199Sahrens zfs_close(szhp); 6952199Sahrens } 6962199Sahrens 6972199Sahrens return (zfs_iter_filesystems(zhp, destroy_snap_clones, arg)); 6982199Sahrens } 699789Sahrens 700789Sahrens static int 701789Sahrens zfs_do_destroy(int argc, char **argv) 702789Sahrens { 703789Sahrens destroy_cbdata_t cb = { 0 }; 704789Sahrens int c; 705789Sahrens zfs_handle_t *zhp; 7062199Sahrens char *cp; 707789Sahrens 708789Sahrens /* check options */ 709789Sahrens while ((c = getopt(argc, argv, "frR")) != -1) { 710789Sahrens switch (c) { 711789Sahrens case 'f': 712789Sahrens cb.cb_force = 1; 713789Sahrens break; 714789Sahrens case 'r': 715789Sahrens cb.cb_recurse = 1; 716789Sahrens break; 717789Sahrens case 'R': 718789Sahrens cb.cb_recurse = 1; 719789Sahrens cb.cb_doclones = 1; 720789Sahrens break; 721789Sahrens case '?': 722789Sahrens default: 723789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 724789Sahrens optopt); 7252082Seschrock usage(B_FALSE); 726789Sahrens } 727789Sahrens } 728789Sahrens 729789Sahrens argc -= optind; 730789Sahrens argv += optind; 731789Sahrens 732789Sahrens /* check number of arguments */ 733789Sahrens if (argc == 0) { 734789Sahrens (void) fprintf(stderr, gettext("missing path argument\n")); 7352082Seschrock usage(B_FALSE); 736789Sahrens } 737789Sahrens if (argc > 1) { 738789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 7392082Seschrock usage(B_FALSE); 740789Sahrens } 741789Sahrens 7422199Sahrens /* 7432199Sahrens * If we are doing recursive destroy of a snapshot, then the 7442199Sahrens * named snapshot may not exist. Go straight to libzfs. 7452199Sahrens */ 7462199Sahrens if (cb.cb_recurse && (cp = strchr(argv[0], '@'))) { 7472199Sahrens int ret; 7482199Sahrens 7492199Sahrens *cp = '\0'; 7502199Sahrens if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_ANY)) == NULL) 7512199Sahrens return (1); 7522199Sahrens *cp = '@'; 7532199Sahrens cp++; 7542199Sahrens 7552199Sahrens if (cb.cb_doclones) { 7562199Sahrens cb.cb_snapname = cp; 7572474Seschrock if (destroy_snap_clones(zhp, &cb) != 0) { 7582474Seschrock zfs_close(zhp); 7592474Seschrock return (1); 7602474Seschrock } 7612199Sahrens } 7622199Sahrens 7632199Sahrens ret = zfs_destroy_snaps(zhp, cp); 7642199Sahrens zfs_close(zhp); 7652199Sahrens if (ret) { 7662199Sahrens (void) fprintf(stderr, 7672199Sahrens gettext("no snapshots destroyed\n")); 7682199Sahrens } 7692199Sahrens return (ret != 0); 7702199Sahrens } 7712199Sahrens 7722199Sahrens 773789Sahrens /* Open the given dataset */ 7742082Seschrock if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_ANY)) == NULL) 775789Sahrens return (1); 776789Sahrens 777789Sahrens cb.cb_target = zhp; 778789Sahrens 779789Sahrens /* 780789Sahrens * Perform an explicit check for pools before going any further. 781789Sahrens */ 782789Sahrens if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL && 783789Sahrens zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { 784789Sahrens (void) fprintf(stderr, gettext("cannot destroy '%s': " 785789Sahrens "operation does not apply to pools\n"), 786789Sahrens zfs_get_name(zhp)); 787789Sahrens (void) fprintf(stderr, gettext("use 'zfs destroy -r " 788789Sahrens "%s' to destroy all datasets in the pool\n"), 789789Sahrens zfs_get_name(zhp)); 790789Sahrens (void) fprintf(stderr, gettext("use 'zpool destroy %s' " 791789Sahrens "to destroy the pool itself\n"), zfs_get_name(zhp)); 792789Sahrens zfs_close(zhp); 793789Sahrens return (1); 794789Sahrens } 795789Sahrens 796789Sahrens /* 797789Sahrens * Check for any dependents and/or clones. 798789Sahrens */ 7992082Seschrock cb.cb_first = B_TRUE; 8002474Seschrock if (!cb.cb_doclones && 8012474Seschrock zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent, 8022474Seschrock &cb) != 0) { 8032474Seschrock zfs_close(zhp); 8042474Seschrock return (1); 8052474Seschrock } 8062474Seschrock 8072474Seschrock 8082474Seschrock if (cb.cb_error || 8092474Seschrock zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) != 0) { 810789Sahrens zfs_close(zhp); 811789Sahrens return (1); 812789Sahrens } 813789Sahrens 814789Sahrens /* 8152474Seschrock * Do the real thing. The callback will close the handle regardless of 8162474Seschrock * whether it succeeds or not. 817789Sahrens */ 8182474Seschrock if (destroy_callback(zhp, &cb) != 0) 8192474Seschrock return (1); 8202474Seschrock 8212474Seschrock return (0); 822789Sahrens } 823789Sahrens 824789Sahrens /* 825866Seschrock * zfs get [-rHp] [-o field[,field]...] [-s source[,source]...] 826866Seschrock * < all | property[,property]... > < fs | snap | vol > ... 827789Sahrens * 828789Sahrens * -r recurse over any child datasets 829789Sahrens * -H scripted mode. Headers are stripped, and fields are separated 830789Sahrens * by tabs instead of spaces. 831789Sahrens * -o Set of fields to display. One of "name,property,value,source". 832789Sahrens * Default is all four. 833789Sahrens * -s Set of sources to allow. One of 834789Sahrens * "local,default,inherited,temporary,none". Default is all 835789Sahrens * five. 836789Sahrens * -p Display values in parsable (literal) format. 837789Sahrens * 838789Sahrens * Prints properties for the given datasets. The user can control which 839789Sahrens * columns to display as well as which property types to allow. 840789Sahrens */ 841789Sahrens typedef struct get_cbdata { 842789Sahrens int cb_sources; 843789Sahrens int cb_columns[4]; 844*2676Seschrock int cb_colwidths[5]; 8452082Seschrock boolean_t cb_scripted; 8462082Seschrock boolean_t cb_literal; 847*2676Seschrock boolean_t cb_first; 848*2676Seschrock zfs_proplist_t *cb_proplist; 849789Sahrens } get_cbdata_t; 850789Sahrens 851789Sahrens #define GET_COL_NAME 1 852789Sahrens #define GET_COL_PROPERTY 2 853789Sahrens #define GET_COL_VALUE 3 854789Sahrens #define GET_COL_SOURCE 4 855789Sahrens 856789Sahrens /* 857*2676Seschrock * Print the column headers for 'zfs get'. 858*2676Seschrock */ 859*2676Seschrock static void 860*2676Seschrock print_get_headers(get_cbdata_t *cbp) 861*2676Seschrock { 862*2676Seschrock zfs_proplist_t *pl = cbp->cb_proplist; 863*2676Seschrock int i; 864*2676Seschrock char *title; 865*2676Seschrock size_t len; 866*2676Seschrock 867*2676Seschrock cbp->cb_first = B_FALSE; 868*2676Seschrock if (cbp->cb_scripted) 869*2676Seschrock return; 870*2676Seschrock 871*2676Seschrock /* 872*2676Seschrock * Start with the length of the column headers. 873*2676Seschrock */ 874*2676Seschrock cbp->cb_colwidths[GET_COL_NAME] = strlen(gettext("NAME")); 875*2676Seschrock cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(gettext("PROPERTY")); 876*2676Seschrock cbp->cb_colwidths[GET_COL_VALUE] = strlen(gettext("VALUE")); 877*2676Seschrock cbp->cb_colwidths[GET_COL_SOURCE] = strlen(gettext("SOURCE")); 878*2676Seschrock 879*2676Seschrock /* 880*2676Seschrock * Go through and calculate the widths for each column. For the 881*2676Seschrock * 'source' column, we kludge it up by taking the worst-case scenario of 882*2676Seschrock * inheriting from the longest name. This is acceptable because in the 883*2676Seschrock * majority of cases 'SOURCE' is the last column displayed, and we don't 884*2676Seschrock * use the width anyway. Note that the 'VALUE' column can be oversized, 885*2676Seschrock * if the name of the property is much longer the any values we find. 886*2676Seschrock */ 887*2676Seschrock for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 888*2676Seschrock /* 889*2676Seschrock * 'PROPERTY' column 890*2676Seschrock */ 891*2676Seschrock if (pl->pl_prop != ZFS_PROP_INVAL) { 892*2676Seschrock len = strlen(zfs_prop_to_name(pl->pl_prop)); 893*2676Seschrock if (len > cbp->cb_colwidths[GET_COL_PROPERTY]) 894*2676Seschrock cbp->cb_colwidths[GET_COL_PROPERTY] = len; 895*2676Seschrock } else { 896*2676Seschrock len = strlen(pl->pl_user_prop); 897*2676Seschrock if (len > cbp->cb_colwidths[GET_COL_PROPERTY]) 898*2676Seschrock cbp->cb_colwidths[GET_COL_PROPERTY] = len; 899*2676Seschrock } 900*2676Seschrock 901*2676Seschrock /* 902*2676Seschrock * 'VALUE' column 903*2676Seschrock */ 904*2676Seschrock if ((pl->pl_prop != ZFS_PROP_NAME || !pl->pl_all) && 905*2676Seschrock pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE]) 906*2676Seschrock cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width; 907*2676Seschrock 908*2676Seschrock /* 909*2676Seschrock * 'NAME' and 'SOURCE' columns 910*2676Seschrock */ 911*2676Seschrock if (pl->pl_prop == ZFS_PROP_NAME && 912*2676Seschrock pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) { 913*2676Seschrock cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width; 914*2676Seschrock cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width + 915*2676Seschrock strlen(gettext("inherited from")); 916*2676Seschrock } 917*2676Seschrock } 918*2676Seschrock 919*2676Seschrock /* 920*2676Seschrock * Now go through and print the headers. 921*2676Seschrock */ 922*2676Seschrock for (i = 0; i < 4; i++) { 923*2676Seschrock switch (cbp->cb_columns[i]) { 924*2676Seschrock case GET_COL_NAME: 925*2676Seschrock title = gettext("NAME"); 926*2676Seschrock break; 927*2676Seschrock case GET_COL_PROPERTY: 928*2676Seschrock title = gettext("PROPERTY"); 929*2676Seschrock break; 930*2676Seschrock case GET_COL_VALUE: 931*2676Seschrock title = gettext("VALUE"); 932*2676Seschrock break; 933*2676Seschrock case GET_COL_SOURCE: 934*2676Seschrock title = gettext("SOURCE"); 935*2676Seschrock break; 936*2676Seschrock default: 937*2676Seschrock title = NULL; 938*2676Seschrock } 939*2676Seschrock 940*2676Seschrock if (title != NULL) { 941*2676Seschrock if (i == 3 || cbp->cb_columns[i + 1] == 0) 942*2676Seschrock (void) printf("%s", title); 943*2676Seschrock else 944*2676Seschrock (void) printf("%-*s ", 945*2676Seschrock cbp->cb_colwidths[cbp->cb_columns[i]], 946*2676Seschrock title); 947*2676Seschrock } 948*2676Seschrock } 949*2676Seschrock (void) printf("\n"); 950*2676Seschrock } 951*2676Seschrock 952*2676Seschrock /* 953789Sahrens * Display a single line of output, according to the settings in the callback 954789Sahrens * structure. 955789Sahrens */ 956789Sahrens static void 957*2676Seschrock print_one_property(zfs_handle_t *zhp, get_cbdata_t *cbp, const char *propname, 958789Sahrens const char *value, zfs_source_t sourcetype, const char *source) 959789Sahrens { 960789Sahrens int i; 961789Sahrens const char *str; 962789Sahrens char buf[128]; 963789Sahrens 964789Sahrens /* 965789Sahrens * Ignore those source types that the user has chosen to ignore. 966789Sahrens */ 967789Sahrens if ((sourcetype & cbp->cb_sources) == 0) 968789Sahrens return; 969789Sahrens 970*2676Seschrock if (cbp->cb_first) 971*2676Seschrock print_get_headers(cbp); 972*2676Seschrock 973789Sahrens for (i = 0; i < 4; i++) { 974789Sahrens switch (cbp->cb_columns[i]) { 975789Sahrens case GET_COL_NAME: 976789Sahrens str = zfs_get_name(zhp); 977789Sahrens break; 978789Sahrens 979789Sahrens case GET_COL_PROPERTY: 980*2676Seschrock str = propname; 981789Sahrens break; 982789Sahrens 983789Sahrens case GET_COL_VALUE: 984789Sahrens str = value; 985789Sahrens break; 986789Sahrens 987789Sahrens case GET_COL_SOURCE: 988789Sahrens switch (sourcetype) { 989789Sahrens case ZFS_SRC_NONE: 990789Sahrens str = "-"; 991789Sahrens break; 992789Sahrens 993789Sahrens case ZFS_SRC_DEFAULT: 994789Sahrens str = "default"; 995789Sahrens break; 996789Sahrens 997789Sahrens case ZFS_SRC_LOCAL: 998789Sahrens str = "local"; 999789Sahrens break; 1000789Sahrens 1001789Sahrens case ZFS_SRC_TEMPORARY: 1002789Sahrens str = "temporary"; 1003789Sahrens break; 1004789Sahrens 1005789Sahrens case ZFS_SRC_INHERITED: 1006789Sahrens (void) snprintf(buf, sizeof (buf), 1007789Sahrens "inherited from %s", source); 1008789Sahrens str = buf; 1009789Sahrens break; 1010789Sahrens } 1011789Sahrens break; 1012789Sahrens 1013789Sahrens default: 1014789Sahrens continue; 1015789Sahrens } 1016789Sahrens 1017789Sahrens if (cbp->cb_columns[i + 1] == 0) 1018789Sahrens (void) printf("%s", str); 1019789Sahrens else if (cbp->cb_scripted) 1020789Sahrens (void) printf("%s\t", str); 1021789Sahrens else 1022*2676Seschrock (void) printf("%-*s ", 1023*2676Seschrock cbp->cb_colwidths[cbp->cb_columns[i]], 1024*2676Seschrock str); 1025789Sahrens 1026789Sahrens } 1027789Sahrens 1028789Sahrens (void) printf("\n"); 1029789Sahrens } 1030789Sahrens 1031789Sahrens /* 1032789Sahrens * Invoked to display the properties for a single dataset. 1033789Sahrens */ 1034789Sahrens static int 1035789Sahrens get_callback(zfs_handle_t *zhp, void *data) 1036789Sahrens { 1037789Sahrens char buf[ZFS_MAXPROPLEN]; 1038789Sahrens zfs_source_t sourcetype; 1039789Sahrens char source[ZFS_MAXNAMELEN]; 1040789Sahrens get_cbdata_t *cbp = data; 1041*2676Seschrock nvlist_t *userprop = zfs_get_user_props(zhp); 1042*2676Seschrock zfs_proplist_t *pl = cbp->cb_proplist; 1043*2676Seschrock nvlist_t *propval; 1044*2676Seschrock char *strval; 1045*2676Seschrock char *sourceval; 1046*2676Seschrock 1047*2676Seschrock for (; pl != NULL; pl = pl->pl_next) { 1048*2676Seschrock /* 1049*2676Seschrock * Skip the special fake placeholder. This will also skip over 1050*2676Seschrock * the name property when 'all' is specified. 1051*2676Seschrock */ 1052*2676Seschrock if (pl->pl_prop == ZFS_PROP_NAME && 1053*2676Seschrock pl == cbp->cb_proplist) 1054*2676Seschrock continue; 1055*2676Seschrock 1056*2676Seschrock if (pl->pl_prop != ZFS_PROP_INVAL) { 1057*2676Seschrock if (zfs_prop_get(zhp, pl->pl_prop, buf, 1058*2676Seschrock sizeof (buf), &sourcetype, source, 1059*2676Seschrock sizeof (source), 1060*2676Seschrock cbp->cb_literal) != 0) { 1061*2676Seschrock if (pl->pl_all) 1062*2676Seschrock continue; 1063*2676Seschrock sourcetype = ZFS_SRC_NONE; 1064*2676Seschrock (void) strlcpy(buf, "-", sizeof (buf)); 1065*2676Seschrock } 1066*2676Seschrock 1067*2676Seschrock print_one_property(zhp, cbp, 1068*2676Seschrock zfs_prop_to_name(pl->pl_prop), 1069*2676Seschrock buf, sourcetype, source); 1070*2676Seschrock } else { 1071*2676Seschrock if (nvlist_lookup_nvlist(userprop, 1072*2676Seschrock pl->pl_user_prop, &propval) != 0) { 1073*2676Seschrock if (pl->pl_all) 1074*2676Seschrock continue; 1075*2676Seschrock sourcetype = ZFS_SRC_NONE; 1076*2676Seschrock strval = "-"; 1077*2676Seschrock } else { 1078*2676Seschrock verify(nvlist_lookup_string(propval, 1079*2676Seschrock ZFS_PROP_VALUE, &strval) == 0); 1080*2676Seschrock verify(nvlist_lookup_string(propval, 1081*2676Seschrock ZFS_PROP_SOURCE, &sourceval) == 0); 1082*2676Seschrock 1083*2676Seschrock if (strcmp(sourceval, 1084*2676Seschrock zfs_get_name(zhp)) == 0) { 1085*2676Seschrock sourcetype = ZFS_SRC_LOCAL; 1086*2676Seschrock } else { 1087*2676Seschrock sourcetype = ZFS_SRC_INHERITED; 1088*2676Seschrock (void) strlcpy(source, 1089*2676Seschrock sourceval, sizeof (source)); 1090*2676Seschrock } 1091*2676Seschrock } 1092*2676Seschrock 1093*2676Seschrock print_one_property(zhp, cbp, 1094*2676Seschrock pl->pl_user_prop, strval, sourcetype, 1095*2676Seschrock source); 1096866Seschrock } 1097789Sahrens } 1098789Sahrens 1099789Sahrens return (0); 1100789Sahrens } 1101789Sahrens 1102789Sahrens static int 1103789Sahrens zfs_do_get(int argc, char **argv) 1104789Sahrens { 1105789Sahrens get_cbdata_t cb = { 0 }; 11062082Seschrock boolean_t recurse = B_FALSE; 1107*2676Seschrock int i, c; 1108*2676Seschrock char *value, *fields; 1109866Seschrock int ret; 1110*2676Seschrock zfs_proplist_t fake_name = { 0 }; 1111789Sahrens 1112789Sahrens /* 1113789Sahrens * Set up default columns and sources. 1114789Sahrens */ 1115789Sahrens cb.cb_sources = ZFS_SRC_ALL; 1116789Sahrens cb.cb_columns[0] = GET_COL_NAME; 1117789Sahrens cb.cb_columns[1] = GET_COL_PROPERTY; 1118789Sahrens cb.cb_columns[2] = GET_COL_VALUE; 1119789Sahrens cb.cb_columns[3] = GET_COL_SOURCE; 1120789Sahrens 1121789Sahrens /* check options */ 1122789Sahrens while ((c = getopt(argc, argv, ":o:s:rHp")) != -1) { 1123789Sahrens switch (c) { 1124789Sahrens case 'p': 11252082Seschrock cb.cb_literal = B_TRUE; 1126789Sahrens break; 1127789Sahrens case 'r': 11282082Seschrock recurse = B_TRUE; 1129789Sahrens break; 1130789Sahrens case 'H': 11312082Seschrock cb.cb_scripted = B_TRUE; 1132789Sahrens break; 1133789Sahrens case ':': 1134789Sahrens (void) fprintf(stderr, gettext("missing argument for " 1135789Sahrens "'%c' option\n"), optopt); 11362082Seschrock usage(B_FALSE); 1137789Sahrens break; 1138789Sahrens case 'o': 1139789Sahrens /* 1140789Sahrens * Process the set of columns to display. We zero out 1141789Sahrens * the structure to give us a blank slate. 1142789Sahrens */ 1143789Sahrens bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 1144789Sahrens i = 0; 1145789Sahrens while (*optarg != '\0') { 1146789Sahrens static char *col_subopts[] = 1147789Sahrens { "name", "property", "value", "source", 1148789Sahrens NULL }; 1149789Sahrens 1150789Sahrens if (i == 4) { 1151789Sahrens (void) fprintf(stderr, gettext("too " 1152789Sahrens "many fields given to -o " 1153789Sahrens "option\n")); 11542082Seschrock usage(B_FALSE); 1155789Sahrens } 1156789Sahrens 1157789Sahrens switch (getsubopt(&optarg, col_subopts, 1158789Sahrens &value)) { 1159789Sahrens case 0: 1160789Sahrens cb.cb_columns[i++] = GET_COL_NAME; 1161789Sahrens break; 1162789Sahrens case 1: 1163789Sahrens cb.cb_columns[i++] = GET_COL_PROPERTY; 1164789Sahrens break; 1165789Sahrens case 2: 1166789Sahrens cb.cb_columns[i++] = GET_COL_VALUE; 1167789Sahrens break; 1168789Sahrens case 3: 1169789Sahrens cb.cb_columns[i++] = GET_COL_SOURCE; 1170789Sahrens break; 1171789Sahrens default: 1172789Sahrens (void) fprintf(stderr, 1173789Sahrens gettext("invalid column name " 1174789Sahrens "'%s'\n"), value); 11752082Seschrock usage(B_FALSE); 1176789Sahrens } 1177789Sahrens } 1178789Sahrens break; 1179789Sahrens 1180789Sahrens case 's': 1181789Sahrens cb.cb_sources = 0; 1182789Sahrens while (*optarg != '\0') { 1183789Sahrens static char *source_subopts[] = { 1184789Sahrens "local", "default", "inherited", 1185789Sahrens "temporary", "none", NULL }; 1186789Sahrens 1187789Sahrens switch (getsubopt(&optarg, source_subopts, 1188789Sahrens &value)) { 1189789Sahrens case 0: 1190789Sahrens cb.cb_sources |= ZFS_SRC_LOCAL; 1191789Sahrens break; 1192789Sahrens case 1: 1193789Sahrens cb.cb_sources |= ZFS_SRC_DEFAULT; 1194789Sahrens break; 1195789Sahrens case 2: 1196789Sahrens cb.cb_sources |= ZFS_SRC_INHERITED; 1197789Sahrens break; 1198789Sahrens case 3: 1199789Sahrens cb.cb_sources |= ZFS_SRC_TEMPORARY; 1200789Sahrens break; 1201789Sahrens case 4: 1202789Sahrens cb.cb_sources |= ZFS_SRC_NONE; 1203789Sahrens break; 1204789Sahrens default: 1205789Sahrens (void) fprintf(stderr, 1206789Sahrens gettext("invalid source " 1207789Sahrens "'%s'\n"), value); 12082082Seschrock usage(B_FALSE); 1209789Sahrens } 1210789Sahrens } 1211789Sahrens break; 1212789Sahrens 1213789Sahrens case '?': 1214789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1215789Sahrens optopt); 12162082Seschrock usage(B_FALSE); 1217789Sahrens } 1218789Sahrens } 1219789Sahrens 1220789Sahrens argc -= optind; 1221789Sahrens argv += optind; 1222789Sahrens 1223789Sahrens if (argc < 1) { 1224789Sahrens (void) fprintf(stderr, gettext("missing property " 1225789Sahrens "argument\n")); 12262082Seschrock usage(B_FALSE); 1227789Sahrens } 1228789Sahrens 1229789Sahrens fields = argv[0]; 1230789Sahrens 1231*2676Seschrock if (zfs_get_proplist(g_zfs, fields, &cb.cb_proplist) != 0) 12322082Seschrock usage(B_FALSE); 1233789Sahrens 1234789Sahrens argc--; 1235789Sahrens argv++; 1236789Sahrens 1237789Sahrens /* 1238*2676Seschrock * As part of zfs_expand_proplist(), we keep track of the maximum column 1239*2676Seschrock * width for each property. For the 'NAME' (and 'SOURCE') columns, we 1240*2676Seschrock * need to know the maximum name length. However, the user likely did 1241*2676Seschrock * not specify 'name' as one of the properties to fetch, so we need to 1242*2676Seschrock * make sure we always include at least this property for 1243*2676Seschrock * print_get_headers() to work properly. 1244789Sahrens */ 1245*2676Seschrock if (cb.cb_proplist != NULL) { 1246*2676Seschrock fake_name.pl_prop = ZFS_PROP_NAME; 1247*2676Seschrock fake_name.pl_width = strlen(gettext("NAME")); 1248*2676Seschrock fake_name.pl_next = cb.cb_proplist; 1249*2676Seschrock cb.cb_proplist = &fake_name; 1250789Sahrens } 1251789Sahrens 1252*2676Seschrock cb.cb_first = B_TRUE; 1253*2676Seschrock 1254789Sahrens /* run for each object */ 1255*2676Seschrock ret = zfs_for_each(argc, argv, recurse, ZFS_TYPE_ANY, NULL, 1256*2676Seschrock &cb.cb_proplist, get_callback, &cb); 1257*2676Seschrock 1258*2676Seschrock if (cb.cb_proplist == &fake_name) 1259*2676Seschrock zfs_free_proplist(fake_name.pl_next); 1260*2676Seschrock else 1261*2676Seschrock zfs_free_proplist(cb.cb_proplist); 1262*2676Seschrock 1263*2676Seschrock return (ret); 1264789Sahrens } 1265789Sahrens 1266789Sahrens /* 1267789Sahrens * inherit [-r] <property> <fs|vol> ... 1268789Sahrens * 1269789Sahrens * -r Recurse over all children 1270789Sahrens * 1271789Sahrens * For each dataset specified on the command line, inherit the given property 1272789Sahrens * from its parent. Inheriting a property at the pool level will cause it to 1273789Sahrens * use the default value. The '-r' flag will recurse over all children, and is 1274789Sahrens * useful for setting a property on a hierarchy-wide basis, regardless of any 1275789Sahrens * local modifications for each dataset. 1276789Sahrens */ 1277789Sahrens static int 1278789Sahrens inherit_callback(zfs_handle_t *zhp, void *data) 1279789Sahrens { 1280*2676Seschrock return (zfs_prop_inherit(zhp, data) != 0); 1281789Sahrens } 1282789Sahrens 1283789Sahrens static int 1284789Sahrens zfs_do_inherit(int argc, char **argv) 1285789Sahrens { 12862082Seschrock boolean_t recurse = B_FALSE; 1287789Sahrens int c; 1288789Sahrens zfs_prop_t prop; 1289789Sahrens char *propname; 1290789Sahrens 1291789Sahrens /* check options */ 1292789Sahrens while ((c = getopt(argc, argv, "r")) != -1) { 1293789Sahrens switch (c) { 1294789Sahrens case 'r': 12952082Seschrock recurse = B_TRUE; 1296789Sahrens break; 1297789Sahrens case '?': 1298789Sahrens default: 1299789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1300789Sahrens optopt); 13012082Seschrock usage(B_FALSE); 1302789Sahrens } 1303789Sahrens } 1304789Sahrens 1305789Sahrens argc -= optind; 1306789Sahrens argv += optind; 1307789Sahrens 1308789Sahrens /* check number of arguments */ 1309789Sahrens if (argc < 1) { 1310789Sahrens (void) fprintf(stderr, gettext("missing property argument\n")); 13112082Seschrock usage(B_FALSE); 1312789Sahrens } 1313789Sahrens if (argc < 2) { 1314789Sahrens (void) fprintf(stderr, gettext("missing dataset argument\n")); 13152082Seschrock usage(B_FALSE); 1316789Sahrens } 1317789Sahrens 1318789Sahrens propname = argv[0]; 1319*2676Seschrock argc--; 1320*2676Seschrock argv++; 1321*2676Seschrock 1322*2676Seschrock if ((prop = zfs_name_to_prop(propname)) != ZFS_PROP_INVAL) { 1323*2676Seschrock if (zfs_prop_readonly(prop)) { 1324*2676Seschrock (void) fprintf(stderr, gettext( 1325*2676Seschrock "%s property is read-only\n"), 1326*2676Seschrock propname); 1327*2676Seschrock return (1); 1328*2676Seschrock } 1329*2676Seschrock if (!zfs_prop_inheritable(prop)) { 1330*2676Seschrock (void) fprintf(stderr, gettext("'%s' property cannot " 1331*2676Seschrock "be inherited\n"), propname); 1332*2676Seschrock if (prop == ZFS_PROP_QUOTA || 1333*2676Seschrock prop == ZFS_PROP_RESERVATION) 1334*2676Seschrock (void) fprintf(stderr, gettext("use 'zfs set " 1335*2676Seschrock "%s=none' to clear\n"), propname); 1336*2676Seschrock return (1); 1337*2676Seschrock } 1338*2676Seschrock } else if (!zfs_prop_user(propname)) { 1339*2676Seschrock (void) fprintf(stderr, gettext( 1340*2676Seschrock "invalid property '%s'\n"), 1341789Sahrens propname); 13422082Seschrock usage(B_FALSE); 1343789Sahrens } 1344*2676Seschrock 1345*2676Seschrock return (zfs_for_each(argc, argv, recurse, 1346*2676Seschrock ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, NULL, NULL, 1347*2676Seschrock inherit_callback, propname)); 1348789Sahrens } 1349789Sahrens 1350789Sahrens /* 13512379Ssjelinek * list [-rH] [-o property[,property]...] [-t type[,type]...] 13522379Ssjelinek * [-s property [-s property]...] [-S property [-S property]...] 13532379Ssjelinek * <dataset> ... 1354789Sahrens * 1355789Sahrens * -r Recurse over all children 1356789Sahrens * -H Scripted mode; elide headers and separate colums by tabs 1357789Sahrens * -o Control which fields to display. 1358866Seschrock * -t Control which object types to display. 13592379Ssjelinek * -s Specify sort columns, descending order. 13602379Ssjelinek * -S Specify sort columns, ascending order. 1361789Sahrens * 1362789Sahrens * When given no arguments, lists all filesystems in the system. 1363789Sahrens * Otherwise, list the specified datasets, optionally recursing down them if 1364789Sahrens * '-r' is specified. 1365789Sahrens */ 1366789Sahrens typedef struct list_cbdata { 13672082Seschrock boolean_t cb_first; 13682082Seschrock boolean_t cb_scripted; 1369*2676Seschrock zfs_proplist_t *cb_proplist; 1370789Sahrens } list_cbdata_t; 1371789Sahrens 1372789Sahrens /* 1373789Sahrens * Given a list of columns to display, output appropriate headers for each one. 1374789Sahrens */ 1375789Sahrens static void 1376*2676Seschrock print_header(zfs_proplist_t *pl) 1377789Sahrens { 1378*2676Seschrock char headerbuf[ZFS_MAXPROPLEN]; 1379*2676Seschrock const char *header; 1380789Sahrens int i; 1381*2676Seschrock boolean_t first = B_TRUE; 1382*2676Seschrock boolean_t right_justify; 1383*2676Seschrock 1384*2676Seschrock for (; pl != NULL; pl = pl->pl_next) { 1385*2676Seschrock if (!first) { 1386789Sahrens (void) printf(" "); 1387*2676Seschrock } else { 1388*2676Seschrock first = B_FALSE; 1389*2676Seschrock } 1390*2676Seschrock 1391*2676Seschrock right_justify = B_FALSE; 1392*2676Seschrock if (pl->pl_prop != ZFS_PROP_INVAL) { 1393*2676Seschrock header = zfs_prop_column_name(pl->pl_prop); 1394*2676Seschrock right_justify = zfs_prop_align_right(pl->pl_prop); 1395*2676Seschrock } else { 1396*2676Seschrock for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 1397*2676Seschrock headerbuf[i] = toupper(pl->pl_user_prop[i]); 1398*2676Seschrock headerbuf[i] = '\0'; 1399*2676Seschrock header = headerbuf; 1400*2676Seschrock } 1401*2676Seschrock 1402*2676Seschrock if (pl->pl_next == NULL && !right_justify) 1403*2676Seschrock (void) printf("%s", header); 1404*2676Seschrock else if (right_justify) 1405*2676Seschrock (void) printf("%*s", pl->pl_width, header); 1406*2676Seschrock else 1407*2676Seschrock (void) printf("%-*s", pl->pl_width, header); 1408789Sahrens } 1409789Sahrens 1410789Sahrens (void) printf("\n"); 1411789Sahrens } 1412789Sahrens 1413789Sahrens /* 1414789Sahrens * Given a dataset and a list of fields, print out all the properties according 1415789Sahrens * to the described layout. 1416789Sahrens */ 1417789Sahrens static void 1418*2676Seschrock print_dataset(zfs_handle_t *zhp, zfs_proplist_t *pl, int scripted) 1419789Sahrens { 1420*2676Seschrock boolean_t first = B_TRUE; 1421789Sahrens char property[ZFS_MAXPROPLEN]; 1422*2676Seschrock nvlist_t *userprops = zfs_get_user_props(zhp); 1423*2676Seschrock nvlist_t *propval; 1424*2676Seschrock char *propstr; 1425*2676Seschrock boolean_t right_justify; 1426*2676Seschrock int width; 1427*2676Seschrock 1428*2676Seschrock for (; pl != NULL; pl = pl->pl_next) { 1429*2676Seschrock if (!first) { 1430789Sahrens if (scripted) 1431789Sahrens (void) printf("\t"); 1432789Sahrens else 1433789Sahrens (void) printf(" "); 1434*2676Seschrock } else { 1435*2676Seschrock first = B_FALSE; 1436789Sahrens } 1437789Sahrens 1438*2676Seschrock right_justify = B_FALSE; 1439*2676Seschrock if (pl->pl_prop != ZFS_PROP_INVAL) { 1440*2676Seschrock if (zfs_prop_get(zhp, pl->pl_prop, property, 1441*2676Seschrock sizeof (property), NULL, NULL, 0, B_FALSE) != 0) 1442*2676Seschrock propstr = "-"; 1443*2676Seschrock else 1444*2676Seschrock propstr = property; 1445*2676Seschrock 1446*2676Seschrock right_justify = zfs_prop_align_right(pl->pl_prop); 1447*2676Seschrock } else { 1448*2676Seschrock if (nvlist_lookup_nvlist(userprops, 1449*2676Seschrock pl->pl_user_prop, &propval) != 0) 1450*2676Seschrock propstr = "-"; 1451*2676Seschrock else 1452*2676Seschrock verify(nvlist_lookup_string(propval, 1453*2676Seschrock ZFS_PROP_VALUE, &propstr) == 0); 1454*2676Seschrock } 1455*2676Seschrock 1456*2676Seschrock width = pl->pl_width; 1457789Sahrens 1458866Seschrock /* 1459866Seschrock * If this is being called in scripted mode, or if this is the 1460866Seschrock * last column and it is left-justified, don't include a width 1461866Seschrock * format specifier. 1462866Seschrock */ 1463*2676Seschrock if (scripted || (pl->pl_next == NULL && !right_justify)) 1464*2676Seschrock (void) printf("%s", propstr); 1465*2676Seschrock else if (right_justify) 1466*2676Seschrock (void) printf("%*s", width, propstr); 1467*2676Seschrock else 1468*2676Seschrock (void) printf("%-*s", width, propstr); 1469789Sahrens } 1470789Sahrens 1471789Sahrens (void) printf("\n"); 1472789Sahrens } 1473789Sahrens 1474789Sahrens /* 1475789Sahrens * Generic callback function to list a dataset or snapshot. 1476789Sahrens */ 1477789Sahrens static int 1478789Sahrens list_callback(zfs_handle_t *zhp, void *data) 1479789Sahrens { 1480789Sahrens list_cbdata_t *cbp = data; 1481789Sahrens 1482789Sahrens if (cbp->cb_first) { 1483789Sahrens if (!cbp->cb_scripted) 1484*2676Seschrock print_header(cbp->cb_proplist); 14852082Seschrock cbp->cb_first = B_FALSE; 1486789Sahrens } 1487789Sahrens 1488*2676Seschrock print_dataset(zhp, cbp->cb_proplist, cbp->cb_scripted); 1489789Sahrens 1490789Sahrens return (0); 1491789Sahrens } 1492789Sahrens 1493789Sahrens static int 1494789Sahrens zfs_do_list(int argc, char **argv) 1495789Sahrens { 1496789Sahrens int c; 14972082Seschrock boolean_t recurse = B_FALSE; 14982082Seschrock boolean_t scripted = B_FALSE; 1499789Sahrens static char default_fields[] = 1500789Sahrens "name,used,available,referenced,mountpoint"; 1501789Sahrens int types = ZFS_TYPE_ANY; 1502789Sahrens char *fields = NULL; 1503789Sahrens char *basic_fields = default_fields; 1504789Sahrens list_cbdata_t cb = { 0 }; 1505789Sahrens char *value; 1506789Sahrens int ret; 1507789Sahrens char *type_subopts[] = { "filesystem", "volume", "snapshot", NULL }; 15082379Ssjelinek zfs_sort_column_t *sortcol = NULL; 1509789Sahrens 1510789Sahrens /* check options */ 15112379Ssjelinek while ((c = getopt(argc, argv, ":o:rt:Hs:S:")) != -1) { 1512789Sahrens switch (c) { 1513789Sahrens case 'o': 1514789Sahrens fields = optarg; 1515789Sahrens break; 1516789Sahrens case 'r': 15172082Seschrock recurse = B_TRUE; 1518789Sahrens break; 1519789Sahrens case 'H': 15202082Seschrock scripted = B_TRUE; 1521789Sahrens break; 15222379Ssjelinek case 's': 1523*2676Seschrock if (zfs_add_sort_column(&sortcol, optarg, 1524*2676Seschrock B_FALSE) != 0) { 15252379Ssjelinek (void) fprintf(stderr, 15262379Ssjelinek gettext("invalid property '%s'\n"), optarg); 15272379Ssjelinek usage(B_FALSE); 15282379Ssjelinek } 15292379Ssjelinek break; 15302379Ssjelinek case 'S': 1531*2676Seschrock if (zfs_add_sort_column(&sortcol, optarg, 1532*2676Seschrock B_TRUE) != 0) { 15332379Ssjelinek (void) fprintf(stderr, 15342379Ssjelinek gettext("invalid property '%s'\n"), optarg); 15352379Ssjelinek usage(B_FALSE); 15362379Ssjelinek } 15372379Ssjelinek break; 1538789Sahrens case 't': 1539789Sahrens types = 0; 1540789Sahrens while (*optarg != '\0') { 1541789Sahrens switch (getsubopt(&optarg, type_subopts, 1542789Sahrens &value)) { 1543789Sahrens case 0: 1544789Sahrens types |= ZFS_TYPE_FILESYSTEM; 1545789Sahrens break; 1546789Sahrens case 1: 1547789Sahrens types |= ZFS_TYPE_VOLUME; 1548789Sahrens break; 1549789Sahrens case 2: 1550789Sahrens types |= ZFS_TYPE_SNAPSHOT; 1551789Sahrens break; 1552789Sahrens default: 1553789Sahrens (void) fprintf(stderr, 1554789Sahrens gettext("invalid type '%s'\n"), 1555789Sahrens value); 15562082Seschrock usage(B_FALSE); 1557789Sahrens } 1558789Sahrens } 1559789Sahrens break; 1560789Sahrens case ':': 1561789Sahrens (void) fprintf(stderr, gettext("missing argument for " 1562789Sahrens "'%c' option\n"), optopt); 15632082Seschrock usage(B_FALSE); 1564789Sahrens break; 1565789Sahrens case '?': 1566789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1567789Sahrens optopt); 15682082Seschrock usage(B_FALSE); 1569789Sahrens } 1570789Sahrens } 1571789Sahrens 1572789Sahrens argc -= optind; 1573789Sahrens argv += optind; 1574789Sahrens 1575789Sahrens if (fields == NULL) 1576789Sahrens fields = basic_fields; 1577789Sahrens 1578866Seschrock /* 1579866Seschrock * If the user specifies '-o all', the zfs_get_proplist() doesn't 1580866Seschrock * normally include the name of the dataset. For 'zfs list', we always 1581866Seschrock * want this property to be first. 1582866Seschrock */ 1583*2676Seschrock if (zfs_get_proplist(g_zfs, fields, &cb.cb_proplist) != 0) 15842082Seschrock usage(B_FALSE); 1585*2676Seschrock 1586789Sahrens cb.cb_scripted = scripted; 15872082Seschrock cb.cb_first = B_TRUE; 1588789Sahrens 1589*2676Seschrock ret = zfs_for_each(argc, argv, recurse, types, sortcol, &cb.cb_proplist, 15902379Ssjelinek list_callback, &cb); 15912379Ssjelinek 1592*2676Seschrock zfs_free_proplist(cb.cb_proplist); 15932379Ssjelinek zfs_free_sort_columns(sortcol); 1594789Sahrens 15952082Seschrock if (ret == 0 && cb.cb_first) 1596789Sahrens (void) printf(gettext("no datasets available\n")); 1597789Sahrens 1598789Sahrens return (ret); 1599789Sahrens } 1600789Sahrens 1601789Sahrens /* 1602789Sahrens * zfs rename <fs | snap | vol> <fs | snap | vol> 1603789Sahrens * 1604789Sahrens * Renames the given dataset to another of the same type. 1605789Sahrens */ 1606789Sahrens /* ARGSUSED */ 1607789Sahrens static int 1608789Sahrens zfs_do_rename(int argc, char **argv) 1609789Sahrens { 1610789Sahrens zfs_handle_t *zhp; 16112082Seschrock int ret; 1612789Sahrens 1613789Sahrens /* check options */ 1614789Sahrens if (argc > 1 && argv[1][0] == '-') { 1615789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1616789Sahrens argv[1][1]); 16172082Seschrock usage(B_FALSE); 1618789Sahrens } 1619789Sahrens 1620789Sahrens /* check number of arguments */ 1621789Sahrens if (argc < 2) { 1622789Sahrens (void) fprintf(stderr, gettext("missing source dataset " 1623789Sahrens "argument\n")); 16242082Seschrock usage(B_FALSE); 1625789Sahrens } 1626789Sahrens if (argc < 3) { 1627789Sahrens (void) fprintf(stderr, gettext("missing target dataset " 1628789Sahrens "argument\n")); 16292082Seschrock usage(B_FALSE); 1630789Sahrens } 1631789Sahrens if (argc > 3) { 1632789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 16332082Seschrock usage(B_FALSE); 1634789Sahrens } 1635789Sahrens 16362082Seschrock if ((zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_ANY)) == NULL) 1637789Sahrens return (1); 1638789Sahrens 16392082Seschrock ret = (zfs_rename(zhp, argv[2]) != 0); 16402082Seschrock 16412082Seschrock zfs_close(zhp); 16422082Seschrock return (ret); 16432082Seschrock } 16442082Seschrock 16452082Seschrock /* 16462082Seschrock * zfs promote <fs> 16472082Seschrock * 16482082Seschrock * Promotes the given clone fs to be the parent 16492082Seschrock */ 16502082Seschrock /* ARGSUSED */ 16512082Seschrock static int 16522082Seschrock zfs_do_promote(int argc, char **argv) 16532082Seschrock { 16542082Seschrock zfs_handle_t *zhp; 16552082Seschrock int ret; 16562082Seschrock 16572082Seschrock /* check options */ 16582082Seschrock if (argc > 1 && argv[1][0] == '-') { 16592082Seschrock (void) fprintf(stderr, gettext("invalid option '%c'\n"), 16602082Seschrock argv[1][1]); 16612082Seschrock usage(B_FALSE); 16622082Seschrock } 16632082Seschrock 16642082Seschrock /* check number of arguments */ 16652082Seschrock if (argc < 2) { 16662082Seschrock (void) fprintf(stderr, gettext("missing clone filesystem" 16672597Snd150628 " argument\n")); 16682082Seschrock usage(B_FALSE); 16692082Seschrock } 16702082Seschrock if (argc > 2) { 16712082Seschrock (void) fprintf(stderr, gettext("too many arguments\n")); 16722082Seschrock usage(B_FALSE); 16732082Seschrock } 16742082Seschrock 16752082Seschrock zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 16762082Seschrock if (zhp == NULL) 16772082Seschrock return (1); 16782082Seschrock 16792082Seschrock ret = (zfs_promote(zhp) != 0); 16802082Seschrock 1681789Sahrens zfs_close(zhp); 1682789Sahrens return (ret); 1683789Sahrens } 1684789Sahrens 1685789Sahrens /* 1686789Sahrens * zfs rollback [-rfR] <snapshot> 1687789Sahrens * 1688789Sahrens * -r Delete any intervening snapshots before doing rollback 1689789Sahrens * -R Delete any snapshots and their clones 1690789Sahrens * -f Force unmount filesystems, even if they are in use. 1691789Sahrens * 1692789Sahrens * Given a filesystem, rollback to a specific snapshot, discarding any changes 1693789Sahrens * since then and making it the active dataset. If more recent snapshots exist, 1694789Sahrens * the command will complain unless the '-r' flag is given. 1695789Sahrens */ 1696789Sahrens typedef struct rollback_cbdata { 1697789Sahrens uint64_t cb_create; 16982082Seschrock boolean_t cb_first; 1699789Sahrens int cb_doclones; 1700789Sahrens char *cb_target; 1701789Sahrens int cb_error; 17022082Seschrock boolean_t cb_recurse; 17032082Seschrock boolean_t cb_dependent; 1704789Sahrens } rollback_cbdata_t; 1705789Sahrens 1706789Sahrens /* 1707789Sahrens * Report any snapshots more recent than the one specified. Used when '-r' is 1708789Sahrens * not specified. We reuse this same callback for the snapshot dependents - if 1709789Sahrens * 'cb_dependent' is set, then this is a dependent and we should report it 1710789Sahrens * without checking the transaction group. 1711789Sahrens */ 1712789Sahrens static int 1713789Sahrens rollback_check(zfs_handle_t *zhp, void *data) 1714789Sahrens { 1715789Sahrens rollback_cbdata_t *cbp = data; 1716789Sahrens 17172082Seschrock if (cbp->cb_doclones) { 17182082Seschrock zfs_close(zhp); 1719789Sahrens return (0); 17202082Seschrock } 1721789Sahrens 1722789Sahrens if (!cbp->cb_dependent) { 1723789Sahrens if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 && 17241294Slling zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 1725789Sahrens zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 1726789Sahrens cbp->cb_create) { 1727789Sahrens 1728789Sahrens if (cbp->cb_first && !cbp->cb_recurse) { 1729789Sahrens (void) fprintf(stderr, gettext("cannot " 1730789Sahrens "rollback to '%s': more recent snapshots " 1731789Sahrens "exist\n"), 1732789Sahrens cbp->cb_target); 1733789Sahrens (void) fprintf(stderr, gettext("use '-r' to " 1734789Sahrens "force deletion of the following " 1735789Sahrens "snapshots:\n")); 1736789Sahrens cbp->cb_first = 0; 1737789Sahrens cbp->cb_error = 1; 1738789Sahrens } 1739789Sahrens 1740789Sahrens if (cbp->cb_recurse) { 17412082Seschrock cbp->cb_dependent = B_TRUE; 17422474Seschrock if (zfs_iter_dependents(zhp, B_TRUE, 17432474Seschrock rollback_check, cbp) != 0) { 17442474Seschrock zfs_close(zhp); 17452474Seschrock return (-1); 17462474Seschrock } 17472082Seschrock cbp->cb_dependent = B_FALSE; 1748789Sahrens } else { 1749789Sahrens (void) fprintf(stderr, "%s\n", 1750789Sahrens zfs_get_name(zhp)); 1751789Sahrens } 1752789Sahrens } 1753789Sahrens } else { 1754789Sahrens if (cbp->cb_first && cbp->cb_recurse) { 1755789Sahrens (void) fprintf(stderr, gettext("cannot rollback to " 1756789Sahrens "'%s': clones of previous snapshots exist\n"), 1757789Sahrens cbp->cb_target); 1758789Sahrens (void) fprintf(stderr, gettext("use '-R' to " 1759789Sahrens "force deletion of the following clones and " 1760789Sahrens "dependents:\n")); 1761789Sahrens cbp->cb_first = 0; 1762789Sahrens cbp->cb_error = 1; 1763789Sahrens } 1764789Sahrens 1765789Sahrens (void) fprintf(stderr, "%s\n", zfs_get_name(zhp)); 1766789Sahrens } 1767789Sahrens 1768789Sahrens zfs_close(zhp); 1769789Sahrens return (0); 1770789Sahrens } 1771789Sahrens 1772789Sahrens static int 1773789Sahrens zfs_do_rollback(int argc, char **argv) 1774789Sahrens { 1775789Sahrens int ret; 1776789Sahrens int c; 1777789Sahrens rollback_cbdata_t cb = { 0 }; 1778789Sahrens zfs_handle_t *zhp, *snap; 1779789Sahrens char parentname[ZFS_MAXNAMELEN]; 1780789Sahrens char *delim; 17811294Slling int force = 0; 1782789Sahrens 1783789Sahrens /* check options */ 1784789Sahrens while ((c = getopt(argc, argv, "rfR")) != -1) { 1785789Sahrens switch (c) { 1786789Sahrens case 'f': 17871294Slling force = 1; 1788789Sahrens break; 1789789Sahrens case 'r': 1790789Sahrens cb.cb_recurse = 1; 1791789Sahrens break; 1792789Sahrens case 'R': 1793789Sahrens cb.cb_recurse = 1; 1794789Sahrens cb.cb_doclones = 1; 1795789Sahrens break; 1796789Sahrens case '?': 1797789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1798789Sahrens optopt); 17992082Seschrock usage(B_FALSE); 1800789Sahrens } 1801789Sahrens } 1802789Sahrens 1803789Sahrens argc -= optind; 1804789Sahrens argv += optind; 1805789Sahrens 1806789Sahrens /* check number of arguments */ 1807789Sahrens if (argc < 1) { 1808789Sahrens (void) fprintf(stderr, gettext("missing dataset argument\n")); 18092082Seschrock usage(B_FALSE); 1810789Sahrens } 1811789Sahrens if (argc > 1) { 1812789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 18132082Seschrock usage(B_FALSE); 1814789Sahrens } 1815789Sahrens 1816789Sahrens /* open the snapshot */ 18172082Seschrock if ((snap = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL) 1818789Sahrens return (1); 1819789Sahrens 18201294Slling /* open the parent dataset */ 18211294Slling (void) strlcpy(parentname, argv[0], sizeof (parentname)); 1822789Sahrens verify((delim = strrchr(parentname, '@')) != NULL); 1823789Sahrens *delim = '\0'; 18242082Seschrock if ((zhp = zfs_open(g_zfs, parentname, ZFS_TYPE_ANY)) == NULL) { 1825789Sahrens zfs_close(snap); 1826789Sahrens return (1); 1827789Sahrens } 1828789Sahrens 1829789Sahrens /* 1830789Sahrens * Check for more recent snapshots and/or clones based on the presence 1831789Sahrens * of '-r' and '-R'. 1832789Sahrens */ 18331294Slling cb.cb_target = argv[0]; 18341294Slling cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 18352082Seschrock cb.cb_first = B_TRUE; 1836789Sahrens cb.cb_error = 0; 18372474Seschrock if ((ret = zfs_iter_children(zhp, rollback_check, &cb)) != 0) 18382474Seschrock goto out; 1839789Sahrens 1840789Sahrens if ((ret = cb.cb_error) != 0) 1841789Sahrens goto out; 1842789Sahrens 1843789Sahrens /* 18441294Slling * Rollback parent to the given snapshot. 1845789Sahrens */ 18461294Slling ret = zfs_rollback(zhp, snap, force); 1847789Sahrens 1848789Sahrens out: 1849789Sahrens zfs_close(snap); 1850789Sahrens zfs_close(zhp); 1851789Sahrens 1852789Sahrens if (ret == 0) 1853789Sahrens return (0); 1854789Sahrens else 1855789Sahrens return (1); 1856789Sahrens } 1857789Sahrens 1858789Sahrens /* 1859789Sahrens * zfs set property=value { fs | snap | vol } ... 1860789Sahrens * 1861789Sahrens * Sets the given property for all datasets specified on the command line. 1862789Sahrens */ 1863789Sahrens typedef struct set_cbdata { 1864789Sahrens char *cb_propname; 1865789Sahrens char *cb_value; 1866789Sahrens } set_cbdata_t; 1867789Sahrens 1868789Sahrens static int 1869789Sahrens set_callback(zfs_handle_t *zhp, void *data) 1870789Sahrens { 1871789Sahrens set_cbdata_t *cbp = data; 1872789Sahrens int ret = 1; 1873789Sahrens 1874*2676Seschrock if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) { 18752169Snd150628 switch (libzfs_errno(g_zfs)) { 18762169Snd150628 case EZFS_MOUNTFAILED: 18772169Snd150628 (void) fprintf(stderr, gettext("property may be set " 18782169Snd150628 "but unable to remount filesystem\n")); 18792169Snd150628 break; 18802169Snd150628 case EZFS_SHAREFAILED: 18812169Snd150628 (void) fprintf(stderr, gettext("property may be set " 18822169Snd150628 "but unable to reshare filesystem\n")); 18832169Snd150628 break; 18842169Snd150628 } 1885789Sahrens return (1); 18862169Snd150628 } 1887789Sahrens ret = 0; 1888789Sahrens error: 1889789Sahrens return (ret); 1890789Sahrens } 1891789Sahrens 1892789Sahrens static int 1893789Sahrens zfs_do_set(int argc, char **argv) 1894789Sahrens { 1895789Sahrens set_cbdata_t cb; 1896789Sahrens 1897789Sahrens /* check for options */ 1898789Sahrens if (argc > 1 && argv[1][0] == '-') { 1899789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1900789Sahrens argv[1][1]); 19012082Seschrock usage(B_FALSE); 1902789Sahrens } 1903789Sahrens 1904789Sahrens /* check number of arguments */ 1905789Sahrens if (argc < 2) { 1906789Sahrens (void) fprintf(stderr, gettext("missing property=value " 1907789Sahrens "argument\n")); 19082082Seschrock usage(B_FALSE); 1909789Sahrens } 1910789Sahrens if (argc < 3) { 1911789Sahrens (void) fprintf(stderr, gettext("missing dataset name\n")); 19122082Seschrock usage(B_FALSE); 1913789Sahrens } 1914789Sahrens 1915789Sahrens /* validate property=value argument */ 1916789Sahrens cb.cb_propname = argv[1]; 1917789Sahrens if ((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) { 1918789Sahrens (void) fprintf(stderr, gettext("missing value in " 1919789Sahrens "property=value argument\n")); 19202082Seschrock usage(B_FALSE); 1921789Sahrens } 1922789Sahrens 1923789Sahrens *cb.cb_value = '\0'; 1924789Sahrens cb.cb_value++; 1925789Sahrens 1926789Sahrens if (*cb.cb_propname == '\0') { 1927789Sahrens (void) fprintf(stderr, 1928789Sahrens gettext("missing property in property=value argument\n")); 19292082Seschrock usage(B_FALSE); 1930789Sahrens } 1931789Sahrens 19322082Seschrock return (zfs_for_each(argc - 2, argv + 2, B_FALSE, 1933*2676Seschrock ZFS_TYPE_ANY, NULL, NULL, set_callback, &cb)); 1934789Sahrens } 1935789Sahrens 1936789Sahrens /* 19372199Sahrens * zfs snapshot [-r] <fs@snap> 1938789Sahrens * 1939789Sahrens * Creates a snapshot with the given name. While functionally equivalent to 1940789Sahrens * 'zfs create', it is a separate command to diffferentiate intent. 1941789Sahrens */ 1942789Sahrens static int 1943789Sahrens zfs_do_snapshot(int argc, char **argv) 1944789Sahrens { 19452199Sahrens int recursive = B_FALSE; 19462199Sahrens int ret; 19472199Sahrens char c; 19482199Sahrens 1949789Sahrens /* check options */ 19502199Sahrens while ((c = getopt(argc, argv, ":r")) != -1) { 19512199Sahrens switch (c) { 19522199Sahrens case 'r': 19532199Sahrens recursive = B_TRUE; 19542199Sahrens break; 19552199Sahrens case '?': 19562199Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 19572199Sahrens optopt); 19582199Sahrens usage(B_FALSE); 19592199Sahrens } 1960789Sahrens } 1961789Sahrens 19622199Sahrens argc -= optind; 19632199Sahrens argv += optind; 19642199Sahrens 1965789Sahrens /* check number of arguments */ 19662199Sahrens if (argc < 1) { 1967789Sahrens (void) fprintf(stderr, gettext("missing snapshot argument\n")); 19682082Seschrock usage(B_FALSE); 1969789Sahrens } 19702199Sahrens if (argc > 1) { 1971789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 19722082Seschrock usage(B_FALSE); 1973789Sahrens } 1974789Sahrens 19752199Sahrens ret = zfs_snapshot(g_zfs, argv[0], recursive); 19762199Sahrens if (ret && recursive) 19772199Sahrens (void) fprintf(stderr, gettext("no snapshots were created\n")); 19782199Sahrens return (ret != 0); 19792199Sahrens 1980789Sahrens } 1981789Sahrens 1982789Sahrens /* 19831749Sahrens * zfs send [-i <fs@snap>] <fs@snap> 1984789Sahrens * 1985789Sahrens * Send a backup stream to stdout. 1986789Sahrens */ 1987789Sahrens static int 19881749Sahrens zfs_do_send(int argc, char **argv) 1989789Sahrens { 1990789Sahrens char *fromname = NULL; 1991789Sahrens zfs_handle_t *zhp_from = NULL, *zhp_to; 1992789Sahrens int c, err; 19932665Snd150628 char fullname[MAXPATHLEN]; 1994789Sahrens 1995789Sahrens /* check options */ 1996789Sahrens while ((c = getopt(argc, argv, ":i:")) != -1) { 1997789Sahrens switch (c) { 1998789Sahrens case 'i': 1999789Sahrens fromname = optarg; 2000789Sahrens break; 2001789Sahrens case ':': 2002789Sahrens (void) fprintf(stderr, gettext("missing argument for " 2003789Sahrens "'%c' option\n"), optopt); 20042082Seschrock usage(B_FALSE); 2005789Sahrens break; 2006789Sahrens case '?': 2007789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2008789Sahrens optopt); 20092082Seschrock usage(B_FALSE); 2010789Sahrens } 2011789Sahrens } 2012789Sahrens 2013789Sahrens argc -= optind; 2014789Sahrens argv += optind; 2015789Sahrens 2016789Sahrens /* check number of arguments */ 2017789Sahrens if (argc < 1) { 2018789Sahrens (void) fprintf(stderr, gettext("missing snapshot argument\n")); 20192082Seschrock usage(B_FALSE); 2020789Sahrens } 2021789Sahrens if (argc > 1) { 2022789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 20232082Seschrock usage(B_FALSE); 2024789Sahrens } 2025789Sahrens 2026789Sahrens if (isatty(STDOUT_FILENO)) { 2027789Sahrens (void) fprintf(stderr, 20281749Sahrens gettext("Error: Stream can not be written " 2029789Sahrens "to a terminal.\n" 2030789Sahrens "You must redirect standard output.\n")); 2031789Sahrens return (1); 2032789Sahrens } 2033789Sahrens 20342665Snd150628 if ((zhp_to = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL) 20352665Snd150628 return (1); 20362665Snd150628 2037789Sahrens if (fromname) { 20382665Snd150628 20392665Snd150628 /* 20402665Snd150628 * If fromname is an abbreviated snapshot name, 20412665Snd150628 * then reconstruct the name of the parent dataset 20422665Snd150628 */ 20432665Snd150628 if ((strchr(fromname, '@') == NULL) || 20442665Snd150628 *fromname == '@') { 20452665Snd150628 char *cp; 20462665Snd150628 cp = strchr(argv[0], '@'); 20472665Snd150628 if (strchr(fromname, '@') == NULL) 20482665Snd150628 *(++cp) = '\0'; 20492665Snd150628 else 20502665Snd150628 *cp = '\0'; 20512665Snd150628 (void) strncpy(fullname, argv[0], sizeof (fullname)); 20522665Snd150628 (void) strlcat(fullname, fromname, sizeof (fullname)); 20532665Snd150628 fromname = fullname; 20542665Snd150628 } 20552665Snd150628 20562082Seschrock if ((zhp_from = zfs_open(g_zfs, fromname, 20572082Seschrock ZFS_TYPE_SNAPSHOT)) == NULL) 2058789Sahrens return (1); 2059789Sahrens } 2060789Sahrens 20611749Sahrens err = zfs_send(zhp_to, zhp_from); 2062789Sahrens 2063789Sahrens if (zhp_from) 2064789Sahrens zfs_close(zhp_from); 2065789Sahrens zfs_close(zhp_to); 2066789Sahrens 2067789Sahrens return (err != 0); 2068789Sahrens } 2069789Sahrens 2070789Sahrens /* 20711749Sahrens * zfs receive <fs@snap> 2072789Sahrens * 2073789Sahrens * Restore a backup stream from stdin. 2074789Sahrens */ 2075789Sahrens static int 20761749Sahrens zfs_do_receive(int argc, char **argv) 2077789Sahrens { 2078789Sahrens int c, err; 20792082Seschrock boolean_t isprefix = B_FALSE; 20802082Seschrock boolean_t dryrun = B_FALSE; 20812082Seschrock boolean_t verbose = B_FALSE; 20822665Snd150628 boolean_t force = B_FALSE; 2083789Sahrens 2084789Sahrens /* check options */ 20852665Snd150628 while ((c = getopt(argc, argv, ":dnvF")) != -1) { 2086789Sahrens switch (c) { 2087789Sahrens case 'd': 20882082Seschrock isprefix = B_TRUE; 2089789Sahrens break; 2090789Sahrens case 'n': 20912082Seschrock dryrun = B_TRUE; 2092789Sahrens break; 2093789Sahrens case 'v': 20942082Seschrock verbose = B_TRUE; 2095789Sahrens break; 20962665Snd150628 case 'F': 20972665Snd150628 force = B_TRUE; 20982665Snd150628 break; 2099789Sahrens case ':': 2100789Sahrens (void) fprintf(stderr, gettext("missing argument for " 2101789Sahrens "'%c' option\n"), optopt); 21022082Seschrock usage(B_FALSE); 2103789Sahrens break; 2104789Sahrens case '?': 2105789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2106789Sahrens optopt); 21072082Seschrock usage(B_FALSE); 2108789Sahrens } 2109789Sahrens } 2110789Sahrens 2111789Sahrens argc -= optind; 2112789Sahrens argv += optind; 2113789Sahrens 2114789Sahrens /* check number of arguments */ 2115789Sahrens if (argc < 1) { 2116789Sahrens (void) fprintf(stderr, gettext("missing snapshot argument\n")); 21172082Seschrock usage(B_FALSE); 2118789Sahrens } 2119789Sahrens if (argc > 1) { 2120789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 21212082Seschrock usage(B_FALSE); 2122789Sahrens } 2123789Sahrens 2124789Sahrens if (isatty(STDIN_FILENO)) { 2125789Sahrens (void) fprintf(stderr, 2126789Sahrens gettext("Error: Backup stream can not be read " 2127789Sahrens "from a terminal.\n" 2128789Sahrens "You must redirect standard input.\n")); 2129789Sahrens return (1); 2130789Sahrens } 2131789Sahrens 21322665Snd150628 err = zfs_receive(g_zfs, argv[0], isprefix, verbose, dryrun, force); 2133789Sahrens return (err != 0); 2134789Sahrens } 2135789Sahrens 21361356Seschrock typedef struct get_all_cbdata { 21371356Seschrock zfs_handle_t **cb_handles; 21381356Seschrock size_t cb_alloc; 21391356Seschrock size_t cb_used; 21401356Seschrock } get_all_cbdata_t; 21411356Seschrock 21421356Seschrock static int 21431356Seschrock get_one_filesystem(zfs_handle_t *zhp, void *data) 21441356Seschrock { 21451356Seschrock get_all_cbdata_t *cbp = data; 21461356Seschrock 21471356Seschrock /* 21481356Seschrock * Skip any zvols 21491356Seschrock */ 21501356Seschrock if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 21511356Seschrock zfs_close(zhp); 21521356Seschrock return (0); 21531356Seschrock } 21541356Seschrock 21551356Seschrock if (cbp->cb_alloc == cbp->cb_used) { 21561356Seschrock zfs_handle_t **handles; 21571356Seschrock 21581356Seschrock if (cbp->cb_alloc == 0) 21591356Seschrock cbp->cb_alloc = 64; 21601356Seschrock else 21611356Seschrock cbp->cb_alloc *= 2; 21621356Seschrock 21631356Seschrock handles = safe_malloc(cbp->cb_alloc * sizeof (void *)); 21641356Seschrock 21651356Seschrock if (cbp->cb_handles) { 21661356Seschrock bcopy(cbp->cb_handles, handles, 21671356Seschrock cbp->cb_used * sizeof (void *)); 21681356Seschrock free(cbp->cb_handles); 21691356Seschrock } 21701356Seschrock 21711356Seschrock cbp->cb_handles = handles; 21721356Seschrock } 21731356Seschrock 21741356Seschrock cbp->cb_handles[cbp->cb_used++] = zhp; 21751356Seschrock 21761356Seschrock return (zfs_iter_filesystems(zhp, get_one_filesystem, data)); 21771356Seschrock } 21781356Seschrock 21791356Seschrock static void 21801356Seschrock get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 21811356Seschrock { 21821356Seschrock get_all_cbdata_t cb = { 0 }; 21831356Seschrock 21842082Seschrock (void) zfs_iter_root(g_zfs, get_one_filesystem, &cb); 21851356Seschrock 21861356Seschrock *fslist = cb.cb_handles; 21871356Seschrock *count = cb.cb_used; 21881356Seschrock } 21891356Seschrock 21901356Seschrock static int 21911356Seschrock mountpoint_compare(const void *a, const void *b) 21921356Seschrock { 21931356Seschrock zfs_handle_t **za = (zfs_handle_t **)a; 21941356Seschrock zfs_handle_t **zb = (zfs_handle_t **)b; 21951356Seschrock char mounta[MAXPATHLEN]; 21961356Seschrock char mountb[MAXPATHLEN]; 21971356Seschrock 21981356Seschrock verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 21992082Seschrock sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 22001356Seschrock verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 22012082Seschrock sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 22021356Seschrock 22031356Seschrock return (strcmp(mounta, mountb)); 22041356Seschrock } 2205789Sahrens 2206789Sahrens /* 2207789Sahrens * Generic callback for sharing or mounting filesystems. Because the code is so 2208789Sahrens * similar, we have a common function with an extra parameter to determine which 2209789Sahrens * mode we are using. 2210789Sahrens */ 2211789Sahrens #define OP_SHARE 0x1 2212789Sahrens #define OP_MOUNT 0x2 2213789Sahrens 2214789Sahrens typedef struct share_mount_cbdata { 2215789Sahrens int cb_type; 2216789Sahrens int cb_explicit; 2217789Sahrens int cb_flags; 2218789Sahrens const char *cb_options; 2219789Sahrens } share_mount_cbdata_t; 2220789Sahrens 2221789Sahrens /* 2222789Sahrens * Share or mount the filesystem. 2223789Sahrens */ 2224789Sahrens static int 2225789Sahrens share_mount_callback(zfs_handle_t *zhp, void *data) 2226789Sahrens { 2227789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 2228789Sahrens char shareopts[ZFS_MAXPROPLEN]; 2229789Sahrens share_mount_cbdata_t *cbp = data; 2230789Sahrens const char *cmdname = cbp->cb_type == OP_SHARE ? "share" : "mount"; 2231789Sahrens struct mnttab mnt; 2232*2676Seschrock uint64_t zoned, canmount; 2233789Sahrens 2234789Sahrens if (cbp->cb_options == NULL) 2235789Sahrens mnt.mnt_mntopts = ""; 2236789Sahrens else 2237789Sahrens mnt.mnt_mntopts = (char *)cbp->cb_options; 2238789Sahrens 2239789Sahrens /* 2240789Sahrens * Check to make sure we can mount/share this dataset. If we are in the 2241789Sahrens * global zone and the filesystem is exported to a local zone, or if we 2242789Sahrens * are in a local zone and the filesystem is not exported, then it is an 2243789Sahrens * error. 2244789Sahrens */ 2245789Sahrens zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2246789Sahrens 2247789Sahrens if (zoned && getzoneid() == GLOBAL_ZONEID) { 2248789Sahrens if (!cbp->cb_explicit) 2249789Sahrens return (0); 2250789Sahrens 2251789Sahrens (void) fprintf(stderr, gettext("cannot %s '%s': dataset is " 2252789Sahrens "exported to a local zone\n"), cmdname, zfs_get_name(zhp)); 2253789Sahrens return (1); 2254789Sahrens 2255789Sahrens } else if (!zoned && getzoneid() != GLOBAL_ZONEID) { 2256789Sahrens if (!cbp->cb_explicit) 2257789Sahrens return (0); 2258789Sahrens 2259789Sahrens (void) fprintf(stderr, gettext("cannot %s '%s': permission " 2260789Sahrens "denied\n"), cmdname, zfs_get_name(zhp)); 2261789Sahrens return (1); 2262789Sahrens } 2263789Sahrens 2264789Sahrens /* 2265789Sahrens * Inore any filesystems which don't apply to us. This includes those 2266789Sahrens * with a legacy mountpoint, or those with legacy share options. 2267789Sahrens */ 2268789Sahrens verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 22692082Seschrock sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0); 2270789Sahrens verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, 22712082Seschrock sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); 2272*2676Seschrock canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT); 2273789Sahrens 2274789Sahrens if (cbp->cb_type == OP_SHARE) { 2275789Sahrens if (strcmp(shareopts, "off") == 0) { 2276789Sahrens if (!cbp->cb_explicit) 2277789Sahrens return (0); 2278789Sahrens 2279789Sahrens (void) fprintf(stderr, gettext("cannot share '%s': " 2280789Sahrens "legacy share\n"), zfs_get_name(zhp)); 2281789Sahrens (void) fprintf(stderr, gettext("use share(1M) to " 2282789Sahrens "share this filesystem\n")); 2283789Sahrens return (1); 2284789Sahrens } 2285789Sahrens } 2286789Sahrens 2287789Sahrens /* 2288789Sahrens * We cannot share or mount legacy filesystems. If the shareopts is 2289789Sahrens * non-legacy but the mountpoint is legacy, we treat it as a legacy 2290789Sahrens * share. 2291789Sahrens */ 2292789Sahrens if (strcmp(mountpoint, "legacy") == 0) { 2293789Sahrens if (!cbp->cb_explicit) 2294789Sahrens return (0); 2295789Sahrens 2296789Sahrens (void) fprintf(stderr, gettext("cannot %s '%s': " 2297789Sahrens "legacy mountpoint\n"), cmdname, zfs_get_name(zhp)); 2298789Sahrens (void) fprintf(stderr, gettext("use %s to " 2299789Sahrens "%s this filesystem\n"), cbp->cb_type == OP_SHARE ? 2300789Sahrens "share(1M)" : "mount(1M)", cmdname); 2301789Sahrens return (1); 2302789Sahrens } 2303789Sahrens 2304789Sahrens if (strcmp(mountpoint, "none") == 0) { 2305789Sahrens if (!cbp->cb_explicit) 2306789Sahrens return (0); 2307789Sahrens 2308789Sahrens (void) fprintf(stderr, gettext("cannot %s '%s': no " 2309789Sahrens "mountpoint set\n"), cmdname, zfs_get_name(zhp)); 2310789Sahrens return (1); 2311789Sahrens } 2312789Sahrens 2313*2676Seschrock if (!canmount) { 2314*2676Seschrock if (!cbp->cb_explicit) 2315*2676Seschrock return (0); 2316*2676Seschrock 2317*2676Seschrock (void) fprintf(stderr, gettext("cannot %s '%s': 'canmount' " 2318*2676Seschrock "property is set to 'off'\n"), cmdname, zfs_get_name(zhp)); 2319*2676Seschrock return (1); 2320*2676Seschrock } 2321*2676Seschrock 2322789Sahrens /* 2323789Sahrens * At this point, we have verified that the mountpoint and/or shareopts 2324789Sahrens * are appropriate for auto management. Determine if the filesystem is 2325789Sahrens * currently mounted or shared, and abort if this is an explicit 2326789Sahrens * request. 2327789Sahrens */ 2328789Sahrens switch (cbp->cb_type) { 2329789Sahrens case OP_SHARE: 2330789Sahrens if (zfs_is_shared(zhp, NULL)) { 2331789Sahrens if (cbp->cb_explicit) { 2332789Sahrens (void) fprintf(stderr, gettext("cannot share " 2333789Sahrens "'%s': filesystem already shared\n"), 2334789Sahrens zfs_get_name(zhp)); 2335789Sahrens return (1); 2336789Sahrens } else { 2337789Sahrens return (0); 2338789Sahrens } 2339789Sahrens } 2340789Sahrens break; 2341789Sahrens 2342789Sahrens case OP_MOUNT: 2343789Sahrens if (!hasmntopt(&mnt, MNTOPT_REMOUNT) && 2344789Sahrens zfs_is_mounted(zhp, NULL)) { 2345789Sahrens if (cbp->cb_explicit) { 2346789Sahrens (void) fprintf(stderr, gettext("cannot mount " 2347789Sahrens "'%s': filesystem already mounted\n"), 2348789Sahrens zfs_get_name(zhp)); 2349789Sahrens return (1); 2350789Sahrens } else { 2351789Sahrens return (0); 2352789Sahrens } 2353789Sahrens } 2354789Sahrens break; 2355789Sahrens } 2356789Sahrens 2357789Sahrens /* 2358789Sahrens * Mount and optionally share the filesystem. 2359789Sahrens */ 2360789Sahrens switch (cbp->cb_type) { 2361789Sahrens case OP_SHARE: 2362789Sahrens { 2363789Sahrens if (!zfs_is_mounted(zhp, NULL) && 2364789Sahrens zfs_mount(zhp, NULL, 0) != 0) 2365789Sahrens return (1); 2366789Sahrens 2367789Sahrens if (zfs_share(zhp) != 0) 2368789Sahrens return (1); 2369789Sahrens } 2370789Sahrens break; 2371789Sahrens 2372789Sahrens case OP_MOUNT: 2373789Sahrens if (zfs_mount(zhp, cbp->cb_options, cbp->cb_flags) != 0) 2374789Sahrens return (1); 2375789Sahrens break; 2376789Sahrens } 2377789Sahrens 2378789Sahrens return (0); 2379789Sahrens } 2380789Sahrens 2381789Sahrens static int 2382789Sahrens share_or_mount(int type, int argc, char **argv) 2383789Sahrens { 2384789Sahrens int do_all = 0; 23852372Slling int c, ret = 0; 2386789Sahrens share_mount_cbdata_t cb = { 0 }; 2387789Sahrens 2388789Sahrens cb.cb_type = type; 2389789Sahrens 2390789Sahrens /* check options */ 2391789Sahrens while ((c = getopt(argc, argv, type == OP_MOUNT ? ":ao:O" : "a")) 2392789Sahrens != -1) { 2393789Sahrens switch (c) { 2394789Sahrens case 'a': 2395789Sahrens do_all = 1; 2396789Sahrens break; 2397789Sahrens case 'o': 2398789Sahrens cb.cb_options = optarg; 2399789Sahrens break; 2400789Sahrens case 'O': 2401789Sahrens cb.cb_flags |= MS_OVERLAY; 2402789Sahrens break; 2403789Sahrens case ':': 2404789Sahrens (void) fprintf(stderr, gettext("missing argument for " 2405789Sahrens "'%c' option\n"), optopt); 24062082Seschrock usage(B_FALSE); 2407789Sahrens break; 2408789Sahrens case '?': 2409789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2410789Sahrens optopt); 24112082Seschrock usage(B_FALSE); 2412789Sahrens } 2413789Sahrens } 2414789Sahrens 2415789Sahrens argc -= optind; 2416789Sahrens argv += optind; 2417789Sahrens 2418789Sahrens /* check number of arguments */ 2419789Sahrens if (do_all) { 24201356Seschrock zfs_handle_t **fslist = NULL; 24211356Seschrock size_t i, count = 0; 24221356Seschrock 2423789Sahrens if (argc != 0) { 2424789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 24252082Seschrock usage(B_FALSE); 2426789Sahrens } 2427789Sahrens 24281356Seschrock get_all_filesystems(&fslist, &count); 24291356Seschrock 24301356Seschrock if (count == 0) 24311356Seschrock return (0); 24321356Seschrock 24331356Seschrock qsort(fslist, count, sizeof (void *), mountpoint_compare); 24341356Seschrock 24351356Seschrock for (i = 0; i < count; i++) { 24362369Slling if (share_mount_callback(fslist[i], &cb) != 0) 24372369Slling ret = 1; 24381356Seschrock } 24391356Seschrock 24401356Seschrock for (i = 0; i < count; i++) 24411356Seschrock zfs_close(fslist[i]); 24421356Seschrock 24431356Seschrock free(fslist); 2444789Sahrens } else if (argc == 0) { 2445789Sahrens struct mnttab entry; 2446789Sahrens 2447789Sahrens if (type == OP_SHARE) { 2448789Sahrens (void) fprintf(stderr, gettext("missing filesystem " 2449789Sahrens "argument\n")); 24502082Seschrock usage(B_FALSE); 2451789Sahrens } 2452789Sahrens 2453789Sahrens /* 2454789Sahrens * When mount is given no arguments, go through /etc/mnttab and 2455789Sahrens * display any active ZFS mounts. We hide any snapshots, since 2456789Sahrens * they are controlled automatically. 2457789Sahrens */ 2458789Sahrens rewind(mnttab_file); 2459789Sahrens while (getmntent(mnttab_file, &entry) == 0) { 2460789Sahrens if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 || 2461789Sahrens strchr(entry.mnt_special, '@') != NULL) 2462789Sahrens continue; 2463789Sahrens 2464789Sahrens (void) printf("%-30s %s\n", entry.mnt_special, 2465789Sahrens entry.mnt_mountp); 2466789Sahrens } 2467789Sahrens 2468789Sahrens } else { 2469789Sahrens zfs_handle_t *zhp; 2470789Sahrens 2471789Sahrens if (argc > 1) { 2472789Sahrens (void) fprintf(stderr, 2473789Sahrens gettext("too many arguments\n")); 24742082Seschrock usage(B_FALSE); 2475789Sahrens } 2476789Sahrens 24772082Seschrock if ((zhp = zfs_open(g_zfs, argv[0], 24782082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 2479789Sahrens ret = 1; 2480789Sahrens else { 24812082Seschrock cb.cb_explicit = B_TRUE; 2482789Sahrens ret = share_mount_callback(zhp, &cb); 2483789Sahrens zfs_close(zhp); 2484789Sahrens } 2485789Sahrens } 2486789Sahrens 2487789Sahrens return (ret); 2488789Sahrens } 2489789Sahrens 2490789Sahrens /* 2491789Sahrens * zfs mount -a 2492789Sahrens * zfs mount filesystem 2493789Sahrens * 2494789Sahrens * Mount all filesystems, or mount the given filesystem. 2495789Sahrens */ 2496789Sahrens static int 2497789Sahrens zfs_do_mount(int argc, char **argv) 2498789Sahrens { 2499789Sahrens return (share_or_mount(OP_MOUNT, argc, argv)); 2500789Sahrens } 2501789Sahrens 2502789Sahrens /* 2503789Sahrens * zfs share -a 2504789Sahrens * zfs share filesystem 2505789Sahrens * 2506789Sahrens * Share all filesystems, or share the given filesystem. 2507789Sahrens */ 2508789Sahrens static int 2509789Sahrens zfs_do_share(int argc, char **argv) 2510789Sahrens { 2511789Sahrens return (share_or_mount(OP_SHARE, argc, argv)); 2512789Sahrens } 2513789Sahrens 2514789Sahrens typedef struct unshare_unmount_node { 2515789Sahrens zfs_handle_t *un_zhp; 2516789Sahrens char *un_mountp; 2517789Sahrens uu_avl_node_t un_avlnode; 2518789Sahrens } unshare_unmount_node_t; 2519789Sahrens 2520789Sahrens /* ARGSUSED */ 2521789Sahrens static int 2522789Sahrens unshare_unmount_compare(const void *larg, const void *rarg, void *unused) 2523789Sahrens { 2524789Sahrens const unshare_unmount_node_t *l = larg; 2525789Sahrens const unshare_unmount_node_t *r = rarg; 2526789Sahrens 2527789Sahrens return (strcmp(l->un_mountp, r->un_mountp)); 2528789Sahrens } 2529789Sahrens 2530789Sahrens /* 2531789Sahrens * Convenience routine used by zfs_do_umount() and manual_unmount(). Given an 2532789Sahrens * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem, 2533789Sahrens * and unmount it appropriately. 2534789Sahrens */ 2535789Sahrens static int 25362082Seschrock unshare_unmount_path(int type, char *path, int flags, boolean_t is_manual) 2537789Sahrens { 2538789Sahrens zfs_handle_t *zhp; 2539789Sahrens int ret; 2540789Sahrens struct stat64 statbuf; 2541789Sahrens struct extmnttab entry; 2542789Sahrens const char *cmdname = (type == OP_SHARE) ? "unshare" : "unmount"; 2543789Sahrens char property[ZFS_MAXPROPLEN]; 2544789Sahrens 2545789Sahrens /* 2546789Sahrens * Search for the path in /etc/mnttab. Rather than looking for the 2547789Sahrens * specific path, which can be fooled by non-standard paths (i.e. ".." 2548789Sahrens * or "//"), we stat() the path and search for the corresponding 2549789Sahrens * (major,minor) device pair. 2550789Sahrens */ 2551789Sahrens if (stat64(path, &statbuf) != 0) { 2552789Sahrens (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"), 2553789Sahrens cmdname, path, strerror(errno)); 2554789Sahrens return (1); 2555789Sahrens } 2556789Sahrens 2557789Sahrens /* 2558789Sahrens * Search for the given (major,minor) pair in the mount table. 2559789Sahrens */ 2560789Sahrens rewind(mnttab_file); 2561789Sahrens while ((ret = getextmntent(mnttab_file, &entry, 0)) == 0) { 2562789Sahrens if (entry.mnt_major == major(statbuf.st_dev) && 2563789Sahrens entry.mnt_minor == minor(statbuf.st_dev)) 2564789Sahrens break; 2565789Sahrens } 2566789Sahrens if (ret != 0) { 2567789Sahrens (void) fprintf(stderr, gettext("cannot %s '%s': not " 2568789Sahrens "currently mounted\n"), cmdname, path); 2569789Sahrens return (1); 2570789Sahrens } 2571789Sahrens 2572789Sahrens if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) { 2573789Sahrens (void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS " 2574789Sahrens "filesystem\n"), cmdname, path); 2575789Sahrens return (1); 2576789Sahrens } 2577789Sahrens 25782082Seschrock if ((zhp = zfs_open(g_zfs, entry.mnt_special, 25792082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 2580789Sahrens return (1); 2581789Sahrens 2582789Sahrens verify(zfs_prop_get(zhp, type == OP_SHARE ? 2583789Sahrens ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property, 25842082Seschrock sizeof (property), NULL, NULL, 0, B_FALSE) == 0); 2585789Sahrens 2586789Sahrens if (type == OP_SHARE) { 2587789Sahrens if (strcmp(property, "off") == 0) { 2588789Sahrens (void) fprintf(stderr, gettext("cannot unshare " 2589789Sahrens "'%s': legacy share\n"), path); 2590789Sahrens (void) fprintf(stderr, gettext("use " 2591789Sahrens "unshare(1M) to unshare this filesystem\n")); 2592789Sahrens ret = 1; 2593789Sahrens } else if (!zfs_is_shared(zhp, NULL)) { 2594789Sahrens (void) fprintf(stderr, gettext("cannot unshare '%s': " 2595789Sahrens "not currently shared\n"), path); 2596789Sahrens ret = 1; 2597789Sahrens } else { 2598789Sahrens ret = zfs_unshareall(zhp); 2599789Sahrens } 2600789Sahrens } else { 26011264Slling if (is_manual) { 26021264Slling ret = zfs_unmount(zhp, NULL, flags); 26031264Slling } else if (strcmp(property, "legacy") == 0) { 26041264Slling (void) fprintf(stderr, gettext("cannot unmount " 26051264Slling "'%s': legacy mountpoint\n"), 26061264Slling zfs_get_name(zhp)); 26071264Slling (void) fprintf(stderr, gettext("use umount(1M) " 26081264Slling "to unmount this filesystem\n")); 26091264Slling ret = 1; 2610789Sahrens } else { 2611789Sahrens ret = zfs_unmountall(zhp, flags); 2612789Sahrens } 2613789Sahrens } 2614789Sahrens 2615789Sahrens zfs_close(zhp); 2616789Sahrens 2617789Sahrens return (ret != 0); 2618789Sahrens } 2619789Sahrens 2620789Sahrens /* 2621789Sahrens * Generic callback for unsharing or unmounting a filesystem. 2622789Sahrens */ 2623789Sahrens static int 2624789Sahrens unshare_unmount(int type, int argc, char **argv) 2625789Sahrens { 2626789Sahrens int do_all = 0; 2627789Sahrens int flags = 0; 2628789Sahrens int ret = 0; 2629789Sahrens int c; 2630789Sahrens zfs_handle_t *zhp; 2631789Sahrens char property[ZFS_MAXPROPLEN]; 2632789Sahrens 2633789Sahrens /* check options */ 2634789Sahrens while ((c = getopt(argc, argv, type == OP_SHARE ? "a" : "af")) != -1) { 2635789Sahrens switch (c) { 2636789Sahrens case 'a': 2637789Sahrens do_all = 1; 2638789Sahrens break; 2639789Sahrens case 'f': 2640789Sahrens flags = MS_FORCE; 2641789Sahrens break; 2642789Sahrens case '?': 2643789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2644789Sahrens optopt); 26452082Seschrock usage(B_FALSE); 2646789Sahrens } 2647789Sahrens } 2648789Sahrens 2649789Sahrens argc -= optind; 2650789Sahrens argv += optind; 2651789Sahrens 2652789Sahrens /* ensure correct number of arguments */ 2653789Sahrens if (do_all) { 2654789Sahrens if (argc != 0) { 2655789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 26562082Seschrock usage(B_FALSE); 2657789Sahrens } 2658789Sahrens } else if (argc != 1) { 2659789Sahrens if (argc == 0) 2660789Sahrens (void) fprintf(stderr, 2661789Sahrens gettext("missing filesystem argument\n")); 2662789Sahrens else 2663789Sahrens (void) fprintf(stderr, 2664789Sahrens gettext("too many arguments\n")); 26652082Seschrock usage(B_FALSE); 2666789Sahrens } 2667789Sahrens 2668789Sahrens if (do_all) { 2669789Sahrens /* 2670789Sahrens * We could make use of zfs_for_each() to walk all datasets in 2671789Sahrens * the system, but this would be very inefficient, especially 2672789Sahrens * since we would have to linearly search /etc/mnttab for each 2673789Sahrens * one. Instead, do one pass through /etc/mnttab looking for 2674789Sahrens * zfs entries and call zfs_unmount() for each one. 2675789Sahrens * 2676789Sahrens * Things get a little tricky if the administrator has created 2677789Sahrens * mountpoints beneath other ZFS filesystems. In this case, we 2678789Sahrens * have to unmount the deepest filesystems first. To accomplish 2679789Sahrens * this, we place all the mountpoints in an AVL tree sorted by 2680789Sahrens * the special type (dataset name), and walk the result in 2681789Sahrens * reverse to make sure to get any snapshots first. 2682789Sahrens */ 2683789Sahrens struct mnttab entry; 2684789Sahrens uu_avl_pool_t *pool; 2685789Sahrens uu_avl_t *tree; 2686789Sahrens unshare_unmount_node_t *node; 2687789Sahrens uu_avl_index_t idx; 2688789Sahrens uu_avl_walk_t *walk; 2689789Sahrens 2690789Sahrens if ((pool = uu_avl_pool_create("unmount_pool", 2691789Sahrens sizeof (unshare_unmount_node_t), 2692789Sahrens offsetof(unshare_unmount_node_t, un_avlnode), 2693789Sahrens unshare_unmount_compare, 2694789Sahrens UU_DEFAULT)) == NULL) { 2695789Sahrens (void) fprintf(stderr, gettext("internal error: " 2696789Sahrens "out of memory\n")); 2697789Sahrens exit(1); 2698789Sahrens } 2699789Sahrens 2700789Sahrens if ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL) { 2701789Sahrens (void) fprintf(stderr, gettext("internal error: " 2702789Sahrens "out of memory\n")); 2703789Sahrens exit(1); 2704789Sahrens } 2705789Sahrens 2706789Sahrens rewind(mnttab_file); 2707789Sahrens while (getmntent(mnttab_file, &entry) == 0) { 2708789Sahrens 2709789Sahrens /* ignore non-ZFS entries */ 2710789Sahrens if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 2711789Sahrens continue; 2712789Sahrens 2713789Sahrens /* ignore snapshots */ 2714789Sahrens if (strchr(entry.mnt_special, '@') != NULL) 2715789Sahrens continue; 2716789Sahrens 27172082Seschrock if ((zhp = zfs_open(g_zfs, entry.mnt_special, 2718789Sahrens ZFS_TYPE_FILESYSTEM)) == NULL) { 2719789Sahrens ret = 1; 2720789Sahrens continue; 2721789Sahrens } 2722789Sahrens 2723789Sahrens verify(zfs_prop_get(zhp, type == OP_SHARE ? 2724789Sahrens ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, 2725789Sahrens property, sizeof (property), NULL, NULL, 27262082Seschrock 0, B_FALSE) == 0); 2727789Sahrens 2728789Sahrens /* Ignore legacy mounts and shares */ 2729789Sahrens if ((type == OP_SHARE && 2730789Sahrens strcmp(property, "off") == 0) || 2731789Sahrens (type == OP_MOUNT && 2732789Sahrens strcmp(property, "legacy") == 0)) { 2733789Sahrens zfs_close(zhp); 2734789Sahrens continue; 2735789Sahrens } 2736789Sahrens 2737789Sahrens node = safe_malloc(sizeof (unshare_unmount_node_t)); 2738789Sahrens node->un_zhp = zhp; 2739789Sahrens 2740789Sahrens if ((node->un_mountp = strdup(entry.mnt_mountp)) == 2741789Sahrens NULL) { 2742789Sahrens (void) fprintf(stderr, gettext("internal error:" 2743789Sahrens " out of memory\n")); 2744789Sahrens exit(1); 2745789Sahrens } 2746789Sahrens 2747789Sahrens uu_avl_node_init(node, &node->un_avlnode, pool); 2748789Sahrens 2749789Sahrens if (uu_avl_find(tree, node, NULL, &idx) == NULL) { 2750789Sahrens uu_avl_insert(tree, node, idx); 2751789Sahrens } else { 2752789Sahrens zfs_close(node->un_zhp); 2753789Sahrens free(node->un_mountp); 2754789Sahrens free(node); 2755789Sahrens } 2756789Sahrens } 2757789Sahrens 2758789Sahrens /* 2759789Sahrens * Walk the AVL tree in reverse, unmounting each filesystem and 2760789Sahrens * removing it from the AVL tree in the process. 2761789Sahrens */ 2762789Sahrens if ((walk = uu_avl_walk_start(tree, 2763789Sahrens UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL) { 2764789Sahrens (void) fprintf(stderr, 2765789Sahrens gettext("internal error: out of memory")); 2766789Sahrens exit(1); 2767789Sahrens } 2768789Sahrens 2769789Sahrens while ((node = uu_avl_walk_next(walk)) != NULL) { 2770789Sahrens uu_avl_remove(tree, node); 2771789Sahrens 2772789Sahrens switch (type) { 2773789Sahrens case OP_SHARE: 2774789Sahrens if (zfs_unshare(node->un_zhp, 2775789Sahrens node->un_mountp) != 0) 2776789Sahrens ret = 1; 2777789Sahrens break; 2778789Sahrens 2779789Sahrens case OP_MOUNT: 2780789Sahrens if (zfs_unmount(node->un_zhp, 2781789Sahrens node->un_mountp, flags) != 0) 2782789Sahrens ret = 1; 2783789Sahrens break; 2784789Sahrens } 2785789Sahrens 2786789Sahrens zfs_close(node->un_zhp); 2787789Sahrens free(node->un_mountp); 2788789Sahrens free(node); 2789789Sahrens } 2790789Sahrens 2791789Sahrens uu_avl_walk_end(walk); 2792789Sahrens uu_avl_destroy(tree); 2793789Sahrens uu_avl_pool_destroy(pool); 2794789Sahrens } else { 2795789Sahrens /* 2796789Sahrens * We have an argument, but it may be a full path or a ZFS 2797789Sahrens * filesystem. Pass full paths off to unmount_path() (shared by 2798789Sahrens * manual_unmount), otherwise open the filesystem and pass to 2799789Sahrens * zfs_unmount(). 2800789Sahrens */ 2801789Sahrens if (argv[0][0] == '/') 2802789Sahrens return (unshare_unmount_path(type, argv[0], 28032082Seschrock flags, B_FALSE)); 28042082Seschrock 28052082Seschrock if ((zhp = zfs_open(g_zfs, argv[0], 28062082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 2807789Sahrens return (1); 2808789Sahrens 2809789Sahrens verify(zfs_prop_get(zhp, type == OP_SHARE ? 2810789Sahrens ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property, 28112082Seschrock sizeof (property), NULL, NULL, 0, B_FALSE) == 0); 2812789Sahrens 2813789Sahrens switch (type) { 2814789Sahrens case OP_SHARE: 2815789Sahrens if (strcmp(property, "off") == 0) { 2816789Sahrens (void) fprintf(stderr, gettext("cannot unshare " 2817789Sahrens "'%s': legacy share\n"), zfs_get_name(zhp)); 2818789Sahrens (void) fprintf(stderr, gettext("use unshare(1M)" 2819789Sahrens " to unshare this filesystem\n")); 2820789Sahrens ret = 1; 2821789Sahrens } else if (!zfs_is_shared(zhp, NULL)) { 2822789Sahrens (void) fprintf(stderr, gettext("cannot unshare " 2823789Sahrens "'%s': not currently shared\n"), 2824789Sahrens zfs_get_name(zhp)); 2825789Sahrens ret = 1; 2826789Sahrens } else if (zfs_unshareall(zhp) != 0) { 2827789Sahrens ret = 1; 2828789Sahrens } 2829789Sahrens break; 2830789Sahrens 2831789Sahrens case OP_MOUNT: 2832789Sahrens if (strcmp(property, "legacy") == 0) { 2833789Sahrens (void) fprintf(stderr, gettext("cannot unmount " 2834789Sahrens "'%s': legacy mountpoint\n"), 2835789Sahrens zfs_get_name(zhp)); 2836789Sahrens (void) fprintf(stderr, gettext("use umount(1M) " 2837789Sahrens "to unmount this filesystem\n")); 2838789Sahrens ret = 1; 2839789Sahrens } else if (!zfs_is_mounted(zhp, NULL)) { 2840789Sahrens (void) fprintf(stderr, gettext("cannot unmount " 2841789Sahrens "'%s': not currently mounted\n"), 2842789Sahrens zfs_get_name(zhp)); 2843789Sahrens ret = 1; 2844789Sahrens } else if (zfs_unmountall(zhp, flags) != 0) { 2845789Sahrens ret = 1; 2846789Sahrens } 2847789Sahrens } 2848789Sahrens 2849789Sahrens zfs_close(zhp); 2850789Sahrens } 2851789Sahrens 2852789Sahrens return (ret); 2853789Sahrens } 2854789Sahrens 2855789Sahrens /* 2856789Sahrens * zfs unmount -a 2857789Sahrens * zfs unmount filesystem 2858789Sahrens * 2859789Sahrens * Unmount all filesystems, or a specific ZFS filesystem. 2860789Sahrens */ 2861789Sahrens static int 2862789Sahrens zfs_do_unmount(int argc, char **argv) 2863789Sahrens { 2864789Sahrens return (unshare_unmount(OP_MOUNT, argc, argv)); 2865789Sahrens } 2866789Sahrens 2867789Sahrens /* 2868789Sahrens * zfs unshare -a 2869789Sahrens * zfs unshare filesystem 2870789Sahrens * 2871789Sahrens * Unshare all filesystems, or a specific ZFS filesystem. 2872789Sahrens */ 2873789Sahrens static int 2874789Sahrens zfs_do_unshare(int argc, char **argv) 2875789Sahrens { 2876789Sahrens return (unshare_unmount(OP_SHARE, argc, argv)); 2877789Sahrens } 2878789Sahrens 2879789Sahrens /* 2880789Sahrens * Called when invoked as /etc/fs/zfs/mount. Do the mount if the mountpoint is 2881789Sahrens * 'legacy'. Otherwise, complain that use should be using 'zfs mount'. 2882789Sahrens */ 2883789Sahrens static int 2884789Sahrens manual_mount(int argc, char **argv) 2885789Sahrens { 2886789Sahrens zfs_handle_t *zhp; 2887789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 2888789Sahrens char mntopts[MNT_LINE_MAX] = { '\0' }; 2889789Sahrens int ret; 2890789Sahrens int c; 2891789Sahrens int flags = 0; 2892789Sahrens char *dataset, *path; 2893789Sahrens 2894789Sahrens /* check options */ 28951544Seschrock while ((c = getopt(argc, argv, ":mo:O")) != -1) { 2896789Sahrens switch (c) { 2897789Sahrens case 'o': 2898789Sahrens (void) strlcpy(mntopts, optarg, sizeof (mntopts)); 2899789Sahrens break; 2900789Sahrens case 'O': 2901789Sahrens flags |= MS_OVERLAY; 2902789Sahrens break; 29031544Seschrock case 'm': 29041544Seschrock flags |= MS_NOMNTTAB; 29051544Seschrock break; 2906789Sahrens case ':': 2907789Sahrens (void) fprintf(stderr, gettext("missing argument for " 2908789Sahrens "'%c' option\n"), optopt); 29092082Seschrock usage(B_FALSE); 2910789Sahrens break; 2911789Sahrens case '?': 2912789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2913789Sahrens optopt); 2914789Sahrens (void) fprintf(stderr, gettext("usage: mount [-o opts] " 2915789Sahrens "<path>\n")); 2916789Sahrens return (2); 2917789Sahrens } 2918789Sahrens } 2919789Sahrens 2920789Sahrens argc -= optind; 2921789Sahrens argv += optind; 2922789Sahrens 2923789Sahrens /* check that we only have two arguments */ 2924789Sahrens if (argc != 2) { 2925789Sahrens if (argc == 0) 2926789Sahrens (void) fprintf(stderr, gettext("missing dataset " 2927789Sahrens "argument\n")); 2928789Sahrens else if (argc == 1) 2929789Sahrens (void) fprintf(stderr, 2930789Sahrens gettext("missing mountpoint argument\n")); 2931789Sahrens else 2932789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 2933789Sahrens (void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n"); 2934789Sahrens return (2); 2935789Sahrens } 2936789Sahrens 2937789Sahrens dataset = argv[0]; 2938789Sahrens path = argv[1]; 2939789Sahrens 2940789Sahrens /* try to open the dataset */ 29412082Seschrock if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) 2942789Sahrens return (1); 2943789Sahrens 2944789Sahrens (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 29452082Seschrock sizeof (mountpoint), NULL, NULL, 0, B_FALSE); 2946789Sahrens 2947789Sahrens /* check for legacy mountpoint and complain appropriately */ 2948789Sahrens ret = 0; 2949789Sahrens if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 2950789Sahrens if (mount(dataset, path, MS_OPTIONSTR | flags, MNTTYPE_ZFS, 2951789Sahrens NULL, 0, mntopts, sizeof (mntopts)) != 0) { 2952789Sahrens (void) fprintf(stderr, gettext("mount failed: %s\n"), 2953789Sahrens strerror(errno)); 2954789Sahrens ret = 1; 2955789Sahrens } 2956789Sahrens } else { 2957789Sahrens (void) fprintf(stderr, gettext("filesystem '%s' cannot be " 2958789Sahrens "mounted using 'mount -F zfs'\n"), dataset); 2959789Sahrens (void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' " 2960789Sahrens "instead.\n"), path); 2961789Sahrens (void) fprintf(stderr, gettext("If you must use 'mount -F zfs' " 2962789Sahrens "or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n")); 2963789Sahrens (void) fprintf(stderr, gettext("See zfs(1M) for more " 2964789Sahrens "information.\n")); 2965789Sahrens ret = 1; 2966789Sahrens } 2967789Sahrens 2968789Sahrens return (ret); 2969789Sahrens } 2970789Sahrens 2971789Sahrens /* 2972789Sahrens * Called when invoked as /etc/fs/zfs/umount. Unlike a manual mount, we allow 2973789Sahrens * unmounts of non-legacy filesystems, as this is the dominant administrative 2974789Sahrens * interface. 2975789Sahrens */ 2976789Sahrens static int 2977789Sahrens manual_unmount(int argc, char **argv) 2978789Sahrens { 2979789Sahrens int flags = 0; 2980789Sahrens int c; 2981789Sahrens 2982789Sahrens /* check options */ 2983789Sahrens while ((c = getopt(argc, argv, "f")) != -1) { 2984789Sahrens switch (c) { 2985789Sahrens case 'f': 2986789Sahrens flags = MS_FORCE; 2987789Sahrens break; 2988789Sahrens case '?': 2989789Sahrens (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2990789Sahrens optopt); 2991789Sahrens (void) fprintf(stderr, gettext("usage: unmount [-f] " 2992789Sahrens "<path>\n")); 2993789Sahrens return (2); 2994789Sahrens } 2995789Sahrens } 2996789Sahrens 2997789Sahrens argc -= optind; 2998789Sahrens argv += optind; 2999789Sahrens 3000789Sahrens /* check arguments */ 3001789Sahrens if (argc != 1) { 3002789Sahrens if (argc == 0) 3003789Sahrens (void) fprintf(stderr, gettext("missing path " 3004789Sahrens "argument\n")); 3005789Sahrens else 3006789Sahrens (void) fprintf(stderr, gettext("too many arguments\n")); 3007789Sahrens (void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n")); 3008789Sahrens return (2); 3009789Sahrens } 3010789Sahrens 30112082Seschrock return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE)); 3012789Sahrens } 3013789Sahrens 3014789Sahrens static int 3015789Sahrens volcheck(zpool_handle_t *zhp, void *data) 3016789Sahrens { 3017789Sahrens int isinit = (int)data; 3018789Sahrens 3019789Sahrens if (isinit) 3020789Sahrens return (zpool_create_zvol_links(zhp)); 3021789Sahrens else 3022789Sahrens return (zpool_remove_zvol_links(zhp)); 3023789Sahrens } 3024789Sahrens 3025789Sahrens /* 3026789Sahrens * Iterate over all pools in the system and either create or destroy /dev/zvol 3027789Sahrens * links, depending on the value of 'isinit'. 3028789Sahrens */ 3029789Sahrens static int 30302082Seschrock do_volcheck(boolean_t isinit) 3031789Sahrens { 30322082Seschrock return (zpool_iter(g_zfs, volcheck, (void *)isinit) ? 1 : 0); 3033789Sahrens } 3034789Sahrens 3035789Sahrens int 3036789Sahrens main(int argc, char **argv) 3037789Sahrens { 3038789Sahrens int ret; 3039789Sahrens int i; 3040789Sahrens char *progname; 3041789Sahrens char *cmdname; 3042789Sahrens 3043789Sahrens (void) setlocale(LC_ALL, ""); 3044789Sahrens (void) textdomain(TEXT_DOMAIN); 3045789Sahrens 3046789Sahrens opterr = 0; 3047789Sahrens 30482082Seschrock if ((g_zfs = libzfs_init()) == NULL) { 30492082Seschrock (void) fprintf(stderr, gettext("internal error: failed to " 30502082Seschrock "initialize ZFS library\n")); 30512082Seschrock return (1); 30522082Seschrock } 30532082Seschrock 30542082Seschrock libzfs_print_on_error(g_zfs, B_TRUE); 30552082Seschrock 3056789Sahrens if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) { 3057789Sahrens (void) fprintf(stderr, gettext("internal error: unable to " 3058789Sahrens "open %s\n"), MNTTAB); 3059789Sahrens return (1); 3060789Sahrens } 3061789Sahrens 3062789Sahrens /* 3063789Sahrens * This command also doubles as the /etc/fs mount and unmount program. 3064789Sahrens * Determine if we should take this behavior based on argv[0]. 3065789Sahrens */ 3066789Sahrens progname = basename(argv[0]); 3067789Sahrens if (strcmp(progname, "mount") == 0) { 3068789Sahrens ret = manual_mount(argc, argv); 3069789Sahrens } else if (strcmp(progname, "umount") == 0) { 3070789Sahrens ret = manual_unmount(argc, argv); 3071789Sahrens } else { 3072789Sahrens /* 3073789Sahrens * Make sure the user has specified some command. 3074789Sahrens */ 3075789Sahrens if (argc < 2) { 3076789Sahrens (void) fprintf(stderr, gettext("missing command\n")); 30772082Seschrock usage(B_FALSE); 3078789Sahrens } 3079789Sahrens 3080789Sahrens cmdname = argv[1]; 3081789Sahrens 3082789Sahrens /* 3083789Sahrens * The 'umount' command is an alias for 'unmount' 3084789Sahrens */ 3085789Sahrens if (strcmp(cmdname, "umount") == 0) 3086789Sahrens cmdname = "unmount"; 3087789Sahrens 3088789Sahrens /* 30891749Sahrens * The 'recv' command is an alias for 'receive' 30901749Sahrens */ 30911749Sahrens if (strcmp(cmdname, "recv") == 0) 30921749Sahrens cmdname = "receive"; 30931749Sahrens 30941749Sahrens /* 3095789Sahrens * Special case '-?' 3096789Sahrens */ 3097789Sahrens if (strcmp(cmdname, "-?") == 0) 30982082Seschrock usage(B_TRUE); 3099789Sahrens 3100789Sahrens /* 3101789Sahrens * 'volinit' and 'volfini' do not appear in the usage message, 3102789Sahrens * so we have to special case them here. 3103789Sahrens */ 3104789Sahrens if (strcmp(cmdname, "volinit") == 0) 31052082Seschrock return (do_volcheck(B_TRUE)); 3106789Sahrens else if (strcmp(cmdname, "volfini") == 0) 31072082Seschrock return (do_volcheck(B_FALSE)); 3108789Sahrens 3109789Sahrens /* 3110789Sahrens * Run the appropriate command. 3111789Sahrens */ 3112789Sahrens for (i = 0; i < NCOMMAND; i++) { 3113789Sahrens if (command_table[i].name == NULL) 3114789Sahrens continue; 3115789Sahrens 3116789Sahrens if (strcmp(cmdname, command_table[i].name) == 0) { 3117789Sahrens current_command = &command_table[i]; 3118789Sahrens ret = command_table[i].func(argc - 1, argv + 1); 3119789Sahrens break; 3120789Sahrens } 3121789Sahrens } 3122789Sahrens 3123789Sahrens if (i == NCOMMAND) { 3124789Sahrens (void) fprintf(stderr, gettext("unrecognized " 3125789Sahrens "command '%s'\n"), cmdname); 31262082Seschrock usage(B_FALSE); 3127789Sahrens } 3128789Sahrens } 3129789Sahrens 3130789Sahrens (void) fclose(mnttab_file); 3131789Sahrens 31322082Seschrock libzfs_fini(g_zfs); 31332082Seschrock 3134789Sahrens /* 3135789Sahrens * The 'ZFS_ABORT' environment variable causes us to dump core on exit 3136789Sahrens * for the purposes of running ::findleaks. 3137789Sahrens */ 3138789Sahrens if (getenv("ZFS_ABORT") != NULL) { 3139789Sahrens (void) printf("dumping core by request\n"); 3140789Sahrens abort(); 3141789Sahrens } 3142789Sahrens 3143789Sahrens return (ret); 3144789Sahrens } 3145