#include <zone.h>
#include <grp.h>
#include <pwd.h>
+#include <signal.h>
#include <sys/mkdev.h>
#include <sys/mntent.h>
#include <sys/mnttab.h>
static int zfs_do_python(int argc, char **argv);
static int zfs_do_hold(int argc, char **argv);
static int zfs_do_release(int argc, char **argv);
+static int zfs_do_diff(int argc, char **argv);
/*
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
HELP_GROUPSPACE,
HELP_HOLD,
HELP_HOLDS,
- HELP_RELEASE
+ HELP_RELEASE,
+ HELP_DIFF
} zfs_help_t;
typedef struct zfs_command {
{ "hold", zfs_do_hold, HELP_HOLD },
{ "holds", zfs_do_python, HELP_HOLDS },
{ "release", zfs_do_release, HELP_RELEASE },
+ { "diff", zfs_do_diff, HELP_DIFF },
};
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
return (gettext("\tholds [-r] <snapshot> ...\n"));
case HELP_RELEASE:
return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
+ case HELP_DIFF:
+ return (gettext("\tdiff [-FHt] <snapshot> "
+ "[snapshot|filesystem]\n"));
}
abort();
free(pt_header);
pt_header = NULL;
}
+
/*
* zfs clone [-p] [-o prop=value] ... <snap> <fs | vol>
*
clone = zfs_open(g_zfs, argv[1], ZFS_TYPE_DATASET);
if (clone != NULL) {
- if ((ret = zfs_mount(clone, NULL, 0)) == 0)
- ret = zfs_share(clone);
+ if (zfs_get_type(clone) != ZFS_TYPE_VOLUME)
+ if ((ret = zfs_mount(clone, NULL, 0)) == 0)
+ ret = zfs_share(clone);
zfs_close(clone);
}
}
{
zfs_type_t type = ZFS_TYPE_FILESYSTEM;
zfs_handle_t *zhp = NULL;
- uint64_t volsize;
+ uint64_t volsize = 0;
int c;
boolean_t noreserve = B_FALSE;
boolean_t bflag = B_FALSE;
int ret = 1;
nvlist_t *props;
uint64_t intval;
- int canmount;
+ int canmount = ZFS_CANMOUNT_OFF;
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
nomem();
zfs_prop_t resv_prop;
char *strval;
- if (p = strchr(argv[0], '/'))
+ if ((p = strchr(argv[0], '/')))
*p = '\0';
zpool_handle = zpool_open(g_zfs, argv[0]);
if (p != NULL)
if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
goto error;
+
+ ret = 0;
/*
* if the user doesn't want the dataset automatically mounted,
* then skip the mount/share step
*/
-
- canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
+ if (zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, type))
+ canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
/*
* Mount and/or share the new filesystem as appropriate. We provide a
* verbose error message to let the user know that their filesystem was
* in fact created, even if we failed to mount or share it.
*/
- ret = 0;
if (canmount == ZFS_CANMOUNT_ON) {
if (zfs_mount(zhp, NULL, 0) != 0) {
(void) fprintf(stderr, gettext("filesystem "
if (version < cb->cb_version) {
char verstr[16];
(void) snprintf(verstr, sizeof (verstr),
- "%llu", cb->cb_version);
+ "%llu", (u_longlong_t)cb->cb_version);
if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
/*
* If they did "zfs upgrade -a", then we could
boolean_t showversions = B_FALSE;
int ret;
upgrade_cbdata_t cb = { 0 };
- char c;
+ signed char c;
int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
/* check options */
ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_FILESYSTEM,
NULL, NULL, 0, upgrade_set_callback, &cb);
(void) printf(gettext("%llu filesystems upgraded\n"),
- cb.cb_numupgraded);
+ (u_longlong_t)cb.cb_numupgraded);
if (cb.cb_numsamegraded) {
(void) printf(gettext("%llu filesystems already at "
"this version\n"),
- cb.cb_numsamegraded);
+ (u_longlong_t)cb.cb_numsamegraded);
}
if (cb.cb_numfailed != 0)
ret = 1;
if (pl->pl_next == NULL && !right_justify)
(void) printf("%s", header);
else if (right_justify)
- (void) printf("%*s", pl->pl_width, header);
+ (void) printf("%*s", (int)pl->pl_width, header);
else
- (void) printf("%-*s", pl->pl_width, header);
+ (void) printf("%-*s", (int)pl->pl_width, header);
}
(void) printf("\n");
usage(B_FALSE);
}
- ret = zfs_for_each(argc - 2, argv + 2, NULL,
+ ret = zfs_for_each(argc - 2, argv + 2, 0,
ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb);
return (ret);
{
boolean_t recursive = B_FALSE;
int ret;
- char c;
+ signed char c;
nvlist_t *props;
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
}
if (holding) {
if (zfs_hold(zhp, delim+1, tag, recursive,
- temphold, B_FALSE) != 0)
+ temphold, B_FALSE, -1, 0, 0) != 0)
++errors;
} else {
if (zfs_release(zhp, delim+1, tag, recursive) != 0)
return (zfs_do_hold_rele_impl(argc, argv, B_FALSE));
}
-typedef struct get_all_cbdata {
- zfs_handle_t **cb_handles;
- size_t cb_alloc;
- size_t cb_used;
- uint_t cb_types;
- boolean_t cb_verbose;
-} get_all_cbdata_t;
-
#define CHECK_SPINNER 30
#define SPINNER_TIME 3 /* seconds */
#define MOUNT_TIME 5 /* seconds */
static int spinval = 0;
static int spincheck = 0;
static time_t last_spin_time = (time_t)0;
- get_all_cbdata_t *cbp = data;
+ get_all_cb_t *cbp = data;
zfs_type_t type = zfs_get_type(zhp);
if (cbp->cb_verbose) {
/*
* Interate over any nested datasets.
*/
- if (type == ZFS_TYPE_FILESYSTEM &&
- zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) {
+ if (zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) {
zfs_close(zhp);
return (1);
}
/*
* Skip any datasets whose type does not match.
*/
- if ((type & cbp->cb_types) == 0) {
+ if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
zfs_close(zhp);
return (0);
}
-
- if (cbp->cb_alloc == cbp->cb_used) {
- zfs_handle_t **handles;
-
- if (cbp->cb_alloc == 0)
- cbp->cb_alloc = 64;
- else
- cbp->cb_alloc *= 2;
-
- handles = safe_malloc(cbp->cb_alloc * sizeof (void *));
-
- if (cbp->cb_handles) {
- bcopy(cbp->cb_handles, handles,
- cbp->cb_used * sizeof (void *));
- free(cbp->cb_handles);
- }
-
- cbp->cb_handles = handles;
- }
-
- cbp->cb_handles[cbp->cb_used++] = zhp;
+ libzfs_add_handle(cbp, zhp);
+ assert(cbp->cb_used <= cbp->cb_alloc);
return (0);
}
static void
-get_all_datasets(uint_t types, zfs_handle_t ***dslist, size_t *count,
- boolean_t verbose)
+get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
{
- get_all_cbdata_t cb = { 0 };
- cb.cb_types = types;
+ get_all_cb_t cb = { 0 };
cb.cb_verbose = verbose;
+ cb.cb_getone = get_one_dataset;
if (verbose)
set_progress_header(gettext("Reading ZFS config"));
-
(void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
*dslist = cb.cb_handles;
finish_progress(gettext("done."));
}
-static int
-dataset_cmp(const void *a, const void *b)
-{
- zfs_handle_t **za = (zfs_handle_t **)a;
- zfs_handle_t **zb = (zfs_handle_t **)b;
- char mounta[MAXPATHLEN];
- char mountb[MAXPATHLEN];
- boolean_t gota, gotb;
-
- if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0)
- verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
- sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
- if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0)
- verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
- sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
-
- if (gota && gotb)
- return (strcmp(mounta, mountb));
-
- if (gota)
- return (-1);
- if (gotb)
- return (1);
-
- return (strcmp(zfs_get_name(a), zfs_get_name(b)));
-}
-
/*
* 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
const char *cmdname = op == OP_SHARE ? "share" : "mount";
struct mnttab mnt;
uint64_t zoned, canmount;
- zfs_type_t type = zfs_get_type(zhp);
boolean_t shared_nfs, shared_smb;
- assert(type & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME));
+ assert(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM);
- if (type == ZFS_TYPE_FILESYSTEM) {
- /*
- * 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.
- */
- zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
+ /*
+ * 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.
+ */
+ zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
- if (zoned && getzoneid() == GLOBAL_ZONEID) {
- if (!explicit)
- return (0);
+ if (zoned && getzoneid() == GLOBAL_ZONEID) {
+ if (!explicit)
+ return (0);
- (void) fprintf(stderr, gettext("cannot %s '%s': "
- "dataset is exported to a local zone\n"), cmdname,
- zfs_get_name(zhp));
- return (1);
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "dataset is exported to a local zone\n"), cmdname,
+ zfs_get_name(zhp));
+ return (1);
- } else if (!zoned && getzoneid() != GLOBAL_ZONEID) {
- if (!explicit)
- return (0);
+ } else if (!zoned && getzoneid() != GLOBAL_ZONEID) {
+ if (!explicit)
+ return (0);
- (void) fprintf(stderr, gettext("cannot %s '%s': "
- "permission denied\n"), cmdname,
- zfs_get_name(zhp));
- return (1);
- }
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "permission denied\n"), cmdname,
+ zfs_get_name(zhp));
+ return (1);
+ }
- /*
- * Ignore any filesystems which don't apply to us. This
- * includes those with a legacy mountpoint, or those with
- * legacy share options.
- */
- verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
- sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
- verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
- sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
- verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts,
- sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0);
-
- if (op == OP_SHARE && strcmp(shareopts, "off") == 0 &&
- strcmp(smbshareopts, "off") == 0) {
- if (!explicit)
- return (0);
+ /*
+ * Ignore any filesystems which don't apply to us. This
+ * includes those with a legacy mountpoint, or those with
+ * legacy share options.
+ */
+ verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
+ sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
+ sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts,
+ sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0);
+
+ if (op == OP_SHARE && strcmp(shareopts, "off") == 0 &&
+ strcmp(smbshareopts, "off") == 0) {
+ if (!explicit)
+ return (0);
- (void) fprintf(stderr, gettext("cannot share '%s': "
- "legacy share\n"), zfs_get_name(zhp));
- (void) fprintf(stderr, gettext("use share(1M) to "
- "share this filesystem, or set "
- "sharenfs property on\n"));
- return (1);
- }
+ (void) fprintf(stderr, gettext("cannot share '%s': "
+ "legacy share\n"), zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use share(1M) to "
+ "share this filesystem, or set "
+ "sharenfs property on\n"));
+ return (1);
+ }
- /*
- * 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.
- */
- if (strcmp(mountpoint, "legacy") == 0) {
- if (!explicit)
- return (0);
+ /*
+ * 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.
+ */
+ if (strcmp(mountpoint, "legacy") == 0) {
+ if (!explicit)
+ return (0);
- (void) fprintf(stderr, gettext("cannot %s '%s': "
- "legacy mountpoint\n"), cmdname, zfs_get_name(zhp));
- (void) fprintf(stderr, gettext("use %s(1M) to "
- "%s this filesystem\n"), cmdname, cmdname);
- return (1);
- }
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "legacy mountpoint\n"), cmdname, zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use %s(1M) to "
+ "%s this filesystem\n"), cmdname, cmdname);
+ return (1);
+ }
- if (strcmp(mountpoint, "none") == 0) {
- if (!explicit)
- return (0);
+ if (strcmp(mountpoint, "none") == 0) {
+ if (!explicit)
+ return (0);
- (void) fprintf(stderr, gettext("cannot %s '%s': no "
- "mountpoint set\n"), cmdname, zfs_get_name(zhp));
- return (1);
- }
+ (void) fprintf(stderr, gettext("cannot %s '%s': no "
+ "mountpoint set\n"), cmdname, zfs_get_name(zhp));
+ return (1);
+ }
- /*
- * canmount explicit outcome
- * on no pass through
- * on yes pass through
- * off no return 0
- * off yes display error, return 1
- * noauto no return 0
- * noauto yes pass through
- */
- canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
- if (canmount == ZFS_CANMOUNT_OFF) {
+ /*
+ * canmount explicit outcome
+ * on no pass through
+ * on yes pass through
+ * off no return 0
+ * off yes display error, return 1
+ * noauto no return 0
+ * noauto yes pass through
+ */
+ canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
+ if (canmount == ZFS_CANMOUNT_OFF) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "'canmount' property is set to 'off'\n"), cmdname,
+ zfs_get_name(zhp));
+ return (1);
+ } else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
+ return (0);
+ }
+
+ /*
+ * 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
+ * filesystem.
+ */
+ switch (op) {
+ case OP_SHARE:
+
+ shared_nfs = zfs_is_shared_nfs(zhp, NULL);
+ shared_smb = zfs_is_shared_smb(zhp, NULL);
+
+ if ((shared_nfs && shared_smb) ||
+ ((shared_nfs && strcmp(shareopts, "on") == 0) &&
+ (strcmp(smbshareopts, "off") == 0)) ||
+ ((shared_smb && strcmp(smbshareopts, "on") == 0) &&
+ (strcmp(shareopts, "off") == 0))) {
if (!explicit)
return (0);
- (void) fprintf(stderr, gettext("cannot %s '%s': "
- "'canmount' property is set to 'off'\n"), cmdname,
+ (void) fprintf(stderr, gettext("cannot share "
+ "'%s': filesystem already shared\n"),
zfs_get_name(zhp));
return (1);
- } else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
- return (0);
}
- /*
- * 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
- * filesystem.
- */
- switch (op) {
- case OP_SHARE:
-
- shared_nfs = zfs_is_shared_nfs(zhp, NULL);
- shared_smb = zfs_is_shared_smb(zhp, NULL);
-
- if (shared_nfs && shared_smb ||
- (shared_nfs && strcmp(shareopts, "on") == 0 &&
- strcmp(smbshareopts, "off") == 0) ||
- (shared_smb && strcmp(smbshareopts, "on") == 0 &&
- strcmp(shareopts, "off") == 0)) {
- if (!explicit)
- return (0);
+ if (!zfs_is_mounted(zhp, NULL) &&
+ zfs_mount(zhp, NULL, 0) != 0)
+ return (1);
- (void) fprintf(stderr, gettext("cannot share "
- "'%s': filesystem already shared\n"),
- zfs_get_name(zhp));
+ if (protocol == NULL) {
+ if (zfs_shareall(zhp) != 0)
return (1);
- }
-
- if (!zfs_is_mounted(zhp, NULL) &&
- zfs_mount(zhp, NULL, 0) != 0)
+ } else if (strcmp(protocol, "nfs") == 0) {
+ if (zfs_share_nfs(zhp))
return (1);
-
- if (protocol == NULL) {
- if (zfs_shareall(zhp) != 0)
- return (1);
- } else if (strcmp(protocol, "nfs") == 0) {
- if (zfs_share_nfs(zhp))
- return (1);
- } else if (strcmp(protocol, "smb") == 0) {
- if (zfs_share_smb(zhp))
- return (1);
- } else {
- (void) fprintf(stderr, gettext("cannot share "
- "'%s': invalid share type '%s' "
- "specified\n"),
- zfs_get_name(zhp), protocol);
+ } else if (strcmp(protocol, "smb") == 0) {
+ if (zfs_share_smb(zhp))
return (1);
- }
-
- break;
+ } else {
+ (void) fprintf(stderr, gettext("cannot share "
+ "'%s': invalid share type '%s' "
+ "specified\n"),
+ zfs_get_name(zhp), protocol);
+ return (1);
+ }
- case OP_MOUNT:
- if (options == NULL)
- mnt.mnt_mntopts = "";
- else
- mnt.mnt_mntopts = (char *)options;
+ break;
- if (!hasmntopt(&mnt, MNTOPT_REMOUNT) &&
- zfs_is_mounted(zhp, NULL)) {
- if (!explicit)
- return (0);
+ case OP_MOUNT:
+ if (options == NULL)
+ mnt.mnt_mntopts = "";
+ else
+ mnt.mnt_mntopts = (char *)options;
- (void) fprintf(stderr, gettext("cannot mount "
- "'%s': filesystem already mounted\n"),
- zfs_get_name(zhp));
- return (1);
- }
+ if (!hasmntopt(&mnt, MNTOPT_REMOUNT) &&
+ zfs_is_mounted(zhp, NULL)) {
+ if (!explicit)
+ return (0);
- if (zfs_mount(zhp, options, flags) != 0)
- return (1);
- break;
+ (void) fprintf(stderr, gettext("cannot mount "
+ "'%s': filesystem already mounted\n"),
+ zfs_get_name(zhp));
+ return (1);
}
- } else
- assert(op == OP_SHARE);
+
+ if (zfs_mount(zhp, options, flags) != 0)
+ return (1);
+ break;
+ }
return (0);
}
/* original length plus new string to append plus 1 for the comma */
if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) {
(void) fprintf(stderr, gettext("the opts argument for "
- "'%c' option is too long (more than %d chars)\n"),
+ "'%s' option is too long (more than %d chars)\n"),
"-o", MNT_LINE_MAX);
usage(B_FALSE);
}
boolean_t verbose = B_FALSE;
int c, ret = 0;
char *options = NULL;
- int types, flags = 0;
+ int flags = 0;
/* check options */
- while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:O" : "a"))
+ while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:" : "a"))
!= -1) {
switch (c) {
case 'a':
append_options(options, optarg);
break;
- case 'O':
- flags |= MS_OVERLAY;
- break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
size_t i, count = 0;
char *protocol = NULL;
- if (op == OP_MOUNT) {
- types = ZFS_TYPE_FILESYSTEM;
- } else if (argc > 0) {
- if (strcmp(argv[0], "nfs") == 0 ||
- strcmp(argv[0], "smb") == 0) {
- types = ZFS_TYPE_FILESYSTEM;
- } else {
+ if (op == OP_SHARE && argc > 0) {
+ if (strcmp(argv[0], "nfs") != 0 &&
+ strcmp(argv[0], "smb") != 0) {
(void) fprintf(stderr, gettext("share type "
"must be 'nfs' or 'smb'\n"));
usage(B_FALSE);
protocol = argv[0];
argc--;
argv++;
- } else {
- types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
}
if (argc != 0) {
}
start_progress_timer();
- get_all_datasets(types, &dslist, &count, verbose);
+ get_all_datasets(&dslist, &count, verbose);
if (count == 0)
return (0);
- qsort(dslist, count, sizeof (void *), dataset_cmp);
+ qsort(dslist, count, sizeof (void *), libzfs_dataset_cmp);
for (i = 0; i < count; i++) {
if (verbose)
}
/*
- * When mount is given no arguments, go through /etc/mnttab and
+ * When mount is given no arguments, go through /etc/mtab and
* display any active ZFS mounts. We hide any snapshots, since
* they are controlled automatically.
*/
} else {
zfs_handle_t *zhp;
- types = ZFS_TYPE_FILESYSTEM;
- if (op == OP_SHARE)
- types |= ZFS_TYPE_VOLUME;
-
if (argc > 1) {
(void) fprintf(stderr,
gettext("too many arguments\n"));
usage(B_FALSE);
}
- if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) {
+ if ((zhp = zfs_open(g_zfs, argv[0],
+ ZFS_TYPE_FILESYSTEM)) == NULL) {
ret = 1;
} else {
ret = share_mount_one(zhp, op, flags, NULL, B_TRUE,
/*
* 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,
+ * absolute path, find the entry /etc/mtab, verify that its a ZFS filesystem,
* and unmount it appropriately.
*/
static int
ino_t path_inode;
/*
- * Search for the path in /etc/mnttab. Rather than looking for the
+ * Search for the path in /etc/mtab. 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.
"currently mounted\n"), cmdname, path);
return (1);
}
- (void) fprintf(stderr, gettext("warning: %s not in mnttab\n"),
+ (void) fprintf(stderr, gettext("warning: %s not in mtab\n"),
path);
if ((ret = umount2(path, flags)) != 0)
(void) fprintf(stderr, gettext("%s: %s\n"), path,
strcmp(smbshare_prop, "off") == 0) {
(void) fprintf(stderr, gettext("cannot unshare "
"'%s': legacy share\n"), path);
- (void) fprintf(stderr, gettext("use "
- "unshare(1M) to unshare this filesystem\n"));
+ (void) fprintf(stderr, gettext("use exportfs(8) "
+ "or smbcontrol(1) to unshare this filesystem\n"));
} else if (!zfs_is_shared(zhp)) {
(void) fprintf(stderr, gettext("cannot unshare '%s': "
"not currently shared\n"), path);
(void) fprintf(stderr, gettext("cannot unmount "
"'%s': legacy mountpoint\n"),
zfs_get_name(zhp));
- (void) fprintf(stderr, gettext("use umount(1M) "
+ (void) fprintf(stderr, gettext("use umount(8) "
"to unmount this filesystem\n"));
} else {
ret = zfs_unmountall(zhp, flags);
int do_all = 0;
int flags = 0;
int ret = 0;
- int types, c;
+ int c;
zfs_handle_t *zhp;
char nfs_mnt_prop[ZFS_MAXPROPLEN];
char sharesmb[ZFS_MAXPROPLEN];
/*
* 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
+ * since we would have to linearly search /etc/mtab for each
+ * one. Instead, do one pass through /etc/mtab looking for
* zfs entries and call zfs_unmount() for each one.
*
* Things get a little tricky if the administrator has created
*/
struct mnttab entry;
uu_avl_pool_t *pool;
- uu_avl_t *tree;
+ uu_avl_t *tree = NULL;
unshare_unmount_node_t *node;
uu_avl_index_t idx;
uu_avl_walk_t *walk;
return (unshare_unmount_path(op, argv[0],
flags, B_FALSE));
- types = ZFS_TYPE_FILESYSTEM;
- if (op == OP_SHARE)
- types |= ZFS_TYPE_VOLUME;
-
- if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL)
+ if ((zhp = zfs_open(g_zfs, argv[0],
+ ZFS_TYPE_FILESYSTEM)) == NULL)
return (1);
- if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
- verify(zfs_prop_get(zhp, op == OP_SHARE ?
- ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
- nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL,
- NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, op == OP_SHARE ?
+ ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
+ nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL,
+ NULL, 0, B_FALSE) == 0);
- switch (op) {
- case OP_SHARE:
- verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
- nfs_mnt_prop,
- sizeof (nfs_mnt_prop),
- NULL, NULL, 0, B_FALSE) == 0);
- verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
- sharesmb, sizeof (sharesmb), NULL, NULL,
- 0, B_FALSE) == 0);
-
- if (strcmp(nfs_mnt_prop, "off") == 0 &&
- strcmp(sharesmb, "off") == 0) {
- (void) fprintf(stderr, gettext("cannot "
- "unshare '%s': legacy share\n"),
- zfs_get_name(zhp));
- (void) fprintf(stderr, gettext("use "
- "unshare(1M) to unshare this "
- "filesystem\n"));
- ret = 1;
- } else if (!zfs_is_shared(zhp)) {
- (void) fprintf(stderr, gettext("cannot "
- "unshare '%s': not currently "
- "shared\n"), zfs_get_name(zhp));
- ret = 1;
- } else if (zfs_unshareall(zhp) != 0) {
- ret = 1;
- }
- break;
+ switch (op) {
+ case OP_SHARE:
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
+ nfs_mnt_prop,
+ sizeof (nfs_mnt_prop),
+ NULL, NULL, 0, B_FALSE) == 0);
+ verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
+ sharesmb, sizeof (sharesmb), NULL, NULL,
+ 0, B_FALSE) == 0);
+
+ if (strcmp(nfs_mnt_prop, "off") == 0 &&
+ strcmp(sharesmb, "off") == 0) {
+ (void) fprintf(stderr, gettext("cannot "
+ "unshare '%s': legacy share\n"),
+ zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use "
+ "unshare(1M) to unshare this "
+ "filesystem\n"));
+ ret = 1;
+ } else if (!zfs_is_shared(zhp)) {
+ (void) fprintf(stderr, gettext("cannot "
+ "unshare '%s': not currently "
+ "shared\n"), zfs_get_name(zhp));
+ ret = 1;
+ } else if (zfs_unshareall(zhp) != 0) {
+ ret = 1;
+ }
+ break;
- case OP_MOUNT:
- if (strcmp(nfs_mnt_prop, "legacy") == 0) {
- (void) fprintf(stderr, gettext("cannot "
- "unmount '%s': legacy "
- "mountpoint\n"), zfs_get_name(zhp));
- (void) fprintf(stderr, gettext("use "
- "umount(1M) to unmount this "
- "filesystem\n"));
- ret = 1;
- } else if (!zfs_is_mounted(zhp, NULL)) {
- (void) fprintf(stderr, gettext("cannot "
- "unmount '%s': not currently "
- "mounted\n"),
- zfs_get_name(zhp));
- ret = 1;
- } else if (zfs_unmountall(zhp, flags) != 0) {
- ret = 1;
- }
- break;
+ case OP_MOUNT:
+ if (strcmp(nfs_mnt_prop, "legacy") == 0) {
+ (void) fprintf(stderr, gettext("cannot "
+ "unmount '%s': legacy "
+ "mountpoint\n"), zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use "
+ "umount(1M) to unmount this "
+ "filesystem\n"));
+ ret = 1;
+ } else if (!zfs_is_mounted(zhp, NULL)) {
+ (void) fprintf(stderr, gettext("cannot "
+ "unmount '%s': not currently "
+ "mounted\n"),
+ zfs_get_name(zhp));
+ ret = 1;
+ } else if (zfs_unmountall(zhp, flags) != 0) {
+ ret = 1;
}
+ break;
}
zfs_close(zhp);
return (-1);
}
+typedef struct option_map {
+ const char *name;
+ int mask;
+} option_map_t;
+
+static const option_map_t option_map[] = {
+ /* Canonicalized filesystem independent options from mount(8) */
+ { MNTOPT_NOAUTO, MS_COMMENT },
+ { MNTOPT_DEFAULTS, MS_COMMENT },
+ { MNTOPT_NODEVICES, MS_NODEV },
+ { MNTOPT_DIRSYNC, MS_DIRSYNC },
+ { MNTOPT_NOEXEC, MS_NOEXEC },
+ { MNTOPT_GROUP, MS_GROUP },
+ { MNTOPT_NETDEV, MS_COMMENT },
+ { MNTOPT_NOFAIL, MS_COMMENT },
+ { MNTOPT_NOSUID, MS_NOSUID },
+ { MNTOPT_OWNER, MS_OWNER },
+ { MNTOPT_REMOUNT, MS_REMOUNT },
+ { MNTOPT_RO, MS_RDONLY },
+ { MNTOPT_SYNC, MS_SYNCHRONOUS },
+ { MNTOPT_USER, MS_USERS },
+ { MNTOPT_USERS, MS_USERS },
+#ifdef MS_NOATIME
+ { MNTOPT_NOATIME, MS_NOATIME },
+#endif
+#ifdef MS_NODIRATIME
+ { MNTOPT_NODIRATIME, MS_NODIRATIME },
+#endif
+#ifdef MS_RELATIME
+ { MNTOPT_RELATIME, MS_RELATIME },
+#endif
+#ifdef MS_STRICTATIME
+ { MNTOPT_DFRATIME, MS_STRICTATIME },
+#endif
+#ifdef HAVE_SELINUX
+ { MNTOPT_CONTEXT, MS_COMMENT },
+ { MNTOPT_FSCONTEXT, MS_COMMENT },
+ { MNTOPT_DEFCONTEXT, MS_COMMENT },
+ { MNTOPT_ROOTCONTEXT, MS_COMMENT },
+#endif
+#ifdef MS_I_VERSION
+ { MNTOPT_IVERSION, MS_I_VERSION },
+#endif
+#ifdef MS_MANDLOCK
+ { MNTOPT_NBMAND, MS_MANDLOCK },
+#endif
+ /* Valid options not found in mount(8) */
+ { MNTOPT_BIND, MS_BIND },
+#ifdef MS_REC
+ { MNTOPT_RBIND, MS_BIND|MS_REC },
+#endif
+ { MNTOPT_COMMENT, MS_COMMENT },
+ { MNTOPT_BOOTWAIT, MS_COMMENT },
+ { MNTOPT_NOBOOTWAIT, MS_COMMENT },
+ { MNTOPT_OPTIONAL, MS_COMMENT },
+ { MNTOPT_SHOWTHROUGH, MS_COMMENT },
+#ifdef MS_NOSUB
+ { MNTOPT_NOSUB, MS_NOSUB },
+#endif
+#ifdef MS_SILENT
+ { MNTOPT_QUIET, MS_SILENT },
+#endif
+ /* Custom zfs options */
+ { MNTOPT_NOXATTR, MS_COMMENT },
+ { NULL, 0 } };
+
+/*
+ * Break the mount option in to a name/value pair. The name is
+ * validated against the option map and mount flags set accordingly.
+ */
+static int
+parse_option(char *mntopt, unsigned long *mntflags, int sloppy)
+{
+ const option_map_t *opt;
+ char *ptr, *name, *value = NULL;
+ int rc;
+
+ name = strdup(mntopt);
+ if (name == NULL)
+ return (ENOMEM);
+
+ for (ptr = name; ptr && *ptr; ptr++) {
+ if (*ptr == '=') {
+ *ptr = '\0';
+ value = ptr+1;
+ break;
+ }
+ }
+
+ for (opt = option_map; opt->name != NULL; opt++) {
+ if (strncmp(name, opt->name, strlen(name)) == 0) {
+ *mntflags |= opt->mask;
+
+ /* MS_USERS implies default user options */
+ if (opt->mask & (MS_USERS))
+ *mntflags |= (MS_NOEXEC|MS_NOSUID|MS_NODEV);
+
+ /* MS_OWNER|MS_GROUP imply default owner options */
+ if (opt->mask & (MS_OWNER | MS_GROUP))
+ *mntflags |= (MS_NOSUID|MS_NODEV);
+
+ rc = 0;
+ goto out;
+ }
+ }
+
+ if (!sloppy)
+ rc = ENOENT;
+out:
+ /* If required further process on the value may be done here */
+ free(name);
+ return (rc);
+}
+
+/*
+ * Translate the mount option string in to MS_* mount flags for the
+ * kernel vfs. When sloppy is non-zero unknown options will be ignored
+ * otherwise they are considered fatal are copied in to badopt.
+ */
+static int
+parse_options(char *mntopts, unsigned long *mntflags, int sloppy, char *badopt)
+{
+ int rc = 0, quote = 0;
+ char *ptr, *opt, *opts;
+
+ opts = strdup(mntopts);
+ if (opts == NULL)
+ return (ENOMEM);
+
+ *mntflags = 0;
+ opt = NULL;
+
+ /*
+ * Scan through all mount options which must be comma delimited.
+ * We must be careful to notice regions which are double quoted
+ * and skip commas in these regions. Each option is then checked
+ * to determine if it is a known option.
+ */
+ for (ptr = opts; ptr && *ptr; ptr++) {
+ if (opt == NULL)
+ opt = ptr;
+
+ if (*ptr == '"')
+ quote = !quote;
+
+ if (quote)
+ continue;
+
+ if ((*ptr == ',') || (*ptr == '\0')) {
+ *ptr = '\0';
+ rc = parse_option(opt, mntflags, sloppy);
+ if (rc) {
+ strcpy(badopt, opt);
+ goto out;
+ }
+
+ opt = NULL;
+ }
+ }
+out:
+ free(opts);
+ return (rc);
+}
+
/*
- * 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'.
+ * Called when invoked as /sbin/mount.zfs, mount helper for mount(8).
*/
static int
manual_mount(int argc, char **argv)
{
zfs_handle_t *zhp;
- char mountpoint[ZFS_MAXPROPLEN];
+ char legacy[ZFS_MAXPROPLEN];
char mntopts[MNT_LINE_MAX] = { '\0' };
- int ret;
- int c;
- int flags = 0;
- char *dataset, *path;
+ char badopt[MNT_LINE_MAX] = { '\0' };
+ char *dataset, *mntpoint;
+ unsigned long mntflags;
+ int sloppy = 0, fake = 0, verbose = 0;
+ int rc, c;
/* check options */
- while ((c = getopt(argc, argv, ":mo:O")) != -1) {
+ while ((c = getopt(argc, argv, "sfnvo:h?")) != -1) {
switch (c) {
- case 'o':
- (void) strlcpy(mntopts, optarg, sizeof (mntopts));
+ case 's':
+ sloppy = 1;
break;
- case 'O':
- flags |= MS_OVERLAY;
+ case 'f':
+ fake = 1;
break;
- case 'm':
- flags |= MS_NOMNTTAB;
+ case 'n':
+ /* Ignored, handled by mount(8) */
break;
- case ':':
- (void) fprintf(stderr, gettext("missing argument for "
- "'%c' option\n"), optopt);
- usage(B_FALSE);
+ case 'v':
+ verbose++;
+ break;
+ case 'o':
+ (void) strlcpy(mntopts, optarg, sizeof (mntopts));
break;
+ case 'h':
case '?':
- (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ (void) fprintf(stderr, gettext("Invalid option '%c'\n"),
optopt);
- (void) fprintf(stderr, gettext("usage: mount [-o opts] "
- "<path>\n"));
- return (2);
+ (void) fprintf(stderr, gettext("Usage: mount.zfs "
+ "[-sfnv] [-o options] <dataset> <mountpoint>\n"));
+ return (MOUNT_USAGE);
}
}
else
(void) fprintf(stderr, gettext("too many arguments\n"));
(void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n");
- return (2);
+ return (MOUNT_USAGE);
}
dataset = argv[0];
- path = argv[1];
+ mntpoint = argv[1];
- /* try to open the dataset */
- if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL)
- return (1);
+ /* try to open the dataset to access the mount point */
+ if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
+ (void) fprintf(stderr, gettext("filesystem '%s' cannot be "
+ "mounted, unable to open the dataset\n"), dataset);
+ return (MOUNT_USAGE);
+ }
- (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
- sizeof (mountpoint), NULL, NULL, 0, B_FALSE);
+ (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, legacy,
+ sizeof (legacy), NULL, NULL, 0, B_FALSE);
- /* check for legacy mountpoint and complain appropriately */
- ret = 0;
- if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
- if (mount(dataset, path, MS_OPTIONSTR | flags, MNTTYPE_ZFS,
- NULL, 0, mntopts, sizeof (mntopts)) != 0) {
- (void) fprintf(stderr, gettext("mount failed: %s\n"),
- strerror(errno));
- ret = 1;
- }
- } else {
+ zfs_close(zhp);
+
+ /* check for legacy mountpoint or util mount option */
+ if ((!strcmp(legacy, ZFS_MOUNTPOINT_LEGACY) == 0) &&
+ (strstr(mntopts, MNTOPT_ZFSUTIL) == NULL)) {
(void) fprintf(stderr, gettext("filesystem '%s' cannot be "
- "mounted using 'mount -F zfs'\n"), dataset);
+ "mounted using 'mount -a -t zfs'\n"), dataset);
(void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' "
- "instead.\n"), path);
- (void) fprintf(stderr, gettext("If you must use 'mount -F zfs' "
- "or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n"));
- (void) fprintf(stderr, gettext("See zfs(1M) for more "
+ "instead.\n"), mntpoint);
+ (void) fprintf(stderr, gettext("If you must use 'mount -a -t "
+ "zfs' or /etc/fstab, use 'zfs set mountpoint=legacy'.\n"));
+ (void) fprintf(stderr, gettext("See zfs(8) for more "
"information.\n"));
- ret = 1;
+ return (MOUNT_USAGE);
}
- return (ret);
+ /* validate mount options and set mntflags */
+ rc = parse_options(mntopts, &mntflags, sloppy, badopt);
+ if (rc) {
+ switch (rc) {
+ case ENOMEM:
+ (void) fprintf(stderr, gettext("filesystem '%s' "
+ "cannot be mounted due to a memory allocation "
+ "failure\n"), dataset);
+ return (MOUNT_SYSERR);
+ case EINVAL:
+ (void) fprintf(stderr, gettext("filesystem '%s' "
+ "cannot be mounted of due to the invalid option "
+ "'%s'\n"), dataset, badopt);
+ (void) fprintf(stderr, gettext("Use the '-s' option "
+ "to ignore the bad mount option.\n"));
+ return (MOUNT_USAGE);
+ default:
+ (void) fprintf(stderr, gettext("filesystem '%s' "
+ "cannot be mounted due to internal error %d\n"),
+ dataset, rc);
+ return (MOUNT_SOFTWARE);
+ }
+ }
+
+ if (verbose > 2)
+ printf("mount.zfs: dataset: \"%s\", mountpoint: \"%s\" "
+ "mountflags: 0x%lx, mountopts: \"%s\"\n", dataset,
+ mntpoint, mntflags, mntopts);
+
+ /* load the zfs posix layer module (zpl) */
+ if (libzfs_load_module("zpl")) {
+ (void) fprintf(stderr, gettext("filesystem '%s' cannot be "
+ "mounted without the zpl kernel module\n"), dataset);
+ (void) fprintf(stderr, gettext("Use 'dmesg' to determine why "
+ "the module could not be loaded.\n"));
+ return (MOUNT_SYSERR);
+ }
+
+ if (!fake) {
+ rc = mount(dataset, mntpoint, MNTTYPE_ZFS, mntflags, mntopts);
+ if (rc) {
+ (void) fprintf(stderr, gettext("filesystem '%s' can"
+ "not be mounted due to error %d\n"), dataset, rc);
+ return (MOUNT_USAGE);
+ }
+ }
+
+ return (MOUNT_SUCCESS);
}
+#ifdef HAVE_UNMOUNT_HELPER
/*
- * 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
- * interface.
+ * Called when invoked as /sbin/umount.zfs, mount helper for mount(8).
+ * Unlike a manual mount, we allow unmounts of non-legacy filesystems,
+ * as this is the dominant administrative interface.
*/
static int
manual_unmount(int argc, char **argv)
{
- int flags = 0;
+ int verbose = 0, flags = 0;
int c;
/* check options */
- while ((c = getopt(argc, argv, "f")) != -1) {
+ while ((c = getopt(argc, argv, "nlfvrh?")) != -1) {
switch (c) {
+ case 'n':
+ /* Ignored, handled by mount(8) */
+ break;
+ case 'l':
+ flags = MS_DETACH;
+ break;
case 'f':
flags = MS_FORCE;
break;
+ case 'v':
+ verbose++;
+ break;
+ case 'r':
+ /* Remount read-only on umount failure, unsupported */
+ (void) fprintf(stderr, gettext("Unsupported option "
+ "'%c'\n"), optopt);
+ return (MOUNT_USAGE);
+ case 'h':
case '?':
- (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ (void) fprintf(stderr, gettext("Invalid option '%c'\n"),
optopt);
- (void) fprintf(stderr, gettext("usage: unmount [-f] "
- "<path>\n"));
- return (2);
+ (void) fprintf(stderr, gettext("Usage: umount.zfs "
+ "[-nlfvr] <mountpoint>\n"));
+ return (MOUNT_USAGE);
}
}
argc -= optind;
argv += optind;
- /* check arguments */
+ /* check that we only have one argument */
if (argc != 1) {
if (argc == 0)
- (void) fprintf(stderr, gettext("missing path "
+ (void) fprintf(stderr, gettext("missing mountpoint "
"argument\n"));
else
(void) fprintf(stderr, gettext("too many arguments\n"));
- (void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n"));
- return (2);
+
+ (void) fprintf(stderr, gettext("Usage: umount.zfs [-nlfvr] "
+ "<mountpoint>\n"));
+ return (MOUNT_USAGE);
}
return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE));
}
+#endif /* HAVE_UNMOUNT_HELPER */
static int
find_command_idx(char *command, int *idx)
return (1);
}
+static int
+zfs_do_diff(int argc, char **argv)
+{
+ zfs_handle_t *zhp;
+ int flags = 0;
+ char *tosnap = NULL;
+ char *fromsnap = NULL;
+ char *atp, *copy;
+ int err;
+ int c;
+
+ while ((c = getopt(argc, argv, "FHt")) != -1) {
+ switch (c) {
+ case 'F':
+ flags |= ZFS_DIFF_CLASSIFY;
+ break;
+ case 'H':
+ flags |= ZFS_DIFF_PARSEABLE;
+ break;
+ case 't':
+ flags |= ZFS_DIFF_TIMESTAMP;
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("invalid option '%c'\n"), optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void) fprintf(stderr,
+ gettext("must provide at least one snapshot name\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc > 2) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ fromsnap = argv[0];
+ tosnap = (argc == 2) ? argv[1] : NULL;
+
+ copy = NULL;
+ if (*fromsnap != '@')
+ copy = strdup(fromsnap);
+ else if (tosnap)
+ copy = strdup(tosnap);
+ if (copy == NULL)
+ usage(B_FALSE);
+
+ if ((atp = strchr(copy, '@')))
+ *atp = '\0';
+
+ if ((zhp = zfs_open(g_zfs, copy, ZFS_TYPE_FILESYSTEM)) == NULL)
+ return (1);
+
+ free(copy);
+
+ /*
+ * Ignore SIGPIPE so that the library can give us
+ * information on any failure
+ */
+ (void) sigignore(SIGPIPE);
+
+ err = zfs_show_diffs(zhp, STDOUT_FILENO, fromsnap, tosnap, flags);
+
+ zfs_close(zhp);
+
+ return (err != 0);
+}
+
int
main(int argc, char **argv)
{
int ret;
- int i;
+ int i = 0;
char *progname;
char *cmdname;
opterr = 0;
- if ((g_zfs = libzfs_init()) == NULL) {
- (void) fprintf(stderr, gettext("internal error: failed to "
- "initialize ZFS library\n"));
- return (1);
- }
-
- zpool_set_history_str("zfs", argc, argv, history_str);
- verify(zpool_stage_history(g_zfs, history_str) == 0);
-
- libzfs_print_on_error(g_zfs, B_TRUE);
-
if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) {
(void) fprintf(stderr, gettext("internal error: unable to "
"open %s\n"), MNTTAB);
* Determine if we should take this behavior based on argv[0].
*/
progname = basename(argv[0]);
- if (strcmp(progname, "mount") == 0) {
+ if (strcmp(progname, "mount.zfs") == 0) {
ret = manual_mount(argc, argv);
- } else if (strcmp(progname, "umount") == 0) {
+#ifdef HAVE_UNMOUNT_HELPER
+ } else if (strcmp(progname, "umount.zfs") == 0) {
ret = manual_unmount(argc, argv);
+#endif /* HAVE_UNMOUNT_HELPER */
} else {
/*
* Make sure the user has specified some command.
/*
* Special case '-?'
*/
- if (strcmp(cmdname, "-?") == 0)
+ if ((strcmp(cmdname, "-?") == 0) ||
+ (strcmp(cmdname, "--help") == 0))
usage(B_TRUE);
+ if ((g_zfs = libzfs_init()) == NULL)
+ return (1);
+
+ zpool_set_history_str("zfs", argc, argv, history_str);
+ verify(zpool_stage_history(g_zfs, history_str) == 0);
+
+ libzfs_print_on_error(g_zfs, B_TRUE);
+
/*
* Run the appropriate command.
*/
(void) fprintf(stderr, gettext("unrecognized "
"command '%s'\n"), cmdname);
usage(B_FALSE);
+ ret = 1;
}
libzfs_mnttab_cache(g_zfs, B_FALSE);
}