xref: /freebsd/lib/libbe/be_access.c (revision 190cef3d)
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];
68 	zfs_handle_t *root_hdl;
69 	struct be_mountcheck_info info;
70 	prop_data_t propinfo;
71 
72 	bzero(&be, BE_MAXPATHLEN);
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 ((err = be_exists(lbh, bootenv)) != 0)
118 		return (set_error(lbh, err));
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 		strlcpy(mnt_temp, "/tmp/be_mount.XXXX", sizeof(mnt_temp));
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 		strlcpy(result_loc, mountpoint == NULL ? mnt_temp : mountpoint,
153 		    BE_MAXPATHLEN);
154 
155 	return (BE_ERR_SUCCESS);
156 }
157 
158 
159 /*
160  * usage
161  */
162 int
163 be_unmount(libbe_handle_t *lbh, char *bootenv, int flags)
164 {
165 	int err, mntflags;
166 	char be[BE_MAXPATHLEN];
167 	struct statfs *mntbuf;
168 	int mntsize;
169 	char *mntpath;
170 
171 	if ((err = be_root_concat(lbh, bootenv, be)) != 0)
172 		return (set_error(lbh, err));
173 
174 	if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
175 		if (errno == EIO)
176 			return (set_error(lbh, BE_ERR_IO));
177 		return (set_error(lbh, BE_ERR_NOMOUNT));
178 	}
179 
180 	mntpath = NULL;
181 	for (int i = 0; i < mntsize; ++i) {
182 		/* 0x000000de is the type number of zfs */
183 		if (mntbuf[i].f_type != 0x000000de)
184 			continue;
185 
186 		if (strcmp(mntbuf[i].f_mntfromname, be) == 0) {
187 			mntpath = mntbuf[i].f_mntonname;
188 			break;
189 		}
190 	}
191 
192 	if (mntpath == NULL)
193 		return (set_error(lbh, BE_ERR_NOMOUNT));
194 
195 	mntflags = (flags & BE_MNT_FORCE) ? MNT_FORCE : 0;
196 
197 	if ((err = unmount(mntpath, mntflags)) != 0) {
198 		switch (errno) {
199 		case ENAMETOOLONG:
200 			return (set_error(lbh, BE_ERR_PATHLEN));
201 		case ELOOP:
202 		case ENOENT:
203 		case ENOTDIR:
204 			return (set_error(lbh, BE_ERR_BADPATH));
205 		case EPERM:
206 			return (set_error(lbh, BE_ERR_PERMS));
207 		case EBUSY:
208 			return (set_error(lbh, BE_ERR_PATHBUSY));
209 		default:
210 			return (set_error(lbh, BE_ERR_UNKNOWN));
211 		}
212 	}
213 
214 	return (set_error(lbh, BE_ERR_SUCCESS));
215 }
216