VirtualBox

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

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

iprt,VBoxServiceAutoMount.cpp: RTPathSetOwner[Ex] should take NIL_RTUID/GID not -1 / ~0, the only excuse is that NIL_RT[UG]ID probably didn't exist when it was written. Ditto for the RTFileSetOwner API (not realized yet).

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