libfuse: util/fusermount.c Source File

libfuse

fusermount.c
1 /*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU GPLv2.
6 See the file COPYING.
7 */
8 /* This program does the mounting and unmounting of FUSE filesystems */
9
10 #define _GNU_SOURCE /* for clone and strchrnul */
11 #include "fuse_config.h"
12 #include "mount_util.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include <getopt.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <pwd.h>
23 #include <paths.h>
24 #include <mntent.h>
25 #include <sys/wait.h>
26 #include <sys/stat.h>
27
28 #include "fuse_mount_compat.h"
29
30 #include <sys/fsuid.h>
31 #include <sys/socket.h>
32 #include <sys/utsname.h>
33 #include <sched.h>
34 #include <stdbool.h>
35 #include <sys/vfs.h>
36
37 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
38
39 #define FUSE_DEV "/dev/fuse"
40
41 static const char *progname;
42
43 static int user_allow_other = 0;
44 static int mount_max = 1000;
45
46 static int auto_unmount = 0;
47
48 #ifdef GETMNTENT_NEEDS_UNESCAPING
49 // Older versions of musl libc don't unescape entries in /etc/mtab
50
51 // unescapes octal sequences like \040 in-place
52 // That's ok, because unescaping can not extend the length of the string.
53 static void unescape(char *buf) {
54 char *src = buf;
55 char *dest = buf;
56 while (1) {
57 char *next_src = strchrnul(src, '\\');
58 int offset = next_src - src;
59 memmove(dest, src, offset);
60 src = next_src;
61 dest += offset;
62
63 if(*src == '\0') {
64 *dest = *src;
65 return;
66 }
67 src++;
68
69 if('0' <= src[0] && src[0] < '2' &&
70 '0' <= src[1] && src[1] < '8' &&
71 '0' <= src[2] && src[2] < '8') {
72 *dest++ = (src[0] - '0') << 6
73 | (src[1] - '0') << 3
74 | (src[2] - '0') << 0;
75 src += 3;
76 } else if (src[0] == '\\') {
77 *dest++ = '\\';
78 src += 1;
79 } else {
80 *dest++ = '\\';
81 }
82 }
83 }
84
85 static struct mntent *GETMNTENT(FILE *stream)
86 {
87 struct mntent *entp = getmntent(stream);
88 if(entp != NULL) {
89 unescape(entp->mnt_fsname);
90 unescape(entp->mnt_dir);
91 unescape(entp->mnt_type);
92 unescape(entp->mnt_opts);
93 }
94 return entp;
95 }
96 #else
97 #define GETMNTENT getmntent
98 #endif // GETMNTENT_NEEDS_UNESCAPING
99
100
101 static const char *get_user_name(void)
102 {
103 struct passwd *pw = getpwuid(getuid());
104 if (pw != NULL && pw->pw_name != NULL)
105 return pw->pw_name;
106 else {
107 fprintf(stderr, "%s: could not determine username\n", progname);
108 return NULL;
109 }
110 }
111
112 static uid_t oldfsuid;
113 static gid_t oldfsgid;
114
115 static void drop_privs(void)
116 {
117 if (getuid() != 0) {
118 oldfsuid = setfsuid(getuid());
119 oldfsgid = setfsgid(getgid());
120 }
121 }
122
123 static void restore_privs(void)
124 {
125 if (getuid() != 0) {
126 setfsuid(oldfsuid);
127 setfsgid(oldfsgid);
128 }
129 }
130
131 #ifndef IGNORE_MTAB
132 /*
133 * Make sure that /etc/mtab is checked and updated atomically
134 */
135 static int lock_umount(void)
136 {
137 const char *mtab_lock = _PATH_MOUNTED ".fuselock";
138 int mtablock;
139 int res;
140 struct stat mtab_stat;
141
142 /* /etc/mtab could be a symlink to /proc/mounts */
143 if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
144 return -1;
145
146 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
147 if (mtablock == -1) {
148 fprintf(stderr, "%s: unable to open fuse lock file: %s\n",
149 progname, strerror(errno));
150 return -1;
151 }
152 res = lockf(mtablock, F_LOCK, 0);
153 if (res < 0) {
154 fprintf(stderr, "%s: error getting lock: %s\n", progname,
155 strerror(errno));
156 close(mtablock);
157 return -1;
158 }
159
160 return mtablock;
161 }
162
163 static void unlock_umount(int mtablock)
164 {
165 if (mtablock >= 0) {
166 int res;
167
168 res = lockf(mtablock, F_ULOCK, 0);
169 if (res < 0) {
170 fprintf(stderr, "%s: error releasing lock: %s\n",
171 progname, strerror(errno));
172 }
173 close(mtablock);
174 }
175 }
176
177 static int add_mount(const char *source, const char *mnt, const char *type,
178 const char *opts)
179 {
180 return fuse_mnt_add_mount(progname, source, mnt, type, opts);
181 }
182
183 static int may_unmount(const char *mnt, int quiet)
184 {
185 struct mntent *entp;
186 FILE *fp;
187 const char *user = NULL;
188 char uidstr[32];
189 unsigned uidlen = 0;
190 int found;
191 const char *mtab = _PATH_MOUNTED;
192
193 user = get_user_name();
194 if (user == NULL)
195 return -1;
196
197 fp = setmntent(mtab, "r");
198 if (fp == NULL) {
199 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
200 strerror(errno));
201 return -1;
202 }
203
204 uidlen = sprintf(uidstr, "%u", getuid());
205
206 found = 0;
207 while ((entp = GETMNTENT(fp)) != NULL) {
208 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
209 (strcmp(entp->mnt_type, "fuse") == 0 ||
210 strcmp(entp->mnt_type, "fuseblk") == 0 ||
211 strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
212 strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
213 char *p = strstr(entp->mnt_opts, "user=");
214 if (p &&
215 (p == entp->mnt_opts || *(p-1) == ',') &&
216 strcmp(p + 5, user) == 0) {
217 found = 1;
218 break;
219 }
220 /* /etc/mtab is a link pointing to
221 /proc/mounts: */
222 else if ((p =
223 strstr(entp->mnt_opts, "user_id=")) &&
224 (p == entp->mnt_opts ||
225 *(p-1) == ',') &&
226 strncmp(p + 8, uidstr, uidlen) == 0 &&
227 (*(p+8+uidlen) == ',' ||
228 *(p+8+uidlen) == '\0')) {
229 found = 1;
230 break;
231 }
232 }
233 }
234 endmntent(fp);
235
236 if (!found) {
237 if (!quiet)
238 fprintf(stderr,
239 "%s: entry for %s not found in %s\n",
240 progname, mnt, mtab);
241 return -1;
242 }
243
244 return 0;
245 }
246 #endif
247
248 /*
249 * Check whether the file specified in "fusermount3 -u" is really a
250 * mountpoint and not a symlink. This is necessary otherwise the user
251 * could move the mountpoint away and replace it with a symlink
252 * pointing to an arbitrary mount, thereby tricking fusermount3 into
253 * unmounting that (umount(2) will follow symlinks).
254 *
255 * This is the child process running in a separate mount namespace, so
256 * we don't mess with the global namespace and if the process is
257 * killed for any reason, mounts are automatically cleaned up.
258 *
259 * First make sure nothing is propagated back into the parent
260 * namespace by marking all mounts "private".
261 *
262 * Then bind mount parent onto a stable base where the user can't move
263 * it around.
264 *
265 * Finally check /proc/mounts for an entry matching the requested
266 * mountpoint. If it's found then we are OK, and the user can't move
267 * it around within the parent directory as rename() will return
268 * EBUSY. Be careful to ignore any mounts that existed before the
269 * bind.
270 */
271 static int check_is_mount_child(void *p)
272 {
273 const char **a = p;
274 const char *last = a[0];
275 const char *mnt = a[1];
276 const char *type = a[2];
277 int res;
278 const char *procmounts = "/proc/mounts";
279 int found;
280 FILE *fp;
281 struct mntent *entp;
282 int count;
283
284 res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL);
285 if (res == -1) {
286 fprintf(stderr, "%s: failed to mark mounts private: %s\n",
287 progname, strerror(errno));
288 return 1;
289 }
290
291 fp = setmntent(procmounts, "r");
292 if (fp == NULL) {
293 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
294 procmounts, strerror(errno));
295 return 1;
296 }
297
298 count = 0;
299 while (GETMNTENT(fp) != NULL)
300 count++;
301 endmntent(fp);
302
303 fp = setmntent(procmounts, "r");
304 if (fp == NULL) {
305 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
306 procmounts, strerror(errno));
307 return 1;
308 }
309
310 res = mount(".", "/", "", MS_BIND | MS_REC, NULL);
311 if (res == -1) {
312 fprintf(stderr, "%s: failed to bind parent to /: %s\n",
313 progname, strerror(errno));
314 return 1;
315 }
316
317 found = 0;
318 while ((entp = GETMNTENT(fp)) != NULL) {
319 if (count > 0) {
320 count--;
321 continue;
322 }
323 if (entp->mnt_dir[0] == '/' &&
324 strcmp(entp->mnt_dir + 1, last) == 0 &&
325 (!type || strcmp(entp->mnt_type, type) == 0)) {
326 found = 1;
327 break;
328 }
329 }
330 endmntent(fp);
331
332 if (!found) {
333 fprintf(stderr, "%s: %s not mounted\n", progname, mnt);
334 return 1;
335 }
336
337 return 0;
338 }
339
340 static pid_t clone_newns(void *a)
341 {
342 char buf[131072];
343 char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15));
344
345 #ifdef __ia64__
346 extern int __clone2(int (*fn)(void *),
347 void *child_stack_base, size_t stack_size,
348 int flags, void *arg, pid_t *ptid,
349 void *tls, pid_t *ctid);
350
351 return __clone2(check_is_mount_child, stack, sizeof(buf) / 2,
352 CLONE_NEWNS, a, NULL, NULL, NULL);
353 #else
354 return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
355 #endif
356 }
357
358 static int check_is_mount(const char *last, const char *mnt, const char *type)
359 {
360 pid_t pid, p;
361 int status;
362 const char *a[3] = { last, mnt, type };
363
364 pid = clone_newns((void *) a);
365 if (pid == (pid_t) -1) {
366 fprintf(stderr, "%s: failed to clone namespace: %s\n",
367 progname, strerror(errno));
368 return -1;
369 }
370 p = waitpid(pid, &status, __WCLONE);
371 if (p == (pid_t) -1) {
372 fprintf(stderr, "%s: waitpid failed: %s\n",
373 progname, strerror(errno));
374 return -1;
375 }
376 if (!WIFEXITED(status)) {
377 fprintf(stderr, "%s: child terminated abnormally (status %i)\n",
378 progname, status);
379 return -1;
380 }
381 if (WEXITSTATUS(status) != 0)
382 return -1;
383
384 return 0;
385 }
386
387 static int chdir_to_parent(char *copy, const char **lastp)
388 {
389 char *tmp;
390 const char *parent;
391 char buf[65536];
392 int res;
393
394 tmp = strrchr(copy, '/');
395 if (tmp == NULL || tmp[1] == '\0') {
396 fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n",
397 progname, copy);
398 return -1;
399 }
400 if (tmp != copy) {
401 *tmp = '\0';
402 parent = copy;
403 *lastp = tmp + 1;
404 } else if (tmp[1] != '\0') {
405 *lastp = tmp + 1;
406 parent = "/";
407 } else {
408 *lastp = ".";
409 parent = "/";
410 }
411
412 res = chdir(parent);
413 if (res == -1) {
414 fprintf(stderr, "%s: failed to chdir to %s: %s\n",
415 progname, parent, strerror(errno));
416 return -1;
417 }
418
419 if (getcwd(buf, sizeof(buf)) == NULL) {
420 fprintf(stderr, "%s: failed to obtain current directory: %s\n",
421 progname, strerror(errno));
422 return -1;
423 }
424 if (strcmp(buf, parent) != 0) {
425 fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname,
426 parent, buf);
427 return -1;
428
429 }
430
431 return 0;
432 }
433
434 #ifndef IGNORE_MTAB
435 static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
436 {
437 int res;
438 char *copy;
439 const char *last;
440 int umount_flags = (lazy ? UMOUNT_DETACH : 0) | UMOUNT_NOFOLLOW;
441
442 if (getuid() != 0) {
443 res = may_unmount(mnt, quiet);
444 if (res == -1)
445 return -1;
446 }
447
448 copy = strdup(mnt);
449 if (copy == NULL) {
450 fprintf(stderr, "%s: failed to allocate memory\n", progname);
451 return -1;
452 }
453
454 drop_privs();
455 res = chdir_to_parent(copy, &last);
456 restore_privs();
457 if (res == -1)
458 goto out;
459
460 res = umount2(last, umount_flags);
461 if (res == -1 && !quiet) {
462 fprintf(stderr, "%s: failed to unmount %s: %s\n",
463 progname, mnt, strerror(errno));
464 }
465
466 out:
467 free(copy);
468 if (res == -1)
469 return -1;
470
471 res = chdir("/");
472 if (res == -1) {
473 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
474 return -1;
475 }
476
477 return fuse_mnt_remove_mount(progname, mnt);
478 }
479
480 static int unmount_fuse(const char *mnt, int quiet, int lazy)
481 {
482 int res;
483 int mtablock = lock_umount();
484
485 res = unmount_fuse_locked(mnt, quiet, lazy);
486 unlock_umount(mtablock);
487
488 return res;
489 }
490
491 static int count_fuse_fs(void)
492 {
493 struct mntent *entp;
494 int count = 0;
495 const char *mtab = _PATH_MOUNTED;
496 FILE *fp = setmntent(mtab, "r");
497 if (fp == NULL) {
498 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
499 strerror(errno));
500 return -1;
501 }
502 while ((entp = GETMNTENT(fp)) != NULL) {
503 if (strcmp(entp->mnt_type, "fuse") == 0 ||
504 strncmp(entp->mnt_type, "fuse.", 5) == 0)
505 count ++;
506 }
507 endmntent(fp);
508 return count;
509 }
510
511
512 #else /* IGNORE_MTAB */
513 static int count_fuse_fs(void)
514 {
515 return 0;
516 }
517
518 static int add_mount(const char *source, const char *mnt, const char *type,
519 const char *opts)
520 {
521 (void) source;
522 (void) mnt;
523 (void) type;
524 (void) opts;
525 return 0;
526 }
527
528 static int unmount_fuse(const char *mnt, int quiet, int lazy)
529 {
530 (void) quiet;
531 return fuse_mnt_umount(progname, mnt, mnt, lazy);
532 }
533 #endif /* IGNORE_MTAB */
534
535 static void strip_line(char *line)
536 {
537 char *s = strchr(line, '#');
538 if (s != NULL)
539 s[0] = '\0';
540 for (s = line + strlen(line) - 1;
541 s >= line && isspace((unsigned char) *s); s--);
542 s[1] = '\0';
543 for (s = line; isspace((unsigned char) *s); s++);
544 if (s != line)
545 memmove(line, s, strlen(s)+1);
546 }
547
548 static void parse_line(char *line, int linenum)
549 {
550 int tmp;
551 if (strcmp(line, "user_allow_other") == 0)
552 user_allow_other = 1;
553 else if (sscanf(line, "mount_max = %i", &tmp) == 1)
554 mount_max = tmp;
555 else if(line[0])
556 fprintf(stderr,
557 "%s: unknown parameter in %s at line %i: '%s'\n",
558 progname, FUSE_CONF, linenum, line);
559 }
560
561 static void read_conf(void)
562 {
563 FILE *fp = fopen(FUSE_CONF, "r");
564 if (fp != NULL) {
565 int linenum = 1;
566 char line[256];
567 int isnewline = 1;
568 while (fgets(line, sizeof(line), fp) != NULL) {
569 if (isnewline) {
570 if (line[strlen(line)-1] == '\n') {
571 strip_line(line);
572 parse_line(line, linenum);
573 } else {
574 isnewline = 0;
575 }
576 } else if(line[strlen(line)-1] == '\n') {
577 fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
578
579 isnewline = 1;
580 }
581 if (isnewline)
582 linenum ++;
583 }
584 if (!isnewline) {
585 fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
586
587 }
588 if (ferror(fp)) {
589 fprintf(stderr, "%s: reading %s: read failed\n", progname, FUSE_CONF);
590 exit(1);
591 }
592 fclose(fp);
593 } else if (errno != ENOENT) {
594 bool fatal = (errno != EACCES && errno != ELOOP &&
595 errno != ENAMETOOLONG && errno != ENOTDIR &&
596 errno != EOVERFLOW);
597 fprintf(stderr, "%s: failed to open %s: %s\n",
598 progname, FUSE_CONF, strerror(errno));
599 if (fatal)
600 exit(1);
601 }
602 }
603
604 static int begins_with(const char *s, const char *beg)
605 {
606 if (strncmp(s, beg, strlen(beg)) == 0)
607 return 1;
608 else
609 return 0;
610 }
611
612 struct mount_flags {
613 const char *opt;
614 unsigned long flag;
615 int on;
616 int safe;
617 };
618
619 static struct mount_flags mount_flags[] = {
620 {"rw", MS_RDONLY, 0, 1},
621 {"ro", MS_RDONLY, 1, 1},
622 {"suid", MS_NOSUID, 0, 0},
623 {"nosuid", MS_NOSUID, 1, 1},
624 {"dev", MS_NODEV, 0, 0},
625 {"nodev", MS_NODEV, 1, 1},
626 {"exec", MS_NOEXEC, 0, 1},
627 {"noexec", MS_NOEXEC, 1, 1},
628 {"async", MS_SYNCHRONOUS, 0, 1},
629 {"sync", MS_SYNCHRONOUS, 1, 1},
630 {"atime", MS_NOATIME, 0, 1},
631 {"noatime", MS_NOATIME, 1, 1},
632 {"diratime", MS_NODIRATIME, 0, 1},
633 {"nodiratime", MS_NODIRATIME, 1, 1},
634 {"lazytime", MS_LAZYTIME, 1, 1},
635 {"nolazytime", MS_LAZYTIME, 0, 1},
636 {"relatime", MS_RELATIME, 1, 1},
637 {"norelatime", MS_RELATIME, 0, 1},
638 {"strictatime", MS_STRICTATIME, 1, 1},
639 {"nostrictatime", MS_STRICTATIME, 0, 1},
640 {"dirsync", MS_DIRSYNC, 1, 1},
641 {NULL, 0, 0, 0}
642 };
643
644 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
645 {
646 int i;
647
648 for (i = 0; mount_flags[i].opt != NULL; i++) {
649 const char *opt = mount_flags[i].opt;
650 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
651 *on = mount_flags[i].on;
652 *flag = mount_flags[i].flag;
653 if (!mount_flags[i].safe && getuid() != 0) {
654 *flag = 0;
655 fprintf(stderr,
656 "%s: unsafe option %s ignored\n",
657 progname, opt);
658 }
659 return 1;
660 }
661 }
662 return 0;
663 }
664
665 static int add_option(char **optsp, const char *opt, unsigned expand)
666 {
667 char *newopts;
668 if (*optsp == NULL)
669 newopts = strdup(opt);
670 else {
671 unsigned oldsize = strlen(*optsp);
672 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
673 newopts = (char *) realloc(*optsp, newsize);
674 if (newopts)
675 sprintf(newopts + oldsize, ",%s", opt);
676 }
677 if (newopts == NULL) {
678 fprintf(stderr, "%s: failed to allocate memory\n", progname);
679 return -1;
680 }
681 *optsp = newopts;
682 return 0;
683 }
684
685 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
686 {
687 int i;
688 int l;
689
690 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
691 return -1;
692
693 for (i = 0; mount_flags[i].opt != NULL; i++) {
694 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
695 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
696 return -1;
697 }
698
699 if (add_option(mnt_optsp, opts, 0) == -1)
700 return -1;
701 /* remove comma from end of opts*/
702 l = strlen(*mnt_optsp);
703 if ((*mnt_optsp)[l-1] == ',')
704 (*mnt_optsp)[l-1] = '\0';
705 if (getuid() != 0) {
706 const char *user = get_user_name();
707 if (user == NULL)
708 return -1;
709
710 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
711 return -1;
712 strcat(*mnt_optsp, user);
713 }
714 return 0;
715 }
716
717 static int opt_eq(const char *s, unsigned len, const char *opt)
718 {
719 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
720 return 1;
721 else
722 return 0;
723 }
724
725 static int get_string_opt(const char *s, unsigned len, const char *opt,
726 char **val)
727 {
728 int i;
729 unsigned opt_len = strlen(opt);
730 char *d;
731
732 if (*val)
733 free(*val);
734 *val = (char *) malloc(len - opt_len + 1);
735 if (!*val) {
736 fprintf(stderr, "%s: failed to allocate memory\n", progname);
737 return 0;
738 }
739
740 d = *val;
741 s += opt_len;
742 len -= opt_len;
743 for (i = 0; i < len; i++) {
744 if (s[i] == '\\' && i + 1 < len)
745 i++;
746 *d++ = s[i];
747 }
748 *d = '\0';
749 return 1;
750 }
751
752 /* The kernel silently truncates the "data" argument to PAGE_SIZE-1 characters.
753 * This can be dangerous if it e.g. truncates the option "group_id=1000" to
754 * "group_id=1".
755 * This wrapper detects this case and bails out with an error.
756 */
757 static int mount_notrunc(const char *source, const char *target,
758 const char *filesystemtype, unsigned long mountflags,
759 const char *data) {
760 if (strlen(data) > sysconf(_SC_PAGESIZE) - 1) {
761 fprintf(stderr, "%s: mount options too long\n", progname);
762 errno = EINVAL;
763 return -1;
764 }
765 return mount(source, target, filesystemtype, mountflags, data);
766 }
767
768
769 static int do_mount(const char *mnt, const char **typep, mode_t rootmode,
770 int fd, const char *opts, const char *dev, char **sourcep,
771 char **mnt_optsp)
772 {
773 int res;
774 int flags = MS_NOSUID | MS_NODEV;
775 char *optbuf;
776 char *mnt_opts = NULL;
777 const char *s;
778 char *d;
779 char *fsname = NULL;
780 char *subtype = NULL;
781 char *source = NULL;
782 char *type = NULL;
783 int blkdev = 0;
784
785 optbuf = (char *) malloc(strlen(opts) + 128);
786 if (!optbuf) {
787 fprintf(stderr, "%s: failed to allocate memory\n", progname);
788 return -1;
789 }
790
791 for (s = opts, d = optbuf; *s;) {
792 unsigned len;
793 const char *fsname_str = "fsname=";
794 const char *subtype_str = "subtype=";
795 bool escape_ok = begins_with(s, fsname_str) ||
796 begins_with(s, subtype_str);
797 for (len = 0; s[len]; len++) {
798 if (escape_ok && s[len] == '\\' && s[len + 1])
799 len++;
800 else if (s[len] == ',')
801 break;
802 }
803 if (begins_with(s, fsname_str)) {
804 if (!get_string_opt(s, len, fsname_str, &fsname))
805 goto err;
806 } else if (begins_with(s, subtype_str)) {
807 if (!get_string_opt(s, len, subtype_str, &subtype))
808 goto err;
809 } else if (opt_eq(s, len, "blkdev")) {
810 if (getuid() != 0) {
811 fprintf(stderr,
812 "%s: option blkdev is privileged\n",
813 progname);
814 goto err;
815 }
816 blkdev = 1;
817 } else if (opt_eq(s, len, "auto_unmount")) {
818 auto_unmount = 1;
819 } else if (!opt_eq(s, len, "nonempty") &&
820 !begins_with(s, "fd=") &&
821 !begins_with(s, "rootmode=") &&
822 !begins_with(s, "user_id=") &&
823 !begins_with(s, "group_id=")) {
824 int on;
825 int flag;
826 int skip_option = 0;
827 if (opt_eq(s, len, "large_read")) {
828 struct utsname utsname;
829 unsigned kmaj, kmin;
830 res = uname(&utsname);
831 if (res == 0 &&
832 sscanf(utsname.release, "%u.%u",
833 &kmaj, &kmin) == 2 &&
834 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
835 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
836 skip_option = 1;
837 }
838 }
839 if (getuid() != 0 && !user_allow_other &&
840 (opt_eq(s, len, "allow_other") ||
841 opt_eq(s, len, "allow_root"))) {
842 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
843 goto err;
844 }
845 if (!skip_option) {
846 if (find_mount_flag(s, len, &on, &flag)) {
847 if (on)
848 flags |= flag;
849 else
850 flags &= ~flag;
851 } else if (opt_eq(s, len, "default_permissions") ||
852 opt_eq(s, len, "allow_other") ||
853 begins_with(s, "max_read=") ||
854 begins_with(s, "blksize=")) {
855 memcpy(d, s, len);
856 d += len;
857 *d++ = ',';
858 } else {
859 fprintf(stderr, "%s: unknown option '%.*s'\n", progname, len, s);
860 exit(1);
861 }
862 }
863 }
864 s += len;
865 if (*s)
866 s++;
867 }
868 *d = '\0';
869 res = get_mnt_opts(flags, optbuf, &mnt_opts);
870 if (res == -1)
871 goto err;
872
873 sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
874 fd, rootmode, getuid(), getgid());
875
876 source = malloc((fsname ? strlen(fsname) : 0) +
877 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
878
879 type = malloc((subtype ? strlen(subtype) : 0) + 32);
880 if (!type || !source) {
881 fprintf(stderr, "%s: failed to allocate memory\n", progname);
882 goto err;
883 }
884
885 if (subtype)
886 sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
887 else
888 strcpy(type, blkdev ? "fuseblk" : "fuse");
889
890 if (fsname)
891 strcpy(source, fsname);
892 else
893 strcpy(source, subtype ? subtype : dev);
894
895 res = mount_notrunc(source, mnt, type, flags, optbuf);
896 if (res == -1 && errno == ENODEV && subtype) {
897 /* Probably missing subtype support */
898 strcpy(type, blkdev ? "fuseblk" : "fuse");
899 if (fsname) {
900 if (!blkdev)
901 sprintf(source, "%s#%s", subtype, fsname);
902 } else {
903 strcpy(source, type);
904 }
905
906 res = mount_notrunc(source, mnt, type, flags, optbuf);
907 }
908 if (res == -1 && errno == EINVAL) {
909 /* It could be an old version not supporting group_id */
910 sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
911 fd, rootmode, getuid());
912 res = mount_notrunc(source, mnt, type, flags, optbuf);
913 }
914 if (res == -1) {
915 int errno_save = errno;
916 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
917 fprintf(stderr, "%s: 'fuseblk' support missing\n",
918 progname);
919 else
920 fprintf(stderr, "%s: mount failed: %s\n", progname,
921 strerror(errno_save));
922 goto err;
923 }
924 *sourcep = source;
925 *typep = type;
926 *mnt_optsp = mnt_opts;
927 free(fsname);
928 free(optbuf);
929
930 return 0;
931
932 err:
933 free(fsname);
934 free(subtype);
935 free(source);
936 free(type);
937 free(mnt_opts);
938 free(optbuf);
939 return -1;
940 }
941
942 static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
943 {
944 int res;
945 const char *mnt = *mntp;
946 const char *origmnt = mnt;
947 struct statfs fs_buf;
948 size_t i;
949
950 res = lstat(mnt, stbuf);
951 if (res == -1) {
952 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
953 progname, mnt, strerror(errno));
954 return -1;
955 }
956
957 /* No permission checking is done for root */
958 if (getuid() == 0)
959 return 0;
960
961 if (S_ISDIR(stbuf->st_mode)) {
962 res = chdir(mnt);
963 if (res == -1) {
964 fprintf(stderr,
965 "%s: failed to chdir to mountpoint: %s\n",
966 progname, strerror(errno));
967 return -1;
968 }
969 mnt = *mntp = ".";
970 res = lstat(mnt, stbuf);
971 if (res == -1) {
972 fprintf(stderr,
973 "%s: failed to access mountpoint %s: %s\n",
974 progname, origmnt, strerror(errno));
975 return -1;
976 }
977
978 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
979 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
980 progname, origmnt);
981 return -1;
982 }
983
984 res = access(mnt, W_OK);
985 if (res == -1) {
986 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
987 progname, origmnt);
988 return -1;
989 }
990 } else if (S_ISREG(stbuf->st_mode)) {
991 static char procfile[256];
992 *mountpoint_fd = open(mnt, O_WRONLY);
993 if (*mountpoint_fd == -1) {
994 fprintf(stderr, "%s: failed to open %s: %s\n",
995 progname, mnt, strerror(errno));
996 return -1;
997 }
998 res = fstat(*mountpoint_fd, stbuf);
999 if (res == -1) {
1000 fprintf(stderr,
1001 "%s: failed to access mountpoint %s: %s\n",
1002 progname, mnt, strerror(errno));
1003 return -1;
1004 }
1005 if (!S_ISREG(stbuf->st_mode)) {
1006 fprintf(stderr,
1007 "%s: mountpoint %s is no longer a regular file\n",
1008 progname, mnt);
1009 return -1;
1010 }
1011
1012 sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
1013 *mntp = procfile;
1014 } else {
1015 fprintf(stderr,
1016 "%s: mountpoint %s is not a directory or a regular file\n",
1017 progname, mnt);
1018 return -1;
1019 }
1020
1021 /* Do not permit mounting over anything in procfs - it has a couple
1022 * places to which we have "write access" without being supposed to be
1023 * able to just put anything we want there.
1024 * Luckily, without allow_other, we can't get other users to actually
1025 * use any fake information we try to put there anyway.
1026 * Use a whitelist to be safe. */
1027 if (statfs(*mntp, &fs_buf)) {
1028 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
1029 progname, mnt, strerror(errno));
1030 return -1;
1031 }
1032
1033 /* Define permitted filesystems for the mount target. This was
1034 * originally the same list as used by the ecryptfs mount helper
1035 * (https://bazaar.launchpad.net/~ecryptfs/ecryptfs/trunk/view/head:/src/utils/mount.ecryptfs_private.c#L225)
1036 * but got expanded as we found more filesystems that needed to be
1037 * overlaid. */
1038 typeof(fs_buf.f_type) f_type_whitelist[] = {
1039 0x61756673 /* AUFS_SUPER_MAGIC */,
1040 0x00000187 /* AUTOFS_SUPER_MAGIC */,
1041 0xCA451A4E /* BCACHEFS_STATFS_MAGIC */,
1042 0x9123683E /* BTRFS_SUPER_MAGIC */,
1043 0x00C36400 /* CEPH_SUPER_MAGIC */,
1044 0xFF534D42 /* CIFS_MAGIC_NUMBER */,
1045 0x0000F15F /* ECRYPTFS_SUPER_MAGIC */,
1046 0X2011BAB0 /* EXFAT_SUPER_MAGIC */,
1047 0x0000EF53 /* EXT[234]_SUPER_MAGIC */,
1048 0xF2F52010 /* F2FS_SUPER_MAGIC */,
1049 0x65735546 /* FUSE_SUPER_MAGIC */,
1050 0x01161970 /* GFS2_MAGIC */,
1051 0x47504653 /* GPFS_SUPER_MAGIC */,
1052 0x0000482b /* HFSPLUS_SUPER_MAGIC */,
1053 0x000072B6 /* JFFS2_SUPER_MAGIC */,
1054 0x3153464A /* JFS_SUPER_MAGIC */,
1055 0x0BD00BD0 /* LL_SUPER_MAGIC */,
1056 0X00004D44 /* MSDOS_SUPER_MAGIC */,
1057 0x0000564C /* NCP_SUPER_MAGIC */,
1058 0x00006969 /* NFS_SUPER_MAGIC */,
1059 0x00003434 /* NILFS_SUPER_MAGIC */,
1060 0x5346544E /* NTFS_SB_MAGIC */,
1061 0x5346414f /* OPENAFS_SUPER_MAGIC */,
1062 0x794C7630 /* OVERLAYFS_SUPER_MAGIC */,
1063 0x52654973 /* REISERFS_SUPER_MAGIC */,
1064 0xFE534D42 /* SMB2_SUPER_MAGIC */,
1065 0x73717368 /* SQUASHFS_MAGIC */,
1066 0x01021994 /* TMPFS_MAGIC */,
1067 0x24051905 /* UBIFS_SUPER_MAGIC */,
1068 0x736675005346544e /* UFSD */,
1069 0x58465342 /* XFS_SB_MAGIC */,
1070 0x2FC12FC1 /* ZFS_SUPER_MAGIC */,
1071 };
1072 for (i = 0; i < sizeof(f_type_whitelist)/sizeof(f_type_whitelist[0]); i++) {
1073 if (f_type_whitelist[i] == fs_buf.f_type)
1074 return 0;
1075 }
1076
1077 fprintf(stderr, "%s: mounting over filesystem type %#010lx is forbidden\n",
1078 progname, (unsigned long)fs_buf.f_type);
1079 return -1;
1080 }
1081
1082 static int try_open(const char *dev, char **devp, int silent)
1083 {
1084 int fd = open(dev, O_RDWR);
1085 if (fd != -1) {
1086 *devp = strdup(dev);
1087 if (*devp == NULL) {
1088 fprintf(stderr, "%s: failed to allocate memory\n",
1089 progname);
1090 close(fd);
1091 fd = -1;
1092 }
1093 } else if (errno == ENODEV ||
1094 errno == ENOENT)/* check for ENOENT too, for the udev case */
1095 return -2;
1096 else if (!silent) {
1097 fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
1098 strerror(errno));
1099 }
1100 return fd;
1101 }
1102
1103 static int try_open_fuse_device(char **devp)
1104 {
1105 int fd;
1106
1107 drop_privs();
1108 fd = try_open(FUSE_DEV, devp, 0);
1109 restore_privs();
1110 return fd;
1111 }
1112
1113 static int open_fuse_device(char **devp)
1114 {
1115 int fd = try_open_fuse_device(devp);
1116 if (fd >= -1)
1117 return fd;
1118
1119 fprintf(stderr,
1120 "%s: fuse device not found, try 'modprobe fuse' first\n",
1121 progname);
1122
1123 return -1;
1124 }
1125
1126
1127 static int mount_fuse(const char *mnt, const char *opts, const char **type)
1128 {
1129 int res;
1130 int fd;
1131 char *dev;
1132 struct stat stbuf;
1133 char *source = NULL;
1134 char *mnt_opts = NULL;
1135 const char *real_mnt = mnt;
1136 int mountpoint_fd = -1;
1137
1138 fd = open_fuse_device(&dev);
1139 if (fd == -1)
1140 return -1;
1141
1142 drop_privs();
1143 read_conf();
1144
1145 if (getuid() != 0 && mount_max != -1) {
1146 int mount_count = count_fuse_fs();
1147 if (mount_count >= mount_max) {
1148 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1149 goto fail_close_fd;
1150 }
1151 }
1152
1153 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1154 restore_privs();
1155 if (res != -1)
1156 res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT,
1157 fd, opts, dev, &source, &mnt_opts);
1158
1159 if (mountpoint_fd != -1)
1160 close(mountpoint_fd);
1161
1162 if (res == -1)
1163 goto fail_close_fd;
1164
1165 res = chdir("/");
1166 if (res == -1) {
1167 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1168 goto fail_close_fd;
1169 }
1170
1171 if (geteuid() == 0) {
1172 res = add_mount(source, mnt, *type, mnt_opts);
1173 if (res == -1) {
1174 /* Can't clean up mount in a non-racy way */
1175 goto fail_close_fd;
1176 }
1177 }
1178
1179 out_free:
1180 free(source);
1181 free(mnt_opts);
1182 free(dev);
1183
1184 return fd;
1185
1186 fail_close_fd:
1187 close(fd);
1188 fd = -1;
1189 goto out_free;
1190 }
1191
1192 static int send_fd(int sock_fd, int fd)
1193 {
1194 int retval;
1195 struct msghdr msg;
1196 struct cmsghdr *p_cmsg;
1197 struct iovec vec;
1198 size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
1199 int *p_fds;
1200 char sendchar = 0;
1201
1202 msg.msg_control = cmsgbuf;
1203 msg.msg_controllen = sizeof(cmsgbuf);
1204 p_cmsg = CMSG_FIRSTHDR(&msg);
1205 p_cmsg->cmsg_level = SOL_SOCKET;
1206 p_cmsg->cmsg_type = SCM_RIGHTS;
1207 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1208 p_fds = (int *) CMSG_DATA(p_cmsg);
1209 *p_fds = fd;
1210 msg.msg_controllen = p_cmsg->cmsg_len;
1211 msg.msg_name = NULL;
1212 msg.msg_namelen = 0;
1213 msg.msg_iov = &vec;
1214 msg.msg_iovlen = 1;
1215 msg.msg_flags = 0;
1216 /* "To pass file descriptors or credentials you need to send/read at
1217 * least one byte" (man 7 unix) */
1218 vec.iov_base = &sendchar;
1219 vec.iov_len = sizeof(sendchar);
1220 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1221 if (retval != 1) {
1222 perror("sending file descriptor");
1223 return -1;
1224 }
1225 return 0;
1226 }
1227
1228 /* Helper for should_auto_unmount
1229 *
1230 * fusermount typically has the s-bit set - initial open of `mnt` was as root
1231 * and got EACCESS as 'allow_other' was not specified.
1232 * Try opening `mnt` again with uid and guid of the calling process.
1233 */
1234 static int recheck_ENOTCONN_as_owner(const char *mnt)
1235 {
1236 int pid = fork();
1237 if(pid == -1) {
1238 perror("fuse: recheck_ENOTCONN_as_owner can't fork");
1239 _exit(EXIT_FAILURE);
1240 } else if(pid == 0) {
1241 uid_t uid = getuid();
1242 gid_t gid = getgid();
1243 if(setresgid(gid, gid, gid) == -1) {
1244 perror("fuse: can't set resgid");
1245 _exit(EXIT_FAILURE);
1246 }
1247 if(setresuid(uid, uid, uid) == -1) {
1248 perror("fuse: can't set resuid");
1249 _exit(EXIT_FAILURE);
1250 }
1251
1252 int fd = open(mnt, O_RDONLY);
1253 if(fd == -1 && errno == ENOTCONN)
1254 _exit(EXIT_SUCCESS);
1255 else
1256 _exit(EXIT_FAILURE);
1257 } else {
1258 int status;
1259 int res = waitpid(pid, &status, 0);
1260 if (res == -1) {
1261 perror("fuse: waiting for child failed");
1262 _exit(EXIT_FAILURE);
1263 }
1264 return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS;
1265 }
1266 }
1267
1268 /* The parent fuse process has died: decide whether to auto_unmount.
1269 *
1270 * In the normal case (umount or fusermount -u), the filesystem
1271 * has already been unmounted. If we simply unmount again we can
1272 * cause problems with stacked mounts (e.g. autofs).
1273 *
1274 * So we unmount here only in abnormal case where fuse process has
1275 * died without unmount happening. To detect this, we first look in
1276 * the mount table to make sure the mountpoint is still mounted and
1277 * has proper type. If so, we then see if opening the mount dir is
1278 * returning 'Transport endpoint is not connected'.
1279 *
1280 * The order of these is important, because if autofs is in use,
1281 * opening the dir to check for ENOTCONN will cause a new mount
1282 * in the normal case where filesystem has been unmounted cleanly.
1283 */
1284 static int should_auto_unmount(const char *mnt, const char *type)
1285 {
1286 char *copy;
1287 const char *last;
1288 int result = 0;
1289 int fd;
1290
1291 copy = strdup(mnt);
1292 if (copy == NULL) {
1293 fprintf(stderr, "%s: failed to allocate memory\n", progname);
1294 return 0;
1295 }
1296
1297 if (chdir_to_parent(copy, &last) == -1)
1298 goto out;
1299 if (check_is_mount(last, mnt, type) == -1)
1300 goto out;
1301
1302 fd = open(mnt, O_RDONLY);
1303
1304 if (fd != -1) {
1305 close(fd);
1306 } else {
1307 switch(errno) {
1308 case ENOTCONN:
1309 result = 1;
1310 break;
1311 case EACCES:
1312 result = recheck_ENOTCONN_as_owner(mnt);
1313 break;
1314 default:
1315 result = 0;
1316 break;
1317 }
1318 }
1319 out:
1320 free(copy);
1321 return result;
1322 }
1323
1324 static void usage(void)
1325 {
1326 printf("%s: [options] mountpoint\n"
1327 "Options:\n"
1328 " -h print help\n"
1329 " -V print version\n"
1330 " -o opt[,opt...] mount options\n"
1331 " -u unmount\n"
1332 " -q quiet\n"
1333 " -z lazy unmount\n",
1334 progname);
1335 exit(1);
1336 }
1337
1338 static void show_version(void)
1339 {
1340 printf("fusermount3 version: %s\n", PACKAGE_VERSION);
1341 exit(0);
1342 }
1343
1344 int main(int argc, char *argv[])
1345 {
1346 sigset_t sigset;
1347 int ch;
1348 int fd;
1349 int res;
1350 char *origmnt;
1351 char *mnt;
1352 static int unmount = 0;
1353 static int lazy = 0;
1354 static int quiet = 0;
1355 char *commfd;
1356 int cfd;
1357 const char *opts = "";
1358 const char *type = NULL;
1359 int setup_auto_unmount_only = 0;
1360
1361 static const struct option long_opts[] = {
1362 {"unmount", no_argument, NULL, 'u'},
1363 // Note: auto-unmount deliberately does not have a short version.
1364 // It's meant for internal use by mount.c's setup_auto_unmount.
1365 {"auto-unmount", no_argument, NULL, 'U'},
1366 {"lazy", no_argument, NULL, 'z'},
1367 {"quiet", no_argument, NULL, 'q'},
1368 {"help", no_argument, NULL, 'h'},
1369 {"version", no_argument, NULL, 'V'},
1370 {"options", required_argument, NULL, 'o'},
1371 {0, 0, 0, 0}};
1372
1373 progname = strdup(argc > 0 ? argv[0] : "fusermount");
1374 if (progname == NULL) {
1375 fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1376 exit(1);
1377 }
1378
1379 while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
1380 NULL)) != -1) {
1381 switch (ch) {
1382 case 'h':
1383 usage();
1384 break;
1385
1386 case 'V':
1387 show_version();
1388 break;
1389
1390 case 'o':
1391 opts = optarg;
1392 break;
1393
1394 case 'u':
1395 unmount = 1;
1396 break;
1397 case 'U':
1398 unmount = 1;
1399 auto_unmount = 1;
1400 setup_auto_unmount_only = 1;
1401 break;
1402 case 'z':
1403 lazy = 1;
1404 break;
1405
1406 case 'q':
1407 quiet = 1;
1408 break;
1409
1410 default:
1411 exit(1);
1412 }
1413 }
1414
1415 if (lazy && !unmount) {
1416 fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1417 exit(1);
1418 }
1419
1420 if (optind >= argc) {
1421 fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1422 exit(1);
1423 } else if (argc > optind + 1) {
1424 fprintf(stderr, "%s: extra arguments after the mountpoint\n",
1425 progname);
1426 exit(1);
1427 }
1428
1429 origmnt = argv[optind];
1430
1431 drop_privs();
1432 mnt = fuse_mnt_resolve_path(progname, origmnt);
1433 if (mnt != NULL) {
1434 res = chdir("/");
1435 if (res == -1) {
1436 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1437 goto err_out;
1438 }
1439 }
1440 restore_privs();
1441 if (mnt == NULL)
1442 exit(1);
1443
1444 umask(033);
1445 if (!setup_auto_unmount_only && unmount)
1446 goto do_unmount;
1447
1448 commfd = getenv(FUSE_COMMFD_ENV);
1449 if (commfd == NULL) {
1450 fprintf(stderr, "%s: old style mounting not supported\n",
1451 progname);
1452 goto err_out;
1453 }
1454
1455 cfd = atoi(commfd);
1456 {
1457 struct stat statbuf;
1458 fstat(cfd, &statbuf);
1459 if(!S_ISSOCK(statbuf.st_mode)) {
1460 fprintf(stderr,
1461 "%s: file descriptor %i is not a socket, can't send fuse fd\n",
1462 progname, cfd);
1463 goto err_out;
1464 }
1465 }
1466
1467 if (setup_auto_unmount_only)
1468 goto wait_for_auto_unmount;
1469
1470 fd = mount_fuse(mnt, opts, &type);
1471 if (fd == -1)
1472 goto err_out;
1473
1474 res = send_fd(cfd, fd);
1475 if (res != 0) {
1476 umount2(mnt, MNT_DETACH); /* lazy umount */
1477 goto err_out;
1478 }
1479 close(fd);
1480
1481 if (!auto_unmount) {
1482 free(mnt);
1483 free((void*) type);
1484 return 0;
1485 }
1486
1487 wait_for_auto_unmount:
1488 /* Become a daemon and wait for the parent to exit or die.
1489 ie For the control socket to get closed.
1490 btw We don't want to use daemon() function here because
1491 it forks and messes with the file descriptors. */
1492 setsid();
1493 res = chdir("/");
1494 if (res == -1) {
1495 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1496 goto err_out;
1497 }
1498
1499 sigfillset(&sigset);
1500 sigprocmask(SIG_BLOCK, &sigset, NULL);
1501
1502 lazy = 1;
1503 quiet = 1;
1504
1505 while (1) {
1506 unsigned char buf[16];
1507 int n = recv(cfd, buf, sizeof(buf), 0);
1508 if (!n)
1509 break;
1510
1511 if (n < 0) {
1512 if (errno == EINTR)
1513 continue;
1514 break;
1515 }
1516 }
1517
1518 if (!should_auto_unmount(mnt, type)) {
1519 goto success_out;
1520 }
1521
1522 do_unmount:
1523 if (geteuid() == 0)
1524 res = unmount_fuse(mnt, quiet, lazy);
1525 else {
1526 res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
1527 if (res == -1 && !quiet)
1528 fprintf(stderr,
1529 "%s: failed to unmount %s: %s\n",
1530 progname, mnt, strerror(errno));
1531 }
1532 if (res == -1)
1533 goto err_out;
1534
1535 success_out:
1536 free((void*) type);
1537 free(mnt);
1538 return 0;
1539
1540 err_out:
1541 free((void*) type);
1542 free(mnt);
1543 exit(1);
1544 }