VirtualBox

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

Last change on this file since 6734 was 6734, checked in by vboxsync, 17 years ago

Don't list the header in SOURCES, this isn't automake.

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

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