xref: /freebsd/lib/libbe/be_access.c (revision 78b9f0095b4af3aca6c931b2c7b009ddb8a05125)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in>
5  * Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include "be.h"
34 #include "be_impl.h"
35 
36 struct be_mountcheck_info {
37 	const char *path;
38 	char *name;
39 };
40 
41 static int
42 be_mountcheck_cb(zfs_handle_t *zfs_hdl, void *data)
43 {
44 	struct be_mountcheck_info *info;
45 	char *mountpoint;
46 
47 	if (data == NULL)
48 		return (1);
49 	info = (struct be_mountcheck_info *)data;
50 	if (!zfs_is_mounted(zfs_hdl, &mountpoint))
51 		return (0);
52 	if (strcmp(mountpoint, info->path) == 0) {
53 		info->name = strdup(zfs_get_name(zfs_hdl));
54 		free(mountpoint);
55 		return (1);
56 	}
57 	free(mountpoint);
58 	return (0);
59 }
60 
61 /*
62  * usage
63  */
64 int
65 be_mounted_at(libbe_handle_t *lbh, const char *path, nvlist_t *details)
66 {
67 	char be[BE_MAXPATHLEN + 1];
68 	zfs_handle_t *root_hdl;
69 	struct be_mountcheck_info info;
70 	prop_data_t propinfo;
71 
72 	bzero(&be, BE_MAXPATHLEN + 1);
73 	if ((root_hdl = zfs_open(lbh->lzh, lbh->root,
74 	    ZFS_TYPE_FILESYSTEM)) == NULL)
75 		return (BE_ERR_ZFSOPEN);
76 
77 	info.path = path;
78 	info.name = NULL;
79 	zfs_iter_filesystems(root_hdl, be_mountcheck_cb, &info);
80 	zfs_close(root_hdl);
81 
82 	if (info.name != NULL) {
83 		if (details != NULL) {
84 			if ((root_hdl = zfs_open(lbh->lzh, lbh->root,
85 			    ZFS_TYPE_FILESYSTEM)) == NULL) {
86 				free(info.name);
87 				return (BE_ERR_ZFSOPEN);
88 			}
89 
90 			propinfo.lbh = lbh;
91 			propinfo.list = details;
92 			propinfo.single_object = false;
93 			prop_list_builder_cb(root_hdl, &propinfo);
94 			zfs_close(root_hdl);
95 		}
96 		free(info.name);
97 		return (0);
98 	}
99 	return (1);
100 }
101 
102 /*
103  * usage
104  */
105 int
106 be_mount(libbe_handle_t *lbh, char *bootenv, char *mountpoint, int flags,
107     char *result_loc)
108 {
109 	char be[BE_MAXPATHLEN];
110 	char mnt_temp[BE_MAXPATHLEN];
111 	int mntflags;
112 	int err;
113 
114 	if ((err = be_root_concat(lbh, bootenv, be)) != 0)
115 		return (set_error(lbh, err));
116 
117 	if (!be_exists(lbh, bootenv))
118 		return (set_error(lbh, BE_ERR_NOENT));
119 
120 	if (is_mounted(lbh->lzh, be, NULL))
121 		return (set_error(lbh, BE_ERR_MOUNTED));
122 
123 	mntflags = (flags & BE_MNT_FORCE) ? MNT_FORCE : 0;
124 
125 	/* Create mountpoint if it is not specified */
126 	if (mountpoint == NULL) {
127 		strcpy(mnt_temp, "/tmp/be_mount.XXXX");
128 		if (mkdtemp(mnt_temp) == NULL)
129 			return (set_error(lbh, BE_ERR_IO));
130 	}
131 
132 	char opt = '\0';
133 	if ((err = zmount(be, (mountpoint == NULL) ? mnt_temp : mountpoint,
134 	    mntflags, __DECONST(char *, MNTTYPE_ZFS), NULL, 0, &opt, 1)) != 0) {
135 		switch (errno) {
136 		case ENAMETOOLONG:
137 			return (set_error(lbh, BE_ERR_PATHLEN));
138 		case ELOOP:
139 		case ENOENT:
140 		case ENOTDIR:
141 			return (set_error(lbh, BE_ERR_BADPATH));
142 		case EPERM:
143 			return (set_error(lbh, BE_ERR_PERMS));
144 		case EBUSY:
145 			return (set_error(lbh, BE_ERR_PATHBUSY));
146 		default:
147 			return (set_error(lbh, BE_ERR_UNKNOWN));
148 		}
149 	}
150 
151 	if (result_loc != NULL)
152 		strcpy(result_loc, mountpoint == NULL ? mnt_temp : mountpoint);
153 
154 	return (BE_ERR_SUCCESS);
155 }
156 
157 
158 /*
159  * usage
160  */
161 int
162 be_unmount(libbe_handle_t *lbh, char *bootenv, int flags)
163 {
164 	int err, mntflags;
165 	char be[BE_MAXPATHLEN];
166 	struct statfs *mntbuf;
167 	int mntsize;
168 	char *mntpath;
169 
170 	if ((err = be_root_concat(lbh, bootenv, be)) != 0)
171 		return (set_error(lbh, err));
172 
173 	if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
174 		if (errno == EIO)
175 			return (set_error(lbh, BE_ERR_IO));
176 		return (set_error(lbh, BE_ERR_NOMOUNT));
177 	}
178 
179 	mntpath = NULL;
180 	for (int i = 0; i < mntsize; ++i) {
181 		/* 0x000000de is the type number of zfs */
182 		if (mntbuf[i].f_type != 0x000000de)
183 			continue;
184 
185 		if (strcmp(mntbuf[i].f_mntfromname, be) == 0) {
186 			mntpath = mntbuf[i].f_mntonname;
187 			break;
188 		}
189 	}
190 
191 	if (mntpath == NULL)
192 		return (set_error(lbh, BE_ERR_NOMOUNT));
193 
194 	mntflags = (flags & BE_MNT_FORCE) ? MNT_FORCE : 0;
195 
196 	if ((err = unmount(mntpath, mntflags)) != 0) {
197 		switch (errno) {
198 		case ENAMETOOLONG:
199 			return (set_error(lbh, BE_ERR_PATHLEN));
200 		case ELOOP:
201 		case ENOENT:
202 		case ENOTDIR:
203 			return (set_error(lbh, BE_ERR_BADPATH));
204 		case EPERM:
205 			return (set_error(lbh, BE_ERR_PERMS));
206 		case EBUSY:
207 			return (set_error(lbh, BE_ERR_PATHBUSY));
208 		default:
209 			return (set_error(lbh, BE_ERR_UNKNOWN));
210 		}
211 	}
212 
213 	return (set_error(lbh, BE_ERR_SUCCESS));
214 }
215