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 GPL.
6  See the file COPYING.
7 */
8 /* This program does the mounting and unmounting of FUSE filesystems */
9 
10 #define _GNU_SOURCE /* for clone */
11 #include <config.h>
12 
13 #include "mount_util.h"
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 #include <sys/mount.h>
28 #include <sys/fsuid.h>
29 #include <sys/socket.h>
30 #include <sys/utsname.h>
31 #include <sched.h>
32 
33 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
34 
35 #define FUSE_DEV "/dev/fuse"
36 #define FUSE_CONF "/etc/fuse.conf"
37 
38 #ifndef MS_DIRSYNC
39 #define MS_DIRSYNC 128
40 #endif
41 #ifndef MS_REC
42 #define MS_REC 16384
43 #endif
44 #ifndef MS_PRIVATE
45 #define MS_PRIVATE (1<<18)
46 #endif
47 
48 #ifndef UMOUNT_DETACH
49 #define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */
50 #endif
51 #ifndef UMOUNT_NOFOLLOW
52 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
53 #endif
54 #ifndef UMOUNT_UNUSED
55 #define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
56 #endif
57 
58 static const char *progname;
59 
60 static int user_allow_other = 0;
61 static int mount_max = 1000;
62 
63 static int auto_unmount = 0;
64 
65 static const char *get_user_name(void)
66 {
67  struct passwd *pw = getpwuid(getuid());
68  if (pw != NULL && pw->pw_name != NULL)
69  return pw->pw_name;
70  else {
71  fprintf(stderr, "%s: could not determine username\n", progname);
72  return NULL;
73  }
74 }
75 
76 static uid_t oldfsuid;
77 static gid_t oldfsgid;
78 
79 static void drop_privs(void)
80 {
81  if (getuid() != 0) {
82  oldfsuid = setfsuid(getuid());
83  oldfsgid = setfsgid(getgid());
84  }
85 }
86 
87 static void restore_privs(void)
88 {
89  if (getuid() != 0) {
90  setfsuid(oldfsuid);
91  setfsgid(oldfsgid);
92  }
93 }
94 
95 #ifndef IGNORE_MTAB
96 /*
97  * Make sure that /etc/mtab is checked and updated atomically
98  */
99 static int lock_umount(void)
100 {
101  const char *mtab_lock = _PATH_MOUNTED ".fuselock";
102  int mtablock;
103  int res;
104  struct stat mtab_stat;
105 
106  /* /etc/mtab could be a symlink to /proc/mounts */
107  if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
108  return -1;
109 
110  mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
111  if (mtablock == -1) {
112  fprintf(stderr, "%s: unable to open fuse lock file: %s\n",
113  progname, strerror(errno));
114  return -1;
115  }
116  res = lockf(mtablock, F_LOCK, 0);
117  if (res < 0) {
118  fprintf(stderr, "%s: error getting lock: %s\n", progname,
119  strerror(errno));
120  close(mtablock);
121  return -1;
122  }
123 
124  return mtablock;
125 }
126 
127 static void unlock_umount(int mtablock)
128 {
129  if (mtablock >= 0) {
130  int res;
131 
132  res = lockf(mtablock, F_ULOCK, 0);
133  if (res < 0) {
134  fprintf(stderr, "%s: error releasing lock: %s\n",
135  progname, strerror(errno));
136  }
137  close(mtablock);
138  }
139 }
140 
141 static int add_mount(const char *source, const char *mnt, const char *type,
142  const char *opts)
143 {
144  return fuse_mnt_add_mount(progname, source, mnt, type, opts);
145 }
146 
147 static int may_unmount(const char *mnt, int quiet)
148 {
149  struct mntent *entp;
150  FILE *fp;
151  const char *user = NULL;
152  char uidstr[32];
153  unsigned uidlen = 0;
154  int found;
155  const char *mtab = _PATH_MOUNTED;
156 
157  user = get_user_name();
158  if (user == NULL)
159  return -1;
160 
161  fp = setmntent(mtab, "r");
162  if (fp == NULL) {
163  fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
164  strerror(errno));
165  return -1;
166  }
167 
168  uidlen = sprintf(uidstr, "%u", getuid());
169 
170  found = 0;
171  while ((entp = getmntent(fp)) != NULL) {
172  if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
173  (strcmp(entp->mnt_type, "fuse") == 0 ||
174  strcmp(entp->mnt_type, "fuseblk") == 0 ||
175  strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
176  strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
177  char *p = strstr(entp->mnt_opts, "user=");
178  if (p &&
179  (p == entp->mnt_opts || *(p-1) == ',') &&
180  strcmp(p + 5, user) == 0) {
181  found = 1;
182  break;
183  }
184  /* /etc/mtab is a link pointing to
185  /proc/mounts: */
186  else if ((p =
187  strstr(entp->mnt_opts, "user_id=")) &&
188  (p == entp->mnt_opts ||
189  *(p-1) == ',') &&
190  strncmp(p + 8, uidstr, uidlen) == 0 &&
191  (*(p+8+uidlen) == ',' ||
192  *(p+8+uidlen) == '\0')) {
193  found = 1;
194  break;
195  }
196  }
197  }
198  endmntent(fp);
199 
200  if (!found) {
201  if (!quiet)
202  fprintf(stderr,
203  "%s: entry for %s not found in %s\n",
204  progname, mnt, mtab);
205  return -1;
206  }
207 
208  return 0;
209 }
210 
211 /*
212  * Check whether the file specified in "fusermount3 -u" is really a
213  * mountpoint and not a symlink. This is necessary otherwise the user
214  * could move the mountpoint away and replace it with a symlink
215  * pointing to an arbitrary mount, thereby tricking fusermount3 into
216  * unmounting that (umount(2) will follow symlinks).
217  *
218  * This is the child process running in a separate mount namespace, so
219  * we don't mess with the global namespace and if the process is
220  * killed for any reason, mounts are automatically cleaned up.
221  *
222  * First make sure nothing is propagated back into the parent
223  * namespace by marking all mounts "private".
224  *
225  * Then bind mount parent onto a stable base where the user can't move
226  * it around.
227  *
228  * Finally check /proc/mounts for an entry matching the requested
229  * mountpoint. If it's found then we are OK, and the user can't move
230  * it around within the parent directory as rename() will return
231  * EBUSY. Be careful to ignore any mounts that existed before the
232  * bind.
233  */
234 static int check_is_mount_child(void *p)
235 {
236  const char **a = p;
237  const char *last = a[0];
238  const char *mnt = a[1];
239  int res;
240  const char *procmounts = "/proc/mounts";
241  int found;
242  FILE *fp;
243  struct mntent *entp;
244  int count;
245 
246  res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL);
247  if (res == -1) {
248  fprintf(stderr, "%s: failed to mark mounts private: %s\n",
249  progname, strerror(errno));
250  return 1;
251  }
252 
253  fp = setmntent(procmounts, "r");
254  if (fp == NULL) {
255  fprintf(stderr, "%s: failed to open %s: %s\n", progname,
256  procmounts, strerror(errno));
257  return 1;
258  }
259 
260  count = 0;
261  while (getmntent(fp) != NULL)
262  count++;
263  endmntent(fp);
264 
265  fp = setmntent(procmounts, "r");
266  if (fp == NULL) {
267  fprintf(stderr, "%s: failed to open %s: %s\n", progname,
268  procmounts, strerror(errno));
269  return 1;
270  }
271 
272  res = mount(".", "/", "", MS_BIND | MS_REC, NULL);
273  if (res == -1) {
274  fprintf(stderr, "%s: failed to bind parent to /: %s\n",
275  progname, strerror(errno));
276  return 1;
277  }
278 
279  found = 0;
280  while ((entp = getmntent(fp)) != NULL) {
281  if (count > 0) {
282  count--;
283  continue;
284  }
285  if (entp->mnt_dir[0] == '/' &&
286  strcmp(entp->mnt_dir + 1, last) == 0) {
287  found = 1;
288  break;
289  }
290  }
291  endmntent(fp);
292 
293  if (!found) {
294  fprintf(stderr, "%s: %s not mounted\n", progname, mnt);
295  return 1;
296  }
297 
298  return 0;
299 }
300 
301 static pid_t clone_newns(void *a)
302 {
303  char buf[131072];
304  char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15));
305 
306 #ifdef __ia64__
307  extern int __clone2(int (*fn)(void *),
308  void *child_stack_base, size_t stack_size,
309  int flags, void *arg, pid_t *ptid,
310  void *tls, pid_t *ctid);
311 
312  return __clone2(check_is_mount_child, stack, sizeof(buf) / 2,
313  CLONE_NEWNS, a, NULL, NULL, NULL);
314 #else
315  return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
316 #endif
317 }
318 
319 static int check_is_mount(const char *last, const char *mnt)
320 {
321  pid_t pid, p;
322  int status;
323  const char *a[2] = { last, mnt };
324 
325  pid = clone_newns((void *) a);
326  if (pid == (pid_t) -1) {
327  fprintf(stderr, "%s: failed to clone namespace: %s\n",
328  progname, strerror(errno));
329  return -1;
330  }
331  p = waitpid(pid, &status, __WCLONE);
332  if (p == (pid_t) -1) {
333  fprintf(stderr, "%s: waitpid failed: %s\n",
334  progname, strerror(errno));
335  return -1;
336  }
337  if (!WIFEXITED(status)) {
338  fprintf(stderr, "%s: child terminated abnormally (status %i)\n",
339  progname, status);
340  return -1;
341  }
342  if (WEXITSTATUS(status) != 0)
343  return -1;
344 
345  return 0;
346 }
347 
348 static int chdir_to_parent(char *copy, const char **lastp)
349 {
350  char *tmp;
351  const char *parent;
352  char buf[65536];
353  int res;
354 
355  tmp = strrchr(copy, '/');
356  if (tmp == NULL || tmp[1] == '\0') {
357  fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n",
358  progname, copy);
359  return -1;
360  }
361  if (tmp != copy) {
362  *tmp = '\0';
363  parent = copy;
364  *lastp = tmp + 1;
365  } else if (tmp[1] != '\0') {
366  *lastp = tmp + 1;
367  parent = "/";
368  } else {
369  *lastp = ".";
370  parent = "/";
371  }
372 
373  res = chdir(parent);
374  if (res == -1) {
375  fprintf(stderr, "%s: failed to chdir to %s: %s\n",
376  progname, parent, strerror(errno));
377  return -1;
378  }
379 
380  if (getcwd(buf, sizeof(buf)) == NULL) {
381  fprintf(stderr, "%s: failed to obtain current directory: %s\n",
382  progname, strerror(errno));
383  return -1;
384  }
385  if (strcmp(buf, parent) != 0) {
386  fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname,
387  parent, buf);
388  return -1;
389 
390  }
391 
392  return 0;
393 }
394 
395 /* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
396 static int umount_nofollow_support(void)
397 {
398  int res = umount2("", UMOUNT_UNUSED);
399  if (res != -1 || errno != EINVAL)
400  return 0;
401 
402  res = umount2("", UMOUNT_NOFOLLOW);
403  if (res != -1 || errno != ENOENT)
404  return 0;
405 
406  return 1;
407 }
408 
409 static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
410 {
411  int res;
412  char *copy;
413  const char *last;
414  int umount_flags = lazy ? UMOUNT_DETACH : 0;
415 
416  if (getuid() != 0) {
417  res = may_unmount(mnt, quiet);
418  if (res == -1)
419  return -1;
420  }
421 
422  copy = strdup(mnt);
423  if (copy == NULL) {
424  fprintf(stderr, "%s: failed to allocate memory\n", progname);
425  return -1;
426  }
427 
428  res = chdir_to_parent(copy, &last);
429  if (res == -1)
430  goto out;
431 
432  if (umount_nofollow_support()) {
433  umount_flags |= UMOUNT_NOFOLLOW;
434  } else {
435  res = check_is_mount(last, mnt);
436  if (res == -1)
437  goto out;
438  }
439 
440  res = umount2(last, umount_flags);
441  if (res == -1 && !quiet) {
442  fprintf(stderr, "%s: failed to unmount %s: %s\n",
443  progname, mnt, strerror(errno));
444  }
445 
446 out:
447  if (res == -1)
448  return -1;
449 
450  res = chdir("/");
451  if (res == -1) {
452  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
453  return -1;
454  }
455 
456  return fuse_mnt_remove_mount(progname, mnt);
457 }
458 
459 static int unmount_fuse(const char *mnt, int quiet, int lazy)
460 {
461  int res;
462  int mtablock = lock_umount();
463 
464  res = unmount_fuse_locked(mnt, quiet, lazy);
465  unlock_umount(mtablock);
466 
467  return res;
468 }
469 
470 static int count_fuse_fs(void)
471 {
472  struct mntent *entp;
473  int count = 0;
474  const char *mtab = _PATH_MOUNTED;
475  FILE *fp = setmntent(mtab, "r");
476  if (fp == NULL) {
477  fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
478  strerror(errno));
479  return -1;
480  }
481  while ((entp = getmntent(fp)) != NULL) {
482  if (strcmp(entp->mnt_type, "fuse") == 0 ||
483  strncmp(entp->mnt_type, "fuse.", 5) == 0)
484  count ++;
485  }
486  endmntent(fp);
487  return count;
488 }
489 
490 
491 #else /* IGNORE_MTAB */
492 static int count_fuse_fs(void)
493 {
494  return 0;
495 }
496 
497 static int add_mount(const char *source, const char *mnt, const char *type,
498  const char *opts)
499 {
500  (void) source;
501  (void) mnt;
502  (void) type;
503  (void) opts;
504  return 0;
505 }
506 
507 static int unmount_fuse(const char *mnt, int quiet, int lazy)
508 {
509  (void) quiet;
510  return fuse_mnt_umount(progname, mnt, mnt, lazy);
511 }
512 #endif /* IGNORE_MTAB */
513 
514 static void strip_line(char *line)
515 {
516  char *s = strchr(line, '#');
517  if (s != NULL)
518  s[0] = '\0';
519  for (s = line + strlen(line) - 1;
520  s >= line && isspace((unsigned char) *s); s--);
521  s[1] = '\0';
522  for (s = line; isspace((unsigned char) *s); s++);
523  if (s != line)
524  memmove(line, s, strlen(s)+1);
525 }
526 
527 static void parse_line(char *line, int linenum)
528 {
529  int tmp;
530  if (strcmp(line, "user_allow_other") == 0)
531  user_allow_other = 1;
532  else if (sscanf(line, "mount_max = %i", &tmp) == 1)
533  mount_max = tmp;
534  else if(line[0])
535  fprintf(stderr,
536  "%s: unknown parameter in %s at line %i: '%s'\n",
537  progname, FUSE_CONF, linenum, line);
538 }
539 
540 static void read_conf(void)
541 {
542  FILE *fp = fopen(FUSE_CONF, "r");
543  if (fp != NULL) {
544  int linenum = 1;
545  char line[256];
546  int isnewline = 1;
547  while (fgets(line, sizeof(line), fp) != NULL) {
548  if (isnewline) {
549  if (line[strlen(line)-1] == '\n') {
550  strip_line(line);
551  parse_line(line, linenum);
552  } else {
553  isnewline = 0;
554  }
555  } else if(line[strlen(line)-1] == '\n') {
556  fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
557 
558  isnewline = 1;
559  }
560  if (isnewline)
561  linenum ++;
562  }
563  if (!isnewline) {
564  fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
565 
566  }
567  fclose(fp);
568  } else if (errno != ENOENT) {
569  fprintf(stderr, "%s: failed to open %s: %s\n",
570  progname, FUSE_CONF, strerror(errno));
571  }
572 }
573 
574 static int begins_with(const char *s, const char *beg)
575 {
576  if (strncmp(s, beg, strlen(beg)) == 0)
577  return 1;
578  else
579  return 0;
580 }
581 
582 struct mount_flags {
583  const char *opt;
584  unsigned long flag;
585  int on;
586  int safe;
587 };
588 
589 static struct mount_flags mount_flags[] = {
590  {"rw", MS_RDONLY, 0, 1},
591  {"ro", MS_RDONLY, 1, 1},
592  {"suid", MS_NOSUID, 0, 0},
593  {"nosuid", MS_NOSUID, 1, 1},
594  {"dev", MS_NODEV, 0, 0},
595  {"nodev", MS_NODEV, 1, 1},
596  {"exec", MS_NOEXEC, 0, 1},
597  {"noexec", MS_NOEXEC, 1, 1},
598  {"async", MS_SYNCHRONOUS, 0, 1},
599  {"sync", MS_SYNCHRONOUS, 1, 1},
600  {"atime", MS_NOATIME, 0, 1},
601  {"noatime", MS_NOATIME, 1, 1},
602  {"dirsync", MS_DIRSYNC, 1, 1},
603  {NULL, 0, 0, 0}
604 };
605 
606 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
607 {
608  int i;
609 
610  for (i = 0; mount_flags[i].opt != NULL; i++) {
611  const char *opt = mount_flags[i].opt;
612  if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
613  *on = mount_flags[i].on;
614  *flag = mount_flags[i].flag;
615  if (!mount_flags[i].safe && getuid() != 0) {
616  *flag = 0;
617  fprintf(stderr,
618  "%s: unsafe option %s ignored\n",
619  progname, opt);
620  }
621  return 1;
622  }
623  }
624  return 0;
625 }
626 
627 static int add_option(char **optsp, const char *opt, unsigned expand)
628 {
629  char *newopts;
630  if (*optsp == NULL)
631  newopts = strdup(opt);
632  else {
633  unsigned oldsize = strlen(*optsp);
634  unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
635  newopts = (char *) realloc(*optsp, newsize);
636  if (newopts)
637  sprintf(newopts + oldsize, ",%s", opt);
638  }
639  if (newopts == NULL) {
640  fprintf(stderr, "%s: failed to allocate memory\n", progname);
641  return -1;
642  }
643  *optsp = newopts;
644  return 0;
645 }
646 
647 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
648 {
649  int i;
650  int l;
651 
652  if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
653  return -1;
654 
655  for (i = 0; mount_flags[i].opt != NULL; i++) {
656  if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
657  add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
658  return -1;
659  }
660 
661  if (add_option(mnt_optsp, opts, 0) == -1)
662  return -1;
663  /* remove comma from end of opts*/
664  l = strlen(*mnt_optsp);
665  if ((*mnt_optsp)[l-1] == ',')
666  (*mnt_optsp)[l-1] = '\0';
667  if (getuid() != 0) {
668  const char *user = get_user_name();
669  if (user == NULL)
670  return -1;
671 
672  if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
673  return -1;
674  strcat(*mnt_optsp, user);
675  }
676  return 0;
677 }
678 
679 static int opt_eq(const char *s, unsigned len, const char *opt)
680 {
681  if(strlen(opt) == len && strncmp(s, opt, len) == 0)
682  return 1;
683  else
684  return 0;
685 }
686 
687 static int get_string_opt(const char *s, unsigned len, const char *opt,
688  char **val)
689 {
690  int i;
691  unsigned opt_len = strlen(opt);
692  char *d;
693 
694  if (*val)
695  free(*val);
696  *val = (char *) malloc(len - opt_len + 1);
697  if (!*val) {
698  fprintf(stderr, "%s: failed to allocate memory\n", progname);
699  return 0;
700  }
701 
702  d = *val;
703  s += opt_len;
704  len -= opt_len;
705  for (i = 0; i < len; i++) {
706  if (s[i] == '\\' && i + 1 < len)
707  i++;
708  *d++ = s[i];
709  }
710  *d = '\0';
711  return 1;
712 }
713 
714 static int do_mount(const char *mnt, char **typep, mode_t rootmode,
715  int fd, const char *opts, const char *dev, char **sourcep,
716  char **mnt_optsp)
717 {
718  int res;
719  int flags = MS_NOSUID | MS_NODEV;
720  char *optbuf;
721  char *mnt_opts = NULL;
722  const char *s;
723  char *d;
724  char *fsname = NULL;
725  char *subtype = NULL;
726  char *source = NULL;
727  char *type = NULL;
728  int blkdev = 0;
729 
730  optbuf = (char *) malloc(strlen(opts) + 128);
731  if (!optbuf) {
732  fprintf(stderr, "%s: failed to allocate memory\n", progname);
733  return -1;
734  }
735 
736  for (s = opts, d = optbuf; *s;) {
737  unsigned len;
738  const char *fsname_str = "fsname=";
739  const char *subtype_str = "subtype=";
740  for (len = 0; s[len]; len++) {
741  if (s[len] == '\\' && s[len + 1])
742  len++;
743  else if (s[len] == ',')
744  break;
745  }
746  if (begins_with(s, fsname_str)) {
747  if (!get_string_opt(s, len, fsname_str, &fsname))
748  goto err;
749  } else if (begins_with(s, subtype_str)) {
750  if (!get_string_opt(s, len, subtype_str, &subtype))
751  goto err;
752  } else if (opt_eq(s, len, "blkdev")) {
753  if (getuid() != 0) {
754  fprintf(stderr,
755  "%s: option blkdev is privileged\n",
756  progname);
757  goto err;
758  }
759  blkdev = 1;
760  } else if (opt_eq(s, len, "auto_unmount")) {
761  auto_unmount = 1;
762  } else if (!begins_with(s, "fd=") &&
763  !begins_with(s, "rootmode=") &&
764  !begins_with(s, "user_id=") &&
765  !begins_with(s, "group_id=")) {
766  int on;
767  int flag;
768  int skip_option = 0;
769  if (opt_eq(s, len, "large_read")) {
770  struct utsname utsname;
771  unsigned kmaj, kmin;
772  res = uname(&utsname);
773  if (res == 0 &&
774  sscanf(utsname.release, "%u.%u",
775  &kmaj, &kmin) == 2 &&
776  (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
777  fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
778  skip_option = 1;
779  }
780  }
781  if (getuid() != 0 && !user_allow_other &&
782  (opt_eq(s, len, "allow_other") ||
783  opt_eq(s, len, "allow_root"))) {
784  fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
785  goto err;
786  }
787  if (!skip_option) {
788  if (find_mount_flag(s, len, &on, &flag)) {
789  if (on)
790  flags |= flag;
791  else
792  flags &= ~flag;
793  } else {
794  memcpy(d, s, len);
795  d += len;
796  *d++ = ',';
797  }
798  }
799  }
800  s += len;
801  if (*s)
802  s++;
803  }
804  *d = '\0';
805  res = get_mnt_opts(flags, optbuf, &mnt_opts);
806  if (res == -1)
807  goto err;
808 
809  sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
810  fd, rootmode, getuid(), getgid());
811 
812  source = malloc((fsname ? strlen(fsname) : 0) +
813  (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
814 
815  type = malloc((subtype ? strlen(subtype) : 0) + 32);
816  if (!type || !source) {
817  fprintf(stderr, "%s: failed to allocate memory\n", progname);
818  goto err;
819  }
820 
821  if (subtype)
822  sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
823  else
824  strcpy(type, blkdev ? "fuseblk" : "fuse");
825 
826  if (fsname)
827  strcpy(source, fsname);
828  else
829  strcpy(source, subtype ? subtype : dev);
830 
831  res = mount(source, mnt, type, flags, optbuf);
832  if (res == -1 && errno == ENODEV && subtype) {
833  /* Probably missing subtype support */
834  strcpy(type, blkdev ? "fuseblk" : "fuse");
835  if (fsname) {
836  if (!blkdev)
837  sprintf(source, "%s#%s", subtype, fsname);
838  } else {
839  strcpy(source, type);
840  }
841 
842  res = mount(source, mnt, type, flags, optbuf);
843  }
844  if (res == -1 && errno == EINVAL) {
845  /* It could be an old version not supporting group_id */
846  sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
847  fd, rootmode, getuid());
848  res = mount(source, mnt, type, flags, optbuf);
849  }
850  if (res == -1) {
851  int errno_save = errno;
852  if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
853  fprintf(stderr, "%s: 'fuseblk' support missing\n",
854  progname);
855  else
856  fprintf(stderr, "%s: mount failed: %s\n", progname,
857  strerror(errno_save));
858  goto err;
859  }
860  *sourcep = source;
861  *typep = type;
862  *mnt_optsp = mnt_opts;
863  free(fsname);
864  free(optbuf);
865 
866  return 0;
867 
868 err:
869  free(fsname);
870  free(subtype);
871  free(source);
872  free(type);
873  free(mnt_opts);
874  free(optbuf);
875  return -1;
876 }
877 
878 static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
879 {
880  int res;
881  const char *mnt = *mntp;
882  const char *origmnt = mnt;
883 
884  res = lstat(mnt, stbuf);
885  if (res == -1) {
886  fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
887  progname, mnt, strerror(errno));
888  return -1;
889  }
890 
891  /* No permission checking is done for root */
892  if (getuid() == 0)
893  return 0;
894 
895  if (S_ISDIR(stbuf->st_mode)) {
896  res = chdir(mnt);
897  if (res == -1) {
898  fprintf(stderr,
899  "%s: failed to chdir to mountpoint: %s\n",
900  progname, strerror(errno));
901  return -1;
902  }
903  mnt = *mntp = ".";
904  res = lstat(mnt, stbuf);
905  if (res == -1) {
906  fprintf(stderr,
907  "%s: failed to access mountpoint %s: %s\n",
908  progname, origmnt, strerror(errno));
909  return -1;
910  }
911 
912  if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
913  fprintf(stderr, "%s: mountpoint %s not owned by user\n",
914  progname, origmnt);
915  return -1;
916  }
917 
918  res = access(mnt, W_OK);
919  if (res == -1) {
920  fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
921  progname, origmnt);
922  return -1;
923  }
924  } else if (S_ISREG(stbuf->st_mode)) {
925  static char procfile[256];
926  *mountpoint_fd = open(mnt, O_WRONLY);
927  if (*mountpoint_fd == -1) {
928  fprintf(stderr, "%s: failed to open %s: %s\n",
929  progname, mnt, strerror(errno));
930  return -1;
931  }
932  res = fstat(*mountpoint_fd, stbuf);
933  if (res == -1) {
934  fprintf(stderr,
935  "%s: failed to access mountpoint %s: %s\n",
936  progname, mnt, strerror(errno));
937  return -1;
938  }
939  if (!S_ISREG(stbuf->st_mode)) {
940  fprintf(stderr,
941  "%s: mountpoint %s is no longer a regular file\n",
942  progname, mnt);
943  return -1;
944  }
945 
946  sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
947  *mntp = procfile;
948  } else {
949  fprintf(stderr,
950  "%s: mountpoint %s is not a directory or a regular file\n",
951  progname, mnt);
952  return -1;
953  }
954 
955 
956  return 0;
957 }
958 
959 static int try_open(const char *dev, char **devp, int silent)
960 {
961  int fd = open(dev, O_RDWR);
962  if (fd != -1) {
963  *devp = strdup(dev);
964  if (*devp == NULL) {
965  fprintf(stderr, "%s: failed to allocate memory\n",
966  progname);
967  close(fd);
968  fd = -1;
969  }
970  } else if (errno == ENODEV ||
971  errno == ENOENT)/* check for ENOENT too, for the udev case */
972  return -2;
973  else if (!silent) {
974  fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
975  strerror(errno));
976  }
977  return fd;
978 }
979 
980 static int try_open_fuse_device(char **devp)
981 {
982  int fd;
983 
984  drop_privs();
985  fd = try_open(FUSE_DEV, devp, 0);
986  restore_privs();
987  return fd;
988 }
989 
990 static int open_fuse_device(char **devp)
991 {
992  int fd = try_open_fuse_device(devp);
993  if (fd >= -1)
994  return fd;
995 
996  fprintf(stderr,
997  "%s: fuse device not found, try 'modprobe fuse' first\n",
998  progname);
999 
1000  return -1;
1001 }
1002 
1003 
1004 static int mount_fuse(const char *mnt, const char *opts)
1005 {
1006  int res;
1007  int fd;
1008  char *dev;
1009  struct stat stbuf;
1010  char *type = NULL;
1011  char *source = NULL;
1012  char *mnt_opts = NULL;
1013  const char *real_mnt = mnt;
1014  int mountpoint_fd = -1;
1015 
1016  fd = open_fuse_device(&dev);
1017  if (fd == -1)
1018  return -1;
1019 
1020  drop_privs();
1021  read_conf();
1022 
1023  if (getuid() != 0 && mount_max != -1) {
1024  int mount_count = count_fuse_fs();
1025  if (mount_count >= mount_max) {
1026  fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1027  goto fail_close_fd;
1028  }
1029  }
1030 
1031  res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1032  restore_privs();
1033  if (res != -1)
1034  res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
1035  fd, opts, dev, &source, &mnt_opts);
1036 
1037  if (mountpoint_fd != -1)
1038  close(mountpoint_fd);
1039 
1040  if (res == -1)
1041  goto fail_close_fd;
1042 
1043  res = chdir("/");
1044  if (res == -1) {
1045  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1046  goto fail_close_fd;
1047  }
1048 
1049  if (geteuid() == 0) {
1050  res = add_mount(source, mnt, type, mnt_opts);
1051  if (res == -1) {
1052  /* Can't clean up mount in a non-racy way */
1053  goto fail_close_fd;
1054  }
1055  }
1056 
1057 out_free:
1058  free(source);
1059  free(type);
1060  free(mnt_opts);
1061  free(dev);
1062 
1063  return fd;
1064 
1065 fail_close_fd:
1066  close(fd);
1067  fd = -1;
1068  goto out_free;
1069 }
1070 
1071 static int send_fd(int sock_fd, int fd)
1072 {
1073  int retval;
1074  struct msghdr msg;
1075  struct cmsghdr *p_cmsg;
1076  struct iovec vec;
1077  size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
1078  int *p_fds;
1079  char sendchar = 0;
1080 
1081  msg.msg_control = cmsgbuf;
1082  msg.msg_controllen = sizeof(cmsgbuf);
1083  p_cmsg = CMSG_FIRSTHDR(&msg);
1084  p_cmsg->cmsg_level = SOL_SOCKET;
1085  p_cmsg->cmsg_type = SCM_RIGHTS;
1086  p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1087  p_fds = (int *) CMSG_DATA(p_cmsg);
1088  *p_fds = fd;
1089  msg.msg_controllen = p_cmsg->cmsg_len;
1090  msg.msg_name = NULL;
1091  msg.msg_namelen = 0;
1092  msg.msg_iov = &vec;
1093  msg.msg_iovlen = 1;
1094  msg.msg_flags = 0;
1095  /* "To pass file descriptors or credentials you need to send/read at
1096  * least one byte" (man 7 unix) */
1097  vec.iov_base = &sendchar;
1098  vec.iov_len = sizeof(sendchar);
1099  while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1100  if (retval != 1) {
1101  perror("sending file descriptor");
1102  return -1;
1103  }
1104  return 0;
1105 }
1106 
1107 static void usage(void)
1108 {
1109  printf("%s: [options] mountpoint\n"
1110  "Options:\n"
1111  " -h print help\n"
1112  " -V print version\n"
1113  " -o opt[,opt...] mount options\n"
1114  " -u unmount\n"
1115  " -q quiet\n"
1116  " -z lazy unmount\n",
1117  progname);
1118  exit(1);
1119 }
1120 
1121 static void show_version(void)
1122 {
1123  printf("fusermount3 version: %s\n", PACKAGE_VERSION);
1124  exit(0);
1125 }
1126 
1127 int main(int argc, char *argv[])
1128 {
1129  sigset_t sigset;
1130  int ch;
1131  int fd;
1132  int res;
1133  char *origmnt;
1134  char *mnt;
1135  static int unmount = 0;
1136  static int lazy = 0;
1137  static int quiet = 0;
1138  char *commfd;
1139  int cfd;
1140  const char *opts = "";
1141 
1142  static const struct option long_opts[] = {
1143  {"unmount", no_argument, NULL, 'u'},
1144  {"lazy", no_argument, NULL, 'z'},
1145  {"quiet", no_argument, NULL, 'q'},
1146  {"help", no_argument, NULL, 'h'},
1147  {"version", no_argument, NULL, 'V'},
1148  {0, 0, 0, 0}};
1149 
1150  progname = strdup(argv[0]);
1151  if (progname == NULL) {
1152  fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1153  exit(1);
1154  }
1155 
1156  while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
1157  NULL)) != -1) {
1158  switch (ch) {
1159  case 'h':
1160  usage();
1161  break;
1162 
1163  case 'V':
1164  show_version();
1165  break;
1166 
1167  case 'o':
1168  opts = optarg;
1169  break;
1170 
1171  case 'u':
1172  unmount = 1;
1173  break;
1174 
1175  case 'z':
1176  lazy = 1;
1177  break;
1178 
1179  case 'q':
1180  quiet = 1;
1181  break;
1182 
1183  default:
1184  exit(1);
1185  }
1186  }
1187 
1188  if (lazy && !unmount) {
1189  fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1190  exit(1);
1191  }
1192 
1193  if (optind >= argc) {
1194  fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1195  exit(1);
1196  } else if (argc > optind + 1) {
1197  fprintf(stderr, "%s: extra arguments after the mountpoint\n",
1198  progname);
1199  exit(1);
1200  }
1201 
1202  origmnt = argv[optind];
1203 
1204  drop_privs();
1205  mnt = fuse_mnt_resolve_path(progname, origmnt);
1206  if (mnt != NULL) {
1207  res = chdir("/");
1208  if (res == -1) {
1209  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1210  goto err_out;
1211  }
1212  }
1213  restore_privs();
1214  if (mnt == NULL)
1215  exit(1);
1216 
1217  umask(033);
1218  if (unmount)
1219  goto do_unmount;
1220 
1221  commfd = getenv(FUSE_COMMFD_ENV);
1222  if (commfd == NULL) {
1223  fprintf(stderr, "%s: old style mounting not supported\n",
1224  progname);
1225  goto err_out;
1226  }
1227 
1228  fd = mount_fuse(mnt, opts);
1229  if (fd == -1)
1230  goto err_out;
1231 
1232  cfd = atoi(commfd);
1233  res = send_fd(cfd, fd);
1234  if (res == -1)
1235  goto err_out;
1236  close(fd);
1237 
1238  if (!auto_unmount) {
1239  free(mnt);
1240  return 0;
1241  }
1242 
1243  /* Become a daemon and wait for the parent to exit or die.
1244  ie For the control socket to get closed.
1245  btw We don't want to use daemon() function here because
1246  it forks and messes with the file descriptors. */
1247  setsid();
1248  res = chdir("/");
1249  if (res == -1) {
1250  fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1251  goto err_out;
1252  }
1253 
1254  sigfillset(&sigset);
1255  sigprocmask(SIG_BLOCK, &sigset, NULL);
1256 
1257  lazy = 1;
1258  quiet = 1;
1259 
1260  while (1) {
1261  unsigned char buf[16];
1262  int n = recv(cfd, buf, sizeof(buf), 0);
1263  if (!n)
1264  break;
1265 
1266  if (n < 0) {
1267  if (errno == EINTR)
1268  continue;
1269  break;
1270  }
1271  }
1272 
1273 do_unmount:
1274  if (geteuid() == 0)
1275  res = unmount_fuse(mnt, quiet, lazy);
1276  else {
1277  res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
1278  if (res == -1 && !quiet)
1279  fprintf(stderr,
1280  "%s: failed to unmount %s: %s\n",
1281  progname, mnt, strerror(errno));
1282  }
1283  if (res == -1)
1284  goto err_out;
1285  return 0;
1286 
1287 err_out:
1288  free(mnt);
1289  exit(1);
1290 }