VBoxServiceAutoMount.cpp revision 1313e5cbe01a41e7ccb1499d2d73c455a2495955
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/* $Id$ */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** @file
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * VBoxService - Auto-mounting for Shared Folders.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*
c7814cf6e1240a519cbec0441e033d0e2470ed00vboxsync * Copyright (C) 2010 Oracle Corporation
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * available from http://www.virtualbox.org. This file is free software;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * you can redistribute it and/or modify it under the terms of the GNU
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * General Public License (GPL) as published by the Free Software
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*******************************************************************************
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync* Header Files *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/assert.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/dir.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/mem.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/path.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/string.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/semaphore.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <VBox/VBoxGuestLib.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include "VBoxServiceInternal.h"
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include "VBoxServiceUtils.h"
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <errno.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <grp.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <sys/mount.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#ifdef RT_OS_SOLARIS
e6e2974634808306e2557acf7b9faae14ff5b93bvboxsync# include <sys/mntent.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync# include <sys/mnttab.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync# include <sys/vfs.h>
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync#else
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync# include <mntent.h>
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync# include <paths.h>
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync#endif
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync#include <unistd.h>
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsyncRT_C_DECLS_BEGIN
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync#include "../../linux/sharedfolders/vbsfmount.h"
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsyncRT_C_DECLS_END
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync#ifdef RT_OS_SOLARIS
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync# define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR "/mnt"
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync#else
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync# define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR "/media"
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync#endif
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync#ifndef _PATH_MOUNTED
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync #ifdef RT_OS_SOLARIS
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync #define _PATH_MOUNTED "/etc/mnttab"
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync #else
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync #define _PATH_MOUNTED "/etc/mtab"
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync #endif
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync#endif
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync/*******************************************************************************
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync* Global Variables *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** The semaphore we're blocking on. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic RTSEMEVENTMULTI g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** The Shared Folders service client ID. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic uint32_t g_SharedFoldersSvcClientID = 0;
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** @copydoc VBOXSERVICE::pfnPreInit */
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsyncstatic DECLCALLBACK(int) VBoxServiceAutoMountPreInit(void)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return VINF_SUCCESS;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** @copydoc VBOXSERVICE::pfnOption */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic DECLCALLBACK(int) VBoxServiceAutoMountOption(const char **ppszShort, int argc, char **argv, int *pi)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync NOREF(ppszShort);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync NOREF(argc);
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync NOREF(argv);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync NOREF(pi);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return VINF_SUCCESS;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** @copydoc VBOXSERVICE::pfnInit */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic DECLCALLBACK(int) VBoxServiceAutoMountInit(void)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountInit\n");
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync int rc = RTSemEventMultiCreate(&g_AutoMountEvent);
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync AssertRCReturn(rc, rc);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync rc = VbglR3SharedFolderConnect(&g_SharedFoldersSvcClientID);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (RT_SUCCESS(rc))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountInit: Service Client ID: %#x\n", g_SharedFoldersSvcClientID);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync else
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /* If the service was not found, we disable this service without
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync causing VBoxService to fail. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync VBoxServiceVerbose(0, "VBoxServiceAutoMountInit: Shared Folders service is not available\n");
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync rc = VERR_SERVICE_DISABLED;
e6e2974634808306e2557acf7b9faae14ff5b93bvboxsync }
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync else
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync VBoxServiceError("Control: Failed to connect to the Shared Folders service! Error: %Rrc\n", rc);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync RTSemEventMultiDestroy(g_AutoMountEvent);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
76a0b518a2bb00a37607af4a8f4ff86e2f8d3134vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return rc;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** @todo Integrate into RTFsQueryMountpoint(). */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic bool VBoxServiceAutoMountShareIsMounted(const char *pszShare,
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync char *pszMountPoint, size_t cbMountPoint)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertPtrReturn(pszShare, VERR_INVALID_PARAMETER);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsync AssertReturn(cbMountPoint, VERR_INVALID_PARAMETER);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync bool fMounted = false;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /* @todo What to do if we have a relative path in mtab instead
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * of an absolute one ("temp" vs. "/media/temp")?
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * procfs contains the full path but not the actual share name ...
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * FILE *pFh = setmntent("/proc/mounts", "r+t"); */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#ifdef RT_OS_SOLARIS
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync FILE *pFh = fopen(_PATH_MOUNTED, "r");
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!pFh)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync VBoxServiceError("VBoxServiceAutoMountShareIsMounted: Could not open mount tab \"%s\"!\n",
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync _PATH_MOUNTED);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync else
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync mnttab mntTab;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync while ((getmntent(pFh, &mntTab)))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!RTStrICmp(mntTab.mnt_special, pszShare))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync fMounted = RTStrPrintf(pszMountPoint, cbMountPoint, "%s", mntTab.mnt_mountp)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync ? true : false;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync break;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync fclose(pFh);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#else
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync FILE *pFh = setmntent(_PATH_MOUNTED, "r+t");
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (pFh == NULL)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync VBoxServiceError("VBoxServiceAutoMountShareIsMounted: Could not open mount tab \"%s\"!\n",
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync _PATH_MOUNTED);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync else
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync mntent *pMntEnt;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync while ((pMntEnt = getmntent(pFh)))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!RTStrICmp(pMntEnt->mnt_fsname, pszShare))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync fMounted = RTStrPrintf(pszMountPoint, cbMountPoint, "%s", pMntEnt->mnt_dir)
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsync ? true : false;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync break;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync endmntent(pFh);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#endif
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync VBoxServiceVerbose(4, "VBoxServiceAutoMountShareIsMounted: Share \"%s\" at mount point \"%s\" = %s\n",
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pszShare, fMounted ? pszMountPoint : "<None>", fMounted ? "Yes" : "No");
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return fMounted;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic int VBoxServiceAutoMountUnmount(const char *pszMountPoint)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync int rc = VINF_SUCCESS;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync uint8_t uTries = 0;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync int r;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync while (uTries++ < 3)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
r = umount(pszMountPoint);
if (r == 0)
break;
RTThreadSleep(5000); /* Wait a while ... */
}
if (r == -1)
rc = RTErrConvertFromErrno(errno);
return rc;
}
static int VBoxServiceAutoMountPrepareMountPoint(const char *pszMountPoint, const char *pszShareName,
vbsf_mount_opts *pOpts)
{
AssertPtrReturn(pOpts, VERR_INVALID_PARAMETER);
AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
AssertPtrReturn(pszShareName, VERR_INVALID_PARAMETER);
RTFMODE fMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG; /* Owner (=root) and the group (=vboxsf) have full access. */
int rc = RTDirCreateFullPath(pszMountPoint, fMode);
if (RT_SUCCESS(rc))
{
rc = RTPathSetOwnerEx(pszMountPoint, NIL_RTUID /* Owner, unchanged */, pOpts->gid, RTPATH_F_ON_LINK);
if (RT_SUCCESS(rc))
{
rc = RTPathSetMode(pszMountPoint, fMode);
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",
fMode, pszMountPoint, rc);
}
}
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",
pszMountPoint, fMode, rc);
return rc;
}
static int VBoxServiceAutoMountSharedFolder(const char *pszShareName, const char *pszMountPoint,
vbsf_mount_opts *pOpts)
{
AssertPtr(pOpts);
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))
&& RTStrICmp(pszMountPoint, szAlreadyMountedTo))
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already mounted to \"%s\", unmounting ...\n",
pszShareName, szAlreadyMountedTo);
rc = VBoxServiceAutoMountUnmount(szAlreadyMountedTo);
if (RT_FAILURE(rc))
VBoxServiceError("VBoxServiceAutoMountWorker: Failed to unmount \"%s\", %s (%d)!\n",
szAlreadyMountedTo, strerror(errno), errno);
}
if (RT_SUCCESS(rc))
rc = VBoxServiceAutoMountPrepareMountPoint(pszMountPoint, pszShareName, pOpts);
if (RT_SUCCESS(rc))
{
#ifdef RT_OS_SOLARIS
int flags = 0; /* No flags used yet. */
int r = mount(pszShareName,
pszMountPoint,
flags,
"vboxsf",
NULL, /* char *dataptr */
0, /* int datalen */
NULL, /* char *optptr */
0); /* int optlen */
if (r == 0)
{
VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);
}
else
{
if (errno != EBUSY) /* Share is already mounted? Then skip error msg. */
VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\", error = %s\n",
pszShareName, pszMountPoint, strerror(errno));
}
#else /* !RT_OS_SOLARIS */
unsigned long flags = MS_NODEV;
const char *szOptions = { "rw" };
struct vbsf_mount_info_new mntinf;
mntinf.nullchar = '\0';
mntinf.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0;
mntinf.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1;
mntinf.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2;
mntinf.length = sizeof(mntinf);
mntinf.uid = pOpts->uid;
mntinf.gid = pOpts->gid;
mntinf.ttl = pOpts->ttl;
mntinf.dmode = pOpts->dmode;
mntinf.fmode = pOpts->fmode;
mntinf.dmask = pOpts->dmask;
mntinf.fmask = pOpts->fmask;
strcpy(mntinf.name, pszShareName);
strcpy(mntinf.nls_name, "\0");
int r = mount(NULL,
pszMountPoint,
"vboxsf",
flags,
&mntinf);
if (r == 0)
{
VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);
r = vbsfmount_complete(pszShareName, pszMountPoint, flags, pOpts);
switch (r)
{
case 0: /* Success. */
errno = 0; /* Clear all errors/warnings. */
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));
break;
default:
VBoxServiceError("VBoxServiceAutoMountWorker: Unknown error while completing mount operation: %d\n", r);
break;
}
}
else /* r == -1, we got some error in errno. */
{
if (errno == EPROTO)
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Messed up share name, re-trying ...\n");
/* Sometimes the mount utility messes up the share name. Try to
* un-mangle it again. */
char szCWD[4096];
size_t cchCWD;
if (!getcwd(szCWD, sizeof(szCWD)))
VBoxServiceError("VBoxServiceAutoMountWorker: Failed to get the current working directory\n");
cchCWD = strlen(szCWD);
if (!strncmp(pszMountPoint, szCWD, cchCWD))
{
while (pszMountPoint[cchCWD] == '/')
++cchCWD;
/* We checked before that we have enough space */
strcpy(mntinf.name, pszMountPoint + cchCWD);
}
r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf);
}
if (errno == EPROTO)
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Re-trying with old mounting structure ...\n");
/* New mount tool with old vboxsf module? Try again using the old
* vbsf_mount_info_old structure. */
struct vbsf_mount_info_old mntinf_old;
memcpy(&mntinf_old.name, &mntinf.name, MAX_HOST_NAME);
memcpy(&mntinf_old.nls_name, mntinf.nls_name, MAX_NLS_NAME);
mntinf_old.uid = mntinf.uid;
mntinf_old.gid = mntinf.gid;
mntinf_old.ttl = mntinf.ttl;
r = mount(NULL, pszMountPoint, "vboxsf", flags, &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",
pszShareName, pszMountPoint, strerror(errno), errno);
rc = RTErrConvertFromErrno(errno);
break;
}
}
}
#endif /* !RT_OS_SOLARIS */
}
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Mounting returned with rc=%Rrc\n", rc);
return rc;
}
static int VBoxServiceAutoMountProcessMappings(PVBGLR3SHAREDFOLDERMAPPING paMappings, uint32_t cMappings,
const char *pszMountDir, const char *pszSharePrefix, uint32_t uClientID)
{
if (cMappings == 0)
return VINF_SUCCESS;
AssertPtrReturn(paMappings, VERR_INVALID_PARAMETER);
AssertPtrReturn(pszMountDir, VERR_INVALID_PARAMETER);
AssertPtrReturn(pszSharePrefix, VERR_INVALID_PARAMETER);
AssertReturn(uClientID > 0, VERR_INVALID_PARAMETER);
int rc = VINF_SUCCESS;
for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
{
char *pszShareName = NULL;
rc = VbglR3SharedFolderGetName(uClientID, paMappings[i].u32Root, &pszShareName);
if ( RT_SUCCESS(rc)
&& *pszShareName)
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Connecting share %u (%s) ...\n", i+1, pszShareName);
char *pszShareNameFull = NULL;
if (RTStrAPrintf(&pszShareNameFull, "%s%s", pszSharePrefix, pszShareName) > 0)
{
char szMountPoint[RTPATH_MAX];
rc = RTPathJoin(szMountPoint, sizeof(szMountPoint), pszMountDir, pszShareNameFull);
if (RT_SUCCESS(rc))
{
VBoxServiceVerbose(4, "VBoxServiceAutoMountWorker: Processing mount point \"%s\"\n", szMountPoint);
struct group *grp_vboxsf = getgrnam("vboxsf");
if (grp_vboxsf)
{
struct vbsf_mount_opts mount_opts =
{
0, /* uid */
grp_vboxsf->gr_gid, /* gid */
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 */
};
rc = VBoxServiceAutoMountSharedFolder(pszShareName, szMountPoint, &mount_opts);
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Group \"vboxsf\" does not exist\n");
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Unable to join mount point/prefix/shrae, rc = %Rrc\n", rc);
RTStrFree(pszShareNameFull);
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Unable to allocate full share name\n");
RTStrFree(pszShareName);
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
paMappings[i].u32Root, rc);
} /* for cMappings. */
return rc;
}
/** @copydoc VBOXSERVICE::pfnWorker */
DECLCALLBACK(int) VBoxServiceAutoMountWorker(bool volatile *pfShutdown)
{
/*
* Tell the control thread that it can continue
* spawning services.
*/
RTThreadUserSignal(RTThreadSelf());
uint32_t cMappings;
PVBGLR3SHAREDFOLDERMAPPING paMappings;
int rc = VbglR3SharedFolderGetMappings(g_SharedFoldersSvcClientID, true /* Only process auto-mounted folders */,
&paMappings, &cMappings);
if ( RT_SUCCESS(rc)
&& cMappings)
{
char *pszMountDir;
rc = VbglR3SharedFolderGetMountDir(&pszMountDir);
if (rc == VERR_NOT_FOUND)
rc = RTStrDupEx(&pszMountDir, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR);
if (RT_SUCCESS(rc))
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount dir set to \"%s\"\n", pszMountDir);
char *pszSharePrefix;
rc = VbglR3SharedFolderGetMountPrefix(&pszSharePrefix);
if (RT_SUCCESS(rc))
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount prefix set to \"%s\"\n", pszSharePrefix);
#ifdef USE_VIRTUAL_SHARES
/* Check for a fixed/virtual auto-mount share. */
if (VbglR3SharedFolderExists(g_SharedFoldersSvcClientID, "vbsfAutoMount"))
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Host supports auto-mount root\n");
}
else
{
#endif
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Got %u shared folder mappings\n", cMappings);
rc = VBoxServiceAutoMountProcessMappings(paMappings, cMappings, pszMountDir, pszSharePrefix, g_SharedFoldersSvcClientID);
#ifdef USE_VIRTUAL_SHARES
}
#endif
RTStrFree(pszSharePrefix);
} /* Mount share prefix. */
else
VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mount prefix, rc = %Rrc\n", rc);
RTStrFree(pszMountDir);
}
else
VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder directory, rc = %Rrc\n", rc);
VbglR3SharedFolderFreeMappings(paMappings);
}
else
{
if (RT_FAILURE(rc))
VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mappings, rc = %Rrc\n", rc);
else if (!cMappings)
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: No shared folder mappings fouund\n");
}
/*
* Because this thread is a one-timer at the moment we don't want to break/change
* the semantics of the main thread's start/stop sub-threads handling.
*
* 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);
}
RTSemEventMultiDestroy(g_AutoMountEvent);
g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Finished with rc=%Rrc\n", rc);
return VINF_SUCCESS;
}
/** @copydoc VBOXSERVICE::pfnTerm */
static DECLCALLBACK(void) VBoxServiceAutoMountTerm(void)
{
VBoxServiceVerbose(3, "VBoxServiceAutoMountTerm\n");
VbglR3SharedFolderDisconnect(g_SharedFoldersSvcClientID);
g_SharedFoldersSvcClientID = 0;
if (g_AutoMountEvent != NIL_RTSEMEVENTMULTI)
{
RTSemEventMultiDestroy(g_AutoMountEvent);
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)
RTSemEventMultiSignal(g_AutoMountEvent);
}
/**
* The 'automount' service description.
*/
VBOXSERVICE g_AutoMount =
{
/* pszName. */
"automount",
/* pszDescription. */
"Auto-mount for Shared Folders",
/* pszUsage. */
NULL,
/* pszOptions. */
NULL,
/* methods */
VBoxServiceAutoMountPreInit,
VBoxServiceAutoMountOption,
VBoxServiceAutoMountInit,
VBoxServiceAutoMountWorker,
VBoxServiceAutoMountStop,
VBoxServiceAutoMountTerm
};