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