"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.10.4/doc/html/fuse-3_810_83_2lib_2mount_8c_source.html" (9 Jun 2021, 93953 Bytes) of package /linux/misc/fuse-3.10.4.tar.xz:


Caution: In this restricted "Fossies" environment the current HTML page may not be correctly presentated and may have some non-functional links. You can here alternatively try to browse the pure source code or just view or download the uninterpreted raw source code. If the rendering is insufficient you may try to find and view the page on the project site itself.

libfuse
mount.c
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4 
5  Architecture specific file system mounting (Linux).
6 
7  This program can be distributed under the terms of the GNU LGPLv2.
8  See the file COPYING.LIB.
9 */
10 
11 #include "config.h"
12 #include "fuse_i.h"
13 #include "fuse_misc.h"
14 #include "fuse_opt.h"
15 #include "mount_util.h"
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <stddef.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <poll.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/wait.h>
28 #include <sys/mount.h>
29 
30 #ifdef __NetBSD__
31 #include <perfuse.h>
32 
33 #define MS_RDONLY MNT_RDONLY
34 #define MS_NOSUID MNT_NOSUID
35 #define MS_NODEV MNT_NODEV
36 #define MS_NOEXEC MNT_NOEXEC
37 #define MS_SYNCHRONOUS MNT_SYNCHRONOUS
38 #define MS_NOATIME MNT_NOATIME
39 
40 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
41 #endif
42 
43 #define FUSERMOUNT_PROG "fusermount3"
44 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
45 
46 #ifndef HAVE_FORK
47 #define fork() vfork()
48 #endif
49 
50 #ifndef MS_DIRSYNC
51 #define MS_DIRSYNC 128
52 #endif
53 
54 enum {
55  KEY_KERN_FLAG,
56  KEY_KERN_OPT,
57  KEY_FUSERMOUNT_OPT,
58  KEY_SUBTYPE_OPT,
59  KEY_MTAB_OPT,
60  KEY_ALLOW_OTHER,
61  KEY_RO,
62 };
63 
64 struct mount_opts {
65  int allow_other;
66  int flags;
67  int auto_unmount;
68  int blkdev;
69  char *fsname;
70  char *subtype;
71  char *subtype_opt;
72  char *mtab_opts;
73  char *fusermount_opts;
74  char *kernel_opts;
75  unsigned max_read;
76 };
77 
78 #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
79 
80 static const struct fuse_opt fuse_mount_opts[] = {
81  FUSE_MOUNT_OPT("allow_other", allow_other),
82  FUSE_MOUNT_OPT("blkdev", blkdev),
83  FUSE_MOUNT_OPT("auto_unmount", auto_unmount),
84  FUSE_MOUNT_OPT("fsname=%s", fsname),
85  FUSE_MOUNT_OPT("max_read=%u", max_read),
86  FUSE_MOUNT_OPT("subtype=%s", subtype),
87  FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
88  FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT),
89  FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
90  FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
91  FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
92  FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
93  FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
94  FUSE_OPT_KEY("context=", KEY_KERN_OPT),
95  FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT),
96  FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT),
97  FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT),
98  FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
99  FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
100  FUSE_OPT_KEY("-r", KEY_RO),
101  FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
102  FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
103  FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
104  FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
105  FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
106  FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
107  FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
108  FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
109  FUSE_OPT_KEY("async", KEY_KERN_FLAG),
110  FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
111  FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
112  FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
113  FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
115 };
116 
117 static void exec_fusermount(const char *argv[])
118 {
119  execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
120  execvp(FUSERMOUNT_PROG, (char **) argv);
121 }
122 
123 void fuse_mount_version(void)
124 {
125  int pid = fork();
126  if (!pid) {
127  const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
128  exec_fusermount(argv);
129  _exit(1);
130  } else if (pid != -1)
131  waitpid(pid, NULL, 0);
132 }
133 
134 struct mount_flags {
135  const char *opt;
136  unsigned long flag;
137  int on;
138 };
139 
140 static const struct mount_flags mount_flags[] = {
141  {"rw", MS_RDONLY, 0},
142  {"ro", MS_RDONLY, 1},
143  {"suid", MS_NOSUID, 0},
144  {"nosuid", MS_NOSUID, 1},
145  {"dev", MS_NODEV, 0},
146  {"nodev", MS_NODEV, 1},
147  {"exec", MS_NOEXEC, 0},
148  {"noexec", MS_NOEXEC, 1},
149  {"async", MS_SYNCHRONOUS, 0},
150  {"sync", MS_SYNCHRONOUS, 1},
151  {"atime", MS_NOATIME, 0},
152  {"noatime", MS_NOATIME, 1},
153 #ifndef __NetBSD__
154  {"dirsync", MS_DIRSYNC, 1},
155 #endif
156  {NULL, 0, 0}
157 };
158 
159 unsigned get_max_read(struct mount_opts *o)
160 {
161  return o->max_read;
162 }
163 
164 static void set_mount_flag(const char *s, int *flags)
165 {
166  int i;
167 
168  for (i = 0; mount_flags[i].opt != NULL; i++) {
169  const char *opt = mount_flags[i].opt;
170  if (strcmp(opt, s) == 0) {
171  if (mount_flags[i].on)
172  *flags |= mount_flags[i].flag;
173  else
174  *flags &= ~mount_flags[i].flag;
175  return;
176  }
177  }
178  fuse_log(FUSE_LOG_ERR, "fuse: internal error, can't find mount flag\n");
179  abort();
180 }
181 
182 static int fuse_mount_opt_proc(void *data, const char *arg, int key,
183  struct fuse_args *outargs)
184 {
185  (void) outargs;
186  struct mount_opts *mo = data;
187 
188  switch (key) {
189  case KEY_RO:
190  arg = "ro";
191  /* fall through */
192  case KEY_KERN_FLAG:
193  set_mount_flag(arg, &mo->flags);
194  return 0;
195 
196  case KEY_KERN_OPT:
197  return fuse_opt_add_opt(&mo->kernel_opts, arg);
198 
199  case KEY_FUSERMOUNT_OPT:
200  return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg);
201 
202  case KEY_SUBTYPE_OPT:
203  return fuse_opt_add_opt(&mo->subtype_opt, arg);
204 
205  case KEY_MTAB_OPT:
206  return fuse_opt_add_opt(&mo->mtab_opts, arg);
207  }
208 
209  /* Pass through unknown options */
210  return 1;
211 }
212 
213 /* return value:
214  * >= 0 => fd
215  * -1 => error
216  */
217 static int receive_fd(int fd)
218 {
219  struct msghdr msg;
220  struct iovec iov;
221  char buf[1];
222  int rv;
223  size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
224  struct cmsghdr *cmsg;
225 
226  iov.iov_base = buf;
227  iov.iov_len = 1;
228 
229  memset(&msg, 0, sizeof(msg));
230  msg.msg_name = 0;
231  msg.msg_namelen = 0;
232  msg.msg_iov = &iov;
233  msg.msg_iovlen = 1;
234  /* old BSD implementations should use msg_accrights instead of
235  * msg_control; the interface is different. */
236  msg.msg_control = ccmsg;
237  msg.msg_controllen = sizeof(ccmsg);
238 
239  while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
240  if (rv == -1) {
241  perror("recvmsg");
242  return -1;
243  }
244  if(!rv) {
245  /* EOF */
246  return -1;
247  }
248 
249  cmsg = CMSG_FIRSTHDR(&msg);
250  if (cmsg->cmsg_type != SCM_RIGHTS) {
251  fuse_log(FUSE_LOG_ERR, "got control message of unknown type %d\n",
252  cmsg->cmsg_type);
253  return -1;
254  }
255  return *(int*)CMSG_DATA(cmsg);
256 }
257 
258 void fuse_kern_unmount(const char *mountpoint, int fd)
259 {
260  int res;
261  int pid;
262 
263  if (fd != -1) {
264  struct pollfd pfd;
265 
266  pfd.fd = fd;
267  pfd.events = 0;
268  res = poll(&pfd, 1, 0);
269 
270  /* Need to close file descriptor, otherwise synchronous umount
271  would recurse into filesystem, and deadlock.
272 
273  Caller expects fuse_kern_unmount to close the fd, so close it
274  anyway. */
275  close(fd);
276 
277  /* If file poll returns POLLERR on the device file descriptor,
278  then the filesystem is already unmounted or the connection
279  was severed via /sys/fs/fuse/connections/NNN/abort */
280  if (res == 1 && (pfd.revents & POLLERR))
281  return;
282  }
283 
284  if (geteuid() == 0) {
285  fuse_mnt_umount("fuse", mountpoint, mountpoint, 1);
286  return;
287  }
288 
289  res = umount2(mountpoint, 2);
290  if (res == 0)
291  return;
292 
293  pid = fork();
294  if(pid == -1)
295  return;
296 
297  if(pid == 0) {
298  const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",
299  "--", mountpoint, NULL };
300 
301  exec_fusermount(argv);
302  _exit(1);
303  }
304  waitpid(pid, NULL, 0);
305 }
306 
307 static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
308  const char *opts, int quiet)
309 {
310  int fds[2], pid;
311  int res;
312  int rv;
313 
314  if (!mountpoint) {
315  fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
316  return -1;
317  }
318 
319  res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
320  if(res == -1) {
321  perror("fuse: socketpair() failed");
322  return -1;
323  }
324 
325  pid = fork();
326  if(pid == -1) {
327  perror("fuse: fork() failed");
328  close(fds[0]);
329  close(fds[1]);
330  return -1;
331  }
332 
333  if(pid == 0) {
334  char env[10];
335  const char *argv[32];
336  int a = 0;
337 
338  if (quiet) {
339  int fd = open("/dev/null", O_RDONLY);
340  if (fd != -1) {
341  dup2(fd, 1);
342  dup2(fd, 2);
343  }
344  }
345 
346  argv[a++] = FUSERMOUNT_PROG;
347  if (opts) {
348  argv[a++] = "-o";
349  argv[a++] = opts;
350  }
351  argv[a++] = "--";
352  argv[a++] = mountpoint;
353  argv[a++] = NULL;
354 
355  close(fds[1]);
356  fcntl(fds[0], F_SETFD, 0);
357  snprintf(env, sizeof(env), "%i", fds[0]);
358  setenv(FUSE_COMMFD_ENV, env, 1);
359  exec_fusermount(argv);
360  perror("fuse: failed to exec fusermount3");
361  _exit(1);
362  }
363 
364  close(fds[0]);
365  rv = receive_fd(fds[1]);
366 
367  if (!mo->auto_unmount) {
368  /* with auto_unmount option fusermount3 will not exit until
369  this socket is closed */
370  close(fds[1]);
371  waitpid(pid, NULL, 0); /* bury zombie */
372  }
373 
374  if (rv >= 0)
375  fcntl(rv, F_SETFD, FD_CLOEXEC);
376 
377  return rv;
378 }
379 
380 #ifndef O_CLOEXEC
381 #define O_CLOEXEC 0
382 #endif
383 
384 static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
385  const char *mnt_opts)
386 {
387  char tmp[128];
388  const char *devname = "/dev/fuse";
389  char *source = NULL;
390  char *type = NULL;
391  struct stat stbuf;
392  int fd;
393  int res;
394 
395  if (!mnt) {
396  fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
397  return -1;
398  }
399 
400  res = stat(mnt, &stbuf);
401  if (res == -1) {
402  fuse_log(FUSE_LOG_ERR, "fuse: failed to access mountpoint %s: %s\n",
403  mnt, strerror(errno));
404  return -1;
405  }
406 
407  if (mo->auto_unmount) {
408  /* Tell the caller to fallback to fusermount3 because
409  auto-unmount does not work otherwise. */
410  return -2;
411  }
412 
413  fd = open(devname, O_RDWR | O_CLOEXEC);
414  if (fd == -1) {
415  if (errno == ENODEV || errno == ENOENT)
416  fuse_log(FUSE_LOG_ERR, "fuse: device not found, try 'modprobe fuse' first\n");
417  else
418  fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n",
419  devname, strerror(errno));
420  return -1;
421  }
422  if (!O_CLOEXEC)
423  fcntl(fd, F_SETFD, FD_CLOEXEC);
424 
425  snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
426  fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
427 
428  res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
429  if (res == -1)
430  goto out_close;
431 
432  source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
433  (mo->subtype ? strlen(mo->subtype) : 0) +
434  strlen(devname) + 32);
435 
436  type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
437  if (!type || !source) {
438  fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate memory\n");
439  goto out_close;
440  }
441 
442  strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
443  if (mo->subtype) {
444  strcat(type, ".");
445  strcat(type, mo->subtype);
446  }
447  strcpy(source,
448  mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
449 
450  res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
451  if (res == -1 && errno == ENODEV && mo->subtype) {
452  /* Probably missing subtype support */
453  strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
454  if (mo->fsname) {
455  if (!mo->blkdev)
456  sprintf(source, "%s#%s", mo->subtype,
457  mo->fsname);
458  } else {
459  strcpy(source, type);
460  }
461  res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
462  }
463  if (res == -1) {
464  /*
465  * Maybe kernel doesn't support unprivileged mounts, in this
466  * case try falling back to fusermount3
467  */
468  if (errno == EPERM) {
469  res = -2;
470  } else {
471  int errno_save = errno;
472  if (mo->blkdev && errno == ENODEV &&
473  !fuse_mnt_check_fuseblk())
474  fuse_log(FUSE_LOG_ERR,
475  "fuse: 'fuseblk' support missing\n");
476  else
477  fuse_log(FUSE_LOG_ERR, "fuse: mount failed: %s\n",
478  strerror(errno_save));
479  }
480 
481  goto out_close;
482  }
483 
484 #ifndef IGNORE_MTAB
485  if (geteuid() == 0) {
486  char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
487  res = -1;
488  if (!newmnt)
489  goto out_umount;
490 
491  res = fuse_mnt_add_mount("fuse", source, newmnt, type,
492  mnt_opts);
493  free(newmnt);
494  if (res == -1)
495  goto out_umount;
496  }
497 #endif /* IGNORE_MTAB */
498  free(type);
499  free(source);
500 
501  return fd;
502 
503 out_umount:
504  umount2(mnt, 2); /* lazy umount */
505 out_close:
506  free(type);
507  free(source);
508  close(fd);
509  return res;
510 }
511 
512 static int get_mnt_flag_opts(char **mnt_optsp, int flags)
513 {
514  int i;
515 
516  if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
517  return -1;
518 
519  for (i = 0; mount_flags[i].opt != NULL; i++) {
520  if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
521  fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
522  return -1;
523  }
524  return 0;
525 }
526 
527 struct mount_opts *parse_mount_opts(struct fuse_args *args)
528 {
529  struct mount_opts *mo;
530 
531  mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
532  if (mo == NULL)
533  return NULL;
534 
535  memset(mo, 0, sizeof(struct mount_opts));
536  mo->flags = MS_NOSUID | MS_NODEV;
537 
538  if (args &&
539  fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
540  goto err_out;
541 
542  return mo;
543 
544 err_out:
545  destroy_mount_opts(mo);
546  return NULL;
547 }
548 
549 void destroy_mount_opts(struct mount_opts *mo)
550 {
551  free(mo->fsname);
552  free(mo->subtype);
553  free(mo->fusermount_opts);
554  free(mo->subtype_opt);
555  free(mo->kernel_opts);
556  free(mo->mtab_opts);
557  free(mo);
558 }
559 
560 
561 int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
562 {
563  int res = -1;
564  char *mnt_opts = NULL;
565 
566  res = -1;
567  if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
568  goto out;
569  if (mo->kernel_opts && fuse_opt_add_opt(&mnt_opts, mo->kernel_opts) == -1)
570  goto out;
571  if (mo->mtab_opts && fuse_opt_add_opt(&mnt_opts, mo->mtab_opts) == -1)
572  goto out;
573 
574  res = fuse_mount_sys(mountpoint, mo, mnt_opts);
575  if (res == -2) {
576  if (mo->fusermount_opts &&
577  fuse_opt_add_opt(&mnt_opts, mo->fusermount_opts) == -1)
578  goto out;
579 
580  if (mo->subtype) {
581  char *tmp_opts = NULL;
582 
583  res = -1;
584  if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
585  fuse_opt_add_opt(&tmp_opts, mo->subtype_opt) == -1) {
586  free(tmp_opts);
587  goto out;
588  }
589 
590  res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
591  free(tmp_opts);
592  if (res == -1)
593  res = fuse_mount_fusermount(mountpoint, mo,
594  mnt_opts, 0);
595  } else {
596  res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
597  }
598  }
599 out:
600  free(mnt_opts);
601  return res;
602 }
#define FUSE_OPT_KEY(templ, key)
Definition: fuse_opt.h:98
int fuse_opt_add_opt(char **opts, const char *opt)
Definition: fuse_opt.c:139
#define FUSE_OPT_END
Definition: fuse_opt.h:104
void fuse_log(enum fuse_log_level level, const char *fmt,...)
Definition: fuse_log.c:33
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:398
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
Definition: fuse_opt.c:144