VirtualBox

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

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

Warning.

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