libfuse

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