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 }