summaryrefslogtreecommitdiff
path: root/libfuse-lite/mount.c (plain)
blob: 0bb3aee54545578ca7efdccb00d199b636fef73b
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 LGPLv2.
6 See the file COPYING.LIB.
7*/
8
9#include "config.h"
10#include "fuse_i.h"
11#include "fuse_opt.h"
12#include "mount_util.h"
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <stddef.h>
18#include <fcntl.h>
19#include <errno.h>
20#include <sys/poll.h>
21#include <sys/socket.h>
22#include <sys/un.h>
23#include <sys/wait.h>
24#include <sys/mount.h>
25
26#ifndef MS_DIRSYNC
27#define MS_DIRSYNC 128
28#endif
29
30enum {
31 KEY_KERN_FLAG,
32 KEY_KERN_OPT,
33 KEY_FUSERMOUNT_OPT,
34 KEY_SUBTYPE_OPT,
35 KEY_MTAB_OPT,
36 KEY_ALLOW_ROOT,
37 KEY_RO,
38 KEY_HELP,
39 KEY_VERSION,
40};
41
42struct mount_opts {
43 int allow_other;
44 int allow_root;
45 int ishelp;
46 int flags;
47 int blkdev;
48 char *fsname;
49 char *mtab_opts;
50 char *fusermount_opts;
51 char *kernel_opts;
52};
53
54#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
55
56static const struct fuse_opt fuse_mount_opts[] = {
57 FUSE_MOUNT_OPT("allow_other", allow_other),
58 FUSE_MOUNT_OPT("allow_root", allow_root),
59 FUSE_MOUNT_OPT("blkdev", blkdev),
60 FUSE_MOUNT_OPT("fsname=%s", fsname),
61 FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
62 FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
63 FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
64 FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
65 FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
66 FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
67 FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
68 FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
69 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
70 FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
71 FUSE_OPT_KEY("-r", KEY_RO),
72 FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
73 FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
74 FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
75 FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
76 FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
77 FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
78 FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
79 FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
80 FUSE_OPT_KEY("async", KEY_KERN_FLAG),
81 FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
82 FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
83 FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
84 FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
85 FUSE_OPT_KEY("-h", KEY_HELP),
86 FUSE_OPT_KEY("--help", KEY_HELP),
87 FUSE_OPT_KEY("-V", KEY_VERSION),
88 FUSE_OPT_KEY("--version", KEY_VERSION),
89 FUSE_OPT_END
90};
91
92struct mount_flags {
93 const char *opt;
94 unsigned long flag;
95 int on;
96};
97
98static struct mount_flags mount_flags[] = {
99 {"rw", MS_RDONLY, 0},
100 {"ro", MS_RDONLY, 1},
101 {"suid", MS_NOSUID, 0},
102 {"nosuid", MS_NOSUID, 1},
103 {"dev", MS_NODEV, 0},
104 {"nodev", MS_NODEV, 1},
105 {"exec", MS_NOEXEC, 0},
106 {"noexec", MS_NOEXEC, 1},
107 {"async", MS_SYNCHRONOUS, 0},
108 {"sync", MS_SYNCHRONOUS, 1},
109 {"atime", MS_NOATIME, 0},
110 {"noatime", MS_NOATIME, 1},
111 {"dirsync", MS_DIRSYNC, 1},
112 {NULL, 0, 0}
113};
114
115static void set_mount_flag(const char *s, int *flags)
116{
117 int i;
118
119 for (i = 0; mount_flags[i].opt != NULL; i++) {
120 const char *opt = mount_flags[i].opt;
121 if (strcmp(opt, s) == 0) {
122 if (mount_flags[i].on)
123 *flags |= mount_flags[i].flag;
124 else
125 *flags &= ~mount_flags[i].flag;
126 return;
127 }
128 }
129 fprintf(stderr, "fuse: internal error, can't find mount flag\n");
130 abort();
131}
132
133static int fuse_mount_opt_proc(void *data, const char *arg, int key,
134 struct fuse_args *outargs)
135{
136 struct mount_opts *mo = data;
137
138 switch (key) {
139 case KEY_ALLOW_ROOT:
140 if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
141 fuse_opt_add_arg(outargs, "-oallow_root") == -1)
142 return -1;
143 return 0;
144
145 case KEY_RO:
146 arg = "ro";
147 /* fall through */
148 case KEY_KERN_FLAG:
149 set_mount_flag(arg, &mo->flags);
150 return 0;
151
152 case KEY_KERN_OPT:
153 return fuse_opt_add_opt(&mo->kernel_opts, arg);
154
155 case KEY_FUSERMOUNT_OPT:
156 return fuse_opt_add_opt(&mo->fusermount_opts, arg);
157
158 case KEY_MTAB_OPT:
159 return fuse_opt_add_opt(&mo->mtab_opts, arg);
160
161 case KEY_HELP:
162 mo->ishelp = 1;
163 break;
164
165 case KEY_VERSION:
166 mo->ishelp = 1;
167 break;
168 }
169 return 1;
170}
171
172void fuse_kern_unmount(const char *mountpoint, int fd)
173{
174 int res;
175
176 if (!mountpoint)
177 return;
178
179 if (fd != -1) {
180 struct pollfd pfd;
181
182 pfd.fd = fd;
183 pfd.events = 0;
184 res = poll(&pfd, 1, 0);
185 /* If file poll returns POLLERR on the device file descriptor,
186 then the filesystem is already unmounted */
187 if (res == 1 && (pfd.revents & POLLERR))
188 return;
189 }
190 close(fd);
191
192 fusermount(1, 0, 1, "", mountpoint);
193}
194
195static int get_mnt_flag_opts(char **mnt_optsp, int flags)
196{
197 int i;
198
199 if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
200 return -1;
201
202 for (i = 0; mount_flags[i].opt != NULL; i++) {
203 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
204 fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
205 return -1;
206 }
207 return 0;
208}
209
210int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
211{
212 struct mount_opts mo;
213 int res = -1;
214 char *mnt_opts = NULL;
215
216 memset(&mo, 0, sizeof(mo));
217 if (getuid())
218 mo.flags = MS_NOSUID | MS_NODEV;
219
220 if (args &&
221 fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
222 return -1;
223
224 if (mo.allow_other && mo.allow_root) {
225 fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
226 goto out;
227 }
228 res = 0;
229 if (mo.ishelp)
230 goto out;
231
232 res = -1;
233 if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
234 goto out;
235 if (!(mo.flags & MS_NODEV) && fuse_opt_add_opt(&mnt_opts, "dev") == -1)
236 goto out;
237 if (!(mo.flags & MS_NOSUID) && fuse_opt_add_opt(&mnt_opts, "suid") == -1)
238 goto out;
239 if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
240 goto out;
241 if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
242 goto out;
243 if (mo.fusermount_opts && fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) < 0)
244 goto out;
245
246 res = fusermount(0, 0, 0, mnt_opts ? mnt_opts : "", mountpoint);
247
248out:
249 free(mnt_opts);
250 free(mo.fsname);
251 free(mo.fusermount_opts);
252 free(mo.kernel_opts);
253 free(mo.mtab_opts);
254 return res;
255}
256
257