2 FUSE: Filesystem in Userspace
3 Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB.
10 #include "fuse_misc.h"
15 #include <sys/sysctl.h>
27 #define FUSERMOUNT_PROG "mount_fusefs"
28 #define FUSE_DEV_TRUNK "/dev/fuse"
45 #define FUSE_DUAL_OPT_KEY(templ, key) \
46 FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
48 static const struct fuse_opt fuse_mount_opts
[] = {
49 { "allow_other", offsetof(struct mount_opts
, allow_other
), 1 },
50 { "allow_root", offsetof(struct mount_opts
, allow_root
), 1 },
51 FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT
),
52 FUSE_OPT_KEY("-r", KEY_RO
),
53 FUSE_OPT_KEY("-h", KEY_HELP
),
54 FUSE_OPT_KEY("--help", KEY_HELP
),
55 FUSE_OPT_KEY("-V", KEY_VERSION
),
56 FUSE_OPT_KEY("--version", KEY_VERSION
),
57 /* standard FreeBSD mount options */
58 FUSE_DUAL_OPT_KEY("dev", KEY_KERN
),
59 FUSE_DUAL_OPT_KEY("async", KEY_KERN
),
60 FUSE_DUAL_OPT_KEY("atime", KEY_KERN
),
61 FUSE_DUAL_OPT_KEY("dev", KEY_KERN
),
62 FUSE_DUAL_OPT_KEY("exec", KEY_KERN
),
63 FUSE_DUAL_OPT_KEY("suid", KEY_KERN
),
64 FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN
),
65 FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN
),
66 FUSE_DUAL_OPT_KEY("sync", KEY_KERN
),
67 FUSE_DUAL_OPT_KEY("union", KEY_KERN
),
68 FUSE_DUAL_OPT_KEY("userquota", KEY_KERN
),
69 FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN
),
70 FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN
),
71 FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN
),
72 FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN
),
73 FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN
),
74 FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN
),
75 FUSE_DUAL_OPT_KEY("acls", KEY_KERN
),
76 FUSE_DUAL_OPT_KEY("force", KEY_KERN
),
77 FUSE_DUAL_OPT_KEY("update", KEY_KERN
),
78 FUSE_DUAL_OPT_KEY("ro", KEY_KERN
),
79 FUSE_DUAL_OPT_KEY("rw", KEY_KERN
),
80 FUSE_DUAL_OPT_KEY("auto", KEY_KERN
),
81 /* options supported under both Linux and FBSD */
82 FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN
),
83 FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN
),
84 FUSE_OPT_KEY("max_read=", KEY_KERN
),
85 FUSE_OPT_KEY("subtype=", KEY_KERN
),
86 /* FBSD FUSE specific mount options */
87 FUSE_DUAL_OPT_KEY("private", KEY_KERN
),
88 FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN
),
89 FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN
),
90 FUSE_OPT_KEY("nosync_unmount", KEY_KERN
),
91 /* stock FBSD mountopt parsing routine lets anything be negated... */
93 * Linux specific mount options, but let just the mount util
96 FUSE_OPT_KEY("fsname=", KEY_KERN
),
97 FUSE_OPT_KEY("nonempty", KEY_KERN
),
98 FUSE_OPT_KEY("large_read", KEY_KERN
),
102 static void mount_help(void)
105 " -o allow_root allow access to root\n"
107 system(FUSERMOUNT_PROG
" --help");
111 static void mount_version(void)
113 system(FUSERMOUNT_PROG
" --version");
116 static int fuse_mount_opt_proc(void *data
, const char *arg
, int key
,
117 struct fuse_args
*outargs
)
119 struct mount_opts
*mo
= data
;
123 if (fuse_opt_add_opt(&mo
->kernel_opts
, "allow_other") == -1 ||
124 fuse_opt_add_arg(outargs
, "-oallow_root") == -1)
133 return fuse_opt_add_opt(&mo
->kernel_opts
, arg
);
148 void fuse_unmount_compat22(const char *mountpoint
)
151 char *ssc
, *umount_cmd
;
155 /* error message is annoying in help output */
157 "/usr/bin/fstat " FUSE_DEV_TRUNK
"* | "
158 "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; "
159 " { if ($3 == %d) print $10; }' | "
162 "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'";
167 * If we don't know the fd, we have to resort to the scripted
168 * solution -- iterating over the fd-s is unpractical, as we
169 * don't know how many of open files we have. (This could be
170 * looked up in procfs -- however, that's optional on FBSD; or
171 * read out from the kmem -- however, that's bound to
172 * privileges (in fact, that's what happens when we call the
173 * setgid kmem fstat(1) utility).
175 if (asprintf(&ssc
, seekscript
, getpid()) == -1)
179 sf
= popen(ssc
, "r");
184 fgets(dev
, sizeof(dev
), sf
);
189 if (asprintf(&umount_cmd
, "/sbin/umount %s", dev
) == -1)
195 static void do_unmount(char *dev
, int fd
)
197 char device_path
[SPECNAMELEN
+ 12];
199 const char umount_cmd
[] = "/sbin/umount";
202 snprintf(device_path
, SPECNAMELEN
+ 12, _PATH_DEV
"%s", dev
);
204 argv
[0] = umount_cmd
;
206 argv
[2] = device_path
;
216 execvp(umount_cmd
, (char **)argv
);
220 waitpid(pid
, NULL
, 0);
223 void fuse_kern_unmount(const char *mountpoint
, int fd
)
230 if (fstat(fd
, &sbuf
) == -1)
233 devname_r(sbuf
.st_rdev
, S_IFCHR
, dev
, 128);
235 if (strncmp(dev
, "fuse", 4))
238 strtol(dev
+ 4, &ep
, 10);
245 /* Check if kernel is doing init in background */
246 static int init_backgrounded(void)
252 if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg
, &len
, NULL
, 0))
259 static int fuse_mount_core(const char *mountpoint
, const char *opts
)
261 const char *mountprog
= FUSERMOUNT_PROG
;
267 fdnam
= getenv("FUSE_DEV_FD");
272 fd
= strtol(fdnam
, &ep
, 10);
275 fprintf(stderr
, "invalid value given in FUSE_DEV_FD\n");
285 dev
= getenv("FUSE_DEV_NAME");
288 dev
= (char *)FUSE_DEV_TRUNK
;
290 if ((fd
= open(dev
, O_RDWR
)) < 0) {
291 perror("fuse: failed to open fuse device");
296 if (getenv("FUSE_NO_MOUNT") || ! mountpoint
)
303 perror("fuse: fork() failed");
309 if (! init_backgrounded()) {
311 * If init is not backgrounded, we have to
312 * call the mount util backgrounded, to avoid
319 perror("fuse: fork() failed");
326 const char *argv
[32];
329 if (! fdnam
&& asprintf(&fdnam
, "%d", fd
) == -1) {
330 perror("fuse: failed to assemble mount arguments");
334 argv
[a
++] = mountprog
;
340 argv
[a
++] = mountpoint
;
342 execvp(mountprog
, (char **) argv
);
343 perror("fuse: failed to exec mount program");
350 if (waitpid(cpid
, &status
, 0) == -1 || WEXITSTATUS(status
) != 0) {
351 perror("fuse: failed to mount file system");
360 int fuse_kern_mount(const char *mountpoint
, struct fuse_args
*args
)
362 struct mount_opts mo
;
365 memset(&mo
, 0, sizeof(mo
));
366 /* mount util should not try to spawn the daemon */
367 setenv("MOUNT_FUSEFS_SAFE", "1", 1);
368 /* to notify the mount util it's called from lib */
369 setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
372 fuse_opt_parse(args
, &mo
, fuse_mount_opts
, fuse_mount_opt_proc
) == -1)
375 if (mo
.allow_other
&& mo
.allow_root
) {
376 fprintf(stderr
, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
382 res
= fuse_mount_core(mountpoint
, mo
.kernel_opts
);
384 free(mo
.kernel_opts
);