VBoxServiceAutoMount.cpp revision 0fb42f85d3c82308466ce750f2126a11f56005df
/* $Id$ */
/** @file
* VBoxService - Auto-mounting for Shared Folders.
*/
/*
* Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/semaphore.h>
#include <VBox/VBoxGuestLib.h>
#include "VBoxServiceInternal.h"
#include "VBoxServiceUtils.h"
#include <errno.h>
#include <grp.h>
#ifdef RT_OS_SOLARIS
#else
# include <mntent.h>
# include <paths.h>
#endif
#include <unistd.h>
#include "../../linux/sharedfolders/vbsfmount.h"
#ifdef RT_OS_SOLARIS
# define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR "/mnt"
#else
# define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR "/media"
#endif
#ifndef _PATH_MOUNTED
#ifdef RT_OS_SOLARIS
#define _PATH_MOUNTED "/etc/mnttab"
#else
#define _PATH_MOUNTED "/etc/mtab"
#endif
#endif
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** The semaphore we're blocking on. */
/** The Shared Folders service client ID. */
static uint32_t g_SharedFoldersSvcClientID = 0;
/** @copydoc VBOXSERVICE::pfnPreInit */
static DECLCALLBACK(int) VBoxServiceAutoMountPreInit(void)
{
return VINF_SUCCESS;
}
/** @copydoc VBOXSERVICE::pfnOption */
static DECLCALLBACK(int) VBoxServiceAutoMountOption(const char **ppszShort, int argc, char **argv, int *pi)
{
return -1;
}
/** @copydoc VBOXSERVICE::pfnInit */
static DECLCALLBACK(int) VBoxServiceAutoMountInit(void)
{
if (RT_SUCCESS(rc))
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountInit: Service Client ID: %#x\n", g_SharedFoldersSvcClientID);
}
else
{
/* If the service was not found, we disable this service without
causing VBoxService to fail. */
{
VBoxServiceVerbose(0, "VBoxServiceAutoMountInit: Shared Folders service is not available\n");
}
else
}
return rc;
}
/** @todo Integrate into RTFsQueryMountpoint(). */
static bool VBoxServiceAutoMountShareIsMounted(const char *pszShare,
{
bool fMounted = false;
/* @todo What to do if we have a relative path in mtab instead
* procfs contains the full path but not the actual share name ...
#ifdef RT_OS_SOLARIS
if (!pFh)
VBoxServiceError("VBoxServiceAutoMountShareIsMounted: Could not open mount tab \"%s\"!\n",
else
{
{
{
? true : false;
break;
}
}
}
#else
VBoxServiceError("VBoxServiceAutoMountShareIsMounted: Could not open mount tab \"%s\"!\n",
else
{
{
{
? true : false;
break;
}
}
}
#endif
VBoxServiceVerbose(4, "VBoxServiceAutoMountShareIsMounted: Share \"%s\" at mount point \"%s\" = %s\n",
return fMounted;
}
static int VBoxServiceAutoMountUnmount(const char *pszMountPoint)
{
int rc = VINF_SUCCESS;
int r;
while (uTries++ < 3)
{
r = umount(pszMountPoint);
if (r == 0)
break;
}
if (r == -1)
return rc;
}
static int VBoxServiceAutoMountPrepareMountPoint(const char *pszMountPoint, const char *pszShareName,
{
RTFMODE fMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG; /* Owner (=root) and the group (=vboxsf) have full access. */
if (RT_SUCCESS(rc))
{
rc = RTPathSetOwnerEx(pszMountPoint, NIL_RTUID /* Owner, unchanged */, pOpts->gid, RTPATH_F_ON_LINK);
if (RT_SUCCESS(rc))
{
if (RT_FAILURE(rc))
{
if (rc == VERR_WRITE_PROTECT)
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountPrepareMountPoint: Mount directory \"%s\" already is used/mounted\n", pszMountPoint);
rc = VINF_SUCCESS;
}
else
VBoxServiceError("VBoxServiceAutoMountPrepareMountPoint: Could not set mode %RTfmode for mount directory \"%s\", rc = %Rrc\n",
}
}
else
VBoxServiceError("VBoxServiceAutoMountPrepareMountPoint: Could not set permissions for mount directory \"%s\", rc = %Rrc\n",
pszMountPoint, rc);
}
else
VBoxServiceError("VBoxServiceAutoMountPrepareMountPoint: Could not create mount directory \"%s\" with mode %RTfmode, rc = %Rrc\n",
return rc;
}
{
int rc = VINF_SUCCESS;
char szAlreadyMountedTo[RTPATH_MAX];
/* If a Shared Folder already is mounted but not to our desired mount point,
* do an unmount first! */
if ( VBoxServiceAutoMountShareIsMounted(pszShareName, szAlreadyMountedTo, sizeof(szAlreadyMountedTo))
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already mounted to \"%s\", unmounting ...\n",
if (RT_FAILURE(rc))
VBoxServiceError("VBoxServiceAutoMountWorker: Failed to unmount \"%s\", %s (%d)!\n",
}
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
#ifdef RT_OS_SOLARIS
int flags = 0;
int r = mount(pszShareName,
"vboxfs",
NULL, /* char *dataptr */
0, /* int datalen */
sizeof(achOptBuf));
if (r == 0)
{
VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);
}
else
{
VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\", error = %s\n",
}
#else /* !RT_OS_SOLARIS */
const char *szOptions = { "rw" };
struct vbsf_mount_info_new mntinf;
"vboxsf",
&mntinf);
if (r == 0)
{
VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);
switch (r)
{
case 0: /* Success. */
break;
case 1:
VBoxServiceError("VBoxServiceAutoMountWorker: Could not update mount table (failed to create memstream): %s\n", strerror(errno));
break;
case 2:
VBoxServiceError("VBoxServiceAutoMountWorker: Could not open mount table for update: %s\n", strerror(errno));
break;
case 3:
/* VBoxServiceError("VBoxServiceAutoMountWorker: Could not add an entry to the mount table: %s\n", strerror(errno)); */
errno = 0;
break;
default:
VBoxServiceError("VBoxServiceAutoMountWorker: Unknown error while completing mount operation: %d\n", r);
break;
}
}
else /* r == -1, we got some error in errno. */
{
{
/* Sometimes the mount utility messes up the share name. Try to
* un-mangle it again. */
char szCWD[4096];
VBoxServiceError("VBoxServiceAutoMountWorker: Failed to get the current working directory\n");
{
++cchCWD;
/* We checked before that we have enough space */
}
}
{
/* New mount tool with old vboxsf module? Try again using the old
* vbsf_mount_info_old structure. */
struct vbsf_mount_info_old mntinf_old;
}
if (r == -1) /* Was there some error from one of the tries above? */
{
switch (errno)
{
/* If we get EINVAL here, the system already has mounted the Shared Folder to another
* mount point. */
case EINVAL:
VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already is mounted!\n", pszShareName);
/* Ignore this error! */
break;
case EBUSY:
/* Ignore these errors! */
break;
default:
VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\": %s (%d)\n",
break;
}
}
}
#endif /* !RT_OS_SOLARIS */
}
return rc;
}
static int VBoxServiceAutoMountProcessMappings(PVBGLR3SHAREDFOLDERMAPPING paMappings, uint32_t cMappings,
{
if (cMappings == 0)
return VINF_SUCCESS;
int rc = VINF_SUCCESS;
{
char *pszShareName = NULL;
if ( RT_SUCCESS(rc)
&& *pszShareName)
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Connecting share %u (%s) ...\n", i+1, pszShareName);
char *pszShareNameFull = NULL;
{
char szMountPoint[RTPATH_MAX];
if (RT_SUCCESS(rc))
{
if (grp_vboxsf)
{
struct vbsf_mount_opts mount_opts =
{
0, /* uid */
0, /* ttl */
0770, /* dmode, owner and group "vboxsf" have full access */
0770, /* fmode, owner and group "vboxsf" have full access */
0, /* dmask */
0, /* fmask */
0, /* ronly */
0, /* noexec */
0, /* nodev */
0, /* nosuid */
0, /* remount */
"\0", /* nls_name */
NULL, /* convertcp */
};
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Group \"vboxsf\" does not exist\n");
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Unable to join mount point/prefix/shrae, rc = %Rrc\n", rc);
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Unable to allocate full share name\n");
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
} /* for cMappings. */
return rc;
}
/** @copydoc VBOXSERVICE::pfnWorker */
{
/*
* Tell the control thread that it can continue
* spawning services.
*/
int rc = VbglR3SharedFolderGetMappings(g_SharedFoldersSvcClientID, true /* Only process auto-mounted folders */,
&paMappings, &cMappings);
if ( RT_SUCCESS(rc)
&& cMappings)
{
char *pszMountDir;
if (rc == VERR_NOT_FOUND)
if (RT_SUCCESS(rc))
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount dir set to \"%s\"\n", pszMountDir);
char *pszSharePrefix;
if (RT_SUCCESS(rc))
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount prefix set to \"%s\"\n", pszSharePrefix);
#ifdef USE_VIRTUAL_SHARES
{
}
else
{
#endif
rc = VBoxServiceAutoMountProcessMappings(paMappings, cMappings, pszMountDir, pszSharePrefix, g_SharedFoldersSvcClientID);
#ifdef USE_VIRTUAL_SHARES
}
#endif
} /* Mount share prefix. */
else
VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mount prefix, rc = %Rrc\n", rc);
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder directory, rc = %Rrc\n", rc);
}
else if (RT_FAILURE(rc))
VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mappings, rc = %Rrc\n", rc);
else
/*
*
* This thread exits so fast while doing its own startup in VBoxServiceStartServices()
* that this->fShutdown flag is set to true in VBoxServiceThread() before we have the
* chance to check for a service failure in VBoxServiceStartServices() to indicate
* a VBoxService startup error.
*
* Therefore *no* service threads are allowed to quit themselves and need to wait
* for the pfShutdown flag to be set by the main thread.
*/
for (;;)
{
/* Do we need to shutdown? */
if (*pfShutdown)
break;
/* Let's sleep for a bit and let others run ... */
RTThreadSleep(500);
}
return VINF_SUCCESS;
}
/** @copydoc VBOXSERVICE::pfnTerm */
static DECLCALLBACK(void) VBoxServiceAutoMountTerm(void)
{
if (g_AutoMountEvent != NIL_RTSEMEVENTMULTI)
{
}
return;
}
/** @copydoc VBOXSERVICE::pfnStop */
static DECLCALLBACK(void) VBoxServiceAutoMountStop(void)
{
/*
* We need this check because at the moment our auto-mount
* thread really is a one-timer which destroys the event itself
* after running.
*/
if (g_AutoMountEvent != NIL_RTSEMEVENTMULTI)
}
/**
* The 'automount' service description.
*/
{
/* pszName. */
"automount",
/* pszDescription. */
"Auto-mount for Shared Folders",
/* pszUsage. */
NULL,
/* pszOptions. */
NULL,
/* methods */
};