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