Пример #1
0
int
libzfs_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)));
}
Пример #2
0
/*
 * Called for each dataset.  If the object is of an appropriate type,
 * add it to the avl tree and recurse over any children as necessary.
 */
static int
zfs_callback(zfs_handle_t *zhp, void *data)
{
	callback_data_t *cb = data;
	int dontclose = 0;
	int include_snaps = zfs_include_snapshots(zhp, cb);

	if ((zfs_get_type(zhp) & cb->cb_types) ||
	    ((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) {
		uu_avl_index_t idx;
		zfs_node_t *node = safe_malloc(sizeof (zfs_node_t));

		node->zn_handle = zhp;
		uu_avl_node_init(node, &node->zn_avlnode, avl_pool);
		if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol,
		    &idx) == NULL) {
			if (cb->cb_proplist) {
				if ((*cb->cb_proplist) &&
				    !(*cb->cb_proplist)->pl_all)
					zfs_prune_proplist(zhp,
					    cb->cb_props_table);

				if (zfs_expand_proplist(zhp, cb->cb_proplist,
				    (cb->cb_flags & ZFS_ITER_RECVD_PROPS),
				    (cb->cb_flags & ZFS_ITER_LITERAL_PROPS))
				    != 0) {
					free(node);
					return (-1);
				}
			}
			uu_avl_insert(cb->cb_avl, node, idx);
			dontclose = 1;
		} else {
			free(node);
		}
	}

	/*
	 * Recurse if necessary.
	 */
	if (cb->cb_flags & ZFS_ITER_RECURSE &&
	    ((cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 ||
	    cb->cb_depth < cb->cb_depth_limit)) {
		cb->cb_depth++;
		if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)
			(void) zfs_iter_filesystems(zhp, zfs_callback, data);
		if ((zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) && include_snaps) {
			(void) zfs_iter_snapshots(zhp,
			    (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback,
			    data);
		}
		cb->cb_depth--;
	}

	if (!dontclose)
		zfs_close(zhp);

	return (0);
}
Пример #3
0
/*
 * Unmount the given filesystem.
 */
int
zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
{
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	struct mnttab entry;
	char *mntpt = NULL;

	/* check to see if we need to unmount the filesystem */
	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM ||
				    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT ) &&
				   libzfs_mnttab_find(hdl, zhp->zfs_name,
						      &entry) == 0)) {
		/*
		 * mountpoint may have come from a call to
		 * getmnt/getmntany if it isn't NULL. If it is NULL,
		 * we know it comes from libzfs_mnttab_find which can
		 * then get freed later. We strdup it to play it safe.
		 */
		if (mountpoint == NULL)
			mntpt = zfs_strdup(hdl, entry.mnt_mountp);
		else
			mntpt = zfs_strdup(hdl, mountpoint);

#if defined(HAVE_ZPL)
		/*
		 * Unshare and unmount the filesystem
		 */
		if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
			return (-1);
#else
		if (unmount_one(hdl, mntpt, flags) != 0) {
			free(mntpt);
#if defined(HAVE_ZPL)
			(void) zfs_shareall(zhp);
#endif
			return (-1);
		}
#endif
		libzfs_mnttab_remove(hdl, zhp->zfs_name);
#if defined(LINUX_PORT)
		/* remove a /etc/mtab entry */
		if (zfs_linux_remove_entry(mntpt, zhp->zfs_name, MTAB_FILE) < 0) {
			free(mntpt);
			return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
				  dgettext(TEXT_DOMAIN, "failed to remove from /etc/mtab '%s'"),
					      zhp->zfs_name));
		}
#endif
		free(mntpt);
	}

	return (0);
}
Пример #4
0
/*ARGSUSED1*/
static int
zvol_cb(zfs_handle_t *zhp, void *unused)
{
	int error = 0;

	if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)
		(void) zfs_iter_children(zhp, zvol_cb, NULL);
	if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME)
		error = zfs_unshare_iscsi(zhp);
	zfs_close(zhp);

	return (error);
}
Пример #5
0
/*
 * This is a ZFS snapshot iterator call-back function which returns the
 * highest number of SUNWzone snapshots that have been taken.
 */
static int
get_snap_max(zfs_handle_t *zhp, void *data)
{
	int			res;
	zfs_snapshot_data_t	*cbp;

	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
		zfs_close(zhp);
		return (0);
	}

	cbp = (zfs_snapshot_data_t *)data;

	if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) {
		char	*nump;
		int	num;

		cbp->num++;
		nump = (char *)(zfs_get_name(zhp) + cbp->len);
		num = atoi(nump);
		if (num > cbp->max)
			cbp->max = num;
	}

	res = zfs_iter_snapshots(zhp, B_FALSE, get_snap_max, data);
	zfs_close(zhp);
	return (res);
}
Пример #6
0
/*
 * Check if the volume type is snapshot volume
 */
boolean_t
fs_is_chkpntvol(char *path)
{
    zfs_handle_t *zhp;
    char vol[ZFS_MAXNAMELEN];

    if (!path || !*path)
        return (FALSE);

    if (get_zfsvolname(vol, sizeof (vol), path) == -1)
        return (FALSE);

    (void) mutex_lock(&zlib_mtx);
    if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
        (void) mutex_unlock(&zlib_mtx);
        return (FALSE);
    }

    if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
        zfs_close(zhp);
        (void) mutex_unlock(&zlib_mtx);
        return (FALSE);
    }
    zfs_close(zhp);
    (void) mutex_unlock(&zlib_mtx);

    return (TRUE);
}
Пример #7
0
static int
mount_cb(zfs_handle_t *zhp, void *data)
{
	get_all_cb_t *cbp = data;

	if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
		zfs_close(zhp);
		return (0);
	}

	if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
		zfs_close(zhp);
		return (0);
	}

	/*
	 * If this filesystem is inconsistent and has a receive resume
	 * token, we can not mount it.
	 */
	if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
	    zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
	    NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
		zfs_close(zhp);
		return (0);
	}

	libzfs_add_handle(cbp, zhp);
	if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
		zfs_close(zhp);
		return (-1);
	}
	return (0);
}
Пример #8
0
static int
mount_cb(zfs_handle_t *zhp, void *data)
{
	get_all_cb_t *cbp = data;

    if (zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS) ==
        ZFS_CRYPT_KEY_UNAVAILABLE) {
        if (zfs_key_load(zhp, B_FALSE, B_FALSE, B_TRUE) != 0) {
            zfs_close(zhp);
            return (0);
        }
    }

	if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
		zfs_close(zhp);
		return (0);
	}

	if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
		zfs_close(zhp);
		return (0);
	}

	libzfs_add_handle(cbp, zhp);
	if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
		zfs_close(zhp);
		return (-1);
	}
	return (0);
}
Пример #9
0
static int
mount_cb(zfs_handle_t *zhp, void *data)
{
	mount_cbdata_t *cbp = data;

	if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) {
		zfs_close(zhp);
		return (0);
	}

	if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
		zfs_close(zhp);
		return (0);
	}

	if (cbp->cb_alloc == cbp->cb_used) {
		void *ptr;

		if ((ptr = zfs_realloc(zhp->zfs_hdl,
		    cbp->cb_datasets, cbp->cb_alloc * sizeof (void *),
		    cbp->cb_alloc * 2 * sizeof (void *))) == NULL)
			return (-1);
		cbp->cb_datasets = ptr;

		cbp->cb_alloc *= 2;
	}

	cbp->cb_datasets[cbp->cb_used++] = zhp;

	return (zfs_iter_filesystems(zhp, mount_cb, cbp));
}
Пример #10
0
int
zfs_key_unload(zfs_handle_t *zhp, boolean_t force)
{
	zfs_cmd_t zc = { { 0 }};
	int ret = 0;
	int terrno;
	int type = zfs_get_type(zhp);
	char errbuf[1024];

	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
	    "cannot unload key for '%s'"), zfs_get_name(zhp));

	if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) == ZIO_CRYPT_OFF) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "no key to unload when encryption=off."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}
	if (zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS) !=
	    ZFS_CRYPT_KEY_AVAILABLE) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "key not present."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	/*
	 * We need to be sure that all the data has been written to
	 * disk before we unload the key so we first have to attempt
	 * an unmount, if that fails we don't continue with the key unload
	 * and instead return the error from zfs_umount.
	 */
	if (type == ZFS_TYPE_FILESYSTEM) {
		if (zfs_is_mounted(zhp, NULL)) {
			ret = zfs_unmountall(zhp, force ? MS_FORCE : 0);
			if (ret) {
				zfs_error_aux(zhp->zfs_hdl,
				    dgettext(TEXT_DOMAIN,
				    "failed to unload key: unmount failed"));
				return (zfs_error(zhp->zfs_hdl,
				    EZFS_KEYERR, errbuf));
			}
		}
	}

	(void) strlcpy(zc.zc_name, zfs_get_name(zhp), sizeof (zc.zc_name));

	errno = 0;
	ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_UNLOAD, &zc);
	terrno = errno;
	if (ret != 0) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "failed to unload key: %s"), strerror(terrno));
		errno = terrno;	/* make sure it is the zfs_ioctl errno */
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}
	zfs_refresh_properties(zhp);

	return (0);
}
Пример #11
0
static int
update_zfs_shares_cb(zfs_handle_t *zhp, void *pcookie)
{
	update_cookie_t *udata = (update_cookie_t *)pcookie;
	char mountpoint[ZFS_MAXPROPLEN];
	char shareopts[ZFS_MAXPROPLEN];
	char *dataset;
	zfs_type_t type = zfs_get_type(zhp);

	if (type == ZFS_TYPE_FILESYSTEM &&
	    zfs_iter_filesystems(zhp, update_zfs_shares_cb, pcookie) != 0) {
		zfs_close(zhp);
		return (1);
	}

	if (type != ZFS_TYPE_FILESYSTEM) {
		zfs_close(zhp);
		return (0);
	}

	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
		zfs_close(zhp);
		return (0);
	}

	dataset = (char *)zfs_get_name(zhp);

	if (dataset == NULL) {
		zfs_close(zhp);
		return (0);
	}

	if (!zfs_is_mounted(zhp, NULL)) {
		zfs_close(zhp);
		return (0);
	}

	if ((udata->proto == NULL || strcmp(udata->proto, "nfs") == 0) &&
	    zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
	    sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
	    strcmp(shareopts, "off") != 0) {
		(void) process_share(udata->handle, NULL, mountpoint, NULL,
		    "nfs", shareopts, NULL, dataset, B_FALSE);
	}

	if ((udata->proto == NULL || strcmp(udata->proto, "smb") == 0) &&
	    zfs_prop_get(zhp, ZFS_PROP_SHARESMB, shareopts,
	    sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
	    strcmp(shareopts, "off") != 0) {
		(void) process_share(udata->handle, NULL, mountpoint, NULL,
		    "smb", shareopts, NULL, dataset, B_FALSE);
	}

	zfs_close(zhp);

	return (0);
}
Пример #12
0
/*
 * Called for each dataset.  If the object the object is of an appropriate type,
 * add it to the avl tree and recurse over any children as necessary.
 */
static int
zfs_callback(zfs_handle_t *zhp, void *data)
{
	callback_data_t *cb = data;
	int dontclose = 0;

	/*
	 * If this object is of the appropriate type, add it to the AVL tree.
	 */
	if (zfs_get_type(zhp) & cb->cb_types) {
		uu_avl_index_t idx;
		zfs_node_t *node = safe_malloc(sizeof (zfs_node_t));

		node->zn_handle = zhp;
		uu_avl_node_init(node, &node->zn_avlnode, avl_pool);
		if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol,
		    &idx) == NULL) {
			if (cb->cb_proplist &&
			    zfs_expand_proplist(zhp, cb->cb_proplist) != 0) {
				free(node);
				return (-1);
			}
			uu_avl_insert(cb->cb_avl, node, idx);
			dontclose = 1;
		} else {
			free(node);
		}
	}

	/*
	 * Recurse if necessary.
	 */
	if (cb->cb_recurse) {
		if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)
			(void) zfs_iter_filesystems(zhp, zfs_callback, data);
		if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT &&
		    (cb->cb_types & ZFS_TYPE_SNAPSHOT))
			(void) zfs_iter_snapshots(zhp, zfs_callback, data);
	}

	if (!dontclose)
		zfs_close(zhp);

	return (0);
}
Пример #13
0
static int
get_one_filesystem(zfs_handle_t *zhp, void *data)
{
	get_all_cbdata_t *cbp = data;
	zfs_type_t type = zfs_get_type(zhp);

	/*
	 * Interate over any nested datasets.
	 */
	if (type == ZFS_TYPE_FILESYSTEM &&
	    zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) {
		zfs_close(zhp);
		return (1);
	}

	/*
	 * Skip any datasets whose type does not match.
	 */
	if ((type & cbp->cb_types) == 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 = (zfs_handle_t **)calloc(1,
		    cbp->cb_alloc * sizeof (void *));

		if (handles == NULL) {
			zfs_close(zhp);
			return (0);
		}
		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;

	return (0);
}
Пример #14
0
/*
 * Iterate over all bookmarks
 */
int
zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
{
	zfs_handle_t *nzhp;
	nvlist_t *props = NULL;
	nvlist_t *bmarks = NULL;
	int err;
	nvpair_t *pair;

	if ((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) != 0)
		return (0);

	/* Setup the requested properties nvlist. */
	props = fnvlist_alloc();
	fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_GUID));
	fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATETXG));
	fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATION));

	/* Allocate an nvlist to hold the bookmarks. */
	bmarks = fnvlist_alloc();

	if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0)
		goto out;

	for (pair = nvlist_next_nvpair(bmarks, NULL);
	    pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) {
		char name[ZFS_MAXNAMELEN];
		char *bmark_name;
		nvlist_t *bmark_props;

		bmark_name = nvpair_name(pair);
		bmark_props = fnvpair_value_nvlist(pair);

		(void) snprintf(name, sizeof (name), "%s#%s", zhp->zfs_name,
		    bmark_name);

		nzhp = make_bookmark_handle(zhp, name, bmark_props);
		if (nzhp == NULL)
			continue;

		if ((err = func(nzhp, data)) != 0)
			goto out;
	}

out:
	fnvlist_free(props);
	fnvlist_free(bmarks);

	return (err);
}
Пример #15
0
int Destroy::iter_dataset(zfs_handle_t *hzfs, void *ptr)
{
    Destroy *self = (Destroy*)ptr;

    if (zfs_get_type(hzfs) == ZFS_TYPE_SNAPSHOT) {
        Dataset ds(hzfs);
        if (self->check_tag(ds) && self->check_age(ds)) {
            self->m_datasets.push_back(ds);
        }
    }

    if (self->m_recursive) {
        zfs_iter_filesystems(hzfs, iter_dataset, self);
        zfs_iter_snapshots(hzfs, B_FALSE, iter_dataset, self);
    }

    return 0;
}
Пример #16
0
/*
 * Unshare the given filesystem.
 */
int
zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
    zfs_share_proto_t *proto)
{
	struct mnttab search = { 0 }, entry;
	char *mntpt = NULL;

	/* check to see if need to unmount the filesystem */
	search.mnt_special = (char *)zfs_get_name(zhp);
	search.mnt_fstype = MNTTYPE_ZFS;

#ifndef __APPLE__
	rewind(zhp->zfs_hdl->libzfs_mnttab);
#endif /*!__APPLE__*/
	if (mountpoint != NULL)
		mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);

	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
	    getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
		zfs_share_proto_t *curr_proto;

		if (mountpoint == NULL)
			mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);

		for (curr_proto = proto; *curr_proto != PROTO_END;
		    curr_proto++) {

			if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) &&
			    unshare_one(zhp->zfs_hdl, zhp->zfs_name,
			    mntpt, *curr_proto) != 0) {
				if (mntpt != NULL)
					free(mntpt);
				return (-1);
			}
		}
	}
	if (mntpt != NULL)
		free(mntpt);

	return (0);
}
Пример #17
0
/*
 * Unmount the given filesystem.
 */
int
zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
{
	struct mnttab search = { 0 }, entry;
	char *mntpt = NULL;

	/* check to see if need to unmount the filesystem */
	search.mnt_special = zhp->zfs_name;
	search.mnt_fstype = MNTTYPE_ZFS;
	rewind(zhp->zfs_hdl->libzfs_mnttab);
	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
	    getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {

		/*
		 * mountpoint may have come from a call to
		 * getmnt/getmntany if it isn't NULL. If it is NULL,
		 * we know it comes from getmntany which can then get
		 * overwritten later. We strdup it to play it safe.
		 */
		if (mountpoint == NULL)
			mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
		else
			mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);

		/*
		 * Unshare and unmount the filesystem
		 */
		if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
			return (-1);

		if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) {
			free(mntpt);
			(void) zfs_shareall(zhp);
			return (-1);
		}
		free(mntpt);
	}

	return (0);
}
Пример #18
0
/*
 * Unmount the given filesystem.
 */
int
zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
{
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	struct mnttab entry;
	char *mntpt = NULL;

	/* check to see if we need to unmount the filesystem */
	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
	    libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) {
		/*
		 * mountpoint may have come from a call to
		 * getmnt/getmntany if it isn't NULL. If it is NULL,
		 * we know it comes from libzfs_mnttab_find which can
		 * then get freed later. We strdup it to play it safe.
		 */
		if (mountpoint == NULL)
			mntpt = zfs_strdup(hdl, entry.mnt_mountp);
		else
			mntpt = zfs_strdup(hdl, mountpoint);

		/*
		 * Unshare and unmount the filesystem
		 */
		if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) {
			free(mntpt);
			return (-1);
		}

		if (unmount_one(hdl, mntpt, flags) != 0) {
			free(mntpt);
			(void) zfs_shareall(zhp);
			return (-1);
		}
		libzfs_mnttab_remove(hdl, zhp->zfs_name);
		free(mntpt);
	}

	return (0);
}
Пример #19
0
/* ARGSUSED */
static int
check_zvol(zfs_handle_t *zhp, void *unused)
{
	int ret;

	if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
		/*
		 * TRANSLATION_NOTE
		 * zfs and dataset are literals that should not be translated.
		 */
		(void) fprintf(stderr, gettext("cannot verify zfs dataset %s: "
		    "volumes cannot be specified as a zone dataset resource\n"),
		    zfs_get_name(zhp));
		ret = -1;
	} else {
		ret = zfs_iter_children(zhp, check_zvol, NULL);
	}

	zfs_close(zhp);

	return (ret);
}
Пример #20
0
static int
mount_cb(zfs_handle_t *zhp, void *data)
{
    get_all_cb_t *cbp = data;

    if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
        zfs_close(zhp);
        return (0);
    }

    if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
        zfs_close(zhp);
        return (0);
    }

    libzfs_add_handle(cbp, zhp);
    if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
        zfs_close(zhp);
        return (-1);
    }
    return (0);
}
Пример #21
0
/*
 * Unshare the given filesystem.
 */
int
zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
    zfs_share_proto_t *proto)
{
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	struct mnttab entry;
	char *mntpt = NULL;

	/* check to see if need to unmount the filesystem */
	rewind(zhp->zfs_hdl->libzfs_mnttab);
	if (mountpoint != NULL)
		mountpoint = mntpt = zfs_strdup(hdl, mountpoint);

	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
	    libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) {
		zfs_share_proto_t *curr_proto;

		if (mountpoint == NULL)
			mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);

		for (curr_proto = proto; *curr_proto != PROTO_END;
		    curr_proto++) {

			while (is_shared(hdl, mntpt, *curr_proto)) {
			    if (unshare_one(hdl, zhp->zfs_name,
					mntpt, *curr_proto) != 0) {
				if (mntpt != NULL)
					free(mntpt);
				return (-1);
			    }
			}
		}
	}
	if (mntpt != NULL)
		free(mntpt);

	return (0);
}
Пример #22
0
/*
 * A ZFS file system iterator call-back function which returns the
 * zfs_handle_t for a ZFS file system on the specified mount point.
 */
static int
match_mountpoint(zfs_handle_t *zhp, void *data)
{
	int			res;
	zfs_mount_data_t	*cbp;
	char			mp[ZFS_MAXPROPLEN];

	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
		zfs_close(zhp);
		return (0);
	}

	cbp = (zfs_mount_data_t *)data;
	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
	    0, B_FALSE) == 0 && strcmp(mp, cbp->match_name) == 0) {
		cbp->match_handle = zhp;
		return (1);
	}

	res = zfs_iter_filesystems(zhp, match_mountpoint, data);
	zfs_close(zhp);
	return (res);
}
Пример #23
0
int
zpool_disable_volumes(zfs_handle_t *nzhp, void *data)
{
	// Same pool?
	if (nzhp && nzhp->zpool_hdl && zpool_get_name(nzhp->zpool_hdl) &&
	    data && !strcmp(zpool_get_name(nzhp->zpool_hdl), (char *)data)) {
		if (zfs_get_type(nzhp) == ZFS_TYPE_VOLUME) {
			char *volume = NULL;
			/*
			 *	/var/run/zfs/zvol/dsk/$POOL/$volume
			 */
			volume = zfs_asprintf(nzhp->zfs_hdl,
			    "%s/zfs/zvol/dsk/%s",
			    ZVOL_ROOT,
			    zfs_get_name(nzhp));
			if (volume) {
				/* Unfortunately, diskutil does not handle our
				 * symlink to /dev/diskX - so we need to
				 * readlink() to find the path
				 */
				char dstlnk[MAXPATHLEN];
				int ret;
				ret = readlink(volume, dstlnk, sizeof(dstlnk));
				if (ret > 0) {
					printf("Attempting to eject volume "
					    "'%s'\n", zfs_get_name(nzhp));
					dstlnk[ret] = '\0';
					do_unmount_volume(dstlnk, 0);
				}
				free(volume);
			}
		}
	}
	(void) zfs_iter_children(nzhp, zpool_disable_volumes, data);
	zfs_close(nzhp);
	return (0);
}
Пример #24
0
/*
 * Called for each dataset.  If the object is of an appropriate type,
 * add it to the avl tree and recurse over any children as necessary.
 */
static int
zfs_callback(zfs_handle_t *zhp, void *data)
{
	callback_data_t *cb = data;
	boolean_t should_close = B_TRUE;
	boolean_t include_snaps = zfs_include_snapshots(zhp, cb);
	boolean_t include_bmarks = (cb->cb_types & ZFS_TYPE_BOOKMARK);

	if ((zfs_get_type(zhp) & cb->cb_types) ||
	    ((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) {
		uu_avl_index_t idx;
		zfs_node_t *node = safe_malloc(sizeof (zfs_node_t));

		node->zn_handle = zhp;
		uu_avl_node_init(node, &node->zn_avlnode, avl_pool);
		if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol,
		    &idx) == NULL) {
			if (cb->cb_proplist) {
				if ((*cb->cb_proplist) &&
				    !(*cb->cb_proplist)->pl_all)
					zfs_prune_proplist(zhp,
					    cb->cb_props_table);

				if (zfs_expand_proplist(zhp, cb->cb_proplist,
				    (cb->cb_flags & ZFS_ITER_RECVD_PROPS),
				    (cb->cb_flags & ZFS_ITER_LITERAL_PROPS))
				    != 0) {
					free(node);
					return (-1);
				}
			}
			uu_avl_insert(cb->cb_avl, node, idx);
			should_close = B_FALSE;
		} else {
			free(node);
		}
	}

	/*
	 * Recurse if necessary.
	 */
	if (cb->cb_flags & ZFS_ITER_RECURSE &&
	    ((cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 ||
	    cb->cb_depth < cb->cb_depth_limit)) {
		cb->cb_depth++;

		/*
		 * If we are not looking for filesystems, we don't need to
		 * recurse into filesystems when we are at our depth limit.
		 */
		if ((cb->cb_depth < cb->cb_depth_limit ||
		    (cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 ||
		    (cb->cb_types &
		    (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) &&
		    zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
			(void) zfs_iter_filesystems(zhp, zfs_callback, data);
		}

		if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
		    ZFS_TYPE_BOOKMARK)) == 0) && include_snaps) {
			(void) zfs_iter_snapshots(zhp,
			    (cb->cb_flags & ZFS_ITER_SIMPLE) != 0,
			    zfs_callback, data, 0, 0);
		}

		if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
		    ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks) {
			(void) zfs_iter_bookmarks(zhp, zfs_callback, data);
		}

		cb->cb_depth--;
	}

	if (should_close)
		zfs_close(zhp);

	return (0);
}
Пример #25
0
/*
 * Sort datasets by specified columns.
 *
 * o  Numeric types sort in ascending order.
 * o  String types sort in alphabetical order.
 * o  Types inappropriate for a row sort that row to the literal
 *    bottom, regardless of the specified ordering.
 *
 * If no sort columns are specified, or two datasets compare equally
 * across all specified columns, they are sorted alphabetically by name
 * with snapshots grouped under their parents.
 */
static int
zfs_sort(const void *larg, const void *rarg, void *data)
{
	zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
	zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
	zfs_sort_column_t *sc = (zfs_sort_column_t *)data;
	zfs_sort_column_t *psc;

	for (psc = sc; psc != NULL; psc = psc->sc_next) {
		char lbuf[ZFS_MAXPROPLEN], rbuf[ZFS_MAXPROPLEN];
		char *lstr, *rstr;
		uint64_t lnum, rnum;
		boolean_t lvalid, rvalid;
		int ret = 0;

		/*
		 * We group the checks below the generic code.  If 'lstr' and
		 * 'rstr' are non-NULL, then we do a string based comparison.
		 * Otherwise, we compare 'lnum' and 'rnum'.
		 */
		lstr = rstr = NULL;
		if (psc->sc_prop == ZPROP_INVAL) {
			nvlist_t *luser, *ruser;
			nvlist_t *lval, *rval;

			luser = zfs_get_user_props(l);
			ruser = zfs_get_user_props(r);

			lvalid = (nvlist_lookup_nvlist(luser,
			    psc->sc_user_prop, &lval) == 0);
			rvalid = (nvlist_lookup_nvlist(ruser,
			    psc->sc_user_prop, &rval) == 0);

			if (lvalid)
				verify(nvlist_lookup_string(lval,
				    ZPROP_VALUE, &lstr) == 0);
			if (rvalid)
				verify(nvlist_lookup_string(rval,
				    ZPROP_VALUE, &rstr) == 0);
		} else if (psc->sc_prop == ZFS_PROP_NAME) {
			lvalid = rvalid = B_TRUE;

			(void) strlcpy(lbuf, zfs_get_name(l), sizeof(lbuf));
			(void) strlcpy(rbuf, zfs_get_name(r), sizeof(rbuf));

			lstr = lbuf;
			rstr = rbuf;
		} else if (zfs_prop_is_string(psc->sc_prop)) {
			lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf,
			    sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0);
			rvalid = (zfs_prop_get(r, psc->sc_prop, rbuf,
			    sizeof (rbuf), NULL, NULL, 0, B_TRUE) == 0);

			lstr = lbuf;
			rstr = rbuf;
		} else {
			lvalid = zfs_prop_valid_for_type(psc->sc_prop,
			    zfs_get_type(l));
			rvalid = zfs_prop_valid_for_type(psc->sc_prop,
			    zfs_get_type(r));

			if (lvalid)
				(void) zfs_prop_get_numeric(l, psc->sc_prop,
				    &lnum, NULL, NULL, 0);
			if (rvalid)
				(void) zfs_prop_get_numeric(r, psc->sc_prop,
				    &rnum, NULL, NULL, 0);
		}

		if (!lvalid && !rvalid)
			continue;
		else if (!lvalid)
			return (1);
		else if (!rvalid)
			return (-1);

		if (lstr)
			ret = strcmp(lstr, rstr);
		else if (lnum < rnum)
			ret = -1;
		else if (lnum > rnum)
			ret = 1;

		if (ret != 0) {
			if (psc->sc_reverse == B_TRUE)
				ret = (ret < 0) ? 1 : -1;
			return (ret);
		}
	}

	return (zfs_compare(larg, rarg, NULL));
}
Пример #26
0
/*
 * Mount the given filesystem.
 *
 * 'flags' appears pretty much always 0 here.
 */
int
zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
{
	struct stat buf;
	char mountpoint[ZFS_MAXPROPLEN];
	char mntopts[MNT_LINE_MAX];
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	int remount;

	if (options == NULL) {
		mntopts[0] = '\0';
	} else {
		(void) strlcpy(mntopts, options, sizeof (mntopts));
	}

	if (strstr(mntopts, MNTOPT_REMOUNT) != NULL)
		remount = 1;

	/*
	 * If the pool is imported read-only then all mounts must be read-only
	 */
#ifdef __LINUX__
	if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
		(void) strlcat(mntopts, "," MNTOPT_RO, sizeof (mntopts));
#else
	if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
		flags |= MS_RDONLY;
#endif /* __LINUX__ */

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
		return (0);

#ifdef __LINUX__

	/*
	 * Append default mount options which apply to the mount point.
	 * This is done because under Linux (unlike Solaris) multiple mount
	 * points may reference a single super block.  This means that just
	 * given a super block there is no back reference to update the per
	 * mount point options.
	 */
	rc = zfs_add_options(zhp, &flags);
	if (rc) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "default options unavailable"));
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
		    mountpoint));
	}

	/*
	 * Append zfsutil option so the mount helper allow the mount
	 */
	strlcat(mntopts, "," MNTOPT_ZFSUTIL, sizeof (mntopts));
#endif /* __LINUX__ */

	/* Create the directory if it doesn't already exist */
#ifdef __APPLE__
	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT &&
	    lstat(mountpoint, &buf) != 0) {
#else
	if (lstat(mountpoint, &buf) != 0) {
#endif
		if (mkdirp(mountpoint, 0755) != 0) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "failed to create mountpoint"));
			return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
			    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
			    mountpoint));
		}

	}

	/*
	 * Determine if the mountpoint is empty.  If so, refuse to perform the
	 * mount.  We don't perform this check if 'remount' is
	 * specified or if overlay option(-O) is given
	 */
	if ((flags & MS_OVERLAY) == 0 && !remount &&
	    !dir_is_empty(mountpoint)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "directory is not empty"));
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
	}

	/* perform the mount */
#ifdef __LINUX__
	rc = do_mount(zfs_get_name(zhp), mountpoint, mntopts);
#elif defined(__APPLE__) || defined (__FREEBSD__)
	if (zmount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
#elif defined(__illumos__)
	if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
#endif /* __LINUX__*/
		/*
		 * Generic errors are nasty, but there are just way too many
		 * from mount(), and they're well-understood.  We pick a few
		 * common ones to improve upon.
		 */
		if (errno == EBUSY) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "mountpoint or dataset is busy"));
		} else if (errno == EPERM) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "Insufficient privileges"));
		} else if (errno == ENOTSUP) {
			char buf[256];
			int spa_version;

			VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
			(void) snprintf(buf, sizeof (buf),
			    dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
			    "file system on a version %d pool. Pool must be"
			    " upgraded to mount this file system."),
			    (u_longlong_t)zfs_prop_get_int(zhp,
			    ZFS_PROP_VERSION), spa_version);
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
#ifdef __APPLE__
		} else if (((errno == ESRCH) || (errno == EINVAL) ||
		    (errno == ENOENT && lstat(mountpoint, &buf) != 0)) &&
		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "The parent file system must be mounted first."));
#endif
		} else {
			zfs_error_aux(hdl, strerror(errno));
		}
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
		    zhp->zfs_name));
	}

#ifdef __APPLE__
	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
		fprintf(stderr, "ZFS: snapshot mountpoint '%s'\n", mountpoint);

	if (!(flags & MS_RDONLY))
		zfs_mount_seticon(mountpoint);
#endif

	/* remove the mounted entry before re-adding on remount */
	if (remount)
		libzfs_mnttab_remove(hdl, zhp->zfs_name);

	/* add the mounted entry into our cache */
	libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint, mntopts);
	return (0);
}

/*
 * Unmount a single filesystem.
 */
static int
unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
{
    int error;
#if 0
    error = unmount(mountpoint, flags);
    if (unmount(mountpoint, flags) != 0) {
		return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
		    mountpoint));
	}
#else
    error = do_unmount(mountpoint, flags);
    if (error != 0) {
        return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
                              dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
                    mountpoint));
    }
#endif

	return (0);
}

/*
 * Unmount the given filesystem.
 */
int
zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
{
	libzfs_handle_t *hdl = zhp->zfs_hdl;
#ifdef __LINUX__
	struct mnttab search = { 0 }, entry;
#else
	struct mnttab entry;
#endif /* __LINUX__ */
	char *mntpt = NULL;

	/* check to see if need to unmount the filesystem */
	if (mountpoint != NULL ||
	    (((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) ||
	    (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)) &&
	    libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) {

		/*
		 * mountpoint may have come from a call to
		 * getmnt/getmntany if it isn't NULL. If it is NULL,
		 * we know it comes from getmntany which can then get
		 * overwritten later. We strdup it to play it safe.
		 */
		if (mountpoint == NULL)
			mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
		else
			mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);

		/*
		 * Unshare and unmount the filesystem
		 */
#ifdef __illumos__
		if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
#else
		if (zfs_unshare_nfs(zhp, mntpt) != 0)
#endif
		return (-1);

		if (unmount_one(hdl, mntpt, flags) != 0) {
			free(mntpt);
#ifdef __illumos__
			(void) zfs_shareall(zhp);
#else
			(void) zfs_share_nfs(zhp);
#endif
			return (-1);
		}
		libzfs_mnttab_remove(hdl, zhp->zfs_name);
		free(mntpt);

	}

	return (0);
}
Пример #27
0
/*
 * A ZFS file system iterator call-back function which returns the
 * zfs_handle_t for a ZFS file system on the specified mount point.
 */
static int
match_mountpoint(zfs_handle_t *zhp, void *data)
{
	int			res;
	zfs_mount_data_t	*cbp;
	char			mp[ZFS_MAXPROPLEN];

	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
		zfs_close(zhp);
		return (0);
	}

	/* First check if the dataset is mounted. */
	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mp, sizeof (mp), NULL, NULL,
	    0, B_FALSE) != 0 || strcmp(mp, "no") == 0) {
		zfs_close(zhp);
		return (0);
	}

	/* Now check mount point. */
	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
	    0, B_FALSE) != 0) {
		zfs_close(zhp);
		return (0);
	}

	cbp = (zfs_mount_data_t *)data;

	if (strcmp(mp, "legacy") == 0) {
		/* If legacy, must look in mnttab for mountpoint. */
		FILE		*fp;
		struct mnttab	entry;
		const char	*nm;

		nm = zfs_get_name(zhp);
		if ((fp = fopen(MNTTAB, "r")) == NULL) {
			zfs_close(zhp);
			return (0);
		}

		while (getmntent(fp, &entry) == 0) {
			if (strcmp(nm, entry.mnt_special) == 0) {
				if (strcmp(entry.mnt_mountp, cbp->match_name)
				    == 0) {
					(void) fclose(fp);
					cbp->match_handle = zhp;
					return (1);
				}
				break;
			}
		}
		(void) fclose(fp);

	} else if (strcmp(mp, cbp->match_name) == 0) {
		cbp->match_handle = zhp;
		return (1);
	}

	/* Iterate over any nested datasets. */
	res = zfs_iter_filesystems(zhp, match_mountpoint, data);
	zfs_close(zhp);
	return (res);
}
Пример #28
0
int
zfs_key_load(zfs_handle_t *zhp, boolean_t mount, boolean_t share,
    boolean_t recursive)
{
	zfs_handle_t *pzhp = NULL;
	zprop_source_t propsrctype;
	char source[ZFS_MAXNAMELEN];
	char keysource[MAXNAMELEN];
	uint64_t ret, crypt, keystatus;
	zfs_cmd_t zc = { {0 }};
	char errbuf[1024];

    fprintf(stderr, "zfs_key_load\r\n");


	(void) strlcpy(zc.zc_name, zfs_get_name(zhp), sizeof (zc.zc_name));
	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
	    "cannot load key for '%s'"), zc.zc_name);

	zfs_refresh_properties(zhp);

	crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);
	if (crypt == ZIO_CRYPT_OFF) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "encryption not enabled on dataset %s."), zc.zc_name);
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);

	if (keystatus == ZFS_CRYPT_KEY_AVAILABLE && !recursive) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "already loaded."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	if (zfs_prop_get(zhp, ZFS_PROP_KEYSOURCE, keysource, ZFS_MAXNAMELEN,
	    &propsrctype, source, sizeof (source), FALSE) != 0) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "no keysource property available."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	if (propsrctype == ZPROP_SRC_INHERITED) {
#if 0 // FIXME
		if (strcmp(source, ZONE_INVISIBLE_SOURCE) == 0) {
			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
			    "key must be loaded from global zone."));
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		}
#endif
		pzhp = make_dataset_handle(zhp->zfs_hdl, source);
		if (pzhp == NULL) {
			errno = EINVAL;
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		}
		keystatus = zfs_prop_get_int(pzhp, ZFS_PROP_KEYSTATUS);
		zfs_close(pzhp);
	}

	if (propsrctype == ZPROP_SRC_DEFAULT) {
		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
		    "invalid keysource property."));
		return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
	}

	if (!zfs_can_prompt_if_needed(keysource)) {
		errno = ENOTTY;
		return (-1);
	}
	/*
	 * NONE we are the top ds asking for crypto so we
	 * need to get and load the key.
	 *
	 * UNAVAILABLE we need to load the key of a higher level
	 * dataset.
	 *
	 * AVAILABLE we are done other than filling in who we
	 * are inheriting the wrapping key from.
	 */
	if (propsrctype == ZPROP_SRC_INHERITED &&
	    keystatus == ZFS_CRYPT_KEY_AVAILABLE) {
		(void) strlcpy(zc.zc_crypto.zic_inherit_dsname, source,
		    sizeof (zc.zc_crypto.zic_inherit_dsname));
		ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_INHERIT, &zc);
		goto out;
	}

	zc.zc_crypto.zic_crypt = crypt;

	ret = key_hdl_to_zc(zhp->zfs_hdl, zhp, keysource, crypt, &zc,
	    ZFS_CRYPTO_KEY_LOAD);
	if (ret != 0) {
		if (errno == ENOTTY)
			ret = 0;
		goto out;
	}

	ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CRYPTO_KEY_LOAD, &zc);
out:
	if (ret != 0) {
		if (errno == EACCES) {
			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
			    "incorrect key."));
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		} else if (!recursive) {
			if (errno == EEXIST) {
				zfs_error_aux(zhp->zfs_hdl,
				    dgettext(TEXT_DOMAIN, "already loaded."));
			} else if (zhp->zfs_hdl->libzfs_desc_active == 0) {
				zfs_error_aux(zhp->zfs_hdl, strerror(errno));
			}
			return (zfs_error(zhp->zfs_hdl, EZFS_KEYERR, errbuf));
		}
	}

	zfs_refresh_properties(zhp);
	if (mount) {
		if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
			if (recursive) {
				ret = zfs_mountall(zhp, 0);
			} else {
				ret = zfs_mount(zhp, NULL, 0);
			}
			if (ret == 0 && share) {
				ret = zfs_share(zhp);
			}
		}
	}

	return (ret);
}
Пример #29
0
/*
 * Unmount a single filesystem.
 */
static int
unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
{
#ifdef __APPLE__
#if !TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE
	/* First try going through diskarb */
	if (diskarb_unmount(mountpoint, flags) == 0) {
		return (0);
	}
#endif
#endif
#ifdef __APPLE__
	if (unmount(mountpoint, flags) != 0) {
#else
	if (umount2(mountpoint, flags) != 0) {
#endif
		zfs_error_aux(hdl, strerror(errno));
		return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
		    mountpoint));
	}

	return (0);
}

/*
 * Unmount the given filesystem.
 */
int
zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
{
	struct mnttab search = { 0 }, entry;
	char *mntpt = NULL;

	/* check to see if need to unmount the filesystem */
	search.mnt_special = zhp->zfs_name;
	search.mnt_fstype = MNTTYPE_ZFS;
#ifndef __APPLE__
	rewind(zhp->zfs_hdl->libzfs_mnttab);
#endif /*!__APPLE__*/
	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
	    getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {

		/*
		 * mountpoint may have come from a call to
		 * getmnt/getmntany if it isn't NULL. If it is NULL,
		 * we know it comes from getmntany which can then get
		 * overwritten later. We strdup it to play it safe.
		 */
		if (mountpoint == NULL)
			mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
		else
			mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);

		/*
		 * Unshare and unmount the filesystem
		 */
#ifndef __APPLE__
		if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
			return (-1);
#endif

		if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) {
			free(mntpt);
			(void) zfs_shareall(zhp);
			return (-1);
		}
		free(mntpt);
	}

	return (0);
}

/*
 * Unmount this filesystem and any children inheriting the mountpoint property.
 * To do this, just act like we're changing the mountpoint property, but don't
 * remount the filesystems afterwards.
 */
int
zfs_unmountall(zfs_handle_t *zhp, int flags)
{
	prop_changelist_t *clp;
	int ret;

	clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags);
	if (clp == NULL)
		return (-1);

	ret = changelist_prefix(clp);
	changelist_free(clp);

	return (ret);
}
Пример #30
0
/*
 * Function:	be_add_children_callback
 * Description:	Callback function used by zfs_iter to look through all
 *		the datasets and snapshots for each BE and add them to
 *		the lists of information to be passed back.
 * Parameters:
 *		zhp - handle to the first zfs dataset. (provided by the
 *		      zfs_iter_* call)
 *		data - pointer to the callback data and where we'll pass
 *		       the BE information back.
 * Returns:
 *		0 - Success
 *		be_errno_t - Failure
 * Scope:
 *		Private
 */
static int
be_add_children_callback(zfs_handle_t *zhp, void *data)
{
	list_callback_data_t	*cb = (list_callback_data_t *)data;
	char			*str = NULL, *ds_path = NULL;
	int			ret = 0;
	struct be_defaults be_defaults;

	be_get_defaults(&be_defaults);

	ds_path = str = strdup(zfs_get_name(zhp));

	/*
	 * get past the end of the container dataset plus the trailing "/"
	 */
	str = str + (strlen(be_container_ds) + 1);
	if (be_defaults.be_deflt_rpool_container) {
		/* just skip if invalid */
		if (!be_valid_be_name(str))
			return (BE_SUCCESS);
	}

	if (cb->be_nodes_head == NULL) {
		if ((cb->be_nodes_head = be_list_alloc(&ret,
		    sizeof (be_node_list_t))) == NULL) {
			ZFS_CLOSE(zhp);
			return (ret);
		}
		cb->be_nodes = cb->be_nodes_head;
	}

	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && !zone_be) {
		be_snapshot_list_t *snapshots = NULL;
		if (cb->be_nodes->be_node_snapshots == NULL) {
			if ((cb->be_nodes->be_node_snapshots =
			    be_list_alloc(&ret, sizeof (be_snapshot_list_t)))
			    == NULL || ret != BE_SUCCESS) {
				ZFS_CLOSE(zhp);
				return (ret);
			}
			cb->be_nodes->be_node_snapshots->be_next_snapshot =
			    NULL;
			snapshots = cb->be_nodes->be_node_snapshots;
		} else {
			for (snapshots = cb->be_nodes->be_node_snapshots;
			    snapshots != NULL;
			    snapshots = snapshots->be_next_snapshot) {
				if (snapshots->be_next_snapshot != NULL)
					continue;
				/*
				 * We're at the end of the list add the
				 * new snapshot.
				 */
				if ((snapshots->be_next_snapshot =
				    be_list_alloc(&ret,
				    sizeof (be_snapshot_list_t))) == NULL ||
				    ret != BE_SUCCESS) {
					ZFS_CLOSE(zhp);
					return (ret);
				}
				snapshots = snapshots->be_next_snapshot;
				snapshots->be_next_snapshot = NULL;
				break;
			}
		}
		if ((ret = be_get_ss_data(zhp, str, snapshots,
		    cb->be_nodes)) != BE_SUCCESS) {
			ZFS_CLOSE(zhp);
			return (ret);
		}
	} else if (strchr(str, '/') == NULL) {
		if (cb->be_nodes->be_node_name != NULL) {
			if ((cb->be_nodes->be_next_node =
			    be_list_alloc(&ret, sizeof (be_node_list_t))) ==
			    NULL || ret != BE_SUCCESS) {
				ZFS_CLOSE(zhp);
				return (ret);
			}
			cb->be_nodes = cb->be_nodes->be_next_node;
			cb->be_nodes->be_next_node = NULL;
		}

		/*
		 * If this is a zone root dataset then we only need
		 * the name of the zone BE at this point. We grab that
		 * and return.
		 */
		if (zone_be) {
			ret = be_get_zone_node_data(cb->be_nodes, str);
			ZFS_CLOSE(zhp);
			return (ret);
		}

		if ((ret = be_get_node_data(zhp, cb->be_nodes, str,
		    cb->zpool_name, cb->current_be, ds_path)) != BE_SUCCESS) {
			ZFS_CLOSE(zhp);
			return (ret);
		}
	} else if (strchr(str, '/') != NULL && !zone_be) {
		be_dataset_list_t *datasets = NULL;
		if (cb->be_nodes->be_node_datasets == NULL) {
			if ((cb->be_nodes->be_node_datasets =
			    be_list_alloc(&ret, sizeof (be_dataset_list_t)))
			    == NULL || ret != BE_SUCCESS) {
				ZFS_CLOSE(zhp);
				return (ret);
			}
			cb->be_nodes->be_node_datasets->be_next_dataset = NULL;
			datasets = cb->be_nodes->be_node_datasets;
		} else {
			for (datasets = cb->be_nodes->be_node_datasets;
			    datasets != NULL;
			    datasets = datasets->be_next_dataset) {
				if (datasets->be_next_dataset != NULL)
					continue;
				/*
				 * We're at the end of the list add
				 * the new dataset.
				 */
				if ((datasets->be_next_dataset =
				    be_list_alloc(&ret,
				    sizeof (be_dataset_list_t)))
				    == NULL || ret != BE_SUCCESS) {
					ZFS_CLOSE(zhp);
					return (ret);
				}
				datasets = datasets->be_next_dataset;
				datasets->be_next_dataset = NULL;
				break;
			}
		}

		if ((ret = be_get_ds_data(zhp, str,
		    datasets, cb->be_nodes)) != BE_SUCCESS) {
			ZFS_CLOSE(zhp);
			return (ret);
		}
	}
	ret = zfs_iter_children(zhp, be_add_children_callback, cb);
	if (ret != 0) {
		be_print_err(gettext("be_add_children_callback: "
		    "encountered error: %s\n"),
		    libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
	}
	ZFS_CLOSE(zhp);
	return (ret);
}