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 }