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