zfs_main.c revision 150586b45b130b4daefa859837f70adb8b0f0f6a
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. 2N/A#
pragma ident "%Z%%M% %I% %E% SMI" 2N/A * These libumem hooks provide a reasonable set of defaults for the allocator's 2N/A * debugging facilities. 2N/A return (
"default,verbose");
/* $UMEM_DEBUG setting */ 2N/A return (
"fail,contents");
/* $UMEM_LOGGING setting */ 2N/A * Master command table. Each ZFS command has a name, associated function, and 2N/A * usage message. The usage messages need to be internationalized, so we have 2N/A * to have a function to return the usage message based on a command index. 2N/A * These commands are organized according to how they are displayed in the usage 2N/A * message. An empty command (one with a NULL name) indicates an empty line in 2N/A * the generic usage message. 2N/A "<filesystem|volume>\n"));
2N/A return (
gettext(
"\tcreate [-p] [-o property=value] ... " 2N/A "\tcreate [-ps] [-b blocksize] [-o property=value] ... " 2N/A "-V <size> <volume>\n"));
2N/A "<filesystem|volume|snapshot>\n"));
2N/A "[-s source[,...]]\n" 2N/A "\t <\"all\" | property[,...]> " 2N/A "[filesystem|volume|snapshot] ...\n"));
2N/A "<filesystem|volume> ...\n"));
2N/A "\tupgrade [-r] [-V version] <-a | filesystem ...>\n"));
2N/A return (
gettext(
"\tlist [-rH] [-o property[,...]] " 2N/A "[-t type[,...]] [-s property] ...\n" 2N/A "\t [-S property] ... " 2N/A "[filesystem|volume|snapshot] ...\n"));
2N/A "\tmount [-vO] [-o opts] <-a | filesystem>\n"));
2N/A return (
gettext(
"\tpromote <clone-filesystem>\n"));
2N/A return (
gettext(
"\treceive [-vnF] <filesystem|volume|" 2N/A "\treceive [-vnF] -d <filesystem>\n"));
2N/A return (
gettext(
"\trename <filesystem|volume|snapshot> " 2N/A "<filesystem|volume|snapshot>\n" 2N/A "\trename -p <filesystem|volume> <filesystem|volume>\n" 2N/A "\trename -r <snapshot> <snapshot>"));
2N/A return (
gettext(
"\trollback [-rRf] <snapshot>\n"));
2N/A return (
gettext(
"\tsend [-i snapshot] <snapshot>\n"));
2N/A "<filesystem|volume> ...\n"));
2N/A "<filesystem@snapname|volume@snapname>\n"));
2N/A "<-a | filesystem|mountpoint>\n"));
2N/A "<-a | filesystem|mountpoint>\n"));
2N/A "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n" 2N/A "\t <filesystem|volume>\n" 2N/A "\tallow [-ld] -e <perm|@setname>[,...] " 2N/A "<filesystem|volume>\n" 2N/A "\tallow -c <perm|@setname>[,...] <filesystem|volume>\n" 2N/A "\tallow -s @setname <perm|@setname>[,...] " 2N/A "<filesystem|volume>\n"));
2N/A "<\"everyone\"|user|group>[,...]\n" 2N/A "\t [<perm|@setname>[,...]] <filesystem|volume>\n" 2N/A "\tunallow [-rld] -e [<perm|@setname>[,...]] " 2N/A "<filesystem|volume>\n" 2N/A "\tunallow [-r] -c [<perm|@setname>[,...]] " 2N/A "<filesystem|volume>\n" 2N/A "\tunallow [-r] -s @setname [<perm|@setname>[,...]] " 2N/A "<filesystem|volume>\n"));
2N/A * Utility function to guarantee malloc() success. 2N/A * Callback routinue that will print out information for each of the 2N/A * Display usage message. If we're inside a command, display only the usage for 2N/A * that command. Otherwise, iterate over the entire command table and display 2N/A * a complete usage message. 2N/A gettext(
"where 'command' is one of the following:\n\n"));
2N/A "pool/[dataset/]*dataset[@name]\n"));
2N/A gettext(
"\nThe following properties are supported:\n"));
2N/A "PROPERTY",
"EDIT",
"INHERIT",
"VALUES");
2N/A /* Iterate over all properties */ 2N/A "with standard units such as K, M, G, etc.\n"));
2N/A "be specified by using a name containing a colon (:).\n"));
2N/A * "zfs set|get" must not be localised this is the 2N/A * command name and arguments. 2N/A gettext(
"\nFor the property list, run: zfs set|get\n"));
2N/A * See comments at end of main(). 2N/A * zfs clone [-p] <snap> <fs | vol> 2N/A * Given an existing dataset, create a writable copy whose initial contents 2N/A * are the same as the source. The newly created dataset maintains a 2N/A * dependency on the original; the original cannot be destroyed so long as 2N/A * The '-p' flag creates all the non-existing ancestors of the target first. 2N/A /* check number of arguments */ 2N/A /* open the source dataset */ 2N/A * Now create the ancestors of the target dataset. If the 2N/A * target already exists and '-p' option was used we should not 2N/A /* pass to libzfs */ 2N/A /* create the mountpoint if necessary */ 2N/A * zfs create [-p] [-o prop=value] ... fs 2N/A * zfs create [-ps] [-b blocksize] [-o prop=value] ... -V vol size 2N/A * Create a new dataset. This command can be used to create filesystems 2N/A * and volumes. Snapshot creation is handled by 'zfs snapshot'. 2N/A * For volumes, the user must specify a size to be used. 2N/A * The '-s' flag applies only to volumes, and indicates that we should not try 2N/A * to set the reservation for this volume. By default we set a reservation 2N/A * equal to the size for any volume. 2N/A * The '-p' flag creates all the non-existing ancestors of the target first. 2N/A "out of memory\n"));
2N/A "error: out of memory\n"));
2N/A "error: out of memory\n"));
2N/A "'=' for -o option\n"));
2N/A "error: out of memory\n"));
2N/A "creating a volume\n"));
2N/A /* check number of arguments */ 2N/A "error: out of memory\n"));
2N/A * Now create the ancestors of target dataset. If the target 2N/A * already exists and '-p' option was used we should not 2N/A /* pass to libzfs */ 2N/A * Mount and/or share the new filesystem as appropriate. We provide a 2N/A * verbose error message to let the user know that their filesystem was 2N/A * in fact created, even if we failed to mount or share it. 2N/A "created, but not mounted\n"));
2N/A "created, but not shared\n"));
2N/A * zfs destroy [-rf] <fs, snap, vol> 2N/A * -r Recursively destroy all children 2N/A * -R Recursively destroy all dependents, including clones 2N/A * -f Force unmounting of any dependents 2N/A * Destroys the given dataset. By default, it will unmount any filesystems, 2N/A * and refuse to destroy a dataset that has any dependents. A dependent can 2N/A * either be a child, or a clone of a child. 2N/A * Check for any dependents based on the '-r' or '-R' flags. 2N/A * This is a direct descendant, not a clone somewhere else in 2N/A "%s has children\n"),
2N/A "the following datasets:\n"));
2N/A * This is a clone. We only want to report this if the '-r' 2N/A * wasn't specified, or the target is a snapshot. 2N/A "%s has dependent clones\n"),
2N/A "the following datasets:\n"));
2N/A * Ignore pools (which we've already flagged as an error before getting 2N/A * Bail out on the first error. 2N/A * Destroy any clones of this snapshot 2N/A /* check number of arguments */ 2N/A * If we are doing recursive destroy of a snapshot, then the 2N/A * named snapshot may not exist. Go straight to libzfs. 2N/A /* Open the given dataset */ 2N/A * Perform an explicit check for pools before going any further. 2N/A "operation does not apply to pools\n"),
2N/A "%s' to destroy all datasets in the pool\n"),
2N/A * Check for any dependents and/or clones. 2N/A * Do the real thing. The callback will close the handle regardless of 2N/A * whether it succeeds or not. 2N/A * zfs get [-rHp] [-o field[,field]...] [-s source[,source]...] 2N/A * < all | property[,property]... > < fs | snap | vol > ... 2N/A * -r recurse over any child datasets 2N/A * -H scripted mode. Headers are stripped, and fields are separated 2N/A * by tabs instead of spaces. 2N/A * -o Set of fields to display. One of "name,property,value,source". 2N/A * Default is all four. 2N/A * -s Set of sources to allow. One of 2N/A * "local,default,inherited,temporary,none". Default is all 2N/A * -p Display values in parsable (literal) format. 2N/A * Prints properties for the given datasets. The user can control which 2N/A * columns to display as well as which property types to allow. 2N/A * Invoked to display the properties for a single dataset. 2N/A * Skip the special fake placeholder. This will also skip over 2N/A * the name property when 'all' is specified. 2N/A * Set up default columns and sources. 2N/A * Process the set of columns to display. We zero out 2N/A * the structure to give us a blank slate. 2N/A {
"name",
"property",
"value",
"source",
2N/A "many fields given to -o " 2N/A "local",
"default",
"inherited",
2N/A * As part of zfs_expand_proplist(), we keep track of the maximum column 2N/A * width for each property. For the 'NAME' (and 'SOURCE') columns, we 2N/A * need to know the maximum name length. However, the user likely did 2N/A * not specify 'name' as one of the properties to fetch, so we need to 2N/A * make sure we always include at least this property for 2N/A * print_get_headers() to work properly. 2N/A /* run for each object */ 2N/A * inherit [-r] <property> <fs|vol> ... 2N/A * -r Recurse over all children 2N/A * For each dataset specified on the command line, inherit the given property 2N/A * from its parent. Inheriting a property at the pool level will cause it to 2N/A * use the default value. The '-r' flag will recurse over all children, and is 2N/A * useful for setting a property on a hierarchy-wide basis, regardless of any 2N/A * local modifications for each dataset. 2N/A /* check number of arguments */ 2N/A "%s property is read-only\n"),
2N/A "formatted using a newer software version and\n" 2N/A "cannot be accessed on the current system.\n\n");
2N/A "out of date, and can be upgraded. After being\n" 2N/A "upgraded, these filesystems (and any 'zfs send' " 2N/A "streams generated from\n" 2N/A "subsequent snapshots) will no longer be " 2N/A "accessible by older software versions.\n\n");
2N/A * If they did "zfs upgrade -a", then we could 2N/A * be doing ioctls to different pools. We need 2N/A * to log this history once to each pool. 2N/A /* can't downgrade */ "it is already at version %u\n"),
* zfs upgrade [-r] [-V <version>] <-a | filesystem> /* Show info on available versions. */ (
void)
printf(
"--- -----------------------------------------" "version, including supported releases, see:\n\n"));
/* Upgrade filesystems */ /* List old-version filesytems */ "formatted with the current version.\n"));
* list [-rH] [-o property[,property]...] [-t type[,type]...] * [-s property [-s property]...] [-S property [-S property]...] * -r Recurse over all children * -H Scripted mode; elide headers and separate colums by tabs * -o Control which fields to display. * -t Control which object types to display. * -s Specify sort columns, descending order. * -S Specify sort columns, ascending order. * When given no arguments, lists all filesystems in the system. * Otherwise, list the specified datasets, optionally recursing down them if * Given a list of columns to display, output appropriate headers for each one. * Given a dataset and a list of fields, print out all the properties according * to the described layout. * If this is being called in scripted mode, or if this is the * last column and it is left-justified, don't include a width * Generic callback function to list a dataset or snapshot. "name,used,available,referenced,mountpoint";
* If the user specifies '-o all', the zfs_get_proplist() doesn't * normally include the name of the dataset. For 'zfs list', we always * want this property to be first. * zfs rename <fs | snap | vol> <fs | snap | vol> * zfs rename -p <fs | vol> <fs | vol> * zfs rename -r <snap> <snap> * Renames the given dataset to another of the same type. * The '-p' flag creates all the non-existing ancestors of the target first. /* check number of arguments */ "rename must be a snapshot\n"));
/* If we were asked and the name looks good, try to create ancestors. */ * Promotes the given clone fs to be the parent /* check number of arguments */ * zfs rollback [-rfR] <snapshot> * -r Delete any intervening snapshots before doing rollback * -R Delete any snapshots and their clones * -f Force unmount filesystems, even if they are in use. * Given a filesystem, rollback to a specific snapshot, discarding any changes * since then and making it the active dataset. If more recent snapshots exist, * the command will complain unless the '-r' flag is given. * Report any snapshots more recent than the one specified. Used when '-r' is * not specified. We reuse this same callback for the snapshot dependents - if * 'cb_dependent' is set, then this is a dependent and we should report it * without checking the transaction group. "rollback to '%s': more recent snapshots " "force deletion of the following " "'%s': clones of previous snapshots exist\n"),
"force deletion of the following clones and " /* check number of arguments */ /* open the parent dataset */ * Check for more recent snapshots and/or clones based on the presence * Rollback parent to the given snapshot. * zfs set property=value { fs | snap | vol } ... * Sets the given property for all datasets specified on the command line. "but unable to remount filesystem\n"));
"but unable to reshare filesystem\n"));
/* check number of arguments */ /* validate property=value argument */ "property=value argument\n"));
gettext(
"missing property in property=value argument\n"));
* zfs snapshot [-r] <fs@snap> * Creates a snapshot with the given name. While functionally equivalent to * 'zfs create', it is a separate command to diffferentiate intent. /* check number of arguments */ * zfs send [-i <@snap>] <fs@snap> * Send a backup stream to stdout. /* check number of arguments */ gettext(
"Error: Stream can not be written to a terminal.\n" "You must redirect standard output.\n"));
* If they specified the full path to the snapshot, chop off * everything except the short name of the snapshot. gettext(
"incremental source must be " "in same filesystem\n"));
gettext(
"invalid incremental source\n"));
* Restore a backup stream from stdin. /* check number of arguments */ gettext(
"Error: Backup stream can not be read " "You must redirect standard input.\n"));
* function to print actual permission when tree has >0 nodes. * Avoid an extra space being printed * for "everyone" which is keyed with a null #
define LINES "-------------------------------------------------------------\n" gettext(
"Failed to retrieve 'allows' on %s\n"),
ds);
"Local+Descendent permissions on (%s)",
* Returns 1 - If permissions should be displayed. * Returns -1 - on failure * Only print permissions if no options were processed * initialize variables for zfs_build_perms based on number * 3 arguments ==> zfs [un]allow joe perm,perm,perm <dataset> or * zfs [un]allow -s @set1 perm,perm <dataset> * 2 arguments ==> zfs [un]allow -c perm,perm <dataset> or * zfs [un]allow -u|-g <name> perm <dataset> or * zfs [un]allow -e perm,perm <dataset> * zfs unallow joe <dataset> * zfs unallow -s @set1 <dataset> * 1 argument ==> zfs [un]allow -e <dataset> or * zfs [un]allow -c <dataset> * for do_allow case make sure who have a know who type * and its not a permission set. gettext(
"Can't set or remove 'allow' permissions " static char spin[] = {
'-',
'\\',
'|',
'/' };
* Interate over any nested datasets. * Skip any datasets whose type does not match. * Generic callback for sharing or mounting filesystems. Because the code is so * similar, we have a common function with an extra parameter to determine which * Share or mount a dataset. * Check to make sure we can mount/share this dataset. If we * are in the global zone and the filesystem is exported to a * local zone, or if we are in a local zone and the * filesystem is not exported, then it is an error. "dataset is exported to a local zone\n"),
cmdname,
* Ignore any filesystems which don't apply to us. This * includes those with a legacy mountpoint, or those with "share this filesystem\n"));
* We cannot share or mount legacy filesystems. If the * shareopts is non-legacy but the mountpoint is legacy, we * treat it as a legacy share. "share(1M)" :
"mount(1M)",
cmdname);
"'canmount' property is set to 'off'\n"),
cmdname,
* At this point, we have verified that the mountpoint and/or * shareopts are appropriate for auto management. If the * filesystem is already mounted or shared, return (failing * for explicit requests); otherwise mount or share the "'%s': filesystem already shared\n"),
"'%s': filesystem already mounted\n"),
* Ignore any volumes that aren't shared. "'shareiscsi' property not set\n"),
"property or use iscsitadm(1M) to share this " "'%s': volume already shared\n"),
* Reports progress in the form "(current/total)". Not thread-safe. static char *
reverse =
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
/* report 1..n instead of 0..n-1 */ /* display header if we're here for the first time */ return;
/* too soon to report again */ /* back up to prepare for overwriting */ /* We put a newline at the end if this is the last one. */ "'%c' option is too long (more than %d chars)\n"),
/* check number of arguments */ "must be 'nfs' or 'iscsi'\n"));
for (i = 0; i <
count; i++) {
"argument (specify -a for all)\n"));
* When mount is given no arguments, go through /etc/mnttab and * display any active ZFS mounts. We hide any snapshots, since * they are controlled automatically. * zfs mount -a [nfs | iscsi] * Mount all filesystems, or mount the given filesystem. * zfs share -a [nfs | iscsi] * Share all filesystems, or share the given filesystem. * Convenience routine used by zfs_do_umount() and manual_unmount(). Given an * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem, * and unmount it appropriately. * Search for the path in /etc/mnttab. Rather than looking for the * specific path, which can be fooled by non-standard paths (i.e. ".." * or "//"), we stat() the path and search for the corresponding * (major,minor) device pair. * Search for the given (major,minor) pair in the mount table. "'%s': legacy share\n"),
path);
"unshare(1M) to unshare this filesystem\n"));
"not currently shared\n"),
path);
"'%s': legacy mountpoint\n"),
"to unmount this filesystem\n"));
* Generic callback for unsharing or unmounting a filesystem. * We could make use of zfs_for_each() to walk all datasets in * the system, but this would be very inefficient, especially * since we would have to linearly search /etc/mnttab for each * one. Instead, do one pass through /etc/mnttab looking for * zfs entries and call zfs_unmount() for each one. * Things get a little tricky if the administrator has created * mountpoints beneath other ZFS filesystems. In this case, we * have to unmount the deepest filesystems first. To accomplish * this, we place all the mountpoints in an AVL tree sorted by * the special type (dataset name), and walk the result in * reverse to make sure to get any snapshots first. /* ignore non-ZFS entries */ /* Ignore legacy mounts and shares */ * Walk the AVL tree in reverse, unmounting each filesystem and * removing it from the AVL tree in the process. gettext(
"internal error: out of memory"));
* Finally, unshare any volumes shared via iSCSI. for (i = 0; i <
count; i++) {
gettext(
"missing filesystem argument\n"));
* We have an argument, but it may be a full path or a ZFS * filesystem. Pass full paths off to unmount_path() (shared by * manual_unmount), otherwise open the filesystem and pass to "unshare '%s': legacy share\n"),
"unshare(1M) to unshare this " "unshare '%s': not currently " "umount(1M) to unmount this " "unmount '%s': not currently " "'%s': 'shareiscsi' property not set\n"),
"'shareiscsi' property or use " "iscsitadm(1M) to share this volume\n"));
"unshare '%s': not currently shared\n"),
* Unmount all filesystems, or a specific ZFS filesystem. * Unshare all filesystems, or a specific ZFS filesystem. * Called when invoked as /etc/fs/zfs/mount. Do the mount if the mountpoint is * 'legacy'. Otherwise, complain that use should be using 'zfs mount'. /* check that we only have two arguments */ gettext(
"missing mountpoint argument\n"));
/* try to open the dataset */ /* check for legacy mountpoint and complain appropriately */ "mounted using 'mount -F zfs'\n"),
dataset);
"or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n"));
* Called when invoked as /etc/fs/zfs/umount. Unlike a manual mount, we allow * unmounts of non-legacy filesystems, as this is the dominant administrative * Iterate over all pools in the system and either create or destroy /dev/zvol * links, depending on the value of 'isinit'. "initialize ZFS library\n"));
* This command also doubles as the /etc/fs mount and unmount program. * Determine if we should take this behavior based on argv[0]. * Make sure the user has specified some command. * The 'umount' command is an alias for 'unmount' * The 'recv' command is an alias for 'receive' * 'volinit' and 'volfini' do not appear in the usage message, * so we have to special case them here. * Run the appropriate command. * The 'ZFS_ABORT' environment variable causes us to dump core on exit * for the purposes of running ::findleaks. (
void)
printf(
"dumping core by request\n");