libfuse
mount_bsd.c
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
4 
5  Architecture specific file system mounting (FreeBSD).
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 
16 #include <sys/param.h>
17 #include "fuse_mount_compat.h"
18 
19 #include <sys/stat.h>
20 #include <sys/wait.h>
21 #include <sys/sysctl.h>
22 #include <sys/user.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <stddef.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <paths.h>
31 #include <limits.h>
32 
33 #define FUSERMOUNT_PROG "mount_fusefs"
34 #define FUSE_DEV_TRUNK "/dev/fuse"
35 
36 enum {
37  KEY_RO,
38  KEY_KERN
39 };
40 
41 struct mount_opts {
42  int allow_other;
43  char *kernel_opts;
44  unsigned max_read;
45 };
46 
47 #define FUSE_DUAL_OPT_KEY(templ, key) \
48  FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
49 
50 static const struct fuse_opt fuse_mount_opts[] = {
51  { "allow_other", offsetof(struct mount_opts, allow_other), 1 },
52  { "max_read=%u", offsetof(struct mount_opts, max_read), 1 },
53  FUSE_OPT_KEY("-r", KEY_RO),
54  /* standard FreeBSD mount options */
55  FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
56  FUSE_DUAL_OPT_KEY("async", KEY_KERN),
57  FUSE_DUAL_OPT_KEY("atime", KEY_KERN),
58  FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
59  FUSE_DUAL_OPT_KEY("exec", KEY_KERN),
60  FUSE_DUAL_OPT_KEY("suid", KEY_KERN),
61  FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN),
62  FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN),
63  FUSE_DUAL_OPT_KEY("sync", KEY_KERN),
64  FUSE_DUAL_OPT_KEY("union", KEY_KERN),
65  FUSE_DUAL_OPT_KEY("userquota", KEY_KERN),
66  FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN),
67  FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN),
68  FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN),
69  FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN),
70  FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN),
71  FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN),
72  FUSE_DUAL_OPT_KEY("acls", KEY_KERN),
73  FUSE_DUAL_OPT_KEY("force", KEY_KERN),
74  FUSE_DUAL_OPT_KEY("update", KEY_KERN),
75  FUSE_DUAL_OPT_KEY("ro", KEY_KERN),
76  FUSE_DUAL_OPT_KEY("rw", KEY_KERN),
77  FUSE_DUAL_OPT_KEY("auto", KEY_KERN),
78  FUSE_DUAL_OPT_KEY("automounted", KEY_KERN),
79  /* options supported under both Linux and FBSD */
80  FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN),
81  FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
82  FUSE_OPT_KEY("max_read=", KEY_KERN),
83  FUSE_OPT_KEY("subtype=", KEY_KERN),
84  /* FBSD FUSE specific mount options */
85  FUSE_DUAL_OPT_KEY("private", KEY_KERN),
86  FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN),
87  FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN),
88  FUSE_OPT_KEY("nosync_unmount", KEY_KERN),
89 #if __FreeBSD_version >= 1200519
90  FUSE_DUAL_OPT_KEY("intr", KEY_KERN),
91 #endif
92  /* stock FBSD mountopt parsing routine lets anything be negated... */
93  /*
94  * Linux specific mount options, but let just the mount util
95  * handle them
96  */
97  FUSE_OPT_KEY("fsname=", KEY_KERN),
99 };
100 
101 void fuse_mount_version(void)
102 {
103  system(FUSERMOUNT_PROG " --version");
104 }
105 
106 unsigned get_max_read(struct mount_opts *o)
107 {
108  return o->max_read;
109 }
110 
111 static int fuse_mount_opt_proc(void *data, const char *arg, int key,
112  struct fuse_args *outargs)
113 {
114  (void) outargs;
115  struct mount_opts *mo = data;
116 
117  switch (key) {
118  case KEY_RO:
119  arg = "ro";
120  /* fall through */
121 
122  case KEY_KERN:
123  return fuse_opt_add_opt(&mo->kernel_opts, arg);
124  }
125 
126  /* Pass through unknown options */
127  return 1;
128 }
129 
130 void fuse_kern_unmount(const char *mountpoint, int fd)
131 {
132  close(fd);
133  unmount(mountpoint, MNT_FORCE);
134 }
135 
136 /* Check if kernel is doing init in background */
137 static int init_backgrounded(void)
138 {
139  unsigned ibg;
140  size_t len;
141 
142  len = sizeof(ibg);
143 
144  if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
145  return 0;
146 
147  return ibg;
148 }
149 
150 
151 static int fuse_mount_core(const char *mountpoint, const char *opts)
152 {
153  const char *mountprog = FUSERMOUNT_PROG;
154  int fd;
155  char *fdnam, *dev;
156  pid_t pid, cpid;
157  int status;
158 
159  fdnam = getenv("FUSE_DEV_FD");
160 
161  if (fdnam) {
162  char *ep;
163 
164  fd = strtol(fdnam, &ep, 10);
165 
166  if (*ep != '\0') {
167  fuse_log(FUSE_LOG_ERR, "invalid value given in FUSE_DEV_FD\n");
168  return -1;
169  }
170 
171  if (fd < 0)
172  return -1;
173 
174  goto mount;
175  }
176 
177  dev = getenv("FUSE_DEV_NAME");
178 
179  if (! dev)
180  dev = (char *)FUSE_DEV_TRUNK;
181 
182  if ((fd = open(dev, O_RDWR)) < 0) {
183  perror("fuse: failed to open fuse device");
184  return -1;
185  }
186 
187 mount:
188  if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
189  goto out;
190 
191  pid = fork();
192  cpid = pid;
193 
194  if (pid == -1) {
195  perror("fuse: fork() failed");
196  close(fd);
197  return -1;
198  }
199 
200  if (pid == 0) {
201  if (! init_backgrounded()) {
202  /*
203  * If init is not backgrounded, we have to
204  * call the mount util backgrounded, to avoid
205  * deadlock.
206  */
207 
208  pid = fork();
209 
210  if (pid == -1) {
211  perror("fuse: fork() failed");
212  close(fd);
213  exit(1);
214  }
215  }
216 
217  if (pid == 0) {
218  const char *argv[32];
219  int a = 0;
220  int ret = -1;
221 
222  if (! fdnam)
223  {
224  ret = asprintf(&fdnam, "%d", fd);
225  if(ret == -1)
226  {
227  perror("fuse: failed to assemble mount arguments");
228  close(fd);
229  exit(1);
230  }
231  }
232 
233  argv[a++] = mountprog;
234  if (opts) {
235  argv[a++] = "-o";
236  argv[a++] = opts;
237  }
238  argv[a++] = fdnam;
239  argv[a++] = mountpoint;
240  argv[a++] = NULL;
241  execvp(mountprog, (char **) argv);
242  perror("fuse: failed to exec mount program");
243  free(fdnam);
244  exit(1);
245  }
246 
247  exit(0);
248  }
249 
250  if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
251  perror("fuse: failed to mount file system");
252  close(fd);
253  return -1;
254  }
255 
256 out:
257  return fd;
258 }
259 
260 struct mount_opts *parse_mount_opts(struct fuse_args *args)
261 {
262  struct mount_opts *mo;
263 
264  mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
265  if (mo == NULL)
266  return NULL;
267 
268  memset(mo, 0, sizeof(struct mount_opts));
269 
270  if (args &&
271  fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
272  goto err_out;
273 
274  return mo;
275 
276 err_out:
277  destroy_mount_opts(mo);
278  return NULL;
279 }
280 
281 void destroy_mount_opts(struct mount_opts *mo)
282 {
283  free(mo->kernel_opts);
284  free(mo);
285 }
286 
287 int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
288 {
289  /* mount util should not try to spawn the daemon */
290  setenv("MOUNT_FUSEFS_SAFE", "1", 1);
291  /* to notify the mount util it's called from lib */
292  setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
293 
294  return fuse_mount_core(mountpoint, mo->kernel_opts);
295 }
void fuse_log(enum fuse_log_level level, const char *fmt,...)
Definition: fuse_log.c:33
#define FUSE_OPT_KEY(templ, key)
Definition: fuse_opt.h:98
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(char **opts, const char *opt)
Definition: fuse_opt.c:139
#define FUSE_OPT_END
Definition: fuse_opt.h:104