libfuse

mount.fuse.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
9 #include <config.h>
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <errno.h>
16 #include <stdint.h>
17
18 static char *progname;
19
20 static char *xstrdup(const char *s)
21 {
22 char *t = strdup(s);
23 if (!t) {
24 fprintf(stderr, "%s: failed to allocate memory\n", progname);
25 exit(1);
26 }
27 return t;
28 }
29
30 static void *xrealloc(void *oldptr, size_t size)
31 {
32 void *ptr = realloc(oldptr, size);
33 if (!ptr) {
34 fprintf(stderr, "%s: failed to allocate memory\n", progname);
35 exit(1);
36 }
37 return ptr;
38 }
39
40 static void add_arg(char **cmdp, const char *opt)
41 {
42 size_t optlen = strlen(opt);
43 size_t cmdlen = *cmdp ? strlen(*cmdp) : 0;
44 if (optlen >= (SIZE_MAX - cmdlen - 4)/4) {
45 fprintf(stderr, "%s: argument too long\n", progname);
46 exit(1);
47 }
48 char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4);
49 char *s;
50 s = cmd + cmdlen;
51 if (*cmdp)
52 *s++ = ' ';
53
54 *s++ = '\'';
55 for (; *opt; opt++) {
56 if (*opt == '\'') {
57 *s++ = '\'';
58 *s++ = '\\';
59 *s++ = '\'';
60 *s++ = '\'';
61 } else
62 *s++ = *opt;
63 }
64 *s++ = '\'';
65 *s = '\0';
66 *cmdp = cmd;
67 }
68
69 static char *add_option(const char *opt, char *options)
70 {
71 int oldlen = options ? strlen(options) : 0;
72
73 options = xrealloc(options, oldlen + 1 + strlen(opt) + 1);
74 if (!oldlen)
75 strcpy(options, opt);
76 else {
77 strcat(options, ",");
78 strcat(options, opt);
79 }
80 return options;
81 }
82
83 int main(int argc, char *argv[])
84 {
85 char *type = NULL;
86 char *source;
87 const char *mountpoint;
88 char *basename;
89 char *options = NULL;
90 char *command = NULL;
91 char *setuid = NULL;
92 int i;
93 int dev = 1;
94 int suid = 1;
95
96 progname = argv[0];
97 basename = strrchr(argv[0], '/');
98 if (basename)
99 basename++;
100 else
101 basename = argv[0];
102
103 if (strncmp(basename, "mount.fuse.", 11) == 0)
104 type = basename + 11;
105 if (strncmp(basename, "mount.fuseblk.", 14) == 0)
106 type = basename + 14;
107
108 if (type && !type[0])
109 type = NULL;
110
111 if (argc < 3) {
112 fprintf(stderr,
113 "usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
114 progname, type ? "source" : "type#[source]");
115 exit(1);
116 }
117
118 source = argv[1];
119 if (!source[0])
120 source = NULL;
121
122 mountpoint = argv[2];
123
124 for (i = 3; i < argc; i++) {
125 if (strcmp(argv[i], "-v") == 0) {
126 continue;
127 } else if (strcmp(argv[i], "-t") == 0) {
128 i++;
129
130 if (i == argc) {
131 fprintf(stderr,
132 "%s: missing argument to option '-t'\n",
133 progname);
134 exit(1);
135 }
136 type = argv[i];
137 if (strncmp(type, "fuse.", 5) == 0)
138 type += 5;
139 else if (strncmp(type, "fuseblk.", 8) == 0)
140 type += 8;
141
142 if (!type[0]) {
143 fprintf(stderr,
144 "%s: empty type given as argument to option '-t'\n",
145 progname);
146 exit(1);
147 }
148 } else if (strcmp(argv[i], "-o") == 0) {
149 char *opts;
150 char *opt;
151 i++;
152 if (i == argc)
153 break;
154
155 opts = xstrdup(argv[i]);
156 opt = strtok(opts, ",");
157 while (opt) {
158 int j;
159 int ignore = 0;
160 const char *ignore_opts[] = { "",
161 "user",
162 "nofail",
163 "nouser",
164 "users",
165 "auto",
166 "noauto",
167 "_netdev",
168 NULL};
169 if (strncmp(opt, "setuid=", 7) == 0) {
170 setuid = xstrdup(opt + 7);
171 ignore = 1;
172 }
173 for (j = 0; ignore_opts[j]; j++)
174 if (strcmp(opt, ignore_opts[j]) == 0)
175 ignore = 1;
176
177 if (!ignore) {
178 if (strcmp(opt, "nodev") == 0)
179 dev = 0;
180 else if (strcmp(opt, "nosuid") == 0)
181 suid = 0;
182
183 options = add_option(opt, options);
184 }
185 opt = strtok(NULL, ",");
186 }
187 }
188 }
189
190 if (dev)
191 options = add_option("dev", options);
192 if (suid)
193 options = add_option("suid", options);
194
195 if (!type) {
196 if (source) {
197 type = xstrdup(source);
198 source = strchr(type, '#');
199 if (source)
200 *source++ = '\0';
201 if (!type[0]) {
202 fprintf(stderr, "%s: empty filesystem type\n",
203 progname);
204 exit(1);
205 }
206 } else {
207 fprintf(stderr, "%s: empty source\n", progname);
208 exit(1);
209 }
210 }
211
212 add_arg(&command, type);
213 if (source)
214 add_arg(&command, source);
215 add_arg(&command, mountpoint);
216 if (options) {
217 add_arg(&command, "-o");
218 add_arg(&command, options);
219 }
220
221 if (setuid && setuid[0]) {
222 char *sucommand = command;
223 command = NULL;
224 add_arg(&command, "su");
225 add_arg(&command, "-");
226 add_arg(&command, setuid);
227 add_arg(&command, "-c");
228 add_arg(&command, sucommand);
229 } else if (!getenv("HOME")) {
230 /* Hack to make filesystems work in the boot environment */
231 setenv("HOME", "/root", 0);
232 }
233
234 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
235 fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
236 strerror(errno));
237 return 1;
238 }