VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/sharedfolders/mount.vboxsf.c@ 20998

Last change on this file since 20998 was 16099, checked in by vboxsync, 16 years ago

Linux shared folders: ignore noauto option

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.2 KB
Line 
1/** @file
2 * vboxvfs -- VirtualBox Guest Additions for Linux: mount(8) helper
3 *
4 * Parses options provided by mount (or user directly)
5 * Packs them into struct vbsfmount and passes to mount(2)
6 * Optionally adds entries to mtab
7 */
8
9/*
10 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
21 * Clara, CA 95054 USA or visit http://www.sun.com if you need
22 * additional information or have any questions.
23 */
24
25
26#ifndef _GNU_SOURCE
27#define _GNU_SOURCE
28#endif
29
30/* #define DEBUG */
31#define DBG if (0)
32#include <errno.h>
33#include <fcntl.h>
34#include <ctype.h>
35#include <getopt.h>
36#include <mntent.h>
37#include <pwd.h>
38#include <stdarg.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <sys/mount.h>
43#include <sys/stat.h>
44#include <sys/types.h>
45#include <unistd.h>
46#include <mntent.h>
47#include <limits.h>
48#include <iconv.h>
49
50#include "vbsfmount.h"
51
52/* Compile-time assertion. If a == 0, we get two identical switch cases, which is not
53 allowed. */
54#define CT_ASSERT(a) \
55 do { \
56 switch(0) { case 0: case (a): ; } \
57 } while (0)
58
59struct opts
60{
61 int uid;
62 int gid;
63 int ttl;
64 int dmode;
65 int fmode;
66 int dmask;
67 int fmask;
68 int ronly;
69 int noexec;
70 int nodev;
71 int nosuid;
72 int remount;
73 char nls_name[MAX_NLS_NAME];
74 char *convertcp;
75};
76
77#define PANIC_ATTR __attribute ((noreturn, __format__ (__printf__, 1, 2)))
78
79static void PANIC_ATTR
80panic (const char *fmt, ...)
81{
82 va_list ap;
83
84 va_start (ap, fmt);
85 vfprintf (stderr, fmt, ap);
86 va_end (ap);
87 exit (EXIT_FAILURE);
88}
89
90static void PANIC_ATTR
91panic_err (const char *fmt, ...)
92{
93 va_list ap;
94 int errno_code = errno;
95
96 va_start (ap, fmt);
97 vfprintf (stderr, fmt, ap);
98 va_end (ap);
99 fprintf (stderr, ": %s\n", strerror (errno_code));
100 exit (EXIT_FAILURE);
101}
102
103static int
104safe_atoi (const char *s, size_t size, int base)
105{
106 char *endptr;
107 long long int val = strtoll (s, &endptr, base);
108
109 if (val < INT_MIN || val > INT_MAX || endptr < s + size)
110 {
111 errno = ERANGE;
112 panic_err ("could not convert %.*s to integer, result = %d",
113 (int)size, s, (int) val);
114 }
115 return (int) val;
116}
117
118static void
119process_mount_opts (const char *s, struct opts *opts)
120{
121 const char *next = s;
122 size_t len;
123 typedef enum handler_opt
124 {
125 HORW,
126 HORO,
127 HOUID,
128 HOGID,
129 HOTTL,
130 HODMODE,
131 HOFMODE,
132 HOUMASK,
133 HODMASK,
134 HOFMASK,
135 HOIOCHARSET,
136 HOCONVERTCP,
137 HONOEXEC,
138 HOEXEC,
139 HONODEV,
140 HODEV,
141 HONOSUID,
142 HOSUID,
143 HOREMOUNT,
144 HONOAUTO
145 } handler_opt;
146 struct
147 {
148 const char *name;
149 handler_opt opt;
150 int has_arg;
151 const char *desc;
152 } handlers[]
153 =
154 {
155 {"rw", HORW, 0, "mount read write (default)"},
156 {"ro", HORO, 0, "mount read only"},
157 {"uid", HOUID, 1, "default file owner user id"},
158 {"gid", HOGID, 1, "default file owner group id"},
159 {"ttl", HOTTL, 1, "time to live for dentry"},
160 {"iocharset", HOIOCHARSET, 1, "i/o charset (default utf8)"},
161 {"convertcp", HOCONVERTCP, 1, "convert share name from given charset to utf8"},
162 {"dmode", HODMODE, 1, "mode of all directories"},
163 {"fmode", HOFMODE, 1, "mode of all regular files"},
164 {"umask", HOUMASK, 1, "umask of directories and regular files"},
165 {"dmask", HODMASK, 1, "umask of directories"},
166 {"fmask", HOFMASK, 1, "umask of regular files"},
167 {"noexec", HONOEXEC, 0, 0 }, /* don't document these options directly here */
168 {"exec", HOEXEC, 0, 0 }, /* as they are well known and described in the */
169 {"nodev", HONODEV, 0, 0 }, /* usual manpages */
170 {"dev", HODEV, 0, 0 },
171 {"nosuid", HONOSUID, 0, 0 },
172 {"suid", HOSUID, 0, 0 },
173 {"remount", HOREMOUNT, 0, 0 },
174 {"noauto", HONOAUTO, 0, 0 },
175 {NULL, 0, 0, NULL}
176 }, *handler;
177
178 while (next)
179 {
180 const char *val;
181 size_t key_len, val_len;
182
183 s = next;
184 next = strchr (s, ',');
185 if (!next)
186 {
187 len = strlen (s);
188 }
189 else
190 {
191 len = next - s;
192 next += 1;
193 if (!*next)
194 next = 0;
195 }
196
197 val = NULL;
198 val_len = 0;
199 for (key_len = 0; key_len < len; ++key_len)
200 {
201 if (s[key_len] == '=')
202 {
203 if (key_len + 1 < len)
204 {
205 val = s + key_len + 1;
206 val_len = len - key_len - 1;
207 }
208 break;
209 }
210 }
211
212 for (handler = handlers; handler->name; ++handler)
213 {
214 size_t j;
215 for (j = 0; j < key_len && handler->name[j] == s[j]; ++j)
216 ;
217
218 if (j == key_len && !handler->name[j])
219 {
220 if (handler->has_arg)
221 {
222 if (!(val && *val))
223 {
224 panic ("%.*s requires an argument (i.e. %.*s=<arg>)\n",
225 (int)len, s, (int)len, s);
226 }
227 }
228
229 switch(handler->opt)
230 {
231 case HORW:
232 opts->ronly = 0;
233 break;
234 case HORO:
235 opts->ronly = 1;
236 break;
237 case HONOEXEC:
238 opts->noexec = 1;
239 break;
240 case HOEXEC:
241 opts->noexec = 0;
242 break;
243 case HONODEV:
244 opts->nodev = 1;
245 break;
246 case HODEV:
247 opts->nodev = 0;
248 break;
249 case HONOSUID:
250 opts->nosuid = 1;
251 break;
252 case HOSUID:
253 opts->nosuid = 0;
254 break;
255 case HOREMOUNT:
256 opts->remount = 1;
257 break;
258 case HOUID:
259 opts->uid = safe_atoi (val, val_len, 10);
260 break;
261 case HOGID:
262 opts->gid = safe_atoi (val, val_len, 10);
263 break;
264 case HOTTL:
265 opts->ttl = safe_atoi (val, val_len, 10);
266 break;
267 case HODMODE:
268 opts->dmode = safe_atoi (val, val_len, 8);
269 break;
270 case HOFMODE:
271 opts->fmode = safe_atoi (val, val_len, 8);
272 break;
273 case HOUMASK:
274 opts->dmask = opts->fmask = safe_atoi (val, val_len, 8);
275 break;
276 case HODMASK:
277 opts->dmask = safe_atoi (val, val_len, 8);
278 break;
279 case HOFMASK:
280 opts->fmask = safe_atoi (val, val_len, 8);
281 break;
282 case HOIOCHARSET:
283 if (val_len + 1 > sizeof (opts->nls_name))
284 {
285 panic ("iocharset name too long\n");
286 }
287 memcpy (opts->nls_name, val, val_len);
288 opts->nls_name[val_len] = 0;
289 break;
290 case HOCONVERTCP:
291 opts->convertcp = malloc (val_len + 1);
292 if (!opts->convertcp)
293 {
294 panic_err ("could not allocate memory");
295 }
296 memcpy (opts->convertcp, val, val_len);
297 opts->convertcp[val_len] = 0;
298 break;
299 case HONOAUTO:
300 break;
301 }
302 break;
303 }
304 continue;
305 }
306
307 if (!handler->name)
308 {
309 fprintf (stderr, "unknown mount option `%.*s'\n", (int)len, s);
310 fprintf (stderr, "valid options:\n");
311
312 for (handler = handlers; handler->name; ++handler)
313 {
314 if (handler->desc)
315 fprintf (stderr, " %-10s%s %s\n", handler->name,
316 handler->has_arg ? "=<arg>" : "", handler->desc);
317 }
318 exit (EXIT_FAILURE);
319 }
320 }
321}
322
323static void
324complete (char *host_name, char *mount_point,
325 unsigned long flags, struct opts *opts)
326{
327 FILE *f, *m;
328 char *buf;
329 size_t size;
330 struct mntent e;
331
332 m = open_memstream (&buf, &size);
333 if (!m)
334 panic_err ("could not update mount table (failed to create memstream)");
335
336 if (opts->uid)
337 fprintf (m, "uid=%d,", opts->uid);
338 if (opts->gid)
339 fprintf (m, "gid=%d,", opts->gid);
340 if (opts->ttl)
341 fprintf (m, "ttl=%d,", opts->ttl);
342 if (*opts->nls_name)
343 fprintf (m, "iocharset=%s,", opts->nls_name);
344 if (flags & MS_NOSUID)
345 fprintf (m, "%s,", MNTOPT_NOSUID);
346 if (flags & MS_RDONLY)
347 fprintf (m, "%s,", MNTOPT_RO);
348 else
349 fprintf (m, "%s,", MNTOPT_RW);
350
351 fclose (m);
352
353 if (size > 0)
354 buf[size - 1] = 0;
355 else
356 buf = "defaults";
357
358 f = setmntent (MOUNTED, "a+");
359 if (!f)
360 panic_err ("could not open mount table for update");
361
362 e.mnt_fsname = host_name;
363 e.mnt_dir = mount_point;
364 e.mnt_type = "vboxsf";
365 e.mnt_opts = buf;
366 e.mnt_freq = 0;
367 e.mnt_passno = 0;
368
369 if (addmntent (f, &e))
370 {
371 if (size > 0)
372 {
373 memset (buf, 0, size);
374 free (buf);
375 }
376 panic_err ("could not add an entry to the mount table");
377 }
378
379 endmntent (f);
380
381 if (size > 0)
382 {
383 memset (buf, 0, size);
384 free (buf);
385 }
386}
387
388static void
389convertcp (char *in_codeset, char *host_name, struct vbsf_mount_info_new *info)
390{
391 char *i = host_name;
392 char *o = info->name;
393 size_t ib = strlen (host_name);
394 size_t ob = sizeof (info->name) - 1;
395 iconv_t cd;
396
397 cd = iconv_open ("UTF-8", in_codeset);
398 if (cd == (iconv_t) -1)
399 {
400 panic_err ("could not convert share name, iconv_open `%s' failed",
401 in_codeset);
402 }
403
404 while (ib)
405 {
406 size_t c = iconv (cd, &i, &ib, &o, &ob);
407 if (c == (size_t) -1)
408 {
409 panic_err ("could not convert share name(%s) at %d",
410 host_name, (int)(strlen (host_name) - ib));
411 }
412 }
413 *o = 0;
414}
415
416
417/**
418 * Print out a usage message and exit.
419 *
420 * @param name The name of the application
421 */
422static void __attribute ((noreturn)) usage(char *name)
423{
424 printf("Usage: %s [OPTIONS] NAME MOUNTPOINT\n"
425 "Mount the VirtualBox shared folder NAME from the host system to MOUNTPOINT.\n"
426 "\n"
427 " -w mount the shared folder writably (the default)\n"
428 " -r mount the shared folder read-only\n"
429 " -n do not create an mtab entry\n"
430 " -o OPTION[,OPTION...] use the mount options specified\n"
431 "\n", name);
432 printf("Available mount options are:\n"
433 " rw mount writably (the default)\n"
434 " ro mount read only\n"
435 " uid=UID set the default file owner user id to UID\n"
436 " gid=GID set the default file owner group id to GID\n"
437 " ttl=TTL set the \"time to live\" to TID for the dentry\n");
438 printf(" dmode=MODE override the mode of all directories to (octal) MODE\n"
439 " fmode=MODE override the mode of all regular files to (octal) MODE\n"
440 " umask=UMASK set the umask to (octal) UMASK\n");
441 printf(" dmask=UMASK set the umask applied to directories only\n"
442 " fmask=UMASK set the umask applied to regular files only\n"
443 " iocharset CHARSET use the character set CHARSET for I/O operations\n"
444 " (default set is utf8)\n"
445 " convertcp CHARSET convert the folder name from CHARSET to utf8\n"
446 "\n");
447 printf("Less common used options:\n"
448 " noexec,exec,nodev,dev,nosuid,suid\n");
449 exit(1);
450}
451
452int
453main (int argc, char **argv)
454{
455 int c;
456 int err;
457 int nomtab = 0;
458 unsigned long flags = MS_NODEV;
459 char *host_name;
460 char *mount_point;
461 struct vbsf_mount_info_new mntinf;
462 struct opts opts =
463 {
464 0, /* uid */
465 0, /* gid */
466 0, /* ttl */
467 ~0, /* dmode */
468 ~0, /* fmode*/
469 0, /* dmask */
470 0, /* fmask */
471 0, /* ronly */
472 0, /* noexec */
473 0, /* nodev */
474 0, /* nosuid */
475 0, /* remount */
476 "\0", /* nls_name */
477 NULL, /* convertcp */
478 };
479
480 mntinf.nullchar = '\0';
481 mntinf.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0;
482 mntinf.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1;
483 mntinf.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2;
484 mntinf.length = sizeof(mntinf);
485
486 if (getuid ())
487 panic ("Only root can mount shared folders from the host.\n");
488
489 if (!argv[0])
490 argv[0] = "mount.vboxsf";
491
492 /* Compile-time assertions */
493 CT_ASSERT(sizeof(uid_t) == sizeof(int));
494 CT_ASSERT(sizeof(gid_t) == sizeof(int));
495
496 while ((c = getopt (argc, argv, "rwno:h")) != -1)
497 {
498 switch (c)
499 {
500 default:
501 fprintf (stderr, "unknown option `%c:%#x'\n", c, c);
502 case '?':
503 case 'h':
504 usage(argv[0]);
505
506 case 'r':
507 opts.ronly = 1;
508 break;
509
510 case 'w':
511 opts.ronly = 0;
512
513 case 'o':
514 process_mount_opts (optarg, &opts);
515 break;
516
517 case 'n':
518 nomtab = 1;
519 break;
520 }
521 }
522
523 if (argc - optind < 2)
524 usage(argv[0]);
525
526 host_name = argv[optind];
527 mount_point = argv[optind + 1];
528
529 if (opts.convertcp)
530 convertcp (opts.convertcp, host_name, &mntinf);
531 else
532 {
533 if (strlen (host_name) > MAX_HOST_NAME - 1)
534 panic ("host name is too big\n");
535
536 strcpy (mntinf.name, host_name);
537 }
538
539 if (strlen (opts.nls_name) > MAX_NLS_NAME - 1)
540 panic ("%s: the character set name for I/O is too long.\n", argv[0]);
541
542 strcpy (mntinf.nls_name, opts.nls_name);
543
544 if (opts.ronly)
545 flags |= MS_RDONLY;
546 if (opts.noexec)
547 flags |= MS_NOEXEC;
548 if (opts.nodev)
549 flags |= MS_NODEV;
550
551 mntinf.uid = opts.uid;
552 mntinf.gid = opts.gid;
553 mntinf.ttl = opts.ttl;
554 mntinf.dmode = opts.dmode;
555 mntinf.fmode = opts.fmode;
556 mntinf.dmask = opts.dmask;
557 mntinf.fmask = opts.fmask;
558
559 err = mount (NULL, mount_point, "vboxsf", flags, &mntinf);
560 if (err == -1 && errno == EPROTO)
561 {
562 /* New mount tool with old vboxsf module? Try again using the old
563 * vbsf_mount_info_old structure. */
564 struct vbsf_mount_info_old mntinf_old;
565 memcpy(&mntinf_old.name, &mntinf.name, MAX_HOST_NAME);
566 memcpy(&mntinf_old.nls_name, mntinf.nls_name, MAX_NLS_NAME);
567 mntinf_old.uid = mntinf.uid;
568 mntinf_old.gid = mntinf.gid;
569 mntinf_old.ttl = mntinf.ttl;
570 err = mount (NULL, mount_point, "vboxsf", flags, &mntinf_old);
571 }
572 if (err)
573 panic_err ("%s: mounting failed with the error", argv[0]);
574
575 if (!nomtab)
576 complete (host_name, mount_point, flags, &opts);
577
578 exit (EXIT_SUCCESS);
579}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette