VirtualBox

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

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

Solaris build fix.

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