Esempio n. 1
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);
}
Esempio n. 2
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);
}
Esempio n. 3
0
/* zfs_remount: called only from rollback to clear the page cache for now */
int
zfs_remount(zfs_handle_t *zhp)
{
	char* mountpoint = 0;
	if (!zfs_is_mounted(zhp, &mountpoint))
		return 0;
	VERIFY(0 != mountpoint);

	int result = 0;
#undef mount
	if (0 != mount(zfs_get_name(zhp), mountpoint, MNTTYPE_ZFS/*ignored*/, MS_REMOUNT, 0))
		result = errno;
#define mount __bogus__ // don't accidentally move my cheese

	if (mountpoint)
		free(mountpoint);

	return result;
}
Esempio n. 4
0
/*
 * Check to see if the filesystem is currently shared.
 */
zfs_share_type_t
zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
{
	char *mountpoint;
	zfs_share_type_t rc;

	if (!zfs_is_mounted(zhp, &mountpoint))
		return (SHARED_NOT_SHARED);

	if ((rc = is_shared(zhp->zfs_hdl, mountpoint, proto))) {
		if (where != NULL)
			*where = mountpoint;
		else
			free(mountpoint);
		return (rc);
	} else {
		free(mountpoint);
		return (SHARED_NOT_SHARED);
	}
}
Esempio n. 5
0
/*
 * Given a ZFS handle and a property, construct a complete list of datasets
 * that need to be modified as part of this process.  For anything but the
 * 'mountpoint' and 'sharenfs' properties, this just returns an empty list.
 * Otherwise, we iterate over all children and look for any datasets that
 * inherit the property.  For each such dataset, we add it to the list and
 * mark whether it was shared beforehand.
 */
prop_changelist_t *
changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
    int mnt_flags)
{
	prop_changelist_t *clp;
	prop_changenode_t *cn;
	zfs_handle_t *temp;
	char property[ZFS_MAXPROPLEN];
	uu_compare_fn_t *compare = NULL;
	boolean_t legacy = B_FALSE;

	if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
		return (NULL);

	/*
	 * For mountpoint-related tasks, we want to sort everything by
	 * mountpoint, so that we mount and unmount them in the appropriate
	 * order, regardless of their position in the hierarchy.
	 */
	if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
	    prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS ||
	    prop == ZFS_PROP_SHARESMB) {

		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
		    property, sizeof (property),
		    NULL, NULL, 0, B_FALSE) == 0 &&
		    (strcmp(property, "legacy") == 0 ||
		    strcmp(property, "none") == 0)) {

			legacy = B_TRUE;
		}
		if (!legacy) {
			compare = compare_mountpoints;
			clp->cl_sorted = B_TRUE;
		}
	}

	clp->cl_pool = uu_list_pool_create("changelist_pool",
	    sizeof (prop_changenode_t),
	    offsetof(prop_changenode_t, cn_listnode),
	    compare, 0);
	if (clp->cl_pool == NULL) {
		assert(uu_error() == UU_ERROR_NO_MEMORY);
		(void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
		changelist_free(clp);
		return (NULL);
	}

	clp->cl_list = uu_list_create(clp->cl_pool, NULL,
	    clp->cl_sorted ? UU_LIST_SORTED : 0);
	clp->cl_gflags = gather_flags;
	clp->cl_mflags = mnt_flags;

	if (clp->cl_list == NULL) {
		assert(uu_error() == UU_ERROR_NO_MEMORY);
		(void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
		changelist_free(clp);
		return (NULL);
	}

	/*
	 * If this is a rename or the 'zoned' property, we pretend we're
	 * changing the mountpoint and flag it so we can catch all children in
	 * change_one().
	 *
	 * Flag cl_alldependents to catch all children plus the dependents
	 * (clones) that are not in the hierarchy.
	 */
	if (prop == ZFS_PROP_NAME) {
		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
		clp->cl_alldependents = B_TRUE;
	} else if (prop == ZFS_PROP_ZONED) {
		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
		clp->cl_allchildren = B_TRUE;
	} else if (prop == ZFS_PROP_CANMOUNT) {
		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
	} else if (prop == ZFS_PROP_VOLSIZE) {
		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
	} else {
		clp->cl_prop = prop;
	}
	clp->cl_realprop = prop;

	if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
	    clp->cl_prop != ZFS_PROP_SHARENFS &&
	    clp->cl_prop != ZFS_PROP_SHARESMB)
		return (clp);

	/*
	 * If watching SHARENFS or SHARESMB then
	 * also watch its companion property.
	 */
	if (clp->cl_prop == ZFS_PROP_SHARENFS)
		clp->cl_shareprop = ZFS_PROP_SHARESMB;
	else if (clp->cl_prop == ZFS_PROP_SHARESMB)
		clp->cl_shareprop = ZFS_PROP_SHARENFS;

	if (clp->cl_alldependents) {
		if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
			changelist_free(clp);
			return (NULL);
		}
	} else if (zfs_iter_children(zhp, change_one, clp) != 0) {
		changelist_free(clp);
		return (NULL);
	}

	/*
	 * We have to re-open ourselves because we auto-close all the handles
	 * and can't tell the difference.
	 */
	if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp),
	    ZFS_TYPE_DATASET)) == NULL) {
		changelist_free(clp);
		return (NULL);
	}

	/*
	 * Always add ourself to the list.  We add ourselves to the end so that
	 * we're the last to be unmounted.
	 */
	if ((cn = zfs_alloc(zhp->zfs_hdl,
	    sizeof (prop_changenode_t))) == NULL) {
		zfs_close(temp);
		changelist_free(clp);
		return (NULL);
	}

	cn->cn_handle = temp;
	cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
	    zfs_is_mounted(temp, NULL);
	cn->cn_shared = zfs_is_shared(temp);
	cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
	cn->cn_needpost = B_TRUE;

	uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
	if (clp->cl_sorted) {
		uu_list_index_t idx;
		(void) uu_list_find(clp->cl_list, cn, NULL, &idx);
		uu_list_insert(clp->cl_list, cn, idx);
	} else {
		/*
		 * Add the target dataset to the end of the list.
		 * The list is not really unsorted. The list will be
		 * in reverse dataset name order. This is necessary
		 * when the original mountpoint is legacy or none.
		 */
		verify(uu_list_insert_after(clp->cl_list,
		    uu_list_last(clp->cl_list), cn) == 0);
	}

	/*
	 * If the mountpoint property was previously 'legacy', or 'none',
	 * record it as the behavior of changelist_postfix() will be different.
	 */
	if ((clp->cl_prop == ZFS_PROP_MOUNTPOINT) && legacy) {
		/*
		 * do not automatically mount ex-legacy datasets if
		 * we specifically set canmount to noauto
		 */
		if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) !=
		    ZFS_CANMOUNT_NOAUTO)
			clp->cl_waslegacy = B_TRUE;
	}

	return (clp);
}
Esempio n. 6
0
static int
change_one(zfs_handle_t *zhp, void *data)
{
	prop_changelist_t *clp = data;
	char property[ZFS_MAXPROPLEN];
	char where[64];
	prop_changenode_t *cn;
	zprop_source_t sourcetype;
	zprop_source_t share_sourcetype;

	/*
	 * We only want to unmount/unshare those filesystems that may inherit
	 * from the target filesystem.  If we find any filesystem with a
	 * locally set mountpoint, we ignore any children since changing the
	 * property will not affect them.  If this is a rename, we iterate
	 * over all children regardless, since we need them unmounted in
	 * order to do the rename.  Also, if this is a volume and we're doing
	 * a rename, then always add it to the changelist.
	 */

	if (!(ZFS_IS_VOLUME(zhp) && clp->cl_realprop == ZFS_PROP_NAME) &&
	    zfs_prop_get(zhp, clp->cl_prop, property,
	    sizeof (property), &sourcetype, where, sizeof (where),
	    B_FALSE) != 0) {
		zfs_close(zhp);
		return (0);
	}

	/*
	 * If we are "watching" sharenfs or sharesmb
	 * then check out the companion property which is tracked
	 * in cl_shareprop
	 */
	if (clp->cl_shareprop != ZPROP_INVAL &&
	    zfs_prop_get(zhp, clp->cl_shareprop, property,
	    sizeof (property), &share_sourcetype, where, sizeof (where),
	    B_FALSE) != 0) {
		zfs_close(zhp);
		return (0);
	}

	if (clp->cl_alldependents || clp->cl_allchildren ||
	    sourcetype == ZPROP_SRC_DEFAULT ||
	    sourcetype == ZPROP_SRC_INHERITED ||
	    (clp->cl_shareprop != ZPROP_INVAL &&
	    (share_sourcetype == ZPROP_SRC_DEFAULT ||
	    share_sourcetype == ZPROP_SRC_INHERITED))) {
		if ((cn = zfs_alloc(zfs_get_handle(zhp),
		    sizeof (prop_changenode_t))) == NULL) {
			zfs_close(zhp);
			return (-1);
		}

		cn->cn_handle = zhp;
		cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
		    zfs_is_mounted(zhp, NULL);
		cn->cn_shared = zfs_is_shared(zhp);
		cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
		cn->cn_needpost = B_TRUE;

		/* Indicate if any child is exported to a local zone. */
		if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
			clp->cl_haszonedchild = B_TRUE;

		uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);

		if (clp->cl_sorted) {
			uu_list_index_t idx;

			(void) uu_list_find(clp->cl_list, cn, NULL,
			    &idx);
			uu_list_insert(clp->cl_list, cn, idx);
		} else {
			/*
			 * Add this child to beginning of the list. Children
			 * below this one in the hierarchy will get added above
			 * this one in the list. This produces a list in
			 * reverse dataset name order.
			 * This is necessary when the original mountpoint
			 * is legacy or none.
			 */
			verify(uu_list_insert_before(clp->cl_list,
			    uu_list_first(clp->cl_list), cn) == 0);
		}

		if (!clp->cl_alldependents)
			return (zfs_iter_children(zhp, change_one, data));
	} else {
		zfs_close(zhp);
	}

	return (0);
}
Esempio n. 7
0
/*
 * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
 * reshare the filesystems as necessary.  In changelist_gather() we recorded
 * whether the filesystem was previously shared or mounted.  The action we take
 * depends on the previous state, and whether the value was previously 'legacy'.
 * For non-legacy properties, we only remount/reshare the filesystem if it was
 * previously mounted/shared.  Otherwise, we always remount/reshare the
 * filesystem.
 */
int
changelist_postfix(prop_changelist_t *clp)
{
	prop_changenode_t *cn;
	char shareopts[ZFS_MAXPROPLEN];
	int errors = 0;
	libzfs_handle_t *hdl;

	/*
	 * If we're changing the mountpoint, attempt to destroy the underlying
	 * mountpoint.  All other datasets will have inherited from this dataset
	 * (in which case their mountpoints exist in the filesystem in the new
	 * location), or have explicit mountpoints set (in which case they won't
	 * be in the changelist).
	 */
	if ((cn = uu_list_last(clp->cl_list)) == NULL)
		return (0);

	if (clp->cl_prop == ZFS_PROP_MOUNTPOINT &&
	    !(clp->cl_gflags & CL_GATHER_DONT_UNMOUNT)) {
		remove_mountpoint(cn->cn_handle);
	}

	/*
	 * It is possible that the changelist_prefix() used libshare
	 * to unshare some entries. Since libshare caches data, an
	 * attempt to reshare during postfix can fail unless libshare
	 * is uninitialized here so that it will reinitialize later.
	 */
	if (cn->cn_handle != NULL) {
		hdl = cn->cn_handle->zfs_hdl;
		assert(hdl != NULL);
		zfs_uninit_libshare(hdl);
	}

	/*
	 * We walk the datasets in reverse, because we want to mount any parent
	 * datasets before mounting the children.  We walk all datasets even if
	 * there are errors.
	 */
	for (cn = uu_list_last(clp->cl_list); cn != NULL;
	    cn = uu_list_prev(clp->cl_list, cn)) {

		boolean_t sharenfs;
		boolean_t sharesmb;
		boolean_t mounted;

		/*
		 * If we are in the global zone, but this dataset is exported
		 * to a local zone, do nothing.
		 */
		if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
			continue;

		/* Only do post-processing if it's required */
		if (!cn->cn_needpost)
			continue;
		cn->cn_needpost = B_FALSE;

		zfs_refresh_properties(cn->cn_handle);

		if (ZFS_IS_VOLUME(cn->cn_handle))
			continue;

		/*
		 * Remount if previously mounted or mountpoint was legacy,
		 * or sharenfs or sharesmb  property is set.
		 */
		sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
		    shareopts, sizeof (shareopts), NULL, NULL, 0,
		    B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));

		sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB,
		    shareopts, sizeof (shareopts), NULL, NULL, 0,
		    B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));

		mounted = (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT) ||
		    zfs_is_mounted(cn->cn_handle, NULL);

		if (!mounted && (cn->cn_mounted ||
		    ((sharenfs || sharesmb || clp->cl_waslegacy) &&
		    (zfs_prop_get_int(cn->cn_handle,
		    ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) {

			if (zfs_mount(cn->cn_handle, NULL, 0) != 0)
				errors++;
			else
				mounted = TRUE;
		}

		/*
		 * If the file system is mounted we always re-share even
		 * if the filesystem is currently shared, so that we can
		 * adopt any new options.
		 */
		if (sharenfs && mounted)
			errors += zfs_share_nfs(cn->cn_handle);
		else if (cn->cn_shared || clp->cl_waslegacy)
			errors += zfs_unshare_nfs(cn->cn_handle, NULL);
		if (sharesmb && mounted)
			errors += zfs_share_smb(cn->cn_handle);
		else if (cn->cn_shared || clp->cl_waslegacy)
			errors += zfs_unshare_smb(cn->cn_handle, NULL);
	}

	return (errors ? -1 : 0);
}
Esempio n. 8
0
/*
 * Given a ZFS handle and a property, construct a complete list of datasets
 * that need to be modified as part of this process.  For anything but the
 * 'mountpoint' and 'sharenfs' properties, this just returns an empty list.
 * Otherwise, we iterate over all children and look for any datasets that
 * inherit the property.  For each such dataset, we add it to the list and
 * mark whether it was shared beforehand.
 */
prop_changelist_t *
changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
{
	prop_changelist_t *clp;
	prop_changenode_t *cn;
	zfs_handle_t *temp;
	char property[ZFS_MAXPROPLEN];
	uu_compare_fn_t *compare = NULL;

	if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
		return (NULL);

	/*
	 * For mountpoint-related tasks, we want to sort everything by
	 * mountpoint, so that we mount and unmount them in the appropriate
	 * order, regardless of their position in the hierarchy.
	 */
	if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
	    prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) {
		compare = compare_mountpoints;
		clp->cl_sorted = B_TRUE;
	}

	clp->cl_pool = uu_list_pool_create("changelist_pool",
	    sizeof (prop_changenode_t),
	    offsetof(prop_changenode_t, cn_listnode),
	    compare, 0);
	if (clp->cl_pool == NULL) {
		assert(uu_error() == UU_ERROR_NO_MEMORY);
		(void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
		changelist_free(clp);
		return (NULL);
	}

	clp->cl_list = uu_list_create(clp->cl_pool, NULL,
	    clp->cl_sorted ? UU_LIST_SORTED : 0);
	clp->cl_flags = flags;

	if (clp->cl_list == NULL) {
		assert(uu_error() == UU_ERROR_NO_MEMORY);
		(void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
		changelist_free(clp);
		return (NULL);
	}

	/*
	 * If this is a rename or the 'zoned' property, we pretend we're
	 * changing the mountpoint and flag it so we can catch all children in
	 * change_one().
	 *
	 * Flag cl_alldependents to catch all children plus the dependents
	 * (clones) that are not in the hierarchy.
	 */
	if (prop == ZFS_PROP_NAME) {
		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
		clp->cl_alldependents = B_TRUE;
	} else if (prop == ZFS_PROP_ZONED) {
		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
		clp->cl_allchildren = B_TRUE;
	} else if (prop == ZFS_PROP_CANMOUNT) {
		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
	} else if (prop == ZFS_PROP_VOLSIZE) {
		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
	} else if (prop == ZFS_PROP_VERSION) {
		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
	} else {
		clp->cl_prop = prop;
	}
	clp->cl_realprop = prop;

	if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
	    clp->cl_prop != ZFS_PROP_SHARENFS &&
	    clp->cl_prop != ZFS_PROP_SHAREISCSI)
		return (clp);

	if (clp->cl_alldependents) {
		if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
			changelist_free(clp);
			return (NULL);
		}
	} else if (zfs_iter_children(zhp, change_one, clp) != 0) {
		changelist_free(clp);
		return (NULL);
	}

	/*
	 * We have to re-open ourselves because we auto-close all the handles
	 * and can't tell the difference.
	 */
	if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp),
	    ZFS_TYPE_ANY)) == NULL) {
		changelist_free(clp);
		return (NULL);
	}

	/*
	 * Always add ourself to the list.  We add ourselves to the end so that
	 * we're the last to be unmounted.
	 */
	if ((cn = zfs_alloc(zhp->zfs_hdl,
	    sizeof (prop_changenode_t))) == NULL) {
		zfs_close(temp);
		changelist_free(clp);
		return (NULL);
	}

	cn->cn_handle = temp;
	cn->cn_mounted = zfs_is_mounted(temp, NULL);
	cn->cn_shared = zfs_is_shared(temp);

#ifndef	__APPLE__
	cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
#endif	/*!__APPLE__*/

	uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
	if (clp->cl_sorted) {
		uu_list_index_t idx;
		(void) uu_list_find(clp->cl_list, cn, NULL, &idx);
		uu_list_insert(clp->cl_list, cn, idx);
	} else {
		verify(uu_list_insert_after(clp->cl_list,
		    uu_list_last(clp->cl_list), cn) == 0);
	}

	/*
	 * If the mountpoint property was previously 'legacy', or 'none',
	 * record it as the behavior of changelist_postfix() will be different.
	 */
	if ((clp->cl_prop == ZFS_PROP_MOUNTPOINT) &&
	    (zfs_prop_get(zhp, prop, property, sizeof (property),
	    NULL, NULL, 0, B_FALSE) == 0 &&
	    (strcmp(property, "legacy") == 0 || strcmp(property, "none") == 0)))
		clp->cl_waslegacy = B_TRUE;

	return (clp);
}
Esempio n. 9
0
static int
change_one(zfs_handle_t *zhp, void *data)
{
	prop_changelist_t *clp = data;
	char property[ZFS_MAXPROPLEN];
	char where[64];
	prop_changenode_t *cn;
	zfs_source_t sourcetype;

	/*
	 * We only want to unmount/unshare those filesystems that may inherit
	 * from the target filesystem.  If we find any filesystem with a
	 * locally set mountpoint, we ignore any children since changing the
	 * property will not affect them.  If this is a rename, we iterate
	 * over all children regardless, since we need them unmounted in
	 * order to do the rename.  Also, if this is a volume and we're doing
	 * a rename, then always add it to the changelist.
	 */

	if (!(ZFS_IS_VOLUME(zhp) && clp->cl_realprop == ZFS_PROP_NAME) &&
	    zfs_prop_get(zhp, clp->cl_prop, property,
	    sizeof (property), &sourcetype, where, sizeof (where),
	    B_FALSE) != 0) {
		zfs_close(zhp);
		return (0);
	}

	if (clp->cl_alldependents || clp->cl_allchildren ||
	    sourcetype == ZFS_SRC_DEFAULT || sourcetype == ZFS_SRC_INHERITED) {
		if ((cn = zfs_alloc(zfs_get_handle(zhp),
		    sizeof (prop_changenode_t))) == NULL) {
			zfs_close(zhp);
			return (-1);
		}

		cn->cn_handle = zhp;
		cn->cn_mounted = zfs_is_mounted(zhp, NULL);
		cn->cn_shared = zfs_is_shared(zhp);

#ifndef __APPLE__
		cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);

		/* Indicate if any child is exported to a local zone. */
		if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
			clp->cl_haszonedchild = B_TRUE;
#endif /*!__APPLE__*/

		uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);

		if (clp->cl_sorted) {
			uu_list_index_t idx;

			(void) uu_list_find(clp->cl_list, cn, NULL,
			    &idx);
			uu_list_insert(clp->cl_list, cn, idx);
		} else {
			ASSERT(!clp->cl_alldependents);
			verify(uu_list_insert_before(clp->cl_list,
			    uu_list_first(clp->cl_list), cn) == 0);
		}

		if (!clp->cl_alldependents)
			return (zfs_iter_children(zhp, change_one, data));
	} else {
		zfs_close(zhp);
	}

	return (0);
}
Esempio n. 10
0
/*
 * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
 * reshare the filesystems as necessary.  In changelist_gather() we recorded
 * whether the filesystem was previously shared or mounted.  The action we take
 * depends on the previous state, and whether the value was previously 'legacy'.
 * For non-legacy properties, we only remount/reshare the filesystem if it was
 * previously mounted/shared.  Otherwise, we always remount/reshare the
 * filesystem.
 */
int
changelist_postfix(prop_changelist_t *clp)
{
	prop_changenode_t *cn;
	char shareopts[ZFS_MAXPROPLEN];
	int ret = 0;
	libzfs_handle_t *hdl;

	/*
	 * If we're changing the mountpoint, attempt to destroy the underlying
	 * mountpoint.  All other datasets will have inherited from this dataset
	 * (in which case their mountpoints exist in the filesystem in the new
	 * location), or have explicit mountpoints set (in which case they won't
	 * be in the changelist).
	 */
	if ((cn = uu_list_last(clp->cl_list)) == NULL)
		return (0);

	if (clp->cl_prop == ZFS_PROP_MOUNTPOINT)
		remove_mountpoint(cn->cn_handle);

	/*
	 * It is possible that the changelist_prefix() used libshare
	 * to unshare some entries. Since libshare caches data, an
	 * attempt to reshare during postfix can fail unless libshare
	 * is uninitialized here so that it will reinitialize later.
	 */
	if (cn->cn_handle != NULL) {
		hdl = cn->cn_handle->zfs_hdl;
		assert(hdl != NULL);
#ifndef __APPLE__
		zfs_uninit_libshare(hdl);
#endif
	}

	/*
	 * We walk the datasets in reverse, because we want to mount any parent
	 * datasets before mounting the children.
	 */
	for (cn = uu_list_last(clp->cl_list); cn != NULL;
	    cn = uu_list_prev(clp->cl_list, cn)) {

		boolean_t sharenfs;

#ifndef __APPLE__
		/*
		 * If we are in the global zone, but this dataset is exported
		 * to a local zone, do nothing.
		 */
		if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
			continue;
#endif /*!__APPLE__*/

		zfs_refresh_properties(cn->cn_handle);

		if (ZFS_IS_VOLUME(cn->cn_handle)) {
			/*
			 * If we're doing a rename, recreate the /dev/zvol
			 * links.
			 */
			if (clp->cl_realprop == ZFS_PROP_NAME &&
			    zvol_create_link(cn->cn_handle->zfs_hdl,
			    cn->cn_handle->zfs_name) != 0) {
				ret = -1;
			} else if (cn->cn_shared ||
			    clp->cl_prop == ZFS_PROP_SHAREISCSI) {
				if (zfs_prop_get(cn->cn_handle,
				    ZFS_PROP_SHAREISCSI, shareopts,
				    sizeof (shareopts), NULL, NULL, 0,
				    B_FALSE) == 0 &&
				    strcmp(shareopts, "off") == 0) {
					ret = zfs_unshare_iscsi(cn->cn_handle);
				} else {
					ret = zfs_share_iscsi(cn->cn_handle);
				}
			}

			continue;
		}

		/*
		 * Remount if previously mounted or mountpoint was legacy,
		 * or sharenfs property is set.
		 */
		sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
		    shareopts, sizeof (shareopts), NULL, NULL, 0,
		    B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));

		if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs) &&
		    !zfs_is_mounted(cn->cn_handle, NULL) &&
		    zfs_mount(cn->cn_handle, NULL, 0) != 0)
			ret = -1;

		/*
		 * We always re-share even if the filesystem is currently
		 * shared, so that we can adopt any new options.
		 */
		if (cn->cn_shared || clp->cl_waslegacy || sharenfs) {
			if (sharenfs)
				ret = zfs_share_nfs(cn->cn_handle);
			else
				ret = zfs_unshare_nfs(cn->cn_handle, NULL);
		}
	}

	return (ret);
}
Esempio n. 11
0
int
be_rename(nvlist_t *be_attrs)
{
	be_transaction_data_t	bt = { 0 };
	be_transaction_data_t	cbt = { 0 };
	be_fs_list_data_t	fld = { 0 };
	zfs_handle_t	*zhp = NULL;
	char		root_ds[MAXPATHLEN];
	char		*mp = NULL;
	int		zret = 0, ret = BE_SUCCESS;

	/* Initialize libzfs handle */
	if (!be_zfs_init())
		return (BE_ERR_INIT);

	/* Get original BE name to rename from */
	if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name)
	    != 0) {
		be_print_err(gettext("be_rename: failed to "
		    "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
		be_zfs_fini();
		return (BE_ERR_INVAL);
	}

	/* Get new BE name to rename to */
	if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name)
	    != 0) {
		be_print_err(gettext("be_rename: failed to "
		    "lookup BE_ATTR_NEW_BE_NAME attribute\n"));
		be_zfs_fini();
		return (BE_ERR_INVAL);
	}

	/*
	 * Get the currently active BE and check to see if this
	 * is an attempt to rename the currently active BE.
	 */
	if (be_find_current_be(&cbt) != BE_SUCCESS) {
		be_print_err(gettext("be_rename: failed to find the currently "
		    "active BE\n"));
		be_zfs_fini();
		return (BE_ERR_CURR_BE_NOT_FOUND);
	}

	if (strncmp(bt.obe_name, cbt.obe_name,
	    MAX(strlen(bt.obe_name), strlen(cbt.obe_name))) == 0) {
		be_print_err(gettext("be_rename: This is an attempt to rename "
		    "the currently active BE, which is not supported\n"));
		be_zfs_fini();
		free(cbt.obe_name);
		return (BE_ERR_RENAME_ACTIVE);
	}

	/* Validate original BE name */
	if (!be_valid_be_name(bt.obe_name)) {
		be_print_err(gettext("be_rename: "
		    "invalid BE name %s\n"), bt.obe_name);
		be_zfs_fini();
		return (BE_ERR_INVAL);
	}

	/* Validate new BE name */
	if (!be_valid_be_name(bt.nbe_name)) {
		be_print_err(gettext("be_rename: invalid BE name %s\n"),
		    bt.nbe_name);
		be_zfs_fini();
		return (BE_ERR_INVAL);
	}

	/* Find which zpool the BE is in */
	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
		be_print_err(gettext("be_rename: failed to "
		    "find zpool for BE (%s)\n"), bt.obe_name);
		be_zfs_fini();
		return (BE_ERR_BE_NOENT);
	} else if (zret < 0) {
		be_print_err(gettext("be_rename: zpool_iter failed: %s\n"),
		    libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		be_zfs_fini();
		return (ret);
	}

	/* New BE will reside in the same zpool as orig BE */
	bt.nbe_zpool = bt.obe_zpool;

	be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds, sizeof (root_ds));
	bt.obe_root_ds = strdup(root_ds);
	be_make_root_ds(bt.nbe_zpool, bt.nbe_name, root_ds, sizeof (root_ds));
	bt.nbe_root_ds = strdup(root_ds);

	/*
	 * Generate a list of file systems from the BE that are legacy
	 * mounted before renaming.  We use this list to determine which
	 * entries in the vfstab we need to update after we've renamed the BE.
	 */
	if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL,
	    &fld)) != BE_SUCCESS) {
		be_print_err(gettext("be_rename: failed to "
		    "get legacy mounted file system list for %s\n"),
		    bt.obe_name);
		goto done;
	}

	/* Get handle to BE's root dataset */
	if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM))
	    == NULL) {
		be_print_err(gettext("be_rename: failed to "
		    "open BE root dataset (%s): %s\n"),
		    bt.obe_root_ds, libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}

	/* Rename of BE's root dataset. */
	if (zfs_rename(zhp, bt.nbe_root_ds, B_FALSE, B_FALSE) != 0) {
		be_print_err(gettext("be_rename: failed to "
		    "rename dataset (%s): %s\n"), bt.obe_root_ds,
		    libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}

	/* Refresh handle to BE's root dataset after the rename */
	ZFS_CLOSE(zhp);
	if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds, ZFS_TYPE_FILESYSTEM))
	    == NULL) {
		be_print_err(gettext("be_rename: failed to "
		    "open BE root dataset (%s): %s\n"),
		    bt.obe_root_ds, libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}

	/* If BE is already mounted, get its mountpoint */
	if (zfs_is_mounted(zhp, &mp) && mp == NULL) {
		be_print_err(gettext("be_rename: failed to "
		    "get altroot of mounted BE %s: %s\n"),
		    bt.nbe_name, libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}

	/* Update BE's vfstab */
	if ((ret = be_update_vfstab(bt.nbe_name, bt.obe_zpool, bt.nbe_zpool,
	    &fld, mp)) != BE_SUCCESS) {
		be_print_err(gettext("be_rename: "
		    "failed to update new BE's vfstab (%s)\n"), bt.nbe_name);
		goto done;
	}

	/* Update this BE's GRUB menu entry */
	if (getzoneid() == GLOBAL_ZONEID && (ret = be_update_menu(bt.obe_name,
	    bt.nbe_name, bt.obe_zpool, NULL)) != BE_SUCCESS) {
		be_print_err(gettext("be_rename: "
		    "failed to update grub menu entry from %s to %s\n"),
		    bt.obe_name, bt.nbe_name);
	}

done:
	be_free_fs_list(&fld);

	ZFS_CLOSE(zhp);

	be_zfs_fini();

	free(bt.obe_root_ds);
	free(bt.nbe_root_ds);
	return (ret);
}
Esempio n. 12
0
/*
 * Function:	be_get_node_data
 * Description:	Helper function used to collect all the information to fill
 *		in the be_node_list structure to be returned by be_list.
 * Parameters:
 *		zhp - Handle to the root dataset for the BE whose information
 *		      we're collecting.
 *		be_node - a pointer to the node structure we're filling in.
 *		be_name - The BE name of the node whose information we're
 *		          collecting.
 *		current_be - the name of the currently active BE.
 *		be_ds - The dataset name for the BE.
 *
 * Returns:
 *		BE_SUCCESS - Success
 *		be_errno_t - Failure
 * Scope:
 *		Private
 */
static int
be_get_node_data(
	zfs_handle_t *zhp,
	be_node_list_t *be_node,
	char *be_name,
	const char *rpool,
	char *current_be,
	char *be_ds)
{
	char prop_buf[MAXPATHLEN];
	nvlist_t *userprops = NULL;
	nvlist_t *propval = NULL;
	nvlist_t *zone_propval = NULL;
	char *prop_str = NULL;
	char *zone_prop_str = NULL;
	char *grub_default_bootfs = NULL;
	zpool_handle_t *zphp = NULL;
	int err = 0;

	if (be_node == NULL || be_name == NULL || current_be == NULL ||
	    be_ds == NULL) {
		be_print_err(gettext("be_get_node_data: invalid arguments, "
		    "can not be NULL\n"));
		return (BE_ERR_INVAL);
	}

	errno = 0;

	be_node->be_root_ds = strdup(be_ds);
	if ((err = errno) != 0 || be_node->be_root_ds == NULL) {
		be_print_err(gettext("be_get_node_data: failed to "
		    "copy root dataset name\n"));
		return (errno_to_be_err(err));
	}

	be_node->be_node_name = strdup(be_name);
	if ((err = errno) != 0 || be_node->be_node_name == NULL) {
		be_print_err(gettext("be_get_node_data: failed to "
		    "copy BE name\n"));
		return (errno_to_be_err(err));
	}
	if (strncmp(be_name, current_be, MAXPATHLEN) == 0)
		be_node->be_active = B_TRUE;
	else
		be_node->be_active = B_FALSE;

	be_node->be_rpool = strdup(rpool);
	if (be_node->be_rpool == NULL || (err = errno) != 0) {
		be_print_err(gettext("be_get_node_data: failed to "
		    "copy root pool name\n"));
		return (errno_to_be_err(err));
	}

	be_node->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED);

	if (getzoneid() == GLOBAL_ZONEID) {
		if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
			be_print_err(gettext("be_get_node_data: failed to open "
			    "pool (%s): %s\n"), rpool,
			    libzfs_error_description(g_zfs));
			return (zfs_err_to_be_err(g_zfs));
		}

		(void) zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf,
		    ZFS_MAXPROPLEN, NULL, B_FALSE);
		if (be_has_grub() && (be_default_grub_bootfs(rpool,
		    &grub_default_bootfs) == BE_SUCCESS) &&
		    grub_default_bootfs != NULL)
			if (strcmp(grub_default_bootfs, be_ds) == 0)
				be_node->be_active_on_boot = B_TRUE;
			else
				be_node->be_active_on_boot = B_FALSE;
		else if (prop_buf != NULL && strcmp(prop_buf, be_ds) == 0)
			be_node->be_active_on_boot = B_TRUE;
		else
			be_node->be_active_on_boot = B_FALSE;

		be_node->be_global_active = B_TRUE;

		free(grub_default_bootfs);
		zpool_close(zphp);
	} else {
		if (be_zone_compare_uuids(be_node->be_root_ds))
			be_node->be_global_active = B_TRUE;
		else
			be_node->be_global_active = B_FALSE;
	}

	/*
	 * If the dataset is mounted use the mount point
	 * returned from the zfs_is_mounted call. If the
	 * dataset is not mounted then pull the mount
	 * point information out of the zfs properties.
	 */
	be_node->be_mounted = zfs_is_mounted(zhp,
	    &(be_node->be_mntpt));
	if (!be_node->be_mounted) {
		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
		    ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) == 0)
			be_node->be_mntpt = strdup(prop_buf);
		else
			return (zfs_err_to_be_err(g_zfs));
	}

	be_node->be_node_creation = (time_t)zfs_prop_get_int(zhp,
	    ZFS_PROP_CREATION);

	/* Get all user properties used for libbe */
	if ((userprops = zfs_get_user_props(zhp)) == NULL) {
		be_node->be_policy_type = strdup(be_default_policy());
	} else {
		if (getzoneid() != GLOBAL_ZONEID) {
			if (nvlist_lookup_nvlist(userprops,
			    BE_ZONE_ACTIVE_PROPERTY, &zone_propval) != 0 ||
			    zone_propval == NULL) {
				be_node->be_active_on_boot = B_FALSE;
			} else {
				verify(nvlist_lookup_string(zone_propval,
				    ZPROP_VALUE, &zone_prop_str) == 0);
				if (strcmp(zone_prop_str, "on") == 0) {
					be_node->be_active_on_boot = B_TRUE;
				} else {
					be_node->be_active_on_boot = B_FALSE;
				}
			}
		}

		if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
		    &propval) != 0 || propval == NULL) {
			be_node->be_policy_type =
			    strdup(be_default_policy());
		} else {
			verify(nvlist_lookup_string(propval, ZPROP_VALUE,
			    &prop_str) == 0);
			if (prop_str == NULL || strcmp(prop_str, "-") == 0 ||
			    strcmp(prop_str, "") == 0)
				be_node->be_policy_type =
				    strdup(be_default_policy());
			else
				be_node->be_policy_type = strdup(prop_str);
		}
		if (getzoneid() != GLOBAL_ZONEID) {
			if (nvlist_lookup_nvlist(userprops,
			    BE_ZONE_PARENTBE_PROPERTY, &propval) != 0 &&
			    nvlist_lookup_string(propval, ZPROP_VALUE,
			    &prop_str) == 0) {
				be_node->be_uuid_str = strdup(prop_str);
			}
		} else {
			if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY,
			    &propval) == 0 && nvlist_lookup_string(propval,
			    ZPROP_VALUE, &prop_str) == 0) {
				be_node->be_uuid_str = strdup(prop_str);
			}
		}
	}

	/*
	 * Increment the dataset counter to include the root dataset
	 * of the BE.
	 */
	be_node->be_node_num_datasets++;

	return (BE_SUCCESS);
}
Esempio n. 13
0
/*
 * Function:	be_promote_zone_ds
 * Description:	This function finds the zones for the BE being activated
 *              and the active zonepath dataset for each zone. Then each
 *              active zonepath dataset is promoted.
 *
 * Parameters:
 *              be_name - the name of the global zone BE that we need to
 *                       find the zones for.
 *              be_root_ds - the root dataset for be_name.
 * Return:
 *		BE_SUCCESS - Success
 *		be_errno_t - Failure
 *
 * Scope:
 *		Private
 */
static int
be_promote_zone_ds(char *be_name, char *be_root_ds)
{
	char		*zone_ds = NULL;
	char		*temp_mntpt = NULL;
	char		origin[MAXPATHLEN];
	char		zoneroot_ds[MAXPATHLEN];
	zfs_handle_t	*zhp = NULL;
	zfs_handle_t	*z_zhp = NULL;
	zoneList_t	zone_list = NULL;
	zoneBrandList_t *brands = NULL;
	boolean_t	be_mounted = B_FALSE;
	int		zone_index = 0;
	int		err = BE_SUCCESS;

	/*
	 * Get the supported zone brands so we can pass that
	 * to z_get_nonglobal_zone_list_by_brand. Currently
	 * only the ipkg and labeled brand zones are supported
	 *
	 */
	if ((brands = be_get_supported_brandlist()) == NULL) {
		be_print_err(gettext("be_promote_zone_ds: no supported "
		    "brands\n"));
		return (BE_SUCCESS);
	}

	if ((zhp = zfs_open(g_zfs, be_root_ds,
	    ZFS_TYPE_FILESYSTEM)) == NULL) {
		be_print_err(gettext("be_promote_zone_ds: Failed to open "
		    "dataset (%s): %s\n"), be_root_ds,
		    libzfs_error_description(g_zfs));
		err = zfs_err_to_be_err(g_zfs);
		z_free_brand_list(brands);
		return (err);
	}

	if (!zfs_is_mounted(zhp, &temp_mntpt)) {
		if ((err = _be_mount(be_name, &temp_mntpt,
		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
			be_print_err(gettext("be_promote_zone_ds: failed to "
			    "mount the BE for zones procesing.\n"));
			ZFS_CLOSE(zhp);
			z_free_brand_list(brands);
			return (err);
		}
		be_mounted = B_TRUE;
	}

	/*
	 * Set the zone root to the temp mount point for the BE we just mounted.
	 */
	z_set_zone_root(temp_mntpt);

	/*
	 * Get all the zones based on the brands we're looking for. If no zones
	 * are found that we're interested in unmount the BE and move on.
	 */
	if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
		if (be_mounted)
			(void) _be_unmount(be_name, 0);
		ZFS_CLOSE(zhp);
		z_free_brand_list(brands);
		free(temp_mntpt);
		return (BE_SUCCESS);
	}
	for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
	    != NULL; zone_index++) {
		char *zone_path = NULL;

		/* Skip zones that aren't at least installed */
		if (z_zlist_get_current_state(zone_list, zone_index) <
		    ZONE_STATE_INSTALLED)
			continue;

		if (((zone_path =
		    z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
		    ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
		    !be_zone_supported(zone_ds))
			continue;

		if (be_find_active_zone_root(zhp, zone_ds,
		    zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
			be_print_err(gettext("be_promote_zone_ds: "
			    "Zone does not have an active root "
			    "dataset, skipping this zone.\n"));
			continue;
		}

		if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
		    ZFS_TYPE_FILESYSTEM)) == NULL) {
			be_print_err(gettext("be_promote_zone_ds: "
			    "Failed to open dataset "
			    "(%s): %s\n"), zoneroot_ds,
			    libzfs_error_description(g_zfs));
			err = zfs_err_to_be_err(g_zfs);
			goto done;
		}

		if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
		    sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
			ZFS_CLOSE(z_zhp);
			continue;
		}

		/*
		 * We don't need to close the zfs handle at this
		 * point because the callback funtion
		 * be_promote_ds_callback() will close it for us.
		 */
		if (be_promote_ds_callback(z_zhp, NULL) != 0) {
			be_print_err(gettext("be_promote_zone_ds: "
			    "failed to activate the "
			    "datasets for %s: %s\n"),
			    zoneroot_ds,
			    libzfs_error_description(g_zfs));
			err = BE_ERR_PROMOTE;
			goto done;
		}
	}
done:
	if (be_mounted)
		(void) _be_unmount(be_name, 0);
	ZFS_CLOSE(zhp);
	free(temp_mntpt);
	z_free_brand_list(brands);
	z_free_zone_list(zone_list);
	return (err);
}
Esempio n. 14
0
/*
 * Function:	be_do_installgrub
 * Description:	This function runs installgrub using the grub loader files
 *              from the BE we're activating and installing them on the
 *              pool the BE lives in.
 *
 * Parameters:
 *              bt - The transaction data for the BE we're activating.
 * Return:
 *		BE_SUCCESS - Success
 *		be_errno_t - Failure
 *
 * Scope:
 *		Private
 */
static int
be_do_installgrub(be_transaction_data_t *bt)
{
	zpool_handle_t  *zphp = NULL;
	zfs_handle_t	*zhp = NULL;
	nvlist_t **child, *nv, *config;
	uint_t c, children = 0;
	char *tmp_mntpt = NULL;
	char *pool_mntpnt = NULL;
	char *ptmp_mntpnt = NULL;
	char *orig_mntpnt = NULL;
	FILE *cap_fp = NULL;
	FILE *zpool_cap_fp = NULL;
	char line[BUFSIZ];
	char cap_file[MAXPATHLEN];
	char zpool_cap_file[MAXPATHLEN];
	char stage1[MAXPATHLEN];
	char stage2[MAXPATHLEN];
	char installgrub_cmd[MAXPATHLEN];
	char *vname;
	char be_run_cmd_errbuf[BUFSIZ];
	int ret = BE_SUCCESS;
	int err = 0;
	boolean_t be_mounted = B_FALSE;
	boolean_t pool_mounted = B_FALSE;

	if (!be_has_grub()) {
		be_print_err(gettext("be_do_installgrub: Not supported "
		    "on this architecture\n"));
		return (BE_ERR_NOTSUP);
	}

	if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
	    NULL) {
		be_print_err(gettext("be_do_installgrub: failed to "
		    "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
		    libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		return (ret);
	}
	if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
		if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
			be_print_err(gettext("be_do_installgrub: failed to "
			    "mount BE (%s)\n"), bt->obe_name);
			ZFS_CLOSE(zhp);
			return (ret);
		}
		be_mounted = B_TRUE;
	}
	ZFS_CLOSE(zhp);

	(void) snprintf(stage1, sizeof (stage1), "%s%s", tmp_mntpt, BE_STAGE_1);
	(void) snprintf(stage2, sizeof (stage2), "%s%s", tmp_mntpt, BE_STAGE_2);

	if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
		be_print_err(gettext("be_do_installgrub: failed to open "
		    "pool (%s): %s\n"), bt->obe_zpool,
		    libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		if (be_mounted)
			(void) _be_unmount(bt->obe_name, 0);
		free(tmp_mntpt);
		return (ret);
	}

	if ((config = zpool_get_config(zphp, NULL)) == NULL) {
		be_print_err(gettext("be_do_installgrub: failed to get zpool "
		    "configuration information. %s\n"),
		    libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}

	/*
	 * Get the vdev tree
	 */
	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
		be_print_err(gettext("be_do_installgrub: failed to get vdev "
		    "tree: %s\n"), libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}

	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
	    &children) != 0) {
		be_print_err(gettext("be_do_installgrub: failed to traverse "
		    "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}
	for (c = 0; c < children; c++) {
		uint_t i, nchildren = 0;
		nvlist_t **nvchild;
		vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE);
		if (vname == NULL) {
			be_print_err(gettext(
			    "be_do_installgrub: "
			    "failed to get device name: %s\n"),
			    libzfs_error_description(g_zfs));
			ret = zfs_err_to_be_err(g_zfs);
			goto done;
		}
		if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {

			if (nvlist_lookup_nvlist_array(child[c],
			    ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) {
				be_print_err(gettext("be_do_installgrub: "
				    "failed to traverse the vdev tree: %s\n"),
				    libzfs_error_description(g_zfs));
				ret = zfs_err_to_be_err(g_zfs);
				goto done;
			}

			for (i = 0; i < nchildren; i++) {
				vname = zpool_vdev_name(g_zfs, zphp,
				    nvchild[i], B_FALSE);
				if (vname == NULL) {
					be_print_err(gettext(
					    "be_do_installgrub: "
					    "failed to get device name: %s\n"),
					    libzfs_error_description(g_zfs));
					ret = zfs_err_to_be_err(g_zfs);
					goto done;
				}

				(void) snprintf(installgrub_cmd,
				    sizeof (installgrub_cmd),
				    "%s %s %s /dev/rdsk/%s",
				    BE_INSTALL_GRUB, stage1, stage2, vname);
				if (be_run_cmd(installgrub_cmd,
				    be_run_cmd_errbuf, BUFSIZ, NULL, 0) !=
				    BE_SUCCESS) {
					be_print_err(gettext(
					    "be_do_installgrub: installgrub "
					    "failed for device %s.\n"), vname);
					/* Assume localized cmd err output. */
					be_print_err(gettext(
					    "  Command: \"%s\"\n"),
					    installgrub_cmd);
					be_print_err("%s", be_run_cmd_errbuf);
					free(vname);
					ret = BE_ERR_BOOTFILE_INST;
					goto done;
				}
				free(vname);
			}
		} else {
			(void) snprintf(installgrub_cmd,
			    sizeof (installgrub_cmd), "%s %s %s /dev/rdsk/%s",
			    BE_INSTALL_GRUB, stage1, stage2, vname);
			if (be_run_cmd(installgrub_cmd, be_run_cmd_errbuf,
			    BUFSIZ, NULL, 0) != BE_SUCCESS) {
				be_print_err(gettext(
				    "be_do_installgrub: installgrub "
				    "failed for device %s.\n"), vname);
				/* Assume localized cmd err output. */
				be_print_err(gettext("  Command: \"%s\"\n"),
				    installgrub_cmd);
				be_print_err("%s", be_run_cmd_errbuf);
				free(vname);
				ret = BE_ERR_BOOTFILE_INST;
				goto done;
			}
			free(vname);
		}
	}

	/*
	 * Copy the grub capability file from the BE we're activating into
	 * the root pool.
	 */
	(void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpt,
	    BE_CAP_FILE);

	if ((zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
	    NULL) {
		be_print_err(gettext("be_do_installgrub: zfs_open "
		    "failed: %s\n"), libzfs_error_description(g_zfs));
		zpool_close(zphp);
		return (zfs_err_to_be_err(g_zfs));
	}

	/*
	 * Check to see if the pool's dataset is mounted. If it isn't we'll
	 * attempt to mount it.
	 */
	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt,
	    &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
		be_print_err(gettext("be_do_installgrub: pool dataset "
		    "(%s) could not be mounted\n"), bt->obe_zpool);
		ZFS_CLOSE(zhp);
		zpool_close(zphp);
		return (ret);
	}

	/*
	 * Get the mountpoint for the root pool dataset.
	 */
	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
		be_print_err(gettext("be_do_installgrub: pool "
		    "dataset (%s) is not mounted. Can't check the grub "
		    "version from the grub capability file.\n"), bt->obe_zpool);
		ret = BE_ERR_NO_MENU;
		goto done;
	}

	(void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
	    pool_mntpnt, BE_CAP_FILE);

	free(pool_mntpnt);
	pool_mntpnt = NULL;

	if ((cap_fp = fopen(cap_file, "r")) == NULL) {
		err = errno;
		be_print_err(gettext("be_do_installgrub: failed to open grub "
		    "capability file\n"));
		ret = errno_to_be_err(err);
		goto done;
	}
	if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
		err = errno;
		be_print_err(gettext("be_do_installgrub: failed to open new "
		    "grub capability file\n"));
		ret = errno_to_be_err(err);
		(void) fclose(cap_fp);
		goto done;
	}

	while (fgets(line, BUFSIZ, cap_fp)) {
		(void) fputs(line, zpool_cap_fp);
	}

	(void) fclose(zpool_cap_fp);
	(void) fclose(cap_fp);

done:
	if (pool_mounted) {
		int iret = 0;
		iret = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
		if (ret == BE_SUCCESS)
			ret = iret;
		free(orig_mntpnt);
		free(ptmp_mntpnt);
	}
	ZFS_CLOSE(zhp);
	if (be_mounted)
		(void) _be_unmount(bt->obe_name, 0);
	zpool_close(zphp);
	free(tmp_mntpt);
	return (ret);
}
Esempio n. 15
0
/*
 * Function:	be_get_grub_vers
 * Description:	Gets the grub version number from /boot/grub/capability. If
 *              capability file doesn't exist NULL is returned.
 * Parameters:
 *              bt - The transaction data for the BE we're getting the grub
 *                   version for.
 *              cur_vers - used to return the current version of grub from
 *                         the root pool.
 *              new_vers - used to return the grub version of the BE we're
 *                         activating.
 * Return:
 *              BE_SUCCESS - Success
 *              be_errno_t - Failed to find version
 * Scope:
 *		Private
 */
static int
be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
{
	zfs_handle_t	*zhp = NULL;
	zfs_handle_t	*pool_zhp = NULL;
	int ret = BE_SUCCESS;
	char cap_file[MAXPATHLEN];
	char *temp_mntpnt = NULL;
	char *zpool_mntpt = NULL;
	char *ptmp_mntpnt = NULL;
	char *orig_mntpnt = NULL;
	boolean_t be_mounted = B_FALSE;
	boolean_t pool_mounted = B_FALSE;

	if (!be_has_grub()) {
		be_print_err(gettext("be_get_grub_vers: Not supported on "
		    "this architecture\n"));
		return (BE_ERR_NOTSUP);
	}

	if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
	    bt->obe_root_ds == NULL) {
		be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
		return (BE_ERR_INVAL);
	}

	if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
	    NULL) {
		be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
		    libzfs_error_description(g_zfs));
		return (zfs_err_to_be_err(g_zfs));
	}

	/*
	 * Check to see if the pool's dataset is mounted. If it isn't we'll
	 * attempt to mount it.
	 */
	if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
	    &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
		be_print_err(gettext("be_get_grub_vers: pool dataset "
		    "(%s) could not be mounted\n"), bt->obe_zpool);
		ZFS_CLOSE(pool_zhp);
		return (ret);
	}

	/*
	 * Get the mountpoint for the root pool dataset.
	 */
	if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
		be_print_err(gettext("be_get_grub_vers: pool "
		    "dataset (%s) is not mounted. Can't set the "
		    "default BE in the grub menu.\n"), bt->obe_zpool);
		ret = BE_ERR_NO_MENU;
		goto cleanup;
	}

	/*
	 * get the version of the most recent grub update.
	 */
	(void) snprintf(cap_file, sizeof (cap_file), "%s%s",
	    zpool_mntpt, BE_CAP_FILE);
	free(zpool_mntpt);
	zpool_mntpt = NULL;

	if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
		goto cleanup;

	if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
	    NULL) {
		be_print_err(gettext("be_get_grub_vers: failed to "
		    "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
		    libzfs_error_description(g_zfs));
		free(cur_vers);
		ret = zfs_err_to_be_err(g_zfs);
		goto cleanup;
	}
	if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
		if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
			be_print_err(gettext("be_get_grub_vers: failed to "
			    "mount BE (%s)\n"), bt->obe_name);
			free(*cur_vers);
			*cur_vers = NULL;
			ZFS_CLOSE(zhp);
			goto cleanup;
		}
		be_mounted = B_TRUE;
	}
	ZFS_CLOSE(zhp);

	/*
	 * Now get the grub version for the BE being activated.
	 */
	(void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
	    BE_CAP_FILE);
	ret = get_ver_from_capfile(cap_file, new_vers);
	if (ret != BE_SUCCESS) {
		free(*cur_vers);
		*cur_vers = NULL;
	}
	if (be_mounted)
		(void) _be_unmount(bt->obe_name, 0);

cleanup:
	if (pool_mounted) {
		int iret = BE_SUCCESS;
		iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
		if (ret == BE_SUCCESS)
			ret = iret;
		free(orig_mntpnt);
		free(ptmp_mntpnt);
	}
	ZFS_CLOSE(pool_zhp);

	free(temp_mntpnt);
	return (ret);
}
Esempio n. 16
0
int
sa_get_zfs_shares(sa_handle_t handle, char *groupname)
{
	sa_group_t zfsgroup;
	boolean_t nfs;
	boolean_t nfs_inherited;
	boolean_t smb;
	boolean_t smb_inherited;
	zfs_handle_t **zlist;
	char nfsshareopts[ZFS_MAXPROPLEN];
	char smbshareopts[ZFS_MAXPROPLEN];
	sa_share_t share;
	zprop_source_t source;
	char nfssourcestr[ZFS_MAXPROPLEN];
	char smbsourcestr[ZFS_MAXPROPLEN];
	char mountpoint[ZFS_MAXPROPLEN];
	size_t count = 0, i;
	libzfs_handle_t *zfs_libhandle;
	int err = SA_OK;

	/*
	 * If we can't access libzfs, don't bother doing anything.
	 */
	zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle;
	if (zfs_libhandle == NULL)
		return (SA_SYSTEM_ERR);

	zfsgroup = find_or_create_group(handle, groupname, NULL, &err);
	/* Not an error, this could be a legacy condition */
	if (zfsgroup == NULL)
		return (SA_OK);

	/*
	 * need to walk the mounted ZFS pools and datasets to
	 * find shares that are possible.
	 */
	get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count);
	qsort(zlist, count, sizeof (void *), mountpoint_compare);

	for (i = 0; i < count; i++) {
		char *dataset;

		source = ZPROP_SRC_ALL;
		/* If no mountpoint, skip. */
		if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT,
		    mountpoint, sizeof (mountpoint), NULL, NULL, 0,
		    B_FALSE) != 0)
			continue;

		/*
		 * zfs_get_name value must not be freed. It is just a
		 * pointer to a value in the handle.
		 */
		if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL)
			continue;

		/*
		 * only deal with "mounted" file systems since
		 * unmounted file systems can't actually be shared.
		 */

		if (!zfs_is_mounted(zlist[i], NULL))
			continue;

		nfs = nfs_inherited = B_FALSE;

		if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts,
		    sizeof (nfsshareopts), &source, nfssourcestr,
		    ZFS_MAXPROPLEN, B_FALSE) == 0 &&
		    strcmp(nfsshareopts, "off") != 0) {
			if (source & ZPROP_SRC_INHERITED)
				nfs_inherited = B_TRUE;
			else
				nfs = B_TRUE;
		}

		smb = smb_inherited = B_FALSE;
		if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts,
		    sizeof (smbshareopts), &source, smbsourcestr,
		    ZFS_MAXPROPLEN, B_FALSE) == 0 &&
		    strcmp(smbshareopts, "off") != 0) {
			if (source & ZPROP_SRC_INHERITED)
				smb_inherited = B_TRUE;
			else
				smb = B_TRUE;
		}

		/*
		 * If the mountpoint is already shared, it must be a
		 * non-ZFS share. We want to remove the share from its
		 * parent group and reshare it under ZFS.
		 */
		share = sa_find_share(handle, mountpoint);
		if (share != NULL &&
		    (nfs || smb || nfs_inherited || smb_inherited)) {
			err = sa_remove_share(share);
			share = NULL;
		}

		/*
		 * At this point, we have the information needed to
		 * determine what to do with the share.
		 *
		 * If smb or nfs is set, we have a new sub-group.
		 * If smb_inherit and/or nfs_inherit is set, then
		 * place on an existing sub-group. If both are set,
		 * the existing sub-group is the closest up the tree.
		 */
		if (nfs || smb) {
			/*
			 * Non-inherited is the straightforward
			 * case. sa_zfs_process_share handles it
			 * directly. Make sure that if the "other"
			 * protocol is inherited, that we treat it as
			 * non-inherited as well.
			 */
			if (nfs || nfs_inherited) {
				err = sa_zfs_process_share(handle, zfsgroup,
				    share, mountpoint, "nfs",
				    0, nfsshareopts,
				    nfssourcestr, dataset);
				share = sa_find_share(handle, mountpoint);
			}
			if (smb || smb_inherited) {
				err = sa_zfs_process_share(handle, zfsgroup,
				    share, mountpoint, "smb",
				    0, smbshareopts,
				    smbsourcestr, dataset);
			}
		} else if (nfs_inherited || smb_inherited) {
			char *grpdataset;
			/*
			 * If we only have inherited groups, it is
			 * important to find the closer of the two if
			 * the protocols are set at different
			 * levels. The closest sub-group is the one we
			 * want to work with.
			 */
			if (nfs_inherited && smb_inherited) {
				if (strcmp(nfssourcestr, smbsourcestr) <= 0)
					grpdataset = nfssourcestr;
				else
					grpdataset = smbsourcestr;
			} else if (nfs_inherited) {
				grpdataset = nfssourcestr;
			} else if (smb_inherited) {
				grpdataset = smbsourcestr;
			}
			if (nfs_inherited) {
				err = sa_zfs_process_share(handle, zfsgroup,
				    share, mountpoint, "nfs",
				    ZPROP_SRC_INHERITED, nfsshareopts,
				    grpdataset, dataset);
				share = sa_find_share(handle, mountpoint);
			}
			if (smb_inherited) {
				err = sa_zfs_process_share(handle, zfsgroup,
				    share, mountpoint, "smb",
				    ZPROP_SRC_INHERITED, smbshareopts,
				    grpdataset, dataset);
			}
		}
	}
	/*
	 * Don't need to free the "zlist" variable since it is only a
	 * pointer to a cached value that will be freed when
	 * sa_fini() is called.
	 */
	return (err);
}
Esempio n. 17
0
/*
 * Function:	be_get_ds_data
 * Description:	Helper function used by be_add_children_callback to collect
 *		the dataset related information that will be returned by
 *		be_list.
 * Parameters:
 *		zhp - Handle to the zfs dataset whose information we're
 *		      collecting.
 *		name - The name of the dataset we're processing.
 *		dataset - A pointer to the be_dataset_list structure
 *			  we're filling in.
 *		node - The node structure that this dataset belongs to.
 * Return:
 *		BE_SUCCESS - Success
 *		be_errno_t - Failure
 * Scope:
 *		Private
 */
static int
be_get_ds_data(
	zfs_handle_t *zfshp,
	char *name,
	be_dataset_list_t *dataset,
	be_node_list_t *node)
{
	char			prop_buf[ZFS_MAXPROPLEN];
	nvlist_t		*propval = NULL;
	nvlist_t		*userprops = NULL;
	char			*prop_str = NULL;
	int			err = 0;

	if (zfshp == NULL || name == NULL || dataset == NULL || node == NULL) {
		be_print_err(gettext("be_get_ds_data: invalid arguments, "
		    "can not be NULL\n"));
		return (BE_ERR_INVAL);
	}

	errno = 0;

	dataset->be_dataset_name = strdup(name);
	if ((err = errno) != 0) {
		be_print_err(gettext("be_get_ds_data: failed to copy "
		    "dataset name\n"));
		return (errno_to_be_err(err));
	}

	dataset->be_ds_space_used = zfs_prop_get_int(zfshp, ZFS_PROP_USED);

	/*
	 * If the dataset is mounted use the mount point
	 * returned from the zfs_is_mounted call. If the
	 * dataset is not mounted then pull the mount
	 * point information out of the zfs properties.
	 */
	if (!(dataset->be_ds_mounted = zfs_is_mounted(zfshp,
	    &(dataset->be_ds_mntpt)))) {
		if (zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
		    prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
		    B_FALSE) == 0)
			dataset->be_ds_mntpt = strdup(prop_buf);
		else
			return (zfs_err_to_be_err(g_zfs));
	}
	dataset->be_ds_creation =
	    (time_t)zfs_prop_get_int(zfshp, ZFS_PROP_CREATION);

	/*
	 * Get the user property used for the libbe
	 * cleaup policy
	 */
	if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
		dataset->be_ds_plcy_type =
		    strdup(node->be_policy_type);
	} else {
		if (nvlist_lookup_nvlist(userprops,
		    BE_POLICY_PROPERTY, &propval) != 0 ||
		    propval == NULL) {
			dataset->be_ds_plcy_type =
			    strdup(node->be_policy_type);
		} else {
			verify(nvlist_lookup_string(propval,
			    ZPROP_VALUE, &prop_str) == 0);
			if (prop_str == NULL ||
			    strcmp(prop_str, "-") == 0 ||
			    strcmp(prop_str, "") == 0)
				dataset->be_ds_plcy_type
				    = strdup(node->be_policy_type);
			else
				dataset->be_ds_plcy_type = strdup(prop_str);
		}
	}

	node->be_node_num_datasets++;
	return (BE_SUCCESS);
}
Esempio n. 18
0
/*
 * Mount the given filesystem.
 */
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;
#ifdef __APPLE__
	struct zfs_mount_args mnt_args = {0};
	char  devpath[MAXPATHLEN];
#endif

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

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

#ifdef __APPLE__
	/*
	 * Check for optional paths
	 */
	if (hasoptionalpath(mntopts, "mountdev=", devpath, sizeof (devpath)))
		mnt_args.mountdev = devpath;

	if (hasoptionalpath(mntopts, "mountpoint=", mountpoint,
	    sizeof (mountpoint)))
		goto callmount;
#endif

	/* Create the directory if it doesn't already exist */
	if (lstat(mountpoint, &buf) != 0) {
		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));
		}
	}

#ifndef __APPLE__
	/*
	 * Determine if the mountpoint is empty.  If so, refuse to perform the
	 * mount.  We don't perform this check if MS_OVERLAY is specified, which
	 * would defeat the point.  We also avoid this check if 'remount' is
	 * specified.
	 */
	if ((flags & MS_OVERLAY) == 0 &&
	    strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
	    !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));
	}
#endif /*!__APPLE__*/

	/* perform the mount */
#ifdef __APPLE__
callmount:
	mnt_args.dataset = zfs_get_name(zhp);
	mnt_args.flags = 0;

	if (mount(MNTTYPE_ZFS, mountpoint, flags, &mnt_args) != 0) {
#else
	if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
#endif

#ifdef __APPLE__
		/*
		 * If this was a top-level filesystem, then IOKit
		 * probing may have already mounted it, causing
		 * our call to mount() to fail.
		 */
		if (zfs_is_mounted(zhp, NULL)) {
			goto success;
		}
#endif       
		/*
		 * 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 {
			zfs_error_aux(hdl, strerror(errno));
		}

		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
		    zhp->zfs_name));
	}
#ifdef __APPLE__
success:
	/*
	 * Remove any legacy custom volume icons.
	 */
	{
		char  path[MAXPATHLEN];
		struct stat sbuf;

		snprintf(path, MAXPATHLEN, "%s/%s", mountpoint, MOUNT_POINT_CUSTOM_ICON);
		if (stat(path, &sbuf) == 0 &&
		    sbuf.st_size == 35014 &&
		    sbuf.st_uid == 0) {
			/* Clear "has custom icon" flag */
			(void) removexattr(mountpoint, XATTR_FINDERINFO_NAME, 0);

			/* Clear custom icon file */
			(void) unlink(path);
		}

	}
#endif
	return (0);
}

#ifdef __APPLE__

/*
 * When unmounting, we first talk to diskarb and attempt to unmount via that
 * route. This allows diskarb to tell fsevents, mds, etc. to stop using the
 * filesystem.
 *
 * This code was borrowed from umount(8).
 */

#include <CoreFoundation/CoreFoundation.h>
#include <TargetConditionals.h>

#if !TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE
#include <DiskArbitration/DiskArbitrationPrivate.h>

static void __diskarb_unmount( DADiskRef disk, DADissenterRef dissenter, void * context )
{
    *( ( int * ) context ) = dissenter ? DADissenterGetStatus( dissenter ) : 0;

    CFRunLoopStop( CFRunLoopGetCurrent( ) );
}