VirtualBox

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

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

VBoxService/AutoMount: Logging, handle write protected mounts.

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