VirtualBox

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

Last change on this file since 12726 was 11567, checked in by vboxsync, 16 years ago

Linux additions: shared folders memset fix

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