xref: /aosp_15_r20/external/libfuse/lib/mount_util.c (revision 9e5649576b786774a32d7b0252c9cd8c6538fa49)
1 /*
2   FUSE: Filesystem in Userspace
3   Copyright (C) 2001-2007  Miklos Szeredi <[email protected]>
4 
5   Architecture-independent mounting code.
6 
7   This program can be distributed under the terms of the GNU LGPLv2.
8   See the file COPYING.LIB.
9 */
10 
11 #include "fuse_config.h"
12 #include "mount_util.h"
13 
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <signal.h>
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <limits.h>
23 #include <paths.h>
24 #if !defined( __NetBSD__) && !defined(__FreeBSD__) && !defined(__DragonFly__) && !defined(__ANDROID__)
25 #include <mntent.h>
26 #else
27 #define IGNORE_MTAB
28 #endif
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31 
32 #include "fuse_mount_compat.h"
33 
34 #include <sys/param.h>
35 
36 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
37 #define umount2(mnt, flags) unmount(mnt, ((flags) == 2) ? MNT_FORCE : 0)
38 #endif
39 
40 #ifdef IGNORE_MTAB
41 #define mtab_needs_update(mnt) 0
42 #else
mtab_needs_update(const char * mnt)43 static int mtab_needs_update(const char *mnt)
44 {
45 	int res;
46 	struct stat stbuf;
47 
48 	/* If mtab is within new mount, don't touch it */
49 	if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
50 	    _PATH_MOUNTED[strlen(mnt)] == '/')
51 		return 0;
52 
53 	/*
54 	 * Skip mtab update if /etc/mtab:
55 	 *
56 	 *  - doesn't exist,
57 	 *  - is on a read-only filesystem.
58 	 */
59 	res = lstat(_PATH_MOUNTED, &stbuf);
60 	if (res == -1) {
61 		if (errno == ENOENT)
62 			return 0;
63 	} else {
64 		uid_t ruid;
65 		int err;
66 
67 		ruid = getuid();
68 		if (ruid != 0)
69 			setreuid(0, -1);
70 
71 		res = access(_PATH_MOUNTED, W_OK);
72 		err = (res == -1) ? errno : 0;
73 		if (ruid != 0)
74 			setreuid(ruid, -1);
75 
76 		if (err == EROFS)
77 			return 0;
78 	}
79 
80 	return 1;
81 }
82 #endif /* IGNORE_MTAB */
83 
add_mount(const char * progname,const char * fsname,const char * mnt,const char * type,const char * opts)84 static int add_mount(const char *progname, const char *fsname,
85 		       const char *mnt, const char *type, const char *opts)
86 {
87 	int res;
88 	int status;
89 	sigset_t blockmask;
90 	sigset_t oldmask;
91 
92 	sigemptyset(&blockmask);
93 	sigaddset(&blockmask, SIGCHLD);
94 	res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
95 	if (res == -1) {
96 		fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
97 		return -1;
98 	}
99 
100 	res = fork();
101 	if (res == -1) {
102 		fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
103 		goto out_restore;
104 	}
105 	if (res == 0) {
106 		char *env = NULL;
107 
108 		sigprocmask(SIG_SETMASK, &oldmask, NULL);
109 
110 		if(setuid(geteuid()) == -1) {
111 			fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
112 			res = -1;
113 			goto out_restore;
114 		}
115 
116 		execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
117 		       "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
118 		fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
119 			progname, strerror(errno));
120 		exit(1);
121 	}
122 	res = waitpid(res, &status, 0);
123 	if (res == -1)
124 		fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
125 
126 	if (status != 0)
127 		res = -1;
128 
129  out_restore:
130 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
131 
132 	return res;
133 }
134 
fuse_mnt_add_mount(const char * progname,const char * fsname,const char * mnt,const char * type,const char * opts)135 int fuse_mnt_add_mount(const char *progname, const char *fsname,
136 		       const char *mnt, const char *type, const char *opts)
137 {
138 	if (!mtab_needs_update(mnt))
139 		return 0;
140 
141 	return add_mount(progname, fsname, mnt, type, opts);
142 }
143 
exec_umount(const char * progname,const char * rel_mnt,int lazy)144 static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
145 {
146 	int res;
147 	int status;
148 	sigset_t blockmask;
149 	sigset_t oldmask;
150 
151 	sigemptyset(&blockmask);
152 	sigaddset(&blockmask, SIGCHLD);
153 	res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
154 	if (res == -1) {
155 		fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
156 		return -1;
157 	}
158 
159 	res = fork();
160 	if (res == -1) {
161 		fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
162 		goto out_restore;
163 	}
164 	if (res == 0) {
165 		char *env = NULL;
166 
167 		sigprocmask(SIG_SETMASK, &oldmask, NULL);
168 
169 		if(setuid(geteuid()) == -1) {
170 			fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
171 			res = -1;
172 			goto out_restore;
173 		}
174 
175 		if (lazy) {
176 			execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
177 			       "-l", NULL, &env);
178 		} else {
179 			execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
180 			       NULL, &env);
181 		}
182 		fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
183 			progname, strerror(errno));
184 		exit(1);
185 	}
186 	res = waitpid(res, &status, 0);
187 	if (res == -1)
188 		fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
189 
190 	if (status != 0) {
191 		res = -1;
192 	}
193 
194  out_restore:
195 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
196 	return res;
197 
198 }
199 
fuse_mnt_umount(const char * progname,const char * abs_mnt,const char * rel_mnt,int lazy)200 int fuse_mnt_umount(const char *progname, const char *abs_mnt,
201 		    const char *rel_mnt, int lazy)
202 {
203 	int res;
204 
205 	if (!mtab_needs_update(abs_mnt)) {
206 		res = umount2(rel_mnt, lazy ? 2 : 0);
207 		if (res == -1)
208 			fprintf(stderr, "%s: failed to unmount %s: %s\n",
209 				progname, abs_mnt, strerror(errno));
210 		return res;
211 	}
212 
213 	return exec_umount(progname, rel_mnt, lazy);
214 }
215 
remove_mount(const char * progname,const char * mnt)216 static int remove_mount(const char *progname, const char *mnt)
217 {
218 	int res;
219 	int status;
220 	sigset_t blockmask;
221 	sigset_t oldmask;
222 
223 	sigemptyset(&blockmask);
224 	sigaddset(&blockmask, SIGCHLD);
225 	res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
226 	if (res == -1) {
227 		fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
228 		return -1;
229 	}
230 
231 	res = fork();
232 	if (res == -1) {
233 		fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
234 		goto out_restore;
235 	}
236 	if (res == 0) {
237 		char *env = NULL;
238 
239 		sigprocmask(SIG_SETMASK, &oldmask, NULL);
240 
241 		if(setuid(geteuid()) == -1) {
242 			fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
243 			res = -1;
244 			goto out_restore;
245 		}
246 
247 		execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
248 		       "--fake", mnt, NULL, &env);
249 		fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
250 			progname, strerror(errno));
251 		exit(1);
252 	}
253 	res = waitpid(res, &status, 0);
254 	if (res == -1)
255 		fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
256 
257 	if (status != 0)
258 		res = -1;
259 
260  out_restore:
261 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
262 	return res;
263 }
264 
fuse_mnt_remove_mount(const char * progname,const char * mnt)265 int fuse_mnt_remove_mount(const char *progname, const char *mnt)
266 {
267 	if (!mtab_needs_update(mnt))
268 		return 0;
269 
270 	return remove_mount(progname, mnt);
271 }
272 
fuse_mnt_resolve_path(const char * progname,const char * orig)273 char *fuse_mnt_resolve_path(const char *progname, const char *orig)
274 {
275 	char buf[PATH_MAX];
276 	char *copy;
277 	char *dst;
278 	char *end;
279 	char *lastcomp;
280 	const char *toresolv;
281 
282 	if (!orig[0]) {
283 		fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
284 			orig);
285 		return NULL;
286 	}
287 
288 	copy = strdup(orig);
289 	if (copy == NULL) {
290 		fprintf(stderr, "%s: failed to allocate memory\n", progname);
291 		return NULL;
292 	}
293 
294 	toresolv = copy;
295 	lastcomp = NULL;
296 	for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
297 	if (end[0] != '/') {
298 		char *tmp;
299 		end[1] = '\0';
300 		tmp = strrchr(copy, '/');
301 		if (tmp == NULL) {
302 			lastcomp = copy;
303 			toresolv = ".";
304 		} else {
305 			lastcomp = tmp + 1;
306 			if (tmp == copy)
307 				toresolv = "/";
308 		}
309 		if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
310 			lastcomp = NULL;
311 			toresolv = copy;
312 		}
313 		else if (tmp)
314 			tmp[0] = '\0';
315 	}
316 	if (realpath(toresolv, buf) == NULL) {
317 		fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
318 			strerror(errno));
319 		free(copy);
320 		return NULL;
321 	}
322 	if (lastcomp == NULL)
323 		dst = strdup(buf);
324 	else {
325 		dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
326 		if (dst) {
327 			unsigned buflen = strlen(buf);
328 			if (buflen && buf[buflen-1] == '/')
329 				sprintf(dst, "%s%s", buf, lastcomp);
330 			else
331 				sprintf(dst, "%s/%s", buf, lastcomp);
332 		}
333 	}
334 	free(copy);
335 	if (dst == NULL)
336 		fprintf(stderr, "%s: failed to allocate memory\n", progname);
337 	return dst;
338 }
339 
fuse_mnt_check_fuseblk(void)340 int fuse_mnt_check_fuseblk(void)
341 {
342 	char buf[256];
343 	FILE *f = fopen("/proc/filesystems", "r");
344 	if (!f)
345 		return 1;
346 
347 	while (fgets(buf, sizeof(buf), f))
348 		if (strstr(buf, "fuseblk\n")) {
349 			fclose(f);
350 			return 1;
351 		}
352 
353 	fclose(f);
354 	return 0;
355 }
356 
fuse_mnt_parse_fuse_fd(const char * mountpoint)357 int fuse_mnt_parse_fuse_fd(const char *mountpoint)
358 {
359 	int fd = -1;
360 	int len = 0;
361 
362 	if (sscanf(mountpoint, "/dev/fd/%u%n", &fd, &len) == 1 &&
363 	    len == strlen(mountpoint)) {
364 		return fd;
365 	}
366 
367 	return -1;
368 }
369