VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp@ 33857

Last change on this file since 33857 was 33857, checked in by vboxsync, 14 years ago

Typo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.0 KB
Line 
1/* $Id: VBoxServiceAutoMount.cpp 33857 2010-11-08 15:49:08Z vboxsync $ */
2/** @file
3 * VBoxService - Auto-mounting for Shared Folders.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <iprt/assert.h>
23#include <iprt/dir.h>
24#include <iprt/mem.h>
25#include <iprt/path.h>
26#include <iprt/string.h>
27#include <iprt/semaphore.h>
28#include <VBox/VBoxGuestLib.h>
29#include "VBoxServiceInternal.h"
30#include "VBoxServiceUtils.h"
31
32#include <errno.h>
33#include <grp.h>
34#include <sys/mount.h>
35#ifdef RT_OS_SOLARIS
36# include <sys/mntent.h>
37# include <sys/mnttab.h>
38# include <sys/vfs.h>
39#else
40# include <mntent.h>
41# include <paths.h>
42#endif
43#include <unistd.h>
44
45RT_C_DECLS_BEGIN
46#include "../../linux/sharedfolders/vbsfmount.h"
47RT_C_DECLS_END
48
49#ifdef RT_OS_SOLARIS
50# define AUTO_MOUNT_POINT "/mnt/%s%s"
51#else
52# define AUTO_MOUNT_POINT "/media/%s%s"
53#endif
54
55#ifndef _PATH_MOUNTED
56 #define _PATH_MOUNTED "/etc/mtab"
57#endif
58
59/*******************************************************************************
60* Global Variables *
61*******************************************************************************/
62/** The semaphore we're blocking on. */
63static RTSEMEVENTMULTI g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
64
65
66/** @copydoc VBOXSERVICE::pfnPreInit */
67static DECLCALLBACK(int) VBoxServiceAutoMountPreInit(void)
68{
69 return VINF_SUCCESS;
70}
71
72
73/** @copydoc VBOXSERVICE::pfnOption */
74static DECLCALLBACK(int) VBoxServiceAutoMountOption(const char **ppszShort, int argc, char **argv, int *pi)
75{
76 NOREF(ppszShort);
77 NOREF(argc);
78 NOREF(argv);
79 NOREF(pi);
80 return VINF_SUCCESS;
81}
82
83
84/** @copydoc VBOXSERVICE::pfnInit */
85static DECLCALLBACK(int) VBoxServiceAutoMountInit(void)
86{
87 VBoxServiceVerbose(3, "VBoxServiceAutoMountInit\n");
88
89 int rc = RTSemEventMultiCreate(&g_AutoMountEvent);
90 AssertRCReturn(rc, rc);
91
92 return rc;
93}
94
95
96static bool VBoxServiceAutoMountShareIsMounted(const char *pszShare,
97 char *pszMountPoint, size_t cbMountPoint)
98{
99 AssertPtrReturn(pszShare, VERR_INVALID_PARAMETER);
100 AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
101 AssertReturn(cbMountPoint, VERR_INVALID_PARAMETER);
102
103 bool fMounted = false;
104 /* @todo What to do if we have a relative path in mtab instead
105 * of an absolute one ("temp" vs. "/media/temp")?
106 * procfs contains the full path but not the actual share name ...
107 * FILE *pFh = setmntent("/proc/mounts", "r+t"); */
108#ifdef RT_OS_SOLARIS
109 FILE *pFh = fopen(_PATH_MOUNTED, "r");
110 if (!pFh)
111 VBoxServiceError("VBoxServiceAutoMountShareIsMounted: Could not open mtab!\n");
112 else
113 {
114 mnttab mntTab;
115 while ((getmntent(pFh, &mntTab)))
116 {
117 if (!RTStrICmp(mntTab->mnt_special, pszShare))
118 {
119 fMounted = RTStrPrintf(pszMountPoint, cbMountPoint, "%s", pMntEnt->mnt_mountp)
120 ? true : false;
121 break;
122 }
123 }
124 fclose(pFh);
125 }
126#else
127 FILE *pFh = setmntent(_PATH_MOUNTED, "r+t");
128 if (pFh == NULL)
129 VBoxServiceError("VBoxServiceAutoMountShareIsMounted: Could not open mtab!\n");
130 else
131 {
132 mntent *pMntEnt;
133 while ((pMntEnt = getmntent(pFh)))
134 {
135 if (!RTStrICmp(pMntEnt->mnt_fsname, pszShare))
136 {
137 fMounted = RTStrPrintf(pszMountPoint, cbMountPoint, "%s", pMntEnt->mnt_dir)
138 ? true : false;
139 break;
140 }
141 }
142 endmntent(pFh);
143 }
144#endif
145 return fMounted;
146}
147
148
149static int VBoxServiceAutoMountUnmount(const char *pszMountPoint)
150{
151 AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
152
153 int rc = VINF_SUCCESS;
154 uint8_t uTries = 0;
155 int r;
156 while (uTries++ < 3)
157 {
158 r = umount(pszMountPoint);
159 if (r == 0)
160 break;
161 RTThreadSleep(5000); /* Wait a while ... */
162 }
163 if (r == -1)
164 rc = RTErrConvertFromErrno(errno);
165 return rc;
166}
167
168
169static int VBoxServiceAutoMountPrepareMountPoint(const char *pszMountPoint, const char *pszShareName,
170 vbsf_mount_opts *pOpts)
171{
172 AssertPtrReturn(pOpts, VERR_INVALID_PARAMETER);
173 AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
174 AssertPtrReturn(pszShareName, VERR_INVALID_PARAMETER);
175
176 RTFMODE fMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG; /* Owner (=root) and the group (=vboxsf) have full access. */
177 int rc = RTDirCreateFullPath(pszMountPoint, fMode);
178 if (RT_SUCCESS(rc))
179 {
180 rc = RTPathSetOwnerEx(pszMountPoint, ~0 /* Owner, unchanged */, pOpts->gid, RTPATH_F_ON_LINK);
181 if (RT_SUCCESS(rc))
182 {
183 rc = RTPathSetMode(pszMountPoint, fMode);
184 if (RT_FAILURE(rc))
185 VBoxServiceError(": Could not set mode %RTfmode for mount directory \"%s\", rc = %Rrc\n",
186 fMode, pszMountPoint, rc);
187 }
188 else
189 VBoxServiceError("VBoxServiceAutoMountPrepareMountPoint: Could not set permissions for mount directory \"%s\", rc = %Rrc\n",
190 pszMountPoint, rc);
191 }
192 else
193 VBoxServiceError("VBoxServiceAutoMountPrepareMountPoint: Could not create mount directory \"%s\" with mode %RTfmode, rc = %Rrc\n",
194 pszMountPoint, fMode, rc);
195 return rc;
196}
197
198
199static int VBoxServiceAutoMountSharedFolder(const char *pszShareName, const char *pszMountPoint,
200 vbsf_mount_opts *pOpts)
201{
202 AssertPtr(pOpts);
203
204 int rc;
205 char szAlreadyMountedTo[RTPATH_MAX];
206 /* If a Shared Folder already is mounted but not to our desired mount point,
207 * do an unmount first! */
208 if ( VBoxServiceAutoMountShareIsMounted(pszShareName, szAlreadyMountedTo, sizeof(szAlreadyMountedTo))
209 && RTStrICmp(pszMountPoint, szAlreadyMountedTo))
210 {
211 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already mounted to \"%s\", unmounting ...\n",
212 pszShareName, szAlreadyMountedTo);
213 rc = VBoxServiceAutoMountUnmount(szAlreadyMountedTo);
214 if (RT_FAILURE(rc))
215 VBoxServiceError("VBoxServiceAutoMountWorker: Failed to unmount \"%s\", %s (%d)!\n",
216 szAlreadyMountedTo, strerror(errno), errno);
217 }
218
219 if (RT_SUCCESS(rc))
220 rc = VBoxServiceAutoMountPrepareMountPoint(pszMountPoint, pszShareName, pOpts);
221 if (RT_SUCCESS(rc))
222 {
223#ifdef RT_OS_SOLARIS
224 int flags = 0; /* No flags used yet. */
225 int r = mount(pszShareName,
226 pszMountPoint,
227 flags,
228 "vboxsf",
229 NULL, /* char *dataptr */
230 0, /* int datalen */
231 NULL, /* char *optptr */
232 0); /* int optlen */
233 if (r == 0)
234 {
235 VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);
236 }
237 else
238 {
239 if (errno != EBUSY) /* Share is already mounted? Then skip error msg. */
240 VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\", error = %s\n",
241 pszShareName, pszMountPoint, strerror(errno));
242 }
243#else /* !RT_OS_SOLARIS */
244 unsigned long flags = MS_NODEV;
245
246 const char *szOptions = { "rw" };
247 struct vbsf_mount_info_new mntinf;
248
249 mntinf.nullchar = '\0';
250 mntinf.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0;
251 mntinf.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1;
252 mntinf.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2;
253 mntinf.length = sizeof(mntinf);
254
255 mntinf.uid = pOpts->uid;
256 mntinf.gid = pOpts->gid;
257 mntinf.ttl = pOpts->ttl;
258 mntinf.dmode = pOpts->dmode;
259 mntinf.fmode = pOpts->fmode;
260 mntinf.dmask = pOpts->dmask;
261 mntinf.fmask = pOpts->fmask;
262
263 strcpy(mntinf.name, pszShareName);
264 strcpy(mntinf.nls_name, "\0");
265
266 int r = mount(NULL,
267 pszMountPoint,
268 "vboxsf",
269 flags,
270 &mntinf);
271 if (r == 0)
272 {
273 VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);
274
275 r = vbsfmount_complete(pszShareName, pszMountPoint, flags, pOpts);
276 switch (r)
277 {
278 case 0: /* Success. */
279 errno = 0; /* Clear all errors/warnings. */
280 break;
281
282 case 1:
283 VBoxServiceError("VBoxServiceAutoMountWorker: Could not update mount table (failed to create memstream): %s\n", strerror(errno));
284 break;
285
286 case 2:
287 VBoxServiceError("VBoxServiceAutoMountWorker: Could not open mount table for update: %s\n", strerror(errno));
288 break;
289
290 case 3:
291 VBoxServiceError("VBoxServiceAutoMountWorker: Could not add an entry to the mount table: %s\n", strerror(errno));
292 break;
293
294 default:
295 VBoxServiceError("VBoxServiceAutoMountWorker: Unknown error while completing mount operation: %d\n", r);
296 break;
297 }
298 }
299 else /* r == -1, we got some error in errno. */
300 {
301 if (errno == EPROTO)
302 {
303 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Messed up share name, re-trying ...\n");
304
305 /* Sometimes the mount utility messes up the share name. Try to
306 * un-mangle it again. */
307 char szCWD[4096];
308 size_t cchCWD;
309 if (!getcwd(szCWD, sizeof(szCWD)))
310 VBoxServiceError("VBoxServiceAutoMountWorker: Failed to get the current working directory\n");
311 cchCWD = strlen(szCWD);
312 if (!strncmp(pszMountPoint, szCWD, cchCWD))
313 {
314 while (pszMountPoint[cchCWD] == '/')
315 ++cchCWD;
316 /* We checked before that we have enough space */
317 strcpy(mntinf.name, pszMountPoint + cchCWD);
318 }
319 r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf);
320 }
321 if (errno == EPROTO)
322 {
323 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Re-trying with old mounting structure ...\n");
324
325 /* New mount tool with old vboxsf module? Try again using the old
326 * vbsf_mount_info_old structure. */
327 struct vbsf_mount_info_old mntinf_old;
328 memcpy(&mntinf_old.name, &mntinf.name, MAX_HOST_NAME);
329 memcpy(&mntinf_old.nls_name, mntinf.nls_name, MAX_NLS_NAME);
330 mntinf_old.uid = mntinf.uid;
331 mntinf_old.gid = mntinf.gid;
332 mntinf_old.ttl = mntinf.ttl;
333 r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf_old);
334 }
335 if (r == -1) /* Was there some error from one of the tries above? */
336 {
337 switch (errno)
338 {
339 /* If we get EINVAL here, the system already has mounted the Shared Folder to another
340 * mount point. */
341 case EINVAL:
342 VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already is mounted!\n", pszShareName);
343 /* Ignore this error! */
344 break;
345 case EBUSY:
346 /* Ignore these errors! */
347 break;
348
349 default:
350 VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\": %s (%d)\n",
351 pszShareName, pszMountPoint, strerror(errno), errno);
352 rc = RTErrConvertFromErrno(errno);
353 break;
354 }
355 }
356 }
357#endif /* !RT_OS_SOLARIS */
358 }
359 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Mounting returned with rc=%Rrc\n", rc);
360 return rc;
361}
362
363
364/** @copydoc VBOXSERVICE::pfnWorker */
365DECLCALLBACK(int) VBoxServiceAutoMountWorker(bool volatile *pfShutdown)
366{
367 /*
368 * Tell the control thread that it can continue
369 * spawning services.
370 */
371 RTThreadUserSignal(RTThreadSelf());
372
373 uint32_t u32ClientId;
374 int rc = VbglR3SharedFolderConnect(&u32ClientId);
375 if (!RT_SUCCESS(rc))
376 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Failed to connect to the shared folder service, error %Rrc\n", rc);
377 else
378 {
379 uint32_t cMappings;
380 VBGLR3SHAREDFOLDERMAPPING *paMappings;
381
382 rc = VbglR3SharedFolderGetMappings(u32ClientId, true /* Only process auto-mounted folders */,
383 &paMappings, &cMappings);
384 if (RT_SUCCESS(rc))
385 {
386 char *pszSharePrefix;
387 rc = VbglR3SharedFolderGetMountPrefix(&pszSharePrefix);
388 if (RT_SUCCESS(rc))
389 {
390 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount prefix set to \"%s\"\n", pszSharePrefix);
391#if 0
392 /* Check for a fixed/virtual auto-mount share. */
393 if (VbglR3SharedFolderExists(u32ClientId, "vbsfAutoMount"))
394 {
395 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Host supports auto-mount root\n");
396 }
397 else
398 {
399#endif
400 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Got %u shared folder mappings\n", cMappings);
401 for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
402 {
403 char *pszShareName = NULL;
404 rc = VbglR3SharedFolderGetName(u32ClientId, paMappings[i].u32Root, &pszShareName);
405 if ( RT_SUCCESS(rc)
406 && *pszShareName)
407 {
408 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Connecting share %u (%s) ...\n", i+1, pszShareName);
409
410 char *pszMountPoint = NULL;
411 if ( RTStrAPrintf(&pszMountPoint, AUTO_MOUNT_POINT, pszSharePrefix, pszShareName) > 0
412 && pszMountPoint)
413 {
414 struct group *grp_vboxsf = getgrnam("vboxsf");
415 if (grp_vboxsf)
416 {
417 struct vbsf_mount_opts mount_opts =
418 {
419 0, /* uid */
420 grp_vboxsf->gr_gid, /* gid */
421 0, /* ttl */
422 0770, /* dmode, owner and group "vboxsf" have full access */
423 0770, /* fmode, owner and group "vboxsf" have full access */
424 0, /* dmask */
425 0, /* fmask */
426 0, /* ronly */
427 0, /* noexec */
428 0, /* nodev */
429 0, /* nosuid */
430 0, /* remount */
431 "\0", /* nls_name */
432 NULL, /* convertcp */
433 };
434
435 /* We always use "/media" as our root mounting directory. */
436 /** @todo Detect the correct "media/mnt" directory, based on the current guest (?). */
437 rc = VBoxServiceAutoMountSharedFolder(pszShareName, pszMountPoint, &mount_opts);
438 }
439 else
440 VBoxServiceError("VBoxServiceAutoMountWorker: Group \"vboxsf\" does not exist\n");
441 RTStrFree(pszMountPoint);
442 }
443 else
444 rc = VERR_NO_MEMORY;
445 RTStrFree(pszShareName);
446 }
447 else
448 VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
449 paMappings[i].u32Root, rc);
450 } /* for cMappings. */
451#if 0
452 }
453#endif
454 RTStrFree(pszSharePrefix);
455 } /* Mount prefix. */
456 else
457 VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mount prefix, rc = %Rrc\n", rc);
458 RTMemFree(paMappings);
459 }
460 else
461 VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mappings, rc = %Rrc\n", rc);
462 VbglR3SharedFolderDisconnect(u32ClientId);
463 }
464
465 RTSemEventMultiDestroy(g_AutoMountEvent);
466 g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
467
468 VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Finished\n");
469 return 0;
470}
471
472/** @copydoc VBOXSERVICE::pfnTerm */
473static DECLCALLBACK(void) VBoxServiceAutoMountTerm(void)
474{
475 VBoxServiceVerbose(3, "VBoxServiceAutoMountTerm\n");
476 return;
477}
478
479
480/** @copydoc VBOXSERVICE::pfnStop */
481static DECLCALLBACK(void) VBoxServiceAutoMountStop(void)
482{
483 RTSemEventMultiSignal(g_AutoMountEvent);
484}
485
486
487/**
488 * The 'automount' service description.
489 */
490VBOXSERVICE g_AutoMount =
491{
492 /* pszName. */
493 "automount",
494 /* pszDescription. */
495 "Auto-mount for Shared Folders",
496 /* pszUsage. */
497 NULL,
498 /* pszOptions. */
499 NULL,
500 /* methods */
501 VBoxServiceAutoMountPreInit,
502 VBoxServiceAutoMountOption,
503 VBoxServiceAutoMountInit,
504 VBoxServiceAutoMountWorker,
505 VBoxServiceAutoMountStop,
506 VBoxServiceAutoMountTerm
507};
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