• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   FUSE: Filesystem in Userspace
3   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
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__)
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 a symlink,
58 	 *  - is on a read-only filesystem.
59 	 */
60 	res = lstat(_PATH_MOUNTED, &stbuf);
61 	if (res == -1) {
62 		if (errno == ENOENT)
63 			return 0;
64 	} else {
65 		uid_t ruid;
66 		int err;
67 
68 		if (S_ISLNK(stbuf.st_mode))
69 			return 0;
70 
71 		ruid = getuid();
72 		if (ruid != 0)
73 			setreuid(0, -1);
74 
75 		res = access(_PATH_MOUNTED, W_OK);
76 		err = (res == -1) ? errno : 0;
77 		if (ruid != 0)
78 			setreuid(ruid, -1);
79 
80 		if (err == EROFS)
81 			return 0;
82 	}
83 
84 	return 1;
85 }
86 #endif /* IGNORE_MTAB */
87 
add_mount(const char * progname,const char * fsname,const char * mnt,const char * type,const char * opts)88 static int add_mount(const char *progname, const char *fsname,
89 		       const char *mnt, const char *type, const char *opts)
90 {
91 	int res;
92 	int status;
93 	sigset_t blockmask;
94 	sigset_t oldmask;
95 
96 	sigemptyset(&blockmask);
97 	sigaddset(&blockmask, SIGCHLD);
98 	res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
99 	if (res == -1) {
100 		fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
101 		return -1;
102 	}
103 
104 	res = fork();
105 	if (res == -1) {
106 		fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
107 		goto out_restore;
108 	}
109 	if (res == 0) {
110 		char *env = NULL;
111 
112 		sigprocmask(SIG_SETMASK, &oldmask, NULL);
113 
114 		if(setuid(geteuid()) == -1) {
115 			fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
116 			res = -1;
117 			goto out_restore;
118 		}
119 
120 		execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
121 		       "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
122 		fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
123 			progname, strerror(errno));
124 		exit(1);
125 	}
126 	res = waitpid(res, &status, 0);
127 	if (res == -1)
128 		fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
129 
130 	if (status != 0)
131 		res = -1;
132 
133  out_restore:
134 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
135 
136 	return res;
137 }
138 
fuse_mnt_add_mount(const char * progname,const char * fsname,const char * mnt,const char * type,const char * opts)139 int fuse_mnt_add_mount(const char *progname, const char *fsname,
140 		       const char *mnt, const char *type, const char *opts)
141 {
142 	if (!mtab_needs_update(mnt))
143 		return 0;
144 
145 	return add_mount(progname, fsname, mnt, type, opts);
146 }
147 
exec_umount(const char * progname,const char * rel_mnt,int lazy)148 static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
149 {
150 	int res;
151 	int status;
152 	sigset_t blockmask;
153 	sigset_t oldmask;
154 
155 	sigemptyset(&blockmask);
156 	sigaddset(&blockmask, SIGCHLD);
157 	res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
158 	if (res == -1) {
159 		fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
160 		return -1;
161 	}
162 
163 	res = fork();
164 	if (res == -1) {
165 		fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
166 		goto out_restore;
167 	}
168 	if (res == 0) {
169 		char *env = NULL;
170 
171 		sigprocmask(SIG_SETMASK, &oldmask, NULL);
172 
173 		if(setuid(geteuid()) == -1) {
174 			fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
175 			res = -1;
176 			goto out_restore;
177 		}
178 
179 		if (lazy) {
180 			execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
181 			       "-l", NULL, &env);
182 		} else {
183 			execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
184 			       NULL, &env);
185 		}
186 		fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
187 			progname, strerror(errno));
188 		exit(1);
189 	}
190 	res = waitpid(res, &status, 0);
191 	if (res == -1)
192 		fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
193 
194 	if (status != 0) {
195 		res = -1;
196 	}
197 
198  out_restore:
199 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
200 	return res;
201 
202 }
203 
fuse_mnt_umount(const char * progname,const char * abs_mnt,const char * rel_mnt,int lazy)204 int fuse_mnt_umount(const char *progname, const char *abs_mnt,
205 		    const char *rel_mnt, int lazy)
206 {
207 	int res;
208 
209 	if (!mtab_needs_update(abs_mnt)) {
210 		res = umount2(rel_mnt, lazy ? 2 : 0);
211 		if (res == -1)
212 			fprintf(stderr, "%s: failed to unmount %s: %s\n",
213 				progname, abs_mnt, strerror(errno));
214 		return res;
215 	}
216 
217 	return exec_umount(progname, rel_mnt, lazy);
218 }
219 
remove_mount(const char * progname,const char * mnt)220 static int remove_mount(const char *progname, const char *mnt)
221 {
222 	int res;
223 	int status;
224 	sigset_t blockmask;
225 	sigset_t oldmask;
226 
227 	sigemptyset(&blockmask);
228 	sigaddset(&blockmask, SIGCHLD);
229 	res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
230 	if (res == -1) {
231 		fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
232 		return -1;
233 	}
234 
235 	res = fork();
236 	if (res == -1) {
237 		fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
238 		goto out_restore;
239 	}
240 	if (res == 0) {
241 		char *env = NULL;
242 
243 		sigprocmask(SIG_SETMASK, &oldmask, NULL);
244 
245 		if(setuid(geteuid()) == -1) {
246 			fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
247 			res = -1;
248 			goto out_restore;
249 		}
250 
251 		execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
252 		       "--fake", mnt, NULL, &env);
253 		fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
254 			progname, strerror(errno));
255 		exit(1);
256 	}
257 	res = waitpid(res, &status, 0);
258 	if (res == -1)
259 		fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
260 
261 	if (status != 0)
262 		res = -1;
263 
264  out_restore:
265 	sigprocmask(SIG_SETMASK, &oldmask, NULL);
266 	return res;
267 }
268 
fuse_mnt_remove_mount(const char * progname,const char * mnt)269 int fuse_mnt_remove_mount(const char *progname, const char *mnt)
270 {
271 	if (!mtab_needs_update(mnt))
272 		return 0;
273 
274 	return remove_mount(progname, mnt);
275 }
276 
fuse_mnt_resolve_path(const char * progname,const char * orig)277 char *fuse_mnt_resolve_path(const char *progname, const char *orig)
278 {
279 	char buf[PATH_MAX];
280 	char *copy;
281 	char *dst;
282 	char *end;
283 	char *lastcomp;
284 	const char *toresolv;
285 
286 	if (!orig[0]) {
287 		fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
288 			orig);
289 		return NULL;
290 	}
291 
292 	copy = strdup(orig);
293 	if (copy == NULL) {
294 		fprintf(stderr, "%s: failed to allocate memory\n", progname);
295 		return NULL;
296 	}
297 
298 	toresolv = copy;
299 	lastcomp = NULL;
300 	for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
301 	if (end[0] != '/') {
302 		char *tmp;
303 		end[1] = '\0';
304 		tmp = strrchr(copy, '/');
305 		if (tmp == NULL) {
306 			lastcomp = copy;
307 			toresolv = ".";
308 		} else {
309 			lastcomp = tmp + 1;
310 			if (tmp == copy)
311 				toresolv = "/";
312 		}
313 		if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
314 			lastcomp = NULL;
315 			toresolv = copy;
316 		}
317 		else if (tmp)
318 			tmp[0] = '\0';
319 	}
320 	if (realpath(toresolv, buf) == NULL) {
321 		fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
322 			strerror(errno));
323 		free(copy);
324 		return NULL;
325 	}
326 	if (lastcomp == NULL)
327 		dst = strdup(buf);
328 	else {
329 		dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
330 		if (dst) {
331 			unsigned buflen = strlen(buf);
332 			if (buflen && buf[buflen-1] == '/')
333 				sprintf(dst, "%s%s", buf, lastcomp);
334 			else
335 				sprintf(dst, "%s/%s", buf, lastcomp);
336 		}
337 	}
338 	free(copy);
339 	if (dst == NULL)
340 		fprintf(stderr, "%s: failed to allocate memory\n", progname);
341 	return dst;
342 }
343 
fuse_mnt_check_fuseblk(void)344 int fuse_mnt_check_fuseblk(void)
345 {
346 	char buf[256];
347 	FILE *f = fopen("/proc/filesystems", "r");
348 	if (!f)
349 		return 1;
350 
351 	while (fgets(buf, sizeof(buf), f))
352 		if (strstr(buf, "fuseblk\n")) {
353 			fclose(f);
354 			return 1;
355 		}
356 
357 	fclose(f);
358 	return 0;
359 }
360 
fuse_mnt_parse_fuse_fd(const char * mountpoint)361 int fuse_mnt_parse_fuse_fd(const char *mountpoint)
362 {
363 	int fd = -1;
364 	int len = 0;
365 
366 	if (sscanf(mountpoint, "/dev/fd/%u%n", &fd, &len) == 1 &&
367 	    len == strlen(mountpoint)) {
368 		return fd;
369 	}
370 
371 	return -1;
372 }
373