VBoxServiceAutoMount.cpp revision 38754ce3fec7064c34ccedb1dbce89cdfba65953
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * VBoxService - Auto-mounting for Shared Folders.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Copyright (C) 2010 Oracle Corporation
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * available from http://www.virtualbox.org. This file is free software;
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * you can redistribute it and/or modify it under the terms of the GNU
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * General Public License (GPL) as published by the Free Software
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/*******************************************************************************
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync* Header Files *
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync*******************************************************************************/
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/*******************************************************************************
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync* Global Variables *
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync*******************************************************************************/
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/** The semaphore we're blocking on. */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncstatic RTSEMEVENTMULTI g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/** @copydoc VBOXSERVICE::pfnPreInit */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncstatic DECLCALLBACK(int) VBoxServiceAutoMountPreInit(void)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/** @copydoc VBOXSERVICE::pfnOption */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncstatic DECLCALLBACK(int) VBoxServiceAutoMountOption(const char **ppszShort, int argc, char **argv, int *pi)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/** @copydoc VBOXSERVICE::pfnInit */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncstatic DECLCALLBACK(int) VBoxServiceAutoMountInit(void)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountInit\n");
2f827df539da232220444c27f2b207a707a045b0vboxsyncstatic bool VBoxServiceAutoMountShareIsMounted(const char *pszShare,
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync AssertReturn(cbMountPoint, VERR_INVALID_PARAMETER);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync bool fMounted = false;
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync /* @todo What to do if we have a relative path in mtab instead
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync * of an absolute one ("temp" vs. "/media/temp")?
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync * procfs contains the full path but not the actual share name ...
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync * FILE *pFh = setmntent("/proc/mounts", "r+t"); */
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync VBoxServiceError("VBoxServiceAutoMountShareIsMounted: Could not open mtab!\n");
2f827df539da232220444c27f2b207a707a045b0vboxsync fMounted = RTStrPrintf(pszMountPoint, cbMountPoint, "%s", pMntEnt->mnt_dir)
2f827df539da232220444c27f2b207a707a045b0vboxsync ? true : false;
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsyncstatic int VBoxServiceAutoMountUnmount(const char *pszMountPoint)
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync if (r == 0)
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync if (r == -1)
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsyncstatic int VBoxServiceAutoMountPrepareMountPoint(const char *pszMountPoint, const char *pszShareName,
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync AssertPtrReturn(pszShareName, VERR_INVALID_PARAMETER);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync RTFMODE fMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG; /* Owner (=root) and the group (=vboxsf) have full access. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync int rc = RTDirCreateFullPath(pszMountPoint, fMode);
38754ce3fec7064c34ccedb1dbce89cdfba65953vboxsync rc = RTPathSetOwnerEx(pszMountPoint, ~0 /* Owner, unchanged */, pOpts->gid, RTPATH_F_ON_LINK);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync VBoxServiceError(": Could not set mode %RTfmode for mount directory \"%s\", rc = %Rrc\n",
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync VBoxServiceError("VBoxServiceAutoMountPrepareMountPoint: Could not set permissions for mount directory \"%s\", rc = %Rrc\n",
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync VBoxServiceError("VBoxServiceAutoMountPrepareMountPoint: Could not create mount directory \"%s\" with mode %RTfmode, rc = %Rrc\n",
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsyncstatic int VBoxServiceAutoMountSharedFolder(const char *pszShareName, const char *pszMountPoint,
2f827df539da232220444c27f2b207a707a045b0vboxsync /* If a Shared Folder already is mounted but not to our desired mount point,
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync * do an unmount first! */
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync if ( VBoxServiceAutoMountShareIsMounted(pszShareName, szAlreadyMountedTo, sizeof(szAlreadyMountedTo))
2f827df539da232220444c27f2b207a707a045b0vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already mounted to \"%s\", unmounting ...\n",
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync rc = VBoxServiceAutoMountUnmount(szAlreadyMountedTo);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Failed to unmount \"%s\", %s (%d)!\n",
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync rc = VBoxServiceAutoMountPrepareMountPoint(pszMountPoint, pszShareName, pOpts);
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync 0, /* int datalen */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync 0); /* int optlen */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync if (r == 0)
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync if (errno != EBUSY) /* Share is already mounted? Then skip error msg. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\", error = %s\n",
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#else /* !RT_OS_SOLARIS */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync if (r == 0)
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" was mounted to \"%s\"\n", pszShareName, pszMountPoint);
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync r = vbsfmount_complete(pszShareName, pszMountPoint, flags, pOpts);
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync case 0: /* Success. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Could not update mount table (failed to create memstream): %s\n", strerror(errno));
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Could not open mount table for update: %s\n", strerror(errno));
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Could not add an entry to the mount table: %s\n", strerror(errno));
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Unknown error while completing mount operation: %d\n", r);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync else /* r == -1, we got some error in errno. */
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Messed up share name, re-trying ...\n");
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /* Sometimes the mount utility messes up the share name. Try to
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync * un-mangle it again. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Failed to get the current working directory\n");
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /* We checked before that we have enough space */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Re-trying with old mounting structure ...\n");
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /* New mount tool with old vboxsf module? Try again using the old
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync * vbsf_mount_info_old structure. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync memcpy(&mntinf_old.name, &mntinf.name, MAX_HOST_NAME);
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync memcpy(&mntinf_old.nls_name, mntinf.nls_name, MAX_NLS_NAME);
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync r = mount(NULL, pszMountPoint, "vboxsf", flags, &mntinf_old);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync if (r == -1) /* Was there some error from one of the tries above? */
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync /* If we get EINVAL here, the system already has mounted the Shared Folder to another
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync * mount point. */
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync VBoxServiceVerbose(0, "VBoxServiceAutoMountWorker: Shared folder \"%s\" already is mounted!\n", pszShareName);
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync /* Ignore this error! */
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync /* Ignore these errors! */
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Could not mount shared folder \"%s\" to \"%s\": %s (%d)\n",
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync pszShareName, pszMountPoint, strerror(errno), errno);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#endif /* !RT_OS_SOLARIS */
56f538fa476fdbd9cc3d60438083a3f0d5f3ff7fvboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Mounting returned with rc=%Rrc\n", rc);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/** @copydoc VBOXSERVICE::pfnWorker */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncDECLCALLBACK(int) VBoxServiceAutoMountWorker(bool volatile *pfShutdown)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Tell the control thread that it can continue
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * spawning services.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Failed to connect to the shared folder service, error %Rrc\n", rc);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync rc = VbglR3SharedFolderGetMappings(u32ClientId, true /* Only process auto-mounted folders */,
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync rc = VbglR3SharedFolderGetMountPrefix(&pszSharePrefix);
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount prefix set to \"%s\"\n", pszSharePrefix);
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync /* Check for a fixed/virtual auto-mount share. */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync if (VbglR3SharedFolderExists(u32ClientId, "vbsfAutoMount"))
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Host supports auto-mount root\n");
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Got %u shared folder mappings\n", cMappings);
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync rc = VbglR3SharedFolderGetName(u32ClientId, paMappings[i].u32Root, &pszShareName);
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Connecting share %u (%s) ...\n", i+1, pszShareName);
7cca5a9aeb06913531b982bf772508d09b4c2f0bvboxsync if ( RTStrAPrintf(&pszMountPoint, AUTO_MOUNT_POINT, pszSharePrefix, pszShareName) > 0
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0, /* uid */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0, /* ttl */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0770, /* dmode, owner and group "vboxsf" have full access */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0770, /* fmode, owner and group "vboxsf" have full access */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0, /* dmask */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0, /* fmask */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0, /* ronly */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0, /* noexec */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0, /* nodev */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0, /* nosuid */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync 0, /* remount */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync /* We always use "/media" as our root mounting directory. */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync /** @todo Detect the correct "media/mnt" directory, based on the current guest (?). */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync rc = VBoxServiceAutoMountSharedFolder(pszShareName, pszMountPoint, &mount_opts);
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Group \"vboxsf\" does not exist\n");
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync } /* for cMappings. */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync } /* Mount prefix. */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mount prefix, rc = %Rrc\n", rc);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mappings, rc = %Rrc\n", rc);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Finished\n");
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/** @copydoc VBOXSERVICE::pfnTerm */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncstatic DECLCALLBACK(void) VBoxServiceAutoMountTerm(void)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync VBoxServiceVerbose(3, "VBoxServiceAutoMountTerm\n");
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/** @copydoc VBOXSERVICE::pfnStop */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncstatic DECLCALLBACK(void) VBoxServiceAutoMountStop(void)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * The 'automount' service description.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync /* pszName. */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync "automount",
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync /* pszDescription. */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync "Auto-mount for Shared Folders",
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync /* pszUsage. */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync /* pszOptions. */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync /* methods */