VirtualBox

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

Last change on this file since 33834 was 33834, checked in by vboxsync, 15 years ago

VBoxService/AutoMount: Update, bugfixes.

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