[44863] | 1 | /* $Id: VBoxServiceControlSession.cpp 103471 2024-02-20 09:06:22Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[57659] | 3 | * VBoxServiceControlSession - Guest session handling. Also handles the spawned session processes.
|
---|
[44863] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2013-2023 Oracle and/or its affiliates.
|
---|
[44863] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[44863] | 26 | */
|
---|
| 27 |
|
---|
| 28 |
|
---|
[57358] | 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
[44935] | 32 | #include <iprt/asm.h>
|
---|
[44863] | 33 | #include <iprt/assert.h>
|
---|
[49349] | 34 | #include <iprt/dir.h>
|
---|
[44863] | 35 | #include <iprt/env.h>
|
---|
| 36 | #include <iprt/file.h>
|
---|
| 37 | #include <iprt/getopt.h>
|
---|
| 38 | #include <iprt/handle.h>
|
---|
| 39 | #include <iprt/mem.h>
|
---|
| 40 | #include <iprt/message.h>
|
---|
| 41 | #include <iprt/path.h>
|
---|
| 42 | #include <iprt/pipe.h>
|
---|
| 43 | #include <iprt/poll.h>
|
---|
| 44 | #include <iprt/process.h>
|
---|
[75807] | 45 | #include <iprt/rand.h>
|
---|
[84548] | 46 | #include <iprt/system.h> /* For RTShutdown. */
|
---|
[44863] | 47 |
|
---|
| 48 | #include "VBoxServiceInternal.h"
|
---|
| 49 | #include "VBoxServiceUtils.h"
|
---|
| 50 | #include "VBoxServiceControl.h"
|
---|
| 51 |
|
---|
| 52 | using namespace guestControl;
|
---|
| 53 |
|
---|
[57358] | 54 |
|
---|
| 55 | /*********************************************************************************************************************************
|
---|
[58029] | 56 | * Structures and Typedefs *
|
---|
[57358] | 57 | *********************************************************************************************************************************/
|
---|
[57659] | 58 | /** Generic option indices for session spawn arguments. */
|
---|
[44863] | 59 | enum
|
---|
| 60 | {
|
---|
[47551] | 61 | VBOXSERVICESESSIONOPT_FIRST = 1000, /* For initialization. */
|
---|
[59145] | 62 | VBOXSERVICESESSIONOPT_DOMAIN,
|
---|
[47551] | 63 | #ifdef DEBUG
|
---|
| 64 | VBOXSERVICESESSIONOPT_DUMP_STDOUT,
|
---|
| 65 | VBOXSERVICESESSIONOPT_DUMP_STDERR,
|
---|
| 66 | #endif
|
---|
| 67 | VBOXSERVICESESSIONOPT_LOG_FILE,
|
---|
[44863] | 68 | VBOXSERVICESESSIONOPT_USERNAME,
|
---|
| 69 | VBOXSERVICESESSIONOPT_SESSION_ID,
|
---|
[45415] | 70 | VBOXSERVICESESSIONOPT_SESSION_PROTO,
|
---|
| 71 | VBOXSERVICESESSIONOPT_THREAD_ID
|
---|
[44863] | 72 | };
|
---|
| 73 |
|
---|
| 74 |
|
---|
[83286] | 75 | static int vgsvcGstCtrlSessionCleanupProcesses(const PVBOXSERVICECTRLSESSION pSession);
|
---|
[83595] | 76 | static int vgsvcGstCtrlSessionProcessRemoveInternal(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess);
|
---|
[83286] | 77 |
|
---|
| 78 |
|
---|
[75824] | 79 | /**
|
---|
| 80 | * Helper that grows the scratch buffer.
|
---|
| 81 | * @returns Success indicator.
|
---|
| 82 | */
|
---|
| 83 | static bool vgsvcGstCtrlSessionGrowScratchBuf(void **ppvScratchBuf, uint32_t *pcbScratchBuf, uint32_t cbMinBuf)
|
---|
| 84 | {
|
---|
| 85 | uint32_t cbNew = *pcbScratchBuf * 2;
|
---|
| 86 | if ( cbNew <= VMMDEV_MAX_HGCM_DATA_SIZE
|
---|
| 87 | && cbMinBuf <= VMMDEV_MAX_HGCM_DATA_SIZE)
|
---|
| 88 | {
|
---|
| 89 | while (cbMinBuf > cbNew)
|
---|
| 90 | cbNew *= 2;
|
---|
| 91 | void *pvNew = RTMemRealloc(*ppvScratchBuf, cbNew);
|
---|
| 92 | if (pvNew)
|
---|
| 93 | {
|
---|
| 94 | *ppvScratchBuf = pvNew;
|
---|
| 95 | *pcbScratchBuf = cbNew;
|
---|
| 96 | return true;
|
---|
| 97 | }
|
---|
| 98 | }
|
---|
| 99 | return false;
|
---|
| 100 | }
|
---|
[58029] | 101 |
|
---|
[75824] | 102 |
|
---|
[98526] | 103 | #ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
|
---|
| 104 | /**
|
---|
| 105 | * Free's a guest directory entry.
|
---|
| 106 | *
|
---|
| 107 | * @returns VBox status code.
|
---|
| 108 | * @param pDir Directory entry to free.
|
---|
| 109 | * The pointer will be invalid on success.
|
---|
| 110 | */
|
---|
| 111 | static int vgsvcGstCtrlSessionDirFree(PVBOXSERVICECTRLDIR pDir)
|
---|
| 112 | {
|
---|
| 113 | if (!pDir)
|
---|
| 114 | return VINF_SUCCESS;
|
---|
[75824] | 115 |
|
---|
[99085] | 116 | RTMemFree(pDir->pDirEntryEx);
|
---|
| 117 |
|
---|
[98526] | 118 | int rc;
|
---|
| 119 | if (pDir->hDir != NIL_RTDIR)
|
---|
| 120 | {
|
---|
| 121 | rc = RTDirClose(pDir->hDir);
|
---|
| 122 | pDir->hDir = NIL_RTDIR;
|
---|
| 123 | }
|
---|
| 124 | else
|
---|
| 125 | rc = VINF_SUCCESS;
|
---|
| 126 |
|
---|
| 127 | if (RT_SUCCESS(rc))
|
---|
| 128 | {
|
---|
| 129 | RTStrFree(pDir->pszPathAbs);
|
---|
| 130 | RTListNodeRemove(&pDir->Node);
|
---|
| 131 | RTMemFree(pDir);
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | return rc;
|
---|
| 135 | }
|
---|
| 136 |
|
---|
| 137 |
|
---|
| 138 | /**
|
---|
| 139 | * Acquires an internal guest directory.
|
---|
| 140 | *
|
---|
| 141 | * Must be released via vgsvcGstCtrlSessionDirRelease().
|
---|
| 142 | *
|
---|
[99147] | 143 | * @returns Guest directory entry on success, or NULL if not found.
|
---|
[98526] | 144 | * @param pSession Guest control session to acquire guest directory for.
|
---|
| 145 | * @param uHandle Handle of directory to acquire.
|
---|
| 146 | *
|
---|
| 147 | * @note No locking done yet.
|
---|
| 148 | */
|
---|
| 149 | static PVBOXSERVICECTRLDIR vgsvcGstCtrlSessionDirAcquire(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle)
|
---|
| 150 | {
|
---|
| 151 | AssertPtrReturn(pSession, NULL);
|
---|
| 152 |
|
---|
| 153 | /** @todo Use a map later! */
|
---|
| 154 | PVBOXSERVICECTRLDIR pDirCur;
|
---|
| 155 | RTListForEach(&pSession->lstDirs, pDirCur, VBOXSERVICECTRLDIR, Node)
|
---|
| 156 | {
|
---|
| 157 | if (pDirCur->uHandle == uHandle)
|
---|
| 158 | return pDirCur;
|
---|
| 159 | }
|
---|
| 160 |
|
---|
| 161 | return NULL;
|
---|
| 162 | }
|
---|
| 163 |
|
---|
| 164 |
|
---|
| 165 | /**
|
---|
| 166 | * Releases a formerly acquired guest directory.
|
---|
| 167 | *
|
---|
| 168 | * @param pDir Directory to release.
|
---|
| 169 | */
|
---|
| 170 | static void vgsvcGstCtrlSessionDirRelease(PVBOXSERVICECTRLDIR pDir)
|
---|
| 171 | {
|
---|
| 172 | RT_NOREF(pDir);
|
---|
| 173 | }
|
---|
| 174 | #endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
|
---|
| 175 |
|
---|
| 176 |
|
---|
[99147] | 177 | /**
|
---|
| 178 | * Free's a guest file entry.
|
---|
| 179 | *
|
---|
| 180 | * @returns VBox status code.
|
---|
| 181 | * @param pFile Guest file entry to free.
|
---|
| 182 | * The pointer wil be invalid on success.
|
---|
| 183 | */
|
---|
[83595] | 184 | static int vgsvcGstCtrlSessionFileFree(PVBOXSERVICECTRLFILE pFile)
|
---|
[44863] | 185 | {
|
---|
| 186 | AssertPtrReturn(pFile, VERR_INVALID_POINTER);
|
---|
| 187 |
|
---|
| 188 | int rc = RTFileClose(pFile->hFile);
|
---|
| 189 | if (RT_SUCCESS(rc))
|
---|
| 190 | {
|
---|
[84148] | 191 | RTStrFree(pFile->pszName);
|
---|
| 192 |
|
---|
[44863] | 193 | /* Remove file entry in any case. */
|
---|
| 194 | RTListNodeRemove(&pFile->Node);
|
---|
| 195 | /* Destroy this object. */
|
---|
| 196 | RTMemFree(pFile);
|
---|
| 197 | }
|
---|
| 198 |
|
---|
| 199 | return rc;
|
---|
| 200 | }
|
---|
| 201 |
|
---|
| 202 |
|
---|
[99147] | 203 | /**
|
---|
| 204 | * Acquires an internal guest file entry.
|
---|
| 205 | *
|
---|
| 206 | * Must be released via vgsvcGstCtrlSessionFileRelease().
|
---|
| 207 | *
|
---|
| 208 | * @returns Guest file entry on success, or NULL if not found.
|
---|
| 209 | * @param pSession Guest session to use.
|
---|
| 210 | * @param uHandle Handle of guest file entry to acquire.
|
---|
| 211 | *
|
---|
| 212 | * @note No locking done yet.
|
---|
| 213 | */
|
---|
| 214 | static PVBOXSERVICECTRLFILE vgsvcGstCtrlSessionFileAcquire(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle)
|
---|
[44863] | 215 | {
|
---|
[44963] | 216 | AssertPtrReturn(pSession, NULL);
|
---|
| 217 |
|
---|
[44863] | 218 | /** @todo Use a map later! */
|
---|
[58029] | 219 | PVBOXSERVICECTRLFILE pFileCur;
|
---|
[44963] | 220 | RTListForEach(&pSession->lstFiles, pFileCur, VBOXSERVICECTRLFILE, Node)
|
---|
[44863] | 221 | {
|
---|
| 222 | if (pFileCur->uHandle == uHandle)
|
---|
| 223 | return pFileCur;
|
---|
| 224 | }
|
---|
| 225 |
|
---|
| 226 | return NULL;
|
---|
| 227 | }
|
---|
| 228 |
|
---|
| 229 |
|
---|
[78111] | 230 | /**
|
---|
[99147] | 231 | * Releases a formerly acquired guest file.
|
---|
| 232 | *
|
---|
| 233 | * @param pFile File to release.
|
---|
| 234 | */
|
---|
| 235 | static void vgsvcGstCtrlSessionFileRelease(PVBOXSERVICECTRLFILE pFile)
|
---|
| 236 | {
|
---|
| 237 | RT_NOREF(pFile);
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 |
|
---|
| 241 | /**
|
---|
[78111] | 242 | * Recursion worker for vgsvcGstCtrlSessionHandleDirRemove.
|
---|
| 243 | * Only (recursively) removes directory structures which are not empty. Will fail if not empty.
|
---|
| 244 | *
|
---|
| 245 | * @returns IPRT status code.
|
---|
[79326] | 246 | * @param pszDir The directory buffer, RTPATH_MAX in length.
|
---|
| 247 | * Contains the abs path to the directory to
|
---|
| 248 | * recurse into. Trailing slash.
|
---|
[78111] | 249 | * @param cchDir The length of the directory we're recursing into,
|
---|
| 250 | * including the trailing slash.
|
---|
| 251 | * @param pDirEntry The dir entry buffer. (Shared to save stack.)
|
---|
| 252 | */
|
---|
[79321] | 253 | static int vgsvcGstCtrlSessionHandleDirRemoveSub(char *pszDir, size_t cchDir, PRTDIRENTRY pDirEntry)
|
---|
[78111] | 254 | {
|
---|
| 255 | RTDIR hDir;
|
---|
| 256 | int rc = RTDirOpen(&hDir, pszDir);
|
---|
| 257 | if (RT_FAILURE(rc))
|
---|
[79326] | 258 | {
|
---|
| 259 | /* Ignore non-existing directories like RTDirRemoveRecursive does: */
|
---|
| 260 | if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
|
---|
| 261 | return VINF_SUCCESS;
|
---|
[78111] | 262 | return rc;
|
---|
[79326] | 263 | }
|
---|
[78111] | 264 |
|
---|
[79326] | 265 | for (;;)
|
---|
[78111] | 266 | {
|
---|
[79326] | 267 | rc = RTDirRead(hDir, pDirEntry, NULL);
|
---|
| 268 | if (RT_FAILURE(rc))
|
---|
| 269 | {
|
---|
| 270 | if (rc == VERR_NO_MORE_FILES)
|
---|
| 271 | rc = VINF_SUCCESS;
|
---|
| 272 | break;
|
---|
| 273 | }
|
---|
| 274 |
|
---|
[78111] | 275 | if (!RTDirEntryIsStdDotLink(pDirEntry))
|
---|
| 276 | {
|
---|
| 277 | /* Construct the full name of the entry. */
|
---|
[79321] | 278 | if (cchDir + pDirEntry->cbName + 1 /* dir slash */ < RTPATH_MAX)
|
---|
| 279 | memcpy(&pszDir[cchDir], pDirEntry->szName, pDirEntry->cbName + 1);
|
---|
| 280 | else
|
---|
[78111] | 281 | {
|
---|
| 282 | rc = VERR_FILENAME_TOO_LONG;
|
---|
| 283 | break;
|
---|
| 284 | }
|
---|
| 285 |
|
---|
[79326] | 286 | /* Make sure we've got the entry type. */
|
---|
[78111] | 287 | if (pDirEntry->enmType == RTDIRENTRYTYPE_UNKNOWN)
|
---|
[79321] | 288 | RTDirQueryUnknownType(pszDir, false /*fFollowSymlinks*/, &pDirEntry->enmType);
|
---|
[79326] | 289 |
|
---|
| 290 | /* Recurse into subdirs and remove them: */
|
---|
| 291 | if (pDirEntry->enmType == RTDIRENTRYTYPE_DIRECTORY)
|
---|
[78111] | 292 | {
|
---|
[79326] | 293 | size_t cchSubDir = cchDir + pDirEntry->cbName;
|
---|
| 294 | pszDir[cchSubDir++] = RTPATH_SLASH;
|
---|
| 295 | pszDir[cchSubDir] = '\0';
|
---|
| 296 | rc = vgsvcGstCtrlSessionHandleDirRemoveSub(pszDir, cchSubDir, pDirEntry);
|
---|
| 297 | if (RT_SUCCESS(rc))
|
---|
[78111] | 298 | {
|
---|
[79326] | 299 | pszDir[cchSubDir] = '\0';
|
---|
| 300 | rc = RTDirRemove(pszDir);
|
---|
| 301 | if (RT_FAILURE(rc))
|
---|
| 302 | break;
|
---|
[78111] | 303 | }
|
---|
[79326] | 304 | else
|
---|
[78111] | 305 | break;
|
---|
| 306 | }
|
---|
[79326] | 307 | /* Not a subdirectory - fail: */
|
---|
| 308 | else
|
---|
| 309 | {
|
---|
| 310 | rc = VERR_DIR_NOT_EMPTY;
|
---|
| 311 | break;
|
---|
| 312 | }
|
---|
[78111] | 313 | }
|
---|
| 314 | }
|
---|
[79326] | 315 |
|
---|
[78111] | 316 | RTDirClose(hDir);
|
---|
| 317 | return rc;
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 |
|
---|
[58029] | 321 | static int vgsvcGstCtrlSessionHandleDirRemove(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[49349] | 322 | {
|
---|
| 323 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 324 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 325 |
|
---|
[75824] | 326 | /*
|
---|
| 327 | * Retrieve the message.
|
---|
| 328 | */
|
---|
| 329 | char szDir[RTPATH_MAX];
|
---|
| 330 | uint32_t fFlags; /* DIRREMOVE_FLAG_XXX */
|
---|
| 331 | int rc = VbglR3GuestCtrlDirGetRemove(pHostCtx, szDir, sizeof(szDir), &fFlags);
|
---|
[49349] | 332 | if (RT_SUCCESS(rc))
|
---|
| 333 | {
|
---|
[75824] | 334 | /*
|
---|
| 335 | * Do some validating before executing the job.
|
---|
| 336 | */
|
---|
[77069] | 337 | if (!(fFlags & ~DIRREMOVEREC_FLAG_VALID_MASK))
|
---|
[49349] | 338 | {
|
---|
[77069] | 339 | if (fFlags & DIRREMOVEREC_FLAG_RECURSIVE)
|
---|
[49349] | 340 | {
|
---|
[79326] | 341 | if (fFlags & (DIRREMOVEREC_FLAG_CONTENT_AND_DIR | DIRREMOVEREC_FLAG_CONTENT_ONLY))
|
---|
[78111] | 342 | {
|
---|
[79326] | 343 | uint32_t fFlagsRemRec = fFlags & DIRREMOVEREC_FLAG_CONTENT_AND_DIR
|
---|
| 344 | ? RTDIRRMREC_F_CONTENT_AND_DIR : RTDIRRMREC_F_CONTENT_ONLY;
|
---|
[78111] | 345 | rc = RTDirRemoveRecursive(szDir, fFlagsRemRec);
|
---|
| 346 | }
|
---|
| 347 | else /* Only remove empty directory structures. Will fail if non-empty. */
|
---|
| 348 | {
|
---|
[79321] | 349 | RTDIRENTRY DirEntry;
|
---|
| 350 | RTPathEnsureTrailingSeparator(szDir, sizeof(szDir));
|
---|
| 351 | rc = vgsvcGstCtrlSessionHandleDirRemoveSub(szDir, strlen(szDir), &DirEntry);
|
---|
[78111] | 352 | }
|
---|
[75824] | 353 | VGSvcVerbose(4, "[Dir %s]: rmdir /s (%#x) -> rc=%Rrc\n", szDir, fFlags, rc);
|
---|
[49349] | 354 | }
|
---|
[75824] | 355 | else
|
---|
| 356 | {
|
---|
| 357 | /* Only delete directory if not empty. */
|
---|
[57659] | 358 | rc = RTDirRemove(szDir);
|
---|
[75824] | 359 | VGSvcVerbose(4, "[Dir %s]: rmdir (%#x), rc=%Rrc\n", szDir, fFlags, rc);
|
---|
| 360 | }
|
---|
[49349] | 361 | }
|
---|
| 362 | else
|
---|
[75824] | 363 | {
|
---|
[77069] | 364 | VGSvcError("[Dir %s]: Unsupported flags: %#x (all %#x)\n", szDir, (fFlags & ~DIRREMOVEREC_FLAG_VALID_MASK), fFlags);
|
---|
[49349] | 365 | rc = VERR_NOT_SUPPORTED;
|
---|
[75824] | 366 | }
|
---|
[49349] | 367 |
|
---|
[75824] | 368 | /*
|
---|
| 369 | * Report result back to host.
|
---|
| 370 | */
|
---|
[49349] | 371 | int rc2 = VbglR3GuestCtrlMsgReply(pHostCtx, rc);
|
---|
| 372 | if (RT_FAILURE(rc2))
|
---|
[75824] | 373 | {
|
---|
[58029] | 374 | VGSvcError("[Dir %s]: Failed to report removing status, rc=%Rrc\n", szDir, rc2);
|
---|
[75824] | 375 | if (RT_SUCCESS(rc))
|
---|
| 376 | rc = rc2;
|
---|
| 377 | }
|
---|
[49349] | 378 | }
|
---|
[75824] | 379 | else
|
---|
| 380 | {
|
---|
| 381 | VGSvcError("Error fetching parameters for rmdir operation: %Rrc\n", rc);
|
---|
| 382 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 383 | }
|
---|
[49349] | 384 |
|
---|
[75824] | 385 | VGSvcVerbose(6, "Removing directory '%s' returned rc=%Rrc\n", szDir, rc);
|
---|
[49349] | 386 | return rc;
|
---|
| 387 | }
|
---|
| 388 |
|
---|
| 389 |
|
---|
[58029] | 390 | static int vgsvcGstCtrlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[44963] | 391 | {
|
---|
| 392 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 393 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 394 |
|
---|
[75824] | 395 | /*
|
---|
| 396 | * Retrieve the message.
|
---|
| 397 | */
|
---|
| 398 | char szFile[RTPATH_MAX];
|
---|
| 399 | char szAccess[64];
|
---|
| 400 | char szDisposition[64];
|
---|
| 401 | char szSharing[64];
|
---|
[44863] | 402 | uint32_t uCreationMode = 0;
|
---|
[75824] | 403 | uint64_t offOpen = 0;
|
---|
| 404 | uint32_t uHandle = 0;
|
---|
[44963] | 405 | int rc = VbglR3GuestCtrlFileGetOpen(pHostCtx,
|
---|
[44863] | 406 | /* File to open. */
|
---|
| 407 | szFile, sizeof(szFile),
|
---|
| 408 | /* Open mode. */
|
---|
[47817] | 409 | szAccess, sizeof(szAccess),
|
---|
[44863] | 410 | /* Disposition. */
|
---|
| 411 | szDisposition, sizeof(szDisposition),
|
---|
[47817] | 412 | /* Sharing. */
|
---|
| 413 | szSharing, sizeof(szSharing),
|
---|
[44863] | 414 | /* Creation mode. */
|
---|
| 415 | &uCreationMode,
|
---|
| 416 | /* Offset. */
|
---|
[58029] | 417 | &offOpen);
|
---|
| 418 | VGSvcVerbose(4, "[File %s]: szAccess=%s, szDisposition=%s, szSharing=%s, offOpen=%RU64, rc=%Rrc\n",
|
---|
| 419 | szFile, szAccess, szDisposition, szSharing, offOpen, rc);
|
---|
[44863] | 420 | if (RT_SUCCESS(rc))
|
---|
| 421 | {
|
---|
[48722] | 422 | PVBOXSERVICECTRLFILE pFile = (PVBOXSERVICECTRLFILE)RTMemAllocZ(sizeof(VBOXSERVICECTRLFILE));
|
---|
[44863] | 423 | if (pFile)
|
---|
| 424 | {
|
---|
[75824] | 425 | pFile->hFile = NIL_RTFILE; /* Not zero or NULL! */
|
---|
| 426 | if (szFile[0])
|
---|
[44863] | 427 | {
|
---|
[84148] | 428 | pFile->pszName = RTStrDup(szFile);
|
---|
| 429 | if (!pFile->pszName)
|
---|
| 430 | rc = VERR_NO_MEMORY;
|
---|
[75824] | 431 | /** @todo
|
---|
| 432 | * Implement szSharing!
|
---|
| 433 | */
|
---|
[47817] | 434 | uint64_t fFlags;
|
---|
| 435 | if (RT_SUCCESS(rc))
|
---|
[75824] | 436 | {
|
---|
[84148] | 437 | rc = RTFileModeToFlagsEx(szAccess, szDisposition, NULL /* pszSharing, not used yet */, &fFlags);
|
---|
| 438 | VGSvcVerbose(4, "[File %s] Opening with fFlags=%#RX64 -> rc=%Rrc\n", pFile->pszName, fFlags, rc);
|
---|
| 439 | }
|
---|
| 440 |
|
---|
| 441 | if (RT_SUCCESS(rc))
|
---|
| 442 | {
|
---|
[79287] | 443 | fFlags |= (uCreationMode << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
|
---|
[83534] | 444 | /* If we're opening a file in read-only mode, strip truncation mode.
|
---|
| 445 | * rtFileRecalcAndValidateFlags() will validate it anyway, but avoid asserting in debug builds. */
|
---|
[83536] | 446 | if (fFlags & RTFILE_O_READ)
|
---|
[83534] | 447 | fFlags &= ~RTFILE_O_TRUNCATE;
|
---|
[84148] | 448 | rc = RTFileOpen(&pFile->hFile, pFile->pszName, fFlags);
|
---|
[75824] | 449 | if (RT_SUCCESS(rc))
|
---|
| 450 | {
|
---|
[83349] | 451 | RTFSOBJINFO objInfo;
|
---|
| 452 | rc = RTFileQueryInfo(pFile->hFile, &objInfo, RTFSOBJATTRADD_NOTHING);
|
---|
[75824] | 453 | if (RT_SUCCESS(rc))
|
---|
| 454 | {
|
---|
[83349] | 455 | /* Make sure that we only open stuff we really support.
|
---|
| 456 | * Only POSIX / UNIX we could open stuff like directories and sockets as well. */
|
---|
| 457 | if ( RT_LIKELY(RTFS_IS_FILE(objInfo.Attr.fMode))
|
---|
| 458 | || RTFS_IS_SYMLINK(objInfo.Attr.fMode))
|
---|
| 459 | {
|
---|
| 460 | /* Seeking is optional. However, the whole operation
|
---|
| 461 | * will fail if we don't succeed seeking to the wanted position. */
|
---|
| 462 | if (offOpen)
|
---|
| 463 | rc = RTFileSeek(pFile->hFile, (int64_t)offOpen, RTFILE_SEEK_BEGIN, NULL /* Current offset */);
|
---|
| 464 | if (RT_SUCCESS(rc))
|
---|
| 465 | {
|
---|
| 466 | /*
|
---|
| 467 | * Succeeded!
|
---|
| 468 | */
|
---|
| 469 | uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHostCtx->uContextID);
|
---|
| 470 | pFile->uHandle = uHandle;
|
---|
| 471 | pFile->fOpen = fFlags;
|
---|
| 472 | RTListAppend(&pSession->lstFiles, &pFile->Node);
|
---|
[84148] | 473 | VGSvcVerbose(2, "[File %s] Opened (ID=%RU32)\n", pFile->pszName, pFile->uHandle);
|
---|
[83349] | 474 | }
|
---|
| 475 | else
|
---|
[84148] | 476 | VGSvcError("[File %s] Seeking to offset %RU64 failed: rc=%Rrc\n", pFile->pszName, offOpen, rc);
|
---|
[83349] | 477 | }
|
---|
| 478 | else
|
---|
| 479 | {
|
---|
[84148] | 480 | VGSvcError("[File %s] Unsupported mode %#x\n", pFile->pszName, objInfo.Attr.fMode);
|
---|
[83349] | 481 | rc = VERR_NOT_SUPPORTED;
|
---|
| 482 | }
|
---|
[75824] | 483 | }
|
---|
| 484 | else
|
---|
[84148] | 485 | VGSvcError("[File %s] Getting mode failed with rc=%Rrc\n", pFile->pszName, rc);
|
---|
[75824] | 486 | }
|
---|
| 487 | else
|
---|
[84148] | 488 | VGSvcError("[File %s] Opening failed with rc=%Rrc\n", pFile->pszName, rc);
|
---|
[44863] | 489 | }
|
---|
| 490 | }
|
---|
[75824] | 491 | else
|
---|
[44863] | 492 | {
|
---|
[98526] | 493 | VGSvcError("Opening file failed: Empty filename!\n");
|
---|
[75824] | 494 | rc = VERR_INVALID_NAME;
|
---|
[44863] | 495 | }
|
---|
| 496 |
|
---|
[75824] | 497 | /* clean up if we failed. */
|
---|
[44863] | 498 | if (RT_FAILURE(rc))
|
---|
[48722] | 499 | {
|
---|
[84148] | 500 | RTStrFree(pFile->pszName);
|
---|
[75824] | 501 | if (pFile->hFile != NIL_RTFILE)
|
---|
[48722] | 502 | RTFileClose(pFile->hFile);
|
---|
[44863] | 503 | RTMemFree(pFile);
|
---|
[48722] | 504 | }
|
---|
[44863] | 505 | }
|
---|
| 506 | else
|
---|
| 507 | rc = VERR_NO_MEMORY;
|
---|
| 508 |
|
---|
[75824] | 509 | /*
|
---|
| 510 | * Report result back to host.
|
---|
| 511 | */
|
---|
[45109] | 512 | int rc2 = VbglR3GuestCtrlFileCbOpen(pHostCtx, rc, uHandle);
|
---|
[44863] | 513 | if (RT_FAILURE(rc2))
|
---|
[75824] | 514 | {
|
---|
[58029] | 515 | VGSvcError("[File %s]: Failed to report file open status, rc=%Rrc\n", szFile, rc2);
|
---|
[75824] | 516 | if (RT_SUCCESS(rc))
|
---|
| 517 | rc = rc2;
|
---|
| 518 | }
|
---|
[44863] | 519 | }
|
---|
[75824] | 520 | else
|
---|
| 521 | {
|
---|
| 522 | VGSvcError("Error fetching parameters for open file operation: %Rrc\n", rc);
|
---|
| 523 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 524 | }
|
---|
[44863] | 525 |
|
---|
[71781] | 526 | VGSvcVerbose(4, "[File %s] Opening (open mode='%s', disposition='%s', creation mode=0x%x) returned rc=%Rrc\n",
|
---|
[58029] | 527 | szFile, szAccess, szDisposition, uCreationMode, rc);
|
---|
[44863] | 528 | return rc;
|
---|
| 529 | }
|
---|
| 530 |
|
---|
| 531 |
|
---|
[58029] | 532 | static int vgsvcGstCtrlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[44863] | 533 | {
|
---|
[44963] | 534 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 535 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 536 |
|
---|
[75824] | 537 | /*
|
---|
| 538 | * Retrieve the message.
|
---|
| 539 | */
|
---|
[47817] | 540 | uint32_t uHandle = 0;
|
---|
[44963] | 541 | int rc = VbglR3GuestCtrlFileGetClose(pHostCtx, &uHandle /* File handle to close */);
|
---|
[44863] | 542 | if (RT_SUCCESS(rc))
|
---|
| 543 | {
|
---|
[99147] | 544 | PVBOXSERVICECTRLFILE pFile = vgsvcGstCtrlSessionFileAcquire(pSession, uHandle);
|
---|
[44863] | 545 | if (pFile)
|
---|
[71781] | 546 | {
|
---|
[84148] | 547 | VGSvcVerbose(2, "[File %s] Closing (handle=%RU32)\n", pFile ? pFile->pszName : "<Not found>", uHandle);
|
---|
[83595] | 548 | rc = vgsvcGstCtrlSessionFileFree(pFile);
|
---|
[71781] | 549 | }
|
---|
[44863] | 550 | else
|
---|
[75824] | 551 | {
|
---|
| 552 | VGSvcError("File %u (%#x) not found!\n", uHandle, uHandle);
|
---|
[44863] | 553 | rc = VERR_NOT_FOUND;
|
---|
[75824] | 554 | }
|
---|
[44863] | 555 |
|
---|
[75824] | 556 | /*
|
---|
| 557 | * Report result back to host.
|
---|
| 558 | */
|
---|
[45109] | 559 | int rc2 = VbglR3GuestCtrlFileCbClose(pHostCtx, rc);
|
---|
[44863] | 560 | if (RT_FAILURE(rc2))
|
---|
[75824] | 561 | {
|
---|
[58029] | 562 | VGSvcError("Failed to report file close status, rc=%Rrc\n", rc2);
|
---|
[75824] | 563 | if (RT_SUCCESS(rc))
|
---|
| 564 | rc = rc2;
|
---|
| 565 | }
|
---|
[44863] | 566 | }
|
---|
[75824] | 567 | else
|
---|
| 568 | {
|
---|
| 569 | VGSvcError("Error fetching parameters for close file operation: %Rrc\n", rc);
|
---|
| 570 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 571 | }
|
---|
[44863] | 572 | return rc;
|
---|
| 573 | }
|
---|
| 574 |
|
---|
| 575 |
|
---|
[58029] | 576 | static int vgsvcGstCtrlSessionHandleFileRead(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
|
---|
[75824] | 577 | void **ppvScratchBuf, uint32_t *pcbScratchBuf)
|
---|
[44863] | 578 | {
|
---|
[44963] | 579 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 580 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 581 |
|
---|
[75824] | 582 | /*
|
---|
| 583 | * Retrieve the request.
|
---|
| 584 | */
|
---|
[47817] | 585 | uint32_t uHandle = 0;
|
---|
[44863] | 586 | uint32_t cbToRead;
|
---|
[44963] | 587 | int rc = VbglR3GuestCtrlFileGetRead(pHostCtx, &uHandle, &cbToRead);
|
---|
[44863] | 588 | if (RT_SUCCESS(rc))
|
---|
| 589 | {
|
---|
[75824] | 590 | /*
|
---|
| 591 | * Locate the file and do the reading.
|
---|
| 592 | *
|
---|
| 593 | * If the request is larger than our scratch buffer, try grow it - just
|
---|
| 594 | * ignore failure as the host better respect our buffer limits.
|
---|
| 595 | */
|
---|
[79296] | 596 | uint32_t offNew = 0;
|
---|
| 597 | size_t cbRead = 0;
|
---|
[99147] | 598 | PVBOXSERVICECTRLFILE pFile = vgsvcGstCtrlSessionFileAcquire(pSession, uHandle);
|
---|
[44863] | 599 | if (pFile)
|
---|
| 600 | {
|
---|
[75824] | 601 | if (*pcbScratchBuf < cbToRead)
|
---|
| 602 | vgsvcGstCtrlSessionGrowScratchBuf(ppvScratchBuf, pcbScratchBuf, cbToRead);
|
---|
[44863] | 603 |
|
---|
[75824] | 604 | rc = RTFileRead(pFile->hFile, *ppvScratchBuf, RT_MIN(cbToRead, *pcbScratchBuf), &cbRead);
|
---|
[79296] | 605 | offNew = (int64_t)RTFileTell(pFile->hFile);
|
---|
[84148] | 606 | VGSvcVerbose(5, "[File %s] Read %zu/%RU32 bytes, rc=%Rrc, offNew=%RI64\n", pFile->pszName, cbRead, cbToRead, rc, offNew);
|
---|
[99147] | 607 | vgsvcGstCtrlSessionFileRelease(pFile);
|
---|
[44863] | 608 | }
|
---|
| 609 | else
|
---|
[75824] | 610 | {
|
---|
| 611 | VGSvcError("File %u (%#x) not found!\n", uHandle, uHandle);
|
---|
[44863] | 612 | rc = VERR_NOT_FOUND;
|
---|
[75824] | 613 | }
|
---|
[44863] | 614 |
|
---|
[75824] | 615 | /*
|
---|
| 616 | * Report result and data back to the host.
|
---|
| 617 | */
|
---|
[79296] | 618 | int rc2;
|
---|
| 619 | if (g_fControlHostFeatures0 & VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET)
|
---|
| 620 | rc2 = VbglR3GuestCtrlFileCbReadOffset(pHostCtx, rc, *ppvScratchBuf, (uint32_t)cbRead, offNew);
|
---|
| 621 | else
|
---|
| 622 | rc2 = VbglR3GuestCtrlFileCbRead(pHostCtx, rc, *ppvScratchBuf, (uint32_t)cbRead);
|
---|
[44863] | 623 | if (RT_FAILURE(rc2))
|
---|
[75824] | 624 | {
|
---|
[58029] | 625 | VGSvcError("Failed to report file read status, rc=%Rrc\n", rc2);
|
---|
[75824] | 626 | if (RT_SUCCESS(rc))
|
---|
| 627 | rc = rc2;
|
---|
| 628 | }
|
---|
[44863] | 629 | }
|
---|
[75824] | 630 | else
|
---|
| 631 | {
|
---|
| 632 | VGSvcError("Error fetching parameters for file read operation: %Rrc\n", rc);
|
---|
| 633 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 634 | }
|
---|
[44863] | 635 | return rc;
|
---|
| 636 | }
|
---|
| 637 |
|
---|
| 638 |
|
---|
[58029] | 639 | static int vgsvcGstCtrlSessionHandleFileReadAt(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
|
---|
[75824] | 640 | void **ppvScratchBuf, uint32_t *pcbScratchBuf)
|
---|
[44863] | 641 | {
|
---|
[44963] | 642 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 643 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 644 |
|
---|
[75824] | 645 | /*
|
---|
| 646 | * Retrieve the request.
|
---|
| 647 | */
|
---|
[47817] | 648 | uint32_t uHandle = 0;
|
---|
[58029] | 649 | uint32_t cbToRead;
|
---|
| 650 | uint64_t offReadAt;
|
---|
| 651 | int rc = VbglR3GuestCtrlFileGetReadAt(pHostCtx, &uHandle, &cbToRead, &offReadAt);
|
---|
[44863] | 652 | if (RT_SUCCESS(rc))
|
---|
| 653 | {
|
---|
[75824] | 654 | /*
|
---|
| 655 | * Locate the file and do the reading.
|
---|
| 656 | *
|
---|
| 657 | * If the request is larger than our scratch buffer, try grow it - just
|
---|
| 658 | * ignore failure as the host better respect our buffer limits.
|
---|
| 659 | */
|
---|
[79296] | 660 | int64_t offNew = 0;
|
---|
| 661 | size_t cbRead = 0;
|
---|
[99147] | 662 | PVBOXSERVICECTRLFILE pFile = vgsvcGstCtrlSessionFileAcquire(pSession, uHandle);
|
---|
[44863] | 663 | if (pFile)
|
---|
| 664 | {
|
---|
[75824] | 665 | if (*pcbScratchBuf < cbToRead)
|
---|
| 666 | vgsvcGstCtrlSessionGrowScratchBuf(ppvScratchBuf, pcbScratchBuf, cbToRead);
|
---|
[44863] | 667 |
|
---|
[75824] | 668 | rc = RTFileReadAt(pFile->hFile, (RTFOFF)offReadAt, *ppvScratchBuf, RT_MIN(cbToRead, *pcbScratchBuf), &cbRead);
|
---|
[79296] | 669 | if (RT_SUCCESS(rc))
|
---|
| 670 | {
|
---|
| 671 | offNew = offReadAt + cbRead;
|
---|
| 672 | RTFileSeek(pFile->hFile, offNew, RTFILE_SEEK_BEGIN, NULL); /* RTFileReadAt does not always change position. */
|
---|
| 673 | }
|
---|
| 674 | else
|
---|
| 675 | offNew = (int64_t)RTFileTell(pFile->hFile);
|
---|
[84148] | 676 | VGSvcVerbose(5, "[File %s] Read %zu bytes @ %RU64, rc=%Rrc, offNew=%RI64\n", pFile->pszName, cbRead, offReadAt, rc, offNew);
|
---|
[99147] | 677 | vgsvcGstCtrlSessionFileRelease(pFile);
|
---|
[44863] | 678 | }
|
---|
| 679 | else
|
---|
[75824] | 680 | {
|
---|
| 681 | VGSvcError("File %u (%#x) not found!\n", uHandle, uHandle);
|
---|
[44863] | 682 | rc = VERR_NOT_FOUND;
|
---|
[75824] | 683 | }
|
---|
[44863] | 684 |
|
---|
[75824] | 685 | /*
|
---|
| 686 | * Report result and data back to the host.
|
---|
| 687 | */
|
---|
[79296] | 688 | int rc2;
|
---|
| 689 | if (g_fControlHostFeatures0 & VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET)
|
---|
| 690 | rc2 = VbglR3GuestCtrlFileCbReadOffset(pHostCtx, rc, *ppvScratchBuf, (uint32_t)cbRead, offNew);
|
---|
| 691 | else
|
---|
| 692 | rc2 = VbglR3GuestCtrlFileCbRead(pHostCtx, rc, *ppvScratchBuf, (uint32_t)cbRead);
|
---|
[44863] | 693 | if (RT_FAILURE(rc2))
|
---|
[75824] | 694 | {
|
---|
| 695 | VGSvcError("Failed to report file read at status, rc=%Rrc\n", rc2);
|
---|
| 696 | if (RT_SUCCESS(rc))
|
---|
| 697 | rc = rc2;
|
---|
| 698 | }
|
---|
[44863] | 699 | }
|
---|
[75824] | 700 | else
|
---|
| 701 | {
|
---|
| 702 | VGSvcError("Error fetching parameters for file read at operation: %Rrc\n", rc);
|
---|
| 703 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 704 | }
|
---|
[44863] | 705 | return rc;
|
---|
| 706 | }
|
---|
| 707 |
|
---|
| 708 |
|
---|
[58029] | 709 | static int vgsvcGstCtrlSessionHandleFileWrite(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
|
---|
[75824] | 710 | void **ppvScratchBuf, uint32_t *pcbScratchBuf)
|
---|
[44863] | 711 | {
|
---|
[44963] | 712 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 713 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
[44863] | 714 |
|
---|
[75824] | 715 | /*
|
---|
| 716 | * Retrieve the request and data to write.
|
---|
| 717 | */
|
---|
[47817] | 718 | uint32_t uHandle = 0;
|
---|
[44863] | 719 | uint32_t cbToWrite;
|
---|
[75824] | 720 | int rc = VbglR3GuestCtrlFileGetWrite(pHostCtx, &uHandle, *ppvScratchBuf, *pcbScratchBuf, &cbToWrite);
|
---|
| 721 | if ( rc == VERR_BUFFER_OVERFLOW
|
---|
| 722 | && vgsvcGstCtrlSessionGrowScratchBuf(ppvScratchBuf, pcbScratchBuf, cbToWrite))
|
---|
| 723 | rc = VbglR3GuestCtrlFileGetWrite(pHostCtx, &uHandle, *ppvScratchBuf, *pcbScratchBuf, &cbToWrite);
|
---|
[44863] | 724 | if (RT_SUCCESS(rc))
|
---|
| 725 | {
|
---|
[75824] | 726 | /*
|
---|
| 727 | * Locate the file and do the writing.
|
---|
| 728 | */
|
---|
[79296] | 729 | int64_t offNew = 0;
|
---|
| 730 | size_t cbWritten = 0;
|
---|
[99147] | 731 | PVBOXSERVICECTRLFILE pFile = vgsvcGstCtrlSessionFileAcquire(pSession, uHandle);
|
---|
[44863] | 732 | if (pFile)
|
---|
| 733 | {
|
---|
[75824] | 734 | rc = RTFileWrite(pFile->hFile, *ppvScratchBuf, RT_MIN(cbToWrite, *pcbScratchBuf), &cbWritten);
|
---|
[79296] | 735 | offNew = (int64_t)RTFileTell(pFile->hFile);
|
---|
| 736 | VGSvcVerbose(5, "[File %s] Writing %p LB %RU32 => %Rrc, cbWritten=%zu, offNew=%RI64\n",
|
---|
[84148] | 737 | pFile->pszName, *ppvScratchBuf, RT_MIN(cbToWrite, *pcbScratchBuf), rc, cbWritten, offNew);
|
---|
[99147] | 738 | vgsvcGstCtrlSessionFileRelease(pFile);
|
---|
[44863] | 739 | }
|
---|
| 740 | else
|
---|
[75824] | 741 | {
|
---|
| 742 | VGSvcError("File %u (%#x) not found!\n", uHandle, uHandle);
|
---|
[44863] | 743 | rc = VERR_NOT_FOUND;
|
---|
[75824] | 744 | }
|
---|
[44863] | 745 |
|
---|
[75824] | 746 | /*
|
---|
| 747 | * Report result back to host.
|
---|
| 748 | */
|
---|
[79296] | 749 | int rc2;
|
---|
| 750 | if (g_fControlHostFeatures0 & VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET)
|
---|
| 751 | rc2 = VbglR3GuestCtrlFileCbWriteOffset(pHostCtx, rc, (uint32_t)cbWritten, offNew);
|
---|
| 752 | else
|
---|
| 753 | rc2 = VbglR3GuestCtrlFileCbWrite(pHostCtx, rc, (uint32_t)cbWritten);
|
---|
[44863] | 754 | if (RT_FAILURE(rc2))
|
---|
[75824] | 755 | {
|
---|
[58029] | 756 | VGSvcError("Failed to report file write status, rc=%Rrc\n", rc2);
|
---|
[75824] | 757 | if (RT_SUCCESS(rc))
|
---|
| 758 | rc = rc2;
|
---|
| 759 | }
|
---|
[44863] | 760 | }
|
---|
[75824] | 761 | else
|
---|
| 762 | {
|
---|
| 763 | VGSvcError("Error fetching parameters for file write operation: %Rrc\n", rc);
|
---|
| 764 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 765 | }
|
---|
[44863] | 766 | return rc;
|
---|
| 767 | }
|
---|
| 768 |
|
---|
| 769 |
|
---|
[58029] | 770 | static int vgsvcGstCtrlSessionHandleFileWriteAt(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
|
---|
[75824] | 771 | void **ppvScratchBuf, uint32_t *pcbScratchBuf)
|
---|
[44863] | 772 | {
|
---|
[44963] | 773 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 774 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
[44863] | 775 |
|
---|
[75824] | 776 | /*
|
---|
| 777 | * Retrieve the request and data to write.
|
---|
| 778 | */
|
---|
[47817] | 779 | uint32_t uHandle = 0;
|
---|
[58029] | 780 | uint32_t cbToWrite;
|
---|
| 781 | uint64_t offWriteAt;
|
---|
[75824] | 782 | int rc = VbglR3GuestCtrlFileGetWriteAt(pHostCtx, &uHandle, *ppvScratchBuf, *pcbScratchBuf, &cbToWrite, &offWriteAt);
|
---|
| 783 | if ( rc == VERR_BUFFER_OVERFLOW
|
---|
| 784 | && vgsvcGstCtrlSessionGrowScratchBuf(ppvScratchBuf, pcbScratchBuf, cbToWrite))
|
---|
| 785 | rc = VbglR3GuestCtrlFileGetWriteAt(pHostCtx, &uHandle, *ppvScratchBuf, *pcbScratchBuf, &cbToWrite, &offWriteAt);
|
---|
[44863] | 786 | if (RT_SUCCESS(rc))
|
---|
| 787 | {
|
---|
[75824] | 788 | /*
|
---|
| 789 | * Locate the file and do the writing.
|
---|
| 790 | */
|
---|
[79296] | 791 | int64_t offNew = 0;
|
---|
| 792 | size_t cbWritten = 0;
|
---|
[99147] | 793 | PVBOXSERVICECTRLFILE pFile = vgsvcGstCtrlSessionFileAcquire(pSession, uHandle);
|
---|
[44863] | 794 | if (pFile)
|
---|
| 795 | {
|
---|
[75824] | 796 | rc = RTFileWriteAt(pFile->hFile, (RTFOFF)offWriteAt, *ppvScratchBuf, RT_MIN(cbToWrite, *pcbScratchBuf), &cbWritten);
|
---|
[79296] | 797 | if (RT_SUCCESS(rc))
|
---|
| 798 | {
|
---|
| 799 | offNew = offWriteAt + cbWritten;
|
---|
| 800 |
|
---|
| 801 | /* RTFileWriteAt does not always change position: */
|
---|
| 802 | if (!(pFile->fOpen & RTFILE_O_APPEND))
|
---|
| 803 | RTFileSeek(pFile->hFile, offNew, RTFILE_SEEK_BEGIN, NULL);
|
---|
| 804 | else
|
---|
| 805 | RTFileSeek(pFile->hFile, 0, RTFILE_SEEK_END, (uint64_t *)&offNew);
|
---|
| 806 | }
|
---|
| 807 | else
|
---|
| 808 | offNew = (int64_t)RTFileTell(pFile->hFile);
|
---|
| 809 | VGSvcVerbose(5, "[File %s] Writing %p LB %RU32 @ %RU64 => %Rrc, cbWritten=%zu, offNew=%RI64\n",
|
---|
[84148] | 810 | pFile->pszName, *ppvScratchBuf, RT_MIN(cbToWrite, *pcbScratchBuf), offWriteAt, rc, cbWritten, offNew);
|
---|
[99147] | 811 | vgsvcGstCtrlSessionFileRelease(pFile);
|
---|
[44863] | 812 | }
|
---|
| 813 | else
|
---|
[75824] | 814 | {
|
---|
| 815 | VGSvcError("File %u (%#x) not found!\n", uHandle, uHandle);
|
---|
[44863] | 816 | rc = VERR_NOT_FOUND;
|
---|
[75824] | 817 | }
|
---|
[44863] | 818 |
|
---|
[75824] | 819 | /*
|
---|
| 820 | * Report result back to host.
|
---|
| 821 | */
|
---|
[79296] | 822 | int rc2;
|
---|
| 823 | if (g_fControlHostFeatures0 & VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET)
|
---|
| 824 | rc2 = VbglR3GuestCtrlFileCbWriteOffset(pHostCtx, rc, (uint32_t)cbWritten, offNew);
|
---|
| 825 | else
|
---|
| 826 | rc2 = VbglR3GuestCtrlFileCbWrite(pHostCtx, rc, (uint32_t)cbWritten);
|
---|
[44863] | 827 | if (RT_FAILURE(rc2))
|
---|
[75824] | 828 | {
|
---|
[58029] | 829 | VGSvcError("Failed to report file write status, rc=%Rrc\n", rc2);
|
---|
[75824] | 830 | if (RT_SUCCESS(rc))
|
---|
| 831 | rc = rc2;
|
---|
| 832 | }
|
---|
[44863] | 833 | }
|
---|
[75824] | 834 | else
|
---|
| 835 | {
|
---|
| 836 | VGSvcError("Error fetching parameters for file write at operation: %Rrc\n", rc);
|
---|
| 837 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 838 | }
|
---|
[44863] | 839 | return rc;
|
---|
| 840 | }
|
---|
| 841 |
|
---|
| 842 |
|
---|
[58029] | 843 | static int vgsvcGstCtrlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[44863] | 844 | {
|
---|
[44963] | 845 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 846 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 847 |
|
---|
[75824] | 848 | /*
|
---|
| 849 | * Retrieve the request.
|
---|
| 850 | */
|
---|
[47817] | 851 | uint32_t uHandle = 0;
|
---|
[44863] | 852 | uint32_t uSeekMethod;
|
---|
[58029] | 853 | uint64_t offSeek; /* Will be converted to int64_t. */
|
---|
| 854 | int rc = VbglR3GuestCtrlFileGetSeek(pHostCtx, &uHandle, &uSeekMethod, &offSeek);
|
---|
[44863] | 855 | if (RT_SUCCESS(rc))
|
---|
| 856 | {
|
---|
[58029] | 857 | uint64_t offActual = 0;
|
---|
[75824] | 858 |
|
---|
| 859 | /*
|
---|
| 860 | * Validate and convert the seek method to IPRT speak.
|
---|
| 861 | */
|
---|
| 862 | static const uint8_t s_abMethods[GUEST_FILE_SEEKTYPE_END + 1] =
|
---|
[44863] | 863 | {
|
---|
[75824] | 864 | UINT8_MAX, RTFILE_SEEK_BEGIN, UINT8_MAX, UINT8_MAX, RTFILE_SEEK_CURRENT,
|
---|
[79261] | 865 | UINT8_MAX, UINT8_MAX, UINT8_MAX, RTFILE_SEEK_END
|
---|
[75824] | 866 | };
|
---|
| 867 | if ( uSeekMethod < RT_ELEMENTS(s_abMethods)
|
---|
| 868 | && s_abMethods[uSeekMethod] != UINT8_MAX)
|
---|
| 869 | {
|
---|
| 870 | /*
|
---|
| 871 | * Locate the file and do the seek.
|
---|
| 872 | */
|
---|
[99147] | 873 | PVBOXSERVICECTRLFILE pFile = vgsvcGstCtrlSessionFileAcquire(pSession, uHandle);
|
---|
[75824] | 874 | if (pFile)
|
---|
[44863] | 875 | {
|
---|
[75824] | 876 | rc = RTFileSeek(pFile->hFile, (int64_t)offSeek, s_abMethods[uSeekMethod], &offActual);
|
---|
| 877 | VGSvcVerbose(5, "[File %s]: Seeking to offSeek=%RI64, uSeekMethodIPRT=%u, rc=%Rrc\n",
|
---|
[84148] | 878 | pFile->pszName, offSeek, s_abMethods[uSeekMethod], rc);
|
---|
[99147] | 879 | vgsvcGstCtrlSessionFileRelease(pFile);
|
---|
[44863] | 880 | }
|
---|
[75824] | 881 | else
|
---|
[48775] | 882 | {
|
---|
[75824] | 883 | VGSvcError("File %u (%#x) not found!\n", uHandle, uHandle);
|
---|
| 884 | rc = VERR_NOT_FOUND;
|
---|
[48775] | 885 | }
|
---|
[44863] | 886 | }
|
---|
| 887 | else
|
---|
[75824] | 888 | {
|
---|
| 889 | VGSvcError("Invalid seek method: %#x\n", uSeekMethod);
|
---|
| 890 | rc = VERR_NOT_SUPPORTED;
|
---|
| 891 | }
|
---|
[44863] | 892 |
|
---|
[75824] | 893 | /*
|
---|
| 894 | * Report result back to host.
|
---|
| 895 | */
|
---|
[58029] | 896 | int rc2 = VbglR3GuestCtrlFileCbSeek(pHostCtx, rc, offActual);
|
---|
[44863] | 897 | if (RT_FAILURE(rc2))
|
---|
[75824] | 898 | {
|
---|
[58029] | 899 | VGSvcError("Failed to report file seek status, rc=%Rrc\n", rc2);
|
---|
[75824] | 900 | if (RT_SUCCESS(rc))
|
---|
| 901 | rc = rc2;
|
---|
| 902 | }
|
---|
[44863] | 903 | }
|
---|
[75824] | 904 | else
|
---|
| 905 | {
|
---|
| 906 | VGSvcError("Error fetching parameters for file seek operation: %Rrc\n", rc);
|
---|
| 907 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 908 | }
|
---|
[44863] | 909 | return rc;
|
---|
| 910 | }
|
---|
| 911 |
|
---|
| 912 |
|
---|
[58029] | 913 | static int vgsvcGstCtrlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[44863] | 914 | {
|
---|
[44963] | 915 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 916 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 917 |
|
---|
[75824] | 918 | /*
|
---|
| 919 | * Retrieve the request.
|
---|
| 920 | */
|
---|
[47817] | 921 | uint32_t uHandle = 0;
|
---|
[44963] | 922 | int rc = VbglR3GuestCtrlFileGetTell(pHostCtx, &uHandle);
|
---|
[44863] | 923 | if (RT_SUCCESS(rc))
|
---|
| 924 | {
|
---|
[75824] | 925 | /*
|
---|
| 926 | * Locate the file and ask for the current position.
|
---|
| 927 | */
|
---|
| 928 | uint64_t offCurrent = 0;
|
---|
[99147] | 929 | PVBOXSERVICECTRLFILE pFile = vgsvcGstCtrlSessionFileAcquire(pSession, uHandle);
|
---|
[44863] | 930 | if (pFile)
|
---|
| 931 | {
|
---|
[75824] | 932 | offCurrent = RTFileTell(pFile->hFile);
|
---|
[84148] | 933 | VGSvcVerbose(5, "[File %s]: Telling offCurrent=%RU64\n", pFile->pszName, offCurrent);
|
---|
[99147] | 934 | vgsvcGstCtrlSessionFileRelease(pFile);
|
---|
[44863] | 935 | }
|
---|
| 936 | else
|
---|
[75824] | 937 | {
|
---|
| 938 | VGSvcError("File %u (%#x) not found!\n", uHandle, uHandle);
|
---|
[44863] | 939 | rc = VERR_NOT_FOUND;
|
---|
[75824] | 940 | }
|
---|
[44863] | 941 |
|
---|
[75824] | 942 | /*
|
---|
| 943 | * Report result back to host.
|
---|
| 944 | */
|
---|
| 945 | int rc2 = VbglR3GuestCtrlFileCbTell(pHostCtx, rc, offCurrent);
|
---|
[44863] | 946 | if (RT_FAILURE(rc2))
|
---|
[75824] | 947 | {
|
---|
[58029] | 948 | VGSvcError("Failed to report file tell status, rc=%Rrc\n", rc2);
|
---|
[75824] | 949 | if (RT_SUCCESS(rc))
|
---|
| 950 | rc = rc2;
|
---|
| 951 | }
|
---|
[44863] | 952 | }
|
---|
[75824] | 953 | else
|
---|
| 954 | {
|
---|
| 955 | VGSvcError("Error fetching parameters for file tell operation: %Rrc\n", rc);
|
---|
| 956 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 957 | }
|
---|
[44863] | 958 | return rc;
|
---|
| 959 | }
|
---|
| 960 |
|
---|
| 961 |
|
---|
[79287] | 962 | static int vgsvcGstCtrlSessionHandleFileSetSize(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 963 | {
|
---|
| 964 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 965 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 966 |
|
---|
| 967 | /*
|
---|
| 968 | * Retrieve the request.
|
---|
| 969 | */
|
---|
| 970 | uint32_t uHandle = 0;
|
---|
| 971 | uint64_t cbNew = 0;
|
---|
| 972 | int rc = VbglR3GuestCtrlFileGetSetSize(pHostCtx, &uHandle, &cbNew);
|
---|
| 973 | if (RT_SUCCESS(rc))
|
---|
| 974 | {
|
---|
| 975 | /*
|
---|
| 976 | * Locate the file and ask for the current position.
|
---|
| 977 | */
|
---|
[99147] | 978 | PVBOXSERVICECTRLFILE pFile = vgsvcGstCtrlSessionFileAcquire(pSession, uHandle);
|
---|
[79287] | 979 | if (pFile)
|
---|
| 980 | {
|
---|
| 981 | rc = RTFileSetSize(pFile->hFile, cbNew);
|
---|
[84148] | 982 | VGSvcVerbose(5, "[File %s]: Changing size to %RU64 (%#RX64), rc=%Rrc\n", pFile->pszName, cbNew, cbNew, rc);
|
---|
[99147] | 983 | vgsvcGstCtrlSessionFileRelease(pFile);
|
---|
[79287] | 984 | }
|
---|
| 985 | else
|
---|
| 986 | {
|
---|
| 987 | VGSvcError("File %u (%#x) not found!\n", uHandle, uHandle);
|
---|
| 988 | cbNew = UINT64_MAX;
|
---|
| 989 | rc = VERR_NOT_FOUND;
|
---|
| 990 | }
|
---|
| 991 |
|
---|
| 992 | /*
|
---|
| 993 | * Report result back to host.
|
---|
| 994 | */
|
---|
| 995 | int rc2 = VbglR3GuestCtrlFileCbSetSize(pHostCtx, rc, cbNew);
|
---|
| 996 | if (RT_FAILURE(rc2))
|
---|
| 997 | {
|
---|
| 998 | VGSvcError("Failed to report file tell status, rc=%Rrc\n", rc2);
|
---|
| 999 | if (RT_SUCCESS(rc))
|
---|
| 1000 | rc = rc2;
|
---|
| 1001 | }
|
---|
| 1002 | }
|
---|
| 1003 | else
|
---|
| 1004 | {
|
---|
| 1005 | VGSvcError("Error fetching parameters for file tell operation: %Rrc\n", rc);
|
---|
| 1006 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1007 | }
|
---|
| 1008 | return rc;
|
---|
| 1009 | }
|
---|
| 1010 |
|
---|
| 1011 |
|
---|
[98526] | 1012 | #ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
|
---|
| 1013 | static int vgsvcGstCtrlSessionHandleFileRemove(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1014 | {
|
---|
| 1015 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1016 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1017 |
|
---|
| 1018 | /*
|
---|
| 1019 | * Retrieve the request.
|
---|
| 1020 | */
|
---|
| 1021 | char szPath[RTPATH_MAX];
|
---|
| 1022 | int rc = VbglR3GuestCtrlFileGetRemove(pHostCtx, szPath, sizeof(szPath));
|
---|
| 1023 | if (RT_SUCCESS(rc))
|
---|
| 1024 | {
|
---|
| 1025 | VGSvcVerbose(4, "Deleting file szPath=%s\n", szPath);
|
---|
| 1026 | rc = RTFileDelete(szPath);
|
---|
| 1027 |
|
---|
| 1028 | /*
|
---|
| 1029 | * Report result back to host.
|
---|
| 1030 | */
|
---|
| 1031 | int rc2 = VbglR3GuestCtrlMsgReply(pHostCtx, rc);
|
---|
| 1032 | if (RT_FAILURE(rc2))
|
---|
| 1033 | {
|
---|
| 1034 | VGSvcError("Failed to report file deletion status, rc=%Rrc\n", rc2);
|
---|
| 1035 | if (RT_SUCCESS(rc))
|
---|
| 1036 | rc = rc2;
|
---|
| 1037 | }
|
---|
| 1038 | }
|
---|
| 1039 | else
|
---|
| 1040 | {
|
---|
| 1041 | VGSvcError("Error fetching parameters for file deletion operation: %Rrc\n", rc);
|
---|
| 1042 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1043 | }
|
---|
| 1044 | VGSvcVerbose(5, "Deleting file returned rc=%Rrc\n", rc);
|
---|
| 1045 | return rc;
|
---|
| 1046 | }
|
---|
| 1047 |
|
---|
| 1048 |
|
---|
| 1049 | static int vgsvcGstCtrlSessionHandleDirOpen(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1050 | {
|
---|
| 1051 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1052 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1053 |
|
---|
[98818] | 1054 | char szPath[RTPATH_MAX];
|
---|
| 1055 | uint32_t fFlags;
|
---|
| 1056 | GSTCTLDIRFILTER enmFilter;
|
---|
| 1057 | uint32_t uHandle = 0;
|
---|
| 1058 | uint32_t fReadFlags;
|
---|
| 1059 | GSTCTLFSOBJATTRADD enmAttrAdd;
|
---|
| 1060 | int rc = VbglR3GuestCtrlDirGetOpen(pHostCtx, szPath, sizeof(szPath), &fFlags, &enmFilter, &enmAttrAdd, &fReadFlags);
|
---|
[98791] | 1061 | VGSvcVerbose(4, "[Dir %s]: fFlags=%#x, enmFilter=%#x, rc=%Rrc\n", szPath, fFlags, enmFilter, rc);
|
---|
[98526] | 1062 | if (RT_SUCCESS(rc))
|
---|
| 1063 | {
|
---|
| 1064 | PVBOXSERVICECTRLDIR pDir = (PVBOXSERVICECTRLDIR)RTMemAllocZ(sizeof(VBOXSERVICECTRLDIR));
|
---|
| 1065 | AssertPtrReturn(pDir, VERR_NO_MEMORY);
|
---|
| 1066 | pDir->hDir = NIL_RTDIR; /* Not zero or NULL! */
|
---|
| 1067 | if (szPath[0])
|
---|
| 1068 | {
|
---|
| 1069 | pDir->pszPathAbs = RTStrDup(szPath);
|
---|
| 1070 | if (!pDir->pszPathAbs)
|
---|
| 1071 | rc = VERR_NO_MEMORY;
|
---|
| 1072 |
|
---|
[98818] | 1073 | /* Save reading parameters for subsequent directory entry read calls later. */
|
---|
| 1074 | pDir->fRead = fReadFlags;
|
---|
| 1075 | pDir->enmReadAttrAdd = enmAttrAdd;
|
---|
| 1076 |
|
---|
[99085] | 1077 | pDir->cbDirEntryEx = GSTCTL_DIRENTRY_MAX_SIZE;
|
---|
| 1078 | pDir->pDirEntryEx = (PRTDIRENTRYEX)RTMemAlloc(pDir->cbDirEntryEx);
|
---|
| 1079 | AssertPtrReturn(pDir->pDirEntryEx, VERR_NO_MEMORY);
|
---|
| 1080 |
|
---|
[98526] | 1081 | if (RT_SUCCESS(rc))
|
---|
| 1082 | {
|
---|
| 1083 | rc = RTDirOpenFiltered(&pDir->hDir, pDir->pszPathAbs, (RTDIRFILTER)enmFilter, fFlags);
|
---|
| 1084 | if (RT_SUCCESS(rc))
|
---|
| 1085 | {
|
---|
| 1086 | uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHostCtx->uContextID);
|
---|
| 1087 | pDir->uHandle = uHandle;
|
---|
| 1088 | RTListAppend(&pSession->lstDirs, &pDir->Node);
|
---|
| 1089 | VGSvcVerbose(2, "[Dir %s] Opened (ID=%RU32)\n", pDir->pszPathAbs, pDir->uHandle);
|
---|
| 1090 | }
|
---|
| 1091 | }
|
---|
| 1092 | }
|
---|
| 1093 | else
|
---|
| 1094 | {
|
---|
| 1095 | VGSvcError("Opening directory failed: Empty path!\n");
|
---|
| 1096 | rc = VERR_INVALID_NAME;
|
---|
| 1097 | }
|
---|
| 1098 |
|
---|
| 1099 | /* Clean up if we failed. */
|
---|
| 1100 | if (RT_FAILURE(rc))
|
---|
| 1101 | {
|
---|
| 1102 | RTStrFree(pDir->pszPathAbs);
|
---|
| 1103 | if (pDir->hDir != NIL_RTDIR)
|
---|
| 1104 | RTDirClose(pDir->hDir);
|
---|
| 1105 | RTMemFree(pDir);
|
---|
| 1106 | }
|
---|
| 1107 |
|
---|
| 1108 | /*
|
---|
| 1109 | * Report result back to host.
|
---|
| 1110 | */
|
---|
| 1111 | int rc2 = VbglR3GuestCtrlDirCbOpen(pHostCtx, rc, uHandle);
|
---|
| 1112 | if (RT_FAILURE(rc2))
|
---|
| 1113 | {
|
---|
| 1114 | VGSvcError("[Dir %s]: Failed to report directory open status, rc=%Rrc\n", szPath, rc2);
|
---|
| 1115 | if (RT_SUCCESS(rc))
|
---|
| 1116 | rc = rc2;
|
---|
| 1117 | }
|
---|
| 1118 | }
|
---|
| 1119 | else
|
---|
| 1120 | {
|
---|
| 1121 | VGSvcError("Error fetching parameters for directory open operation: %Rrc\n", rc);
|
---|
| 1122 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1123 | }
|
---|
| 1124 |
|
---|
| 1125 | VGSvcVerbose(4, "[Dir %s] Opening (flags=%#x, filter flags=%#x) returned rc=%Rrc\n",
|
---|
| 1126 | szPath, fFlags, enmFilter, rc);
|
---|
| 1127 | return rc;
|
---|
| 1128 | }
|
---|
| 1129 |
|
---|
| 1130 |
|
---|
| 1131 | static int vgsvcGstCtrlSessionHandleDirClose(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1132 | {
|
---|
| 1133 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1134 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1135 |
|
---|
| 1136 | /*
|
---|
| 1137 | * Retrieve the message.
|
---|
| 1138 | */
|
---|
| 1139 | uint32_t uHandle = 0;
|
---|
| 1140 | int rc = VbglR3GuestCtrlDirGetClose(pHostCtx, &uHandle /* Dir handle to close */);
|
---|
| 1141 | if (RT_SUCCESS(rc))
|
---|
| 1142 | {
|
---|
| 1143 | PVBOXSERVICECTRLDIR pDir = vgsvcGstCtrlSessionDirAcquire(pSession, uHandle);
|
---|
| 1144 | if (pDir)
|
---|
| 1145 | {
|
---|
| 1146 | VGSvcVerbose(2, "[Dir %s] Closing (handle=%RU32)\n", pDir ? pDir->pszPathAbs : "<Not found>", uHandle);
|
---|
| 1147 | rc = vgsvcGstCtrlSessionDirFree(pDir);
|
---|
| 1148 | }
|
---|
| 1149 | else
|
---|
| 1150 | {
|
---|
| 1151 | VGSvcError("Directory %u (%#x) not found!\n", uHandle, uHandle);
|
---|
| 1152 | rc = VERR_NOT_FOUND;
|
---|
| 1153 | }
|
---|
| 1154 |
|
---|
| 1155 | /*
|
---|
| 1156 | * Report result back to host.
|
---|
| 1157 | */
|
---|
| 1158 | int rc2 = VbglR3GuestCtrlDirCbClose(pHostCtx, rc);
|
---|
| 1159 | if (RT_FAILURE(rc2))
|
---|
| 1160 | {
|
---|
| 1161 | VGSvcError("Failed to report directory close status, rc=%Rrc\n", rc2);
|
---|
| 1162 | if (RT_SUCCESS(rc))
|
---|
| 1163 | rc = rc2;
|
---|
| 1164 | }
|
---|
| 1165 | }
|
---|
| 1166 | else
|
---|
| 1167 | {
|
---|
| 1168 | VGSvcError("Error fetching parameters for directory close operation: %Rrc\n", rc);
|
---|
| 1169 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1170 | }
|
---|
| 1171 | return rc;
|
---|
| 1172 | }
|
---|
| 1173 |
|
---|
| 1174 |
|
---|
[99085] | 1175 | /**
|
---|
| 1176 | * Worker function for reading a next guest directory entry.
|
---|
| 1177 | *
|
---|
| 1178 | * @returns VBox status code.
|
---|
| 1179 | * @param pSession Guest Control session to use.
|
---|
| 1180 | * @param pDir Guest directory to read the next entry for.
|
---|
| 1181 | * @param ppDirEntryEx Where to store the pointer to the next guest directory entry on success.
|
---|
| 1182 | * @param pcbDirEntryEx Where to return the size (in bytes) of \a ppGstCtlDirEntryEx on success.
|
---|
| 1183 | * @param ppszUser Where to return the resolved user name string.
|
---|
| 1184 | * @param ppszGroups Where to return the resolved groups string.
|
---|
| 1185 | */
|
---|
| 1186 | static int vgsvcGstCtrlSessionDirReadNext(const PVBOXSERVICECTRLSESSION pSession,
|
---|
| 1187 | PVBOXSERVICECTRLDIR pDir,
|
---|
| 1188 | PGSTCTLDIRENTRYEX *ppDirEntryEx, size_t *pcbDirEntryEx,
|
---|
| 1189 | const char **ppszUser, const char **ppszGroups)
|
---|
| 1190 | {
|
---|
| 1191 | PRTDIRENTRYEX pDirEntryEx = pDir->pDirEntryEx;
|
---|
| 1192 |
|
---|
| 1193 | size_t cbDirEntryEx = pDir->cbDirEntryEx;
|
---|
| 1194 | int rc = RTDirReadEx(pDir->hDir, pDir->pDirEntryEx, &cbDirEntryEx, (RTFSOBJATTRADD)pDir->enmReadAttrAdd, pDir->fRead);
|
---|
| 1195 |
|
---|
| 1196 | VGSvcVerbose(2, "[Dir %s] Read next entry '%s' -> %Rrc (%zu bytes)\n",
|
---|
| 1197 | pDir->pszPathAbs, RT_SUCCESS(rc) ? pDirEntryEx->szName : "<None>", rc, cbDirEntryEx);
|
---|
| 1198 |
|
---|
| 1199 | if (RT_FAILURE(rc))
|
---|
| 1200 | return rc;
|
---|
| 1201 |
|
---|
| 1202 | /* Paranoia. */
|
---|
| 1203 | AssertReturn(cbDirEntryEx <= pDir->cbDirEntryEx, VERR_BUFFER_OVERFLOW);
|
---|
| 1204 |
|
---|
| 1205 | *ppszUser = VGSvcIdCacheGetUidName(&pSession->UidCache,
|
---|
| 1206 | pDirEntryEx->Info.Attr.u.Unix.uid, pDirEntryEx->szName, pDir->pszPathAbs);
|
---|
| 1207 | *ppszGroups = VGSvcIdCacheGetGidName(&pSession->GidCache,
|
---|
| 1208 | pDirEntryEx->Info.Attr.u.Unix.gid, pDirEntryEx->szName, pDir->pszPathAbs);
|
---|
| 1209 |
|
---|
| 1210 | VGSvcVerbose(2, "[Dir %s] Entry '%s': %zu bytes, uid=%s (%d), gid=%s (%d)\n",
|
---|
| 1211 | pDir->pszPathAbs, pDirEntryEx->szName, pDirEntryEx->Info.cbObject,
|
---|
| 1212 | *ppszUser, pDirEntryEx->Info.Attr.u.UnixOwner.uid,
|
---|
| 1213 | *ppszGroups, pDirEntryEx->Info.Attr.u.UnixGroup.gid);
|
---|
| 1214 |
|
---|
| 1215 | /*
|
---|
| 1216 | * For now we ASSUME that RTDIRENTRYEX == GSTCTLDIRENTRYEX, which implies that we simply can cast RTDIRENTRYEX
|
---|
| 1217 | * to GSTCTLDIRENTRYEX. This might change in the future, however, so be extra cautious here.
|
---|
| 1218 | *
|
---|
| 1219 | * Ditto for RTFSOBJATTRADD == GSTCTLFSOBJATTRADD.
|
---|
| 1220 | */
|
---|
| 1221 | AssertCompile(sizeof(GSTCTLDIRENTRYEX) == sizeof(RTDIRENTRYEX));
|
---|
| 1222 | AssertCompile(RT_OFFSETOF(GSTCTLDIRENTRYEX, Info) == RT_OFFSETOF(RTDIRENTRYEX, Info));
|
---|
| 1223 | AssertCompile(RT_OFFSETOF(GSTCTLDIRENTRYEX, cbName) == RT_OFFSETOF(RTDIRENTRYEX, cbName));
|
---|
| 1224 | AssertCompile(RT_OFFSETOF(GSTCTLDIRENTRYEX, szName) == RT_OFFSETOF(RTDIRENTRYEX, szName));
|
---|
| 1225 | AssertCompile(RT_OFFSETOF(GSTCTLFSOBJINFO, Attr) == RT_OFFSETOF(RTFSOBJINFO, Attr));
|
---|
| 1226 |
|
---|
| 1227 | if (RT_SUCCESS(rc))
|
---|
| 1228 | {
|
---|
| 1229 | *ppDirEntryEx = (PGSTCTLDIRENTRYEX)pDirEntryEx;
|
---|
| 1230 | *pcbDirEntryEx = cbDirEntryEx;
|
---|
| 1231 | }
|
---|
| 1232 |
|
---|
| 1233 | return rc;
|
---|
| 1234 | }
|
---|
| 1235 |
|
---|
| 1236 |
|
---|
[98526] | 1237 | static int vgsvcGstCtrlSessionHandleDirRead(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1238 | {
|
---|
| 1239 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1240 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1241 |
|
---|
| 1242 | /*
|
---|
| 1243 | * Retrieve the message.
|
---|
| 1244 | */
|
---|
[98824] | 1245 | uint32_t uHandle;
|
---|
| 1246 | int rc = VbglR3GuestCtrlDirGetRead(pHostCtx, &uHandle);
|
---|
[98526] | 1247 | if (RT_SUCCESS(rc))
|
---|
| 1248 | {
|
---|
| 1249 | PVBOXSERVICECTRLDIR pDir = vgsvcGstCtrlSessionDirAcquire(pSession, uHandle);
|
---|
| 1250 | if (pDir)
|
---|
| 1251 | {
|
---|
[99085] | 1252 | PGSTCTLDIRENTRYEX pDirEntryEx;
|
---|
| 1253 | size_t cbDirEntryEx;
|
---|
| 1254 | const char *pszUser = NULL;
|
---|
| 1255 | const char *pszGroups = NULL;
|
---|
| 1256 | rc = vgsvcGstCtrlSessionDirReadNext(pSession, pDir,
|
---|
| 1257 | &pDirEntryEx, &cbDirEntryEx, &pszUser, &pszGroups);
|
---|
[98526] | 1258 |
|
---|
[99085] | 1259 | VGSvcVerbose(2, "[Dir %s] %Rrc\n", pDir->pszPathAbs, rc);
|
---|
[98824] | 1260 |
|
---|
[99085] | 1261 | int rc2;
|
---|
| 1262 | if (RT_SUCCESS(rc))
|
---|
[99087] | 1263 | rc2 = VbglR3GuestCtrlDirCbReadEx(pHostCtx, rc, pDirEntryEx, (uint32_t)cbDirEntryEx, pszUser, pszGroups);
|
---|
[99085] | 1264 | else
|
---|
| 1265 | rc2 = VbglR3GuestCtrlDirCbRead(pHostCtx, rc, NULL /* pEntry */, 0 /* cbSize */);
|
---|
[98709] | 1266 | if (RT_FAILURE(rc2))
|
---|
| 1267 | VGSvcError("Failed to report directory read status (%Rrc), rc=%Rrc\n", rc, rc2);
|
---|
| 1268 |
|
---|
[99085] | 1269 | VGSvcVerbose(2, "[Dir %s] 2 %Rrc\n", pDir->pszPathAbs, rc);
|
---|
| 1270 |
|
---|
[98709] | 1271 | if (rc == VERR_NO_MORE_FILES) /* Directory reading done. */
|
---|
| 1272 | rc = VINF_SUCCESS;
|
---|
| 1273 |
|
---|
[98526] | 1274 | vgsvcGstCtrlSessionDirRelease(pDir);
|
---|
| 1275 | }
|
---|
| 1276 | else
|
---|
| 1277 | {
|
---|
| 1278 | VGSvcError("Directory %u (%#x) not found!\n", uHandle, uHandle);
|
---|
| 1279 | rc = VERR_NOT_FOUND;
|
---|
| 1280 | }
|
---|
| 1281 | }
|
---|
| 1282 | else
|
---|
| 1283 | {
|
---|
| 1284 | VGSvcError("Error fetching parameters for directory read operation: %Rrc\n", rc);
|
---|
| 1285 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1286 | }
|
---|
| 1287 | return rc;
|
---|
| 1288 | }
|
---|
| 1289 |
|
---|
| 1290 |
|
---|
| 1291 | static int vgsvcGstCtrlSessionHandleDirRewind(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1292 | {
|
---|
| 1293 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1294 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1295 |
|
---|
| 1296 | /*
|
---|
| 1297 | * Retrieve the message.
|
---|
| 1298 | */
|
---|
| 1299 | uint32_t uHandle = 0;
|
---|
| 1300 | int rc = VbglR3GuestCtrlDirGetRewind(pHostCtx, &uHandle);
|
---|
| 1301 | if (RT_SUCCESS(rc))
|
---|
| 1302 | {
|
---|
| 1303 | PVBOXSERVICECTRLDIR pDir = vgsvcGstCtrlSessionDirAcquire(pSession, uHandle);
|
---|
| 1304 | if (pDir)
|
---|
| 1305 | {
|
---|
| 1306 | VGSvcVerbose(2, "[Dir %s] Rewinding (handle=%RU32)\n", pDir ? pDir->pszPathAbs : "<Not found>", uHandle);
|
---|
| 1307 |
|
---|
| 1308 | rc = RTDirRewind(pDir->hDir);
|
---|
| 1309 |
|
---|
| 1310 | vgsvcGstCtrlSessionDirRelease(pDir);
|
---|
| 1311 | }
|
---|
| 1312 | else
|
---|
| 1313 | {
|
---|
| 1314 | VGSvcError("Directory %u (%#x) not found!\n", uHandle, uHandle);
|
---|
| 1315 | rc = VERR_NOT_FOUND;
|
---|
| 1316 | }
|
---|
| 1317 |
|
---|
| 1318 | /*
|
---|
| 1319 | * Report result back to host.
|
---|
| 1320 | */
|
---|
| 1321 | int rc2 = VbglR3GuestCtrlDirCbRewind(pHostCtx, rc);
|
---|
| 1322 | if (RT_FAILURE(rc2))
|
---|
| 1323 | {
|
---|
| 1324 | VGSvcError("Failed to report directory rewind status, rc=%Rrc\n", rc2);
|
---|
| 1325 | if (RT_SUCCESS(rc))
|
---|
| 1326 | rc = rc2;
|
---|
| 1327 | }
|
---|
| 1328 | }
|
---|
| 1329 | else
|
---|
| 1330 | {
|
---|
| 1331 | VGSvcError("Error fetching parameters for directory rewind operation: %Rrc\n", rc);
|
---|
| 1332 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1333 | }
|
---|
| 1334 | return rc;
|
---|
| 1335 | }
|
---|
| 1336 |
|
---|
| 1337 |
|
---|
| 1338 | static int vgsvcGstCtrlSessionHandleDirCreate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1339 | {
|
---|
| 1340 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1341 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1342 |
|
---|
| 1343 | /*
|
---|
| 1344 | * Retrieve the request.
|
---|
| 1345 | */
|
---|
| 1346 | char szPath[RTPATH_MAX];
|
---|
| 1347 | RTFMODE fMode;
|
---|
| 1348 | uint32_t fCreate;
|
---|
| 1349 | int rc = VbglR3GuestCtrlDirGetCreate(pHostCtx, szPath, sizeof(szPath), &fMode, &fCreate);
|
---|
| 1350 | if (RT_SUCCESS(rc))
|
---|
| 1351 | {
|
---|
| 1352 | if (!(fCreate & ~GSTCTL_CREATEDIRECTORY_F_VALID_MASK))
|
---|
| 1353 | {
|
---|
[98774] | 1354 | /* Translate flags. */
|
---|
| 1355 | int fCreateRuntime = 0; /* RTDIRCREATE_FLAGS_XXX */
|
---|
| 1356 | if (fCreate & GSTCTL_CREATEDIRECTORY_F_NO_SYMLINKS)
|
---|
| 1357 | fCreateRuntime |= RTDIRCREATE_FLAGS_NO_SYMLINKS;
|
---|
| 1358 | if (fCreate & GSTCTL_CREATEDIRECTORY_F_IGNORE_UMASK)
|
---|
| 1359 | fCreateRuntime |= RTDIRCREATE_FLAGS_IGNORE_UMASK;
|
---|
| 1360 |
|
---|
| 1361 | if (fCreate & GSTCTL_CREATEDIRECTORY_F_PARENTS)
|
---|
| 1362 | rc = RTDirCreateFullPath(szPath, fMode);
|
---|
| 1363 | else
|
---|
| 1364 | rc = RTDirCreate(szPath, fMode, fCreateRuntime);
|
---|
| 1365 |
|
---|
| 1366 | VGSvcVerbose(4, "Creating directory (szPath='%s', fMode=%#x, fCreate=%#x) -> rc=%Rrc\n", szPath, fMode, fCreate, rc);
|
---|
[98526] | 1367 | }
|
---|
| 1368 | else
|
---|
| 1369 | {
|
---|
| 1370 | VGSvcError("Invalid directory creation flags: %#x\n", fCreate);
|
---|
| 1371 | rc = VERR_NOT_SUPPORTED;
|
---|
| 1372 | }
|
---|
| 1373 |
|
---|
| 1374 | /*
|
---|
| 1375 | * Report result back to host.
|
---|
| 1376 | */
|
---|
| 1377 | int rc2 = VbglR3GuestCtrlMsgReply(pHostCtx, rc);
|
---|
| 1378 | if (RT_FAILURE(rc2))
|
---|
| 1379 | {
|
---|
| 1380 | VGSvcError("Failed to report directory creation status, rc=%Rrc\n", rc2);
|
---|
| 1381 | if (RT_SUCCESS(rc))
|
---|
| 1382 | rc = rc2;
|
---|
| 1383 | }
|
---|
| 1384 | }
|
---|
| 1385 | else
|
---|
| 1386 | {
|
---|
| 1387 | VGSvcError("Error fetching parameters for directory creation operation: %Rrc\n", rc);
|
---|
| 1388 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1389 | }
|
---|
| 1390 | VGSvcVerbose(5, "Creating directory returned rc=%Rrc\n", rc);
|
---|
| 1391 | return rc;
|
---|
| 1392 | }
|
---|
[99085] | 1393 |
|
---|
| 1394 | static int vgsvcGstCtrlSessionHandleDirList(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1395 | {
|
---|
| 1396 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1397 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1398 |
|
---|
| 1399 | /*
|
---|
| 1400 | * Retrieve the request.
|
---|
| 1401 | */
|
---|
| 1402 | uint32_t uHandle;
|
---|
| 1403 | uint32_t cEntries;
|
---|
| 1404 | uint32_t cEntriesRead = 0;
|
---|
| 1405 | uint32_t fFlags;
|
---|
| 1406 | int rc = VbglR3GuestCtrlDirGetList(pHostCtx, &uHandle, &cEntries, &fFlags);
|
---|
| 1407 | if (RT_SUCCESS(rc))
|
---|
| 1408 | {
|
---|
| 1409 | size_t cbGrowSize = _64K;
|
---|
| 1410 | void *pvBuf = RTMemAlloc(cbGrowSize);
|
---|
| 1411 | if (!pvBuf)
|
---|
| 1412 | rc = VERR_NO_MEMORY;
|
---|
| 1413 | size_t cbBufUsed = 0;
|
---|
| 1414 | if (RT_SUCCESS(rc))
|
---|
| 1415 | {
|
---|
| 1416 | if (!(fFlags & ~GSTCTL_DIRLIST_F_VALID_MASK))
|
---|
| 1417 | {
|
---|
| 1418 | size_t cbBufSize = cbGrowSize;
|
---|
| 1419 |
|
---|
| 1420 | PVBOXSERVICECTRLDIR pDir = vgsvcGstCtrlSessionDirAcquire(pSession, uHandle);
|
---|
| 1421 | if (pDir)
|
---|
| 1422 | {
|
---|
| 1423 | PGSTCTLDIRENTRYEX pDirEntryEx;
|
---|
| 1424 | size_t cbDirEntryEx;
|
---|
| 1425 | const char *pszUser = NULL;
|
---|
| 1426 | const char *pszGroups = NULL;
|
---|
| 1427 |
|
---|
| 1428 | while (cEntries--)
|
---|
| 1429 | {
|
---|
| 1430 | rc = vgsvcGstCtrlSessionDirReadNext(pSession, pDir,
|
---|
| 1431 | &pDirEntryEx, &cbDirEntryEx, &pszUser, &pszGroups);
|
---|
| 1432 | if (RT_FAILURE(rc)) /* Might be VERR_NO_MORE_FILES. */
|
---|
| 1433 | break;
|
---|
| 1434 |
|
---|
| 1435 | size_t const cbHdr = sizeof(GSTCTLDIRENTRYLISTHDR);
|
---|
| 1436 | size_t const cbUser = strlen(pszUser) + 1; /* Include terminator. */
|
---|
| 1437 | size_t const cbGroups = strlen(pszGroups) + 1; /* Ditto. */
|
---|
| 1438 | size_t const cbTotal = cbHdr + cbDirEntryEx + cbUser + cbGroups;
|
---|
| 1439 |
|
---|
| 1440 | if (cbBufSize - cbBufUsed < cbTotal) /* Grow buffer, if needed. */
|
---|
| 1441 | {
|
---|
[103415] | 1442 | AssertBreakStmt(cbTotal <= cbGrowSize, rc = VERR_BUFFER_OVERFLOW);
|
---|
[99085] | 1443 | pvBuf = RTMemRealloc(pvBuf, cbBufSize + cbGrowSize);
|
---|
[103415] | 1444 | AssertPtrBreakStmt(pvBuf, rc = VERR_NO_MEMORY);
|
---|
[99085] | 1445 | cbBufSize += cbGrowSize;
|
---|
| 1446 | }
|
---|
| 1447 |
|
---|
| 1448 | GSTCTLDIRENTRYLISTHDR Hdr;
|
---|
[99087] | 1449 | Hdr.cbDirEntryEx = (uint32_t)cbDirEntryEx;
|
---|
| 1450 | Hdr.cbUser = (uint32_t)cbUser;
|
---|
| 1451 | Hdr.cbGroups = (uint32_t)cbGroups;
|
---|
[99085] | 1452 |
|
---|
| 1453 | memcpy((uint8_t *)pvBuf + cbBufUsed, &Hdr, cbHdr);
|
---|
| 1454 | cbBufUsed += cbHdr;
|
---|
| 1455 | memcpy((uint8_t *)pvBuf + cbBufUsed, pDirEntryEx, cbDirEntryEx);
|
---|
| 1456 | cbBufUsed += cbDirEntryEx;
|
---|
| 1457 | memcpy((uint8_t *)pvBuf + cbBufUsed, pszUser, cbUser);
|
---|
| 1458 | cbBufUsed += cbUser;
|
---|
| 1459 | memcpy((uint8_t *)pvBuf + cbBufUsed, pszGroups, cbGroups);
|
---|
| 1460 | cbBufUsed += cbGroups;
|
---|
| 1461 |
|
---|
| 1462 | Assert(cbBufUsed <= cbBufSize);
|
---|
| 1463 | cEntriesRead++;
|
---|
| 1464 | }
|
---|
| 1465 |
|
---|
| 1466 | vgsvcGstCtrlSessionDirRelease(pDir);
|
---|
| 1467 | }
|
---|
| 1468 |
|
---|
| 1469 | VGSvcVerbose(4, "Read %RU32 directory entries (requested %RU32 entries) -> %zu bytes, rc=%Rrc\n",
|
---|
| 1470 | cEntriesRead, cEntries, cbBufUsed, rc);
|
---|
| 1471 |
|
---|
| 1472 | /* Directory reading done? */
|
---|
| 1473 | if ( cEntriesRead
|
---|
| 1474 | && rc == VERR_NO_MORE_FILES)
|
---|
| 1475 | rc = VINF_SUCCESS;
|
---|
| 1476 |
|
---|
| 1477 | /* Note: Subsequent calls will return VERR_NO_MORE_FILES to the host. */
|
---|
| 1478 | }
|
---|
| 1479 | else
|
---|
| 1480 | {
|
---|
| 1481 | VGSvcError("Unsupported directory listing flags: %#x (all %#x)\n", (fFlags & ~GSTCTL_DIRLIST_F_VALID_MASK), fFlags);
|
---|
| 1482 | rc = VERR_NOT_SUPPORTED;
|
---|
| 1483 | }
|
---|
| 1484 | }
|
---|
| 1485 |
|
---|
| 1486 | /*
|
---|
| 1487 | * Report result back to host.
|
---|
| 1488 | */
|
---|
| 1489 | int rc2 = VbglR3GuestCtrlDirCbList(pHostCtx, rc, cEntriesRead, pvBuf, (uint32_t)cbBufUsed);
|
---|
| 1490 | if (RT_FAILURE(rc2))
|
---|
| 1491 | VGSvcError("Failed to report directory listing (%Rrc), rc=%Rrc\n", rc, rc2);
|
---|
| 1492 |
|
---|
| 1493 | if (rc == VERR_NO_MORE_FILES) /* Directory reading done? */
|
---|
| 1494 | rc = VINF_SUCCESS;
|
---|
| 1495 |
|
---|
| 1496 | RTMemFree(pvBuf);
|
---|
| 1497 | }
|
---|
| 1498 | else
|
---|
| 1499 | {
|
---|
| 1500 | VGSvcError("Error fetching parameters for directory listing operation: %Rrc\n", rc);
|
---|
| 1501 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1502 | }
|
---|
| 1503 | VGSvcVerbose(5, "Listing directory returned rc=%Rrc\n", rc);
|
---|
| 1504 | return rc;
|
---|
| 1505 | }
|
---|
[98526] | 1506 | #endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
|
---|
| 1507 |
|
---|
| 1508 |
|
---|
[58029] | 1509 | static int vgsvcGstCtrlSessionHandlePathRename(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[49349] | 1510 | {
|
---|
| 1511 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1512 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1513 |
|
---|
[75824] | 1514 | /*
|
---|
| 1515 | * Retrieve the request.
|
---|
| 1516 | */
|
---|
| 1517 | char szSource[RTPATH_MAX];
|
---|
| 1518 | char szDest[RTPATH_MAX];
|
---|
| 1519 | uint32_t fFlags = 0; /* PATHRENAME_FLAG_XXX */
|
---|
| 1520 | int rc = VbglR3GuestCtrlPathGetRename(pHostCtx, szSource, sizeof(szSource), szDest, sizeof(szDest), &fFlags);
|
---|
[49349] | 1521 | if (RT_SUCCESS(rc))
|
---|
| 1522 | {
|
---|
[75824] | 1523 | /*
|
---|
| 1524 | * Validate the flags (kudos for using the same as IPRT), then do the renaming.
|
---|
| 1525 | */
|
---|
| 1526 | AssertCompile(PATHRENAME_FLAG_NO_REPLACE == RTPATHRENAME_FLAGS_NO_REPLACE);
|
---|
| 1527 | AssertCompile(PATHRENAME_FLAG_REPLACE == RTPATHRENAME_FLAGS_REPLACE);
|
---|
| 1528 | AssertCompile(PATHRENAME_FLAG_NO_SYMLINKS == RTPATHRENAME_FLAGS_NO_SYMLINKS);
|
---|
| 1529 | AssertCompile(PATHRENAME_FLAG_VALID_MASK == (RTPATHRENAME_FLAGS_NO_REPLACE | RTPATHRENAME_FLAGS_REPLACE | RTPATHRENAME_FLAGS_NO_SYMLINKS));
|
---|
| 1530 | if (!(fFlags & ~PATHRENAME_FLAG_VALID_MASK))
|
---|
[49349] | 1531 | {
|
---|
[75824] | 1532 | VGSvcVerbose(4, "Renaming '%s' to '%s', fFlags=%#x, rc=%Rrc\n", szSource, szDest, fFlags, rc);
|
---|
| 1533 | rc = RTPathRename(szSource, szDest, fFlags);
|
---|
[49349] | 1534 | }
|
---|
[75824] | 1535 | else
|
---|
| 1536 | {
|
---|
| 1537 | VGSvcError("Invalid rename flags: %#x\n", fFlags);
|
---|
| 1538 | rc = VERR_NOT_SUPPORTED;
|
---|
| 1539 | }
|
---|
[49349] | 1540 |
|
---|
[75824] | 1541 | /*
|
---|
| 1542 | * Report result back to host.
|
---|
| 1543 | */
|
---|
[49349] | 1544 | int rc2 = VbglR3GuestCtrlMsgReply(pHostCtx, rc);
|
---|
| 1545 | if (RT_FAILURE(rc2))
|
---|
[75824] | 1546 | {
|
---|
[58029] | 1547 | VGSvcError("Failed to report renaming status, rc=%Rrc\n", rc2);
|
---|
[75824] | 1548 | if (RT_SUCCESS(rc))
|
---|
| 1549 | rc = rc2;
|
---|
| 1550 | }
|
---|
[49349] | 1551 | }
|
---|
[75824] | 1552 | else
|
---|
| 1553 | {
|
---|
| 1554 | VGSvcError("Error fetching parameters for rename operation: %Rrc\n", rc);
|
---|
| 1555 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1556 | }
|
---|
| 1557 | VGSvcVerbose(5, "Renaming '%s' to '%s' returned rc=%Rrc\n", szSource, szDest, rc);
|
---|
[49349] | 1558 | return rc;
|
---|
| 1559 | }
|
---|
| 1560 |
|
---|
| 1561 |
|
---|
[71364] | 1562 | /**
|
---|
| 1563 | * Handles getting the user's documents directory.
|
---|
| 1564 | *
|
---|
| 1565 | * @returns VBox status code.
|
---|
| 1566 | * @param pSession Guest session.
|
---|
| 1567 | * @param pHostCtx Host context.
|
---|
| 1568 | */
|
---|
[71314] | 1569 | static int vgsvcGstCtrlSessionHandlePathUserDocuments(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1570 | {
|
---|
| 1571 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1572 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1573 |
|
---|
[75824] | 1574 | /*
|
---|
| 1575 | * Retrieve the request.
|
---|
| 1576 | */
|
---|
[71364] | 1577 | int rc = VbglR3GuestCtrlPathGetUserDocuments(pHostCtx);
|
---|
[71314] | 1578 | if (RT_SUCCESS(rc))
|
---|
[71364] | 1579 | {
|
---|
[75824] | 1580 | /*
|
---|
| 1581 | * Get the path and pass it back to the host..
|
---|
| 1582 | */
|
---|
[71364] | 1583 | char szPath[RTPATH_MAX];
|
---|
| 1584 | rc = RTPathUserDocuments(szPath, sizeof(szPath));
|
---|
[71314] | 1585 | #ifdef DEBUG
|
---|
[71364] | 1586 | VGSvcVerbose(2, "User documents is '%s', rc=%Rrc\n", szPath, rc);
|
---|
[71314] | 1587 | #endif
|
---|
[75824] | 1588 |
|
---|
| 1589 | int rc2 = VbglR3GuestCtrlMsgReplyEx(pHostCtx, rc, 0 /* Type */, szPath,
|
---|
| 1590 | RT_SUCCESS(rc) ? (uint32_t)strlen(szPath) + 1 /* Include terminating zero */ : 0);
|
---|
[71364] | 1591 | if (RT_FAILURE(rc2))
|
---|
[75824] | 1592 | {
|
---|
[71364] | 1593 | VGSvcError("Failed to report user documents, rc=%Rrc\n", rc2);
|
---|
[75824] | 1594 | if (RT_SUCCESS(rc))
|
---|
| 1595 | rc = rc2;
|
---|
| 1596 | }
|
---|
[71364] | 1597 | }
|
---|
[75824] | 1598 | else
|
---|
| 1599 | {
|
---|
| 1600 | VGSvcError("Error fetching parameters for user documents path request: %Rrc\n", rc);
|
---|
| 1601 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1602 | }
|
---|
[71314] | 1603 | return rc;
|
---|
| 1604 | }
|
---|
| 1605 |
|
---|
| 1606 |
|
---|
[71364] | 1607 | /**
|
---|
[84548] | 1608 | * Handles shutting down / rebooting the guest OS.
|
---|
| 1609 | *
|
---|
| 1610 | * @returns VBox status code.
|
---|
| 1611 | * @param pSession Guest session.
|
---|
| 1612 | * @param pHostCtx Host context.
|
---|
| 1613 | */
|
---|
| 1614 | static int vgsvcGstCtrlSessionHandleShutdown(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1615 | {
|
---|
| 1616 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1617 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1618 |
|
---|
| 1619 | /*
|
---|
| 1620 | * Retrieve the request.
|
---|
| 1621 | */
|
---|
| 1622 | uint32_t fAction;
|
---|
| 1623 | int rc = VbglR3GuestCtrlGetShutdown(pHostCtx, &fAction);
|
---|
| 1624 | if (RT_SUCCESS(rc))
|
---|
| 1625 | {
|
---|
| 1626 | VGSvcVerbose(1, "Host requested to %s system ...\n", (fAction & RTSYSTEM_SHUTDOWN_REBOOT) ? "reboot" : "shutdown");
|
---|
| 1627 |
|
---|
| 1628 | /* Reply first to the host, in order to avoid host hangs when issuing the guest shutdown. */
|
---|
| 1629 | rc = VbglR3GuestCtrlMsgReply(pHostCtx, VINF_SUCCESS);
|
---|
| 1630 | if (RT_FAILURE(rc))
|
---|
| 1631 | {
|
---|
| 1632 | VGSvcError("Failed to reply to shutdown / reboot request, rc=%Rrc\n", rc);
|
---|
| 1633 | }
|
---|
| 1634 | else
|
---|
| 1635 | {
|
---|
[103413] | 1636 | uint32_t fSystemShutdown = RTSYSTEM_SHUTDOWN_PLANNED;
|
---|
[84814] | 1637 |
|
---|
[84816] | 1638 | /* Translate SHUTDOWN_FLAG_ into RTSYSTEM_SHUTDOWN_ flags. */
|
---|
[92707] | 1639 | if (fAction & GUEST_SHUTDOWN_FLAG_REBOOT)
|
---|
[84814] | 1640 | fSystemShutdown |= RTSYSTEM_SHUTDOWN_REBOOT;
|
---|
[84816] | 1641 | else /* SHUTDOWN_FLAG_POWER_OFF */
|
---|
[84814] | 1642 | fSystemShutdown |= RTSYSTEM_SHUTDOWN_POWER_OFF;
|
---|
| 1643 |
|
---|
[92707] | 1644 | if (fAction & GUEST_SHUTDOWN_FLAG_FORCE)
|
---|
[84814] | 1645 | fSystemShutdown |= RTSYSTEM_SHUTDOWN_FORCE;
|
---|
| 1646 |
|
---|
| 1647 | rc = RTSystemShutdown(0 /*cMsDelay*/, fSystemShutdown, "VBoxService");
|
---|
[84548] | 1648 | if (RT_FAILURE(rc))
|
---|
[84549] | 1649 | VGSvcError("%s system failed with %Rrc\n",
|
---|
[84594] | 1650 | (fAction & RTSYSTEM_SHUTDOWN_REBOOT) ? "Rebooting" : "Shutting down", rc);
|
---|
[84548] | 1651 | }
|
---|
| 1652 | }
|
---|
| 1653 | else
|
---|
| 1654 | {
|
---|
| 1655 | VGSvcError("Error fetching parameters for shutdown / reboot request: %Rrc\n", rc);
|
---|
| 1656 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1657 | }
|
---|
| 1658 |
|
---|
| 1659 | return rc;
|
---|
| 1660 | }
|
---|
| 1661 |
|
---|
| 1662 |
|
---|
| 1663 | /**
|
---|
[71364] | 1664 | * Handles getting the user's home directory.
|
---|
| 1665 | *
|
---|
| 1666 | * @returns VBox status code.
|
---|
| 1667 | * @param pSession Guest session.
|
---|
| 1668 | * @param pHostCtx Host context.
|
---|
| 1669 | */
|
---|
[71314] | 1670 | static int vgsvcGstCtrlSessionHandlePathUserHome(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1671 | {
|
---|
| 1672 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1673 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1674 |
|
---|
[75824] | 1675 | /*
|
---|
| 1676 | * Retrieve the request.
|
---|
| 1677 | */
|
---|
[71364] | 1678 | int rc = VbglR3GuestCtrlPathGetUserHome(pHostCtx);
|
---|
[71314] | 1679 | if (RT_SUCCESS(rc))
|
---|
[71364] | 1680 | {
|
---|
[75824] | 1681 | /*
|
---|
| 1682 | * Get the path and pass it back to the host..
|
---|
| 1683 | */
|
---|
[71364] | 1684 | char szPath[RTPATH_MAX];
|
---|
| 1685 | rc = RTPathUserHome(szPath, sizeof(szPath));
|
---|
[71314] | 1686 |
|
---|
| 1687 | #ifdef DEBUG
|
---|
[71364] | 1688 | VGSvcVerbose(2, "User home is '%s', rc=%Rrc\n", szPath, rc);
|
---|
[71314] | 1689 | #endif
|
---|
[71364] | 1690 | /* Report back in any case. */
|
---|
[75824] | 1691 | int rc2 = VbglR3GuestCtrlMsgReplyEx(pHostCtx, rc, 0 /* Type */, szPath,
|
---|
| 1692 | RT_SUCCESS(rc) ?(uint32_t)strlen(szPath) + 1 /* Include terminating zero */ : 0);
|
---|
[71364] | 1693 | if (RT_FAILURE(rc2))
|
---|
[75824] | 1694 | {
|
---|
[71364] | 1695 | VGSvcError("Failed to report user home, rc=%Rrc\n", rc2);
|
---|
[75824] | 1696 | if (RT_SUCCESS(rc))
|
---|
| 1697 | rc = rc2;
|
---|
| 1698 | }
|
---|
[71364] | 1699 | }
|
---|
[75824] | 1700 | else
|
---|
| 1701 | {
|
---|
| 1702 | VGSvcError("Error fetching parameters for user home directory path request: %Rrc\n", rc);
|
---|
| 1703 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1704 | }
|
---|
[71314] | 1705 | return rc;
|
---|
| 1706 | }
|
---|
| 1707 |
|
---|
[84147] | 1708 | /**
|
---|
[102654] | 1709 | * Structure for keeping a mount point enumeration context.
|
---|
| 1710 | */
|
---|
| 1711 | typedef struct VGSVCMOUNTPOINTENUMCTX
|
---|
| 1712 | {
|
---|
| 1713 | /** Mount points as strings, delimited with a string terminator ('\0').
|
---|
| 1714 | * List ends with an additional string terminator. Might get re-allocated, so don't rely on this pointer! */
|
---|
| 1715 | char *psz;
|
---|
| 1716 | /** Current size of \a psz in bytes. Includes ending terminator. */
|
---|
| 1717 | size_t cb;
|
---|
| 1718 | /** Total allocation Size of \a psz in bytes. */
|
---|
| 1719 | size_t cbAlloc;
|
---|
| 1720 | } VGSVCMOUNTPOINTENUMCTX;
|
---|
| 1721 | /** Pointer to a structure for keeping a mount point enumeration context. */
|
---|
| 1722 | typedef VGSVCMOUNTPOINTENUMCTX *PVGSVCMOUNTPOINTENUMCTX;
|
---|
| 1723 |
|
---|
| 1724 | /**
|
---|
| 1725 | * Enumeration callback for storing the mount points.
|
---|
| 1726 | *
|
---|
| 1727 | * @returns VBox status code.
|
---|
| 1728 | * @param pszMountpoint Mount point to handle.
|
---|
| 1729 | * @param pvUser Pointer of type PVGSVCMOUNTPOINTENUMCTX.
|
---|
| 1730 | */
|
---|
[103149] | 1731 | static DECLCALLBACK(int) vgsvcGstCtrlSessionHandleMountPointsEnumCallback(const char *pszMountpoint, void *pvUser)
|
---|
[102654] | 1732 | {
|
---|
| 1733 | PVGSVCMOUNTPOINTENUMCTX pCtx = (PVGSVCMOUNTPOINTENUMCTX)pvUser;
|
---|
| 1734 | AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
|
---|
| 1735 |
|
---|
| 1736 | size_t const cch = strlen(pszMountpoint) + 1 /* Entry terminator */;
|
---|
| 1737 | AssertReturn(cch < RTPATH_MAX, VERR_INVALID_PARAMETER); /* Paranoia. */
|
---|
| 1738 | if (cch > pCtx->cbAlloc - pCtx->cb - 1 /* Ending terminator */)
|
---|
| 1739 | {
|
---|
[103471] | 1740 | int rc2 = RTStrRealloc(&pCtx->psz, pCtx->cbAlloc + RT_MAX(_4K, cch));
|
---|
[102654] | 1741 | AssertRCReturn(rc2, rc2);
|
---|
| 1742 | }
|
---|
| 1743 |
|
---|
| 1744 | memcpy(&pCtx->psz[pCtx->cb], pszMountpoint, cch);
|
---|
| 1745 | pCtx->cb += cch;
|
---|
| 1746 | AssertReturn(pCtx->cb <= pCtx->cbAlloc, VERR_BUFFER_OVERFLOW); /* Paranoia. */
|
---|
| 1747 |
|
---|
| 1748 | return VINF_SUCCESS;
|
---|
| 1749 | }
|
---|
| 1750 |
|
---|
| 1751 | /**
|
---|
| 1752 | * Handles getting the current mount points.
|
---|
| 1753 | *
|
---|
| 1754 | * @returns VBox status code.
|
---|
| 1755 | * @param pSession Guest session.
|
---|
| 1756 | * @param pHostCtx Host context.
|
---|
| 1757 | */
|
---|
| 1758 | static int vgsvcGstCtrlSessionHandleMountPoints(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 1759 | {
|
---|
| 1760 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1761 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1762 |
|
---|
| 1763 | /*
|
---|
| 1764 | * Retrieve the request.
|
---|
| 1765 | */
|
---|
[102833] | 1766 | uint32_t fFlags;
|
---|
| 1767 | int rc = VbglR3GuestCtrlGetMountPoints(pHostCtx, &fFlags);
|
---|
[102654] | 1768 | if (RT_SUCCESS(rc))
|
---|
| 1769 | {
|
---|
[102833] | 1770 | /* Note: fFlags is currently unused, so we simply ignore this here. */
|
---|
| 1771 |
|
---|
[102654] | 1772 | VGSVCMOUNTPOINTENUMCTX Ctx;
|
---|
| 1773 | Ctx.cb = 0;
|
---|
| 1774 | Ctx.cbAlloc = _4K; /* Start with something sensible. */
|
---|
| 1775 | Ctx.psz = RTStrAlloc(Ctx.cbAlloc);
|
---|
| 1776 | if (!Ctx.psz)
|
---|
| 1777 | rc = VERR_NO_MEMORY;
|
---|
| 1778 |
|
---|
| 1779 | if (RT_SUCCESS(rc))
|
---|
| 1780 | rc = RTFsMountpointsEnum(vgsvcGstCtrlSessionHandleMountPointsEnumCallback, &Ctx);
|
---|
| 1781 |
|
---|
| 1782 | /* Report back in any case. */
|
---|
| 1783 | int rc2 = VbglR3GuestCtrlMsgReplyEx(pHostCtx, rc, 0 /* Type */, Ctx.psz,
|
---|
| 1784 | RT_SUCCESS(rc) ? (uint32_t)Ctx.cb : 0);
|
---|
| 1785 | if (RT_FAILURE(rc2))
|
---|
| 1786 | {
|
---|
| 1787 | VGSvcError("Failed to report mount points, rc=%Rrc\n", rc2);
|
---|
| 1788 | if (RT_SUCCESS(rc))
|
---|
| 1789 | rc = rc2;
|
---|
| 1790 | }
|
---|
| 1791 |
|
---|
| 1792 | RTStrFree(Ctx.psz);
|
---|
| 1793 | Ctx.psz = NULL;
|
---|
| 1794 | }
|
---|
| 1795 | else
|
---|
| 1796 | {
|
---|
| 1797 | VGSvcError("Error fetching parameters for getting mount points request: %Rrc\n", rc);
|
---|
| 1798 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1799 | }
|
---|
| 1800 | return rc;
|
---|
| 1801 | }
|
---|
| 1802 |
|
---|
| 1803 |
|
---|
| 1804 | /**
|
---|
[44963] | 1805 | * Handles starting a guest processes.
|
---|
| 1806 | *
|
---|
[58029] | 1807 | * @returns VBox status code.
|
---|
[44963] | 1808 | * @param pSession Guest session.
|
---|
[45010] | 1809 | * @param pHostCtx Host context.
|
---|
[44963] | 1810 | */
|
---|
[58029] | 1811 | static int vgsvcGstCtrlSessionHandleProcExec(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[44963] | 1812 | {
|
---|
| 1813 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1814 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1815 |
|
---|
[75824] | 1816 | /* Initialize maximum environment block size -- needed as input
|
---|
| 1817 | * parameter to retrieve the stuff from the host. On output this then
|
---|
| 1818 | * will contain the actual block size. */
|
---|
[84215] | 1819 | PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo;
|
---|
| 1820 | int rc = VbglR3GuestCtrlProcGetStart(pHostCtx, &pStartupInfo);
|
---|
[75824] | 1821 | if (RT_SUCCESS(rc))
|
---|
| 1822 | {
|
---|
[99120] | 1823 | VGSvcVerbose(3, "Request to start process szCmd=%s, fFlags=0x%x, szArgs=%s, szEnv=%s, szCwd=%s, uTimeout=%RU32\n",
|
---|
[84215] | 1824 | pStartupInfo->pszCmd, pStartupInfo->fFlags,
|
---|
| 1825 | pStartupInfo->cArgs ? pStartupInfo->pszArgs : "<None>",
|
---|
| 1826 | pStartupInfo->cEnvVars ? pStartupInfo->pszEnv : "<None>",
|
---|
[99120] | 1827 | pStartupInfo->cbCwd ? pStartupInfo->pszCwd : "<None>",
|
---|
[84215] | 1828 | pStartupInfo->uTimeLimitMS);
|
---|
[75824] | 1829 |
|
---|
| 1830 | bool fStartAllowed = false; /* Flag indicating whether starting a process is allowed or not. */
|
---|
| 1831 | rc = VGSvcGstCtrlSessionProcessStartAllowed(pSession, &fStartAllowed);
|
---|
[44963] | 1832 | if (RT_SUCCESS(rc))
|
---|
| 1833 | {
|
---|
[83286] | 1834 | vgsvcGstCtrlSessionCleanupProcesses(pSession);
|
---|
| 1835 |
|
---|
[75824] | 1836 | if (fStartAllowed)
|
---|
[84215] | 1837 | rc = VGSvcGstCtrlProcessStart(pSession, pStartupInfo, pHostCtx->uContextID);
|
---|
[75824] | 1838 | else
|
---|
| 1839 | rc = VERR_MAX_PROCS_REACHED; /* Maximum number of processes reached. */
|
---|
[44963] | 1840 | }
|
---|
| 1841 |
|
---|
[75824] | 1842 | /* We're responsible for signaling errors to the host (it will wait for ever otherwise). */
|
---|
| 1843 | if (RT_FAILURE(rc))
|
---|
[44963] | 1844 | {
|
---|
[75824] | 1845 | VGSvcError("Starting process failed with rc=%Rrc, protocol=%RU32, parameters=%RU32\n",
|
---|
| 1846 | rc, pHostCtx->uProtocol, pHostCtx->uNumParms);
|
---|
| 1847 | int rc2 = VbglR3GuestCtrlProcCbStatus(pHostCtx, 0 /*nil-PID*/, PROC_STS_ERROR, rc, NULL /*pvData*/, 0 /*cbData*/);
|
---|
[45697] | 1848 | if (RT_FAILURE(rc2))
|
---|
[58029] | 1849 | VGSvcError("Error sending start process status to host, rc=%Rrc\n", rc2);
|
---|
[44963] | 1850 | }
|
---|
[84215] | 1851 |
|
---|
| 1852 | VbglR3GuestCtrlProcStartupInfoFree(pStartupInfo);
|
---|
| 1853 | pStartupInfo = NULL;
|
---|
[44963] | 1854 | }
|
---|
[75824] | 1855 | else
|
---|
| 1856 | {
|
---|
| 1857 | VGSvcError("Failed to retrieve parameters for process start: %Rrc (cParms=%u)\n", rc, pHostCtx->uNumParms);
|
---|
| 1858 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1859 | }
|
---|
[84147] | 1860 |
|
---|
[44963] | 1861 | return rc;
|
---|
| 1862 | }
|
---|
| 1863 |
|
---|
| 1864 |
|
---|
| 1865 | /**
|
---|
[47545] | 1866 | * Sends stdin input to a specific guest process.
|
---|
[44963] | 1867 | *
|
---|
[58029] | 1868 | * @returns VBox status code.
|
---|
| 1869 | * @param pSession The session which is in charge.
|
---|
| 1870 | * @param pHostCtx The host context to use.
|
---|
[75824] | 1871 | * @param ppvScratchBuf The scratch buffer, we may grow it.
|
---|
| 1872 | * @param pcbScratchBuf The scratch buffer size for retrieving the input
|
---|
[58029] | 1873 | * data.
|
---|
[44963] | 1874 | */
|
---|
[58029] | 1875 | static int vgsvcGstCtrlSessionHandleProcInput(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
|
---|
[75824] | 1876 | void **ppvScratchBuf, uint32_t *pcbScratchBuf)
|
---|
[44963] | 1877 | {
|
---|
| 1878 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1879 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1880 |
|
---|
[75824] | 1881 | /*
|
---|
| 1882 | * Retrieve the data from the host.
|
---|
| 1883 | */
|
---|
[44963] | 1884 | uint32_t uPID;
|
---|
[58029] | 1885 | uint32_t fFlags;
|
---|
[75824] | 1886 | uint32_t cbInput;
|
---|
| 1887 | int rc = VbglR3GuestCtrlProcGetInput(pHostCtx, &uPID, &fFlags, *ppvScratchBuf, *pcbScratchBuf, &cbInput);
|
---|
| 1888 | if ( rc == VERR_BUFFER_OVERFLOW
|
---|
| 1889 | && vgsvcGstCtrlSessionGrowScratchBuf(ppvScratchBuf, pcbScratchBuf, cbInput))
|
---|
| 1890 | rc = VbglR3GuestCtrlProcGetInput(pHostCtx, &uPID, &fFlags, *ppvScratchBuf, *pcbScratchBuf, &cbInput);
|
---|
| 1891 | if (RT_SUCCESS(rc))
|
---|
| 1892 | {
|
---|
[92707] | 1893 | if (fFlags & GUEST_PROC_IN_FLAG_EOF)
|
---|
[75824] | 1894 | VGSvcVerbose(4, "Got last process input block for PID=%RU32 (%RU32 bytes) ...\n", uPID, cbInput);
|
---|
[44963] | 1895 |
|
---|
| 1896 | /*
|
---|
[75824] | 1897 | * Locate the process and feed it.
|
---|
[44963] | 1898 | */
|
---|
[58029] | 1899 | PVBOXSERVICECTRLPROCESS pProcess = VGSvcGstCtrlSessionRetainProcess(pSession, uPID);
|
---|
[47545] | 1900 | if (pProcess)
|
---|
[44963] | 1901 | {
|
---|
[92707] | 1902 | rc = VGSvcGstCtrlProcessHandleInput(pProcess, pHostCtx, RT_BOOL(fFlags & GUEST_PROC_IN_FLAG_EOF),
|
---|
[75824] | 1903 | *ppvScratchBuf, RT_MIN(cbInput, *pcbScratchBuf));
|
---|
[47545] | 1904 | if (RT_FAILURE(rc))
|
---|
[76958] | 1905 | VGSvcError("Error handling input message for PID=%RU32, rc=%Rrc\n", uPID, rc);
|
---|
[58029] | 1906 | VGSvcGstCtrlProcessRelease(pProcess);
|
---|
[44963] | 1907 | }
|
---|
| 1908 | else
|
---|
[75824] | 1909 | {
|
---|
| 1910 | VGSvcError("Could not find PID %u for feeding %u bytes to it.\n", uPID, cbInput);
|
---|
| 1911 | rc = VERR_PROCESS_NOT_FOUND;
|
---|
| 1912 | VbglR3GuestCtrlProcCbStatusInput(pHostCtx, uPID, INPUT_STS_ERROR, rc, 0);
|
---|
| 1913 | }
|
---|
[44963] | 1914 | }
|
---|
[75824] | 1915 | else
|
---|
| 1916 | {
|
---|
| 1917 | VGSvcError("Failed to retrieve parameters for process input: %Rrc (scratch %u bytes)\n", rc, *pcbScratchBuf);
|
---|
| 1918 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1919 | }
|
---|
[44963] | 1920 |
|
---|
[75824] | 1921 | VGSvcVerbose(6, "Feeding input to PID=%RU32 resulted in rc=%Rrc\n", uPID, rc);
|
---|
[44963] | 1922 | return rc;
|
---|
| 1923 | }
|
---|
| 1924 |
|
---|
| 1925 |
|
---|
| 1926 | /**
|
---|
[47545] | 1927 | * Gets stdout/stderr output of a specific guest process.
|
---|
[44963] | 1928 | *
|
---|
[58029] | 1929 | * @returns VBox status code.
|
---|
| 1930 | * @param pSession The session which is in charge.
|
---|
| 1931 | * @param pHostCtx The host context to use.
|
---|
[44963] | 1932 | */
|
---|
[58029] | 1933 | static int vgsvcGstCtrlSessionHandleProcOutput(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[44963] | 1934 | {
|
---|
| 1935 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1936 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1937 |
|
---|
[75824] | 1938 | /*
|
---|
| 1939 | * Retrieve the request.
|
---|
| 1940 | */
|
---|
[44963] | 1941 | uint32_t uPID;
|
---|
| 1942 | uint32_t uHandleID;
|
---|
[58029] | 1943 | uint32_t fFlags;
|
---|
| 1944 | int rc = VbglR3GuestCtrlProcGetOutput(pHostCtx, &uPID, &uHandleID, &fFlags);
|
---|
[45415] | 1945 | #ifdef DEBUG_andy
|
---|
[58029] | 1946 | VGSvcVerbose(4, "Getting output for PID=%RU32, CID=%RU32, uHandleID=%RU32, fFlags=%RU32\n",
|
---|
| 1947 | uPID, pHostCtx->uContextID, uHandleID, fFlags);
|
---|
[45415] | 1948 | #endif
|
---|
[44963] | 1949 | if (RT_SUCCESS(rc))
|
---|
| 1950 | {
|
---|
[75824] | 1951 | /*
|
---|
| 1952 | * Locate the process and hand it the output request.
|
---|
| 1953 | */
|
---|
[58029] | 1954 | PVBOXSERVICECTRLPROCESS pProcess = VGSvcGstCtrlSessionRetainProcess(pSession, uPID);
|
---|
[47545] | 1955 | if (pProcess)
|
---|
[44963] | 1956 | {
|
---|
[58029] | 1957 | rc = VGSvcGstCtrlProcessHandleOutput(pProcess, pHostCtx, uHandleID, _64K /* cbToRead */, fFlags);
|
---|
[47545] | 1958 | if (RT_FAILURE(rc))
|
---|
[58029] | 1959 | VGSvcError("Error getting output for PID=%RU32, rc=%Rrc\n", uPID, rc);
|
---|
| 1960 | VGSvcGstCtrlProcessRelease(pProcess);
|
---|
[44963] | 1961 | }
|
---|
| 1962 | else
|
---|
[75824] | 1963 | {
|
---|
| 1964 | VGSvcError("Could not find PID %u for draining handle %u (%#x).\n", uPID, uHandleID, uHandleID);
|
---|
| 1965 | rc = VERR_PROCESS_NOT_FOUND;
|
---|
| 1966 | /** @todo r=bird:
|
---|
| 1967 | *
|
---|
| 1968 | * No way to report status status code for output requests?
|
---|
| 1969 | *
|
---|
| 1970 | */
|
---|
| 1971 | }
|
---|
[44963] | 1972 | }
|
---|
[75824] | 1973 | else
|
---|
| 1974 | {
|
---|
| 1975 | VGSvcError("Error fetching parameters for process output request: %Rrc\n", rc);
|
---|
| 1976 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 1977 | }
|
---|
[44963] | 1978 |
|
---|
[47545] | 1979 | #ifdef DEBUG_andy
|
---|
[58029] | 1980 | VGSvcVerbose(4, "Getting output for PID=%RU32 resulted in rc=%Rrc\n", uPID, rc);
|
---|
[47545] | 1981 | #endif
|
---|
[44963] | 1982 | return rc;
|
---|
| 1983 | }
|
---|
| 1984 |
|
---|
| 1985 |
|
---|
[47545] | 1986 | /**
|
---|
| 1987 | * Tells a guest process to terminate.
|
---|
| 1988 | *
|
---|
[58029] | 1989 | * @returns VBox status code.
|
---|
| 1990 | * @param pSession The session which is in charge.
|
---|
| 1991 | * @param pHostCtx The host context to use.
|
---|
[47545] | 1992 | */
|
---|
[58029] | 1993 | static int vgsvcGstCtrlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[44963] | 1994 | {
|
---|
| 1995 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 1996 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 1997 |
|
---|
[75824] | 1998 | /*
|
---|
| 1999 | * Retrieve the request.
|
---|
| 2000 | */
|
---|
[44963] | 2001 | uint32_t uPID;
|
---|
| 2002 | int rc = VbglR3GuestCtrlProcGetTerminate(pHostCtx, &uPID);
|
---|
| 2003 | if (RT_SUCCESS(rc))
|
---|
| 2004 | {
|
---|
[75824] | 2005 | /*
|
---|
| 2006 | * Locate the process and terminate it.
|
---|
| 2007 | */
|
---|
[58029] | 2008 | PVBOXSERVICECTRLPROCESS pProcess = VGSvcGstCtrlSessionRetainProcess(pSession, uPID);
|
---|
[47545] | 2009 | if (pProcess)
|
---|
[44963] | 2010 | {
|
---|
[58029] | 2011 | rc = VGSvcGstCtrlProcessHandleTerm(pProcess);
|
---|
[83286] | 2012 | if (RT_FAILURE(rc))
|
---|
| 2013 | VGSvcError("Error terminating PID=%RU32, rc=%Rrc\n", uPID, rc);
|
---|
[44963] | 2014 |
|
---|
[58029] | 2015 | VGSvcGstCtrlProcessRelease(pProcess);
|
---|
[44963] | 2016 | }
|
---|
[47545] | 2017 | else
|
---|
[75824] | 2018 | {
|
---|
| 2019 | VGSvcError("Could not find PID %u for termination.\n", uPID);
|
---|
| 2020 | rc = VERR_PROCESS_NOT_FOUND;
|
---|
| 2021 | }
|
---|
[44963] | 2022 | }
|
---|
[75824] | 2023 | else
|
---|
| 2024 | {
|
---|
| 2025 | VGSvcError("Error fetching parameters for process termination request: %Rrc\n", rc);
|
---|
| 2026 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 2027 | }
|
---|
[47545] | 2028 | #ifdef DEBUG_andy
|
---|
[58029] | 2029 | VGSvcVerbose(4, "Terminating PID=%RU32 resulted in rc=%Rrc\n", uPID, rc);
|
---|
[47545] | 2030 | #endif
|
---|
[44963] | 2031 | return rc;
|
---|
| 2032 | }
|
---|
| 2033 |
|
---|
| 2034 |
|
---|
[58029] | 2035 | static int vgsvcGstCtrlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[44963] | 2036 | {
|
---|
| 2037 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 2038 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 2039 |
|
---|
[75824] | 2040 | /*
|
---|
| 2041 | * Retrieve the request.
|
---|
| 2042 | */
|
---|
[44963] | 2043 | uint32_t uPID;
|
---|
[75824] | 2044 | uint32_t uWaitFlags;
|
---|
| 2045 | uint32_t uTimeoutMS;
|
---|
[44963] | 2046 | int rc = VbglR3GuestCtrlProcGetWaitFor(pHostCtx, &uPID, &uWaitFlags, &uTimeoutMS);
|
---|
| 2047 | if (RT_SUCCESS(rc))
|
---|
| 2048 | {
|
---|
[75824] | 2049 | /*
|
---|
| 2050 | * Locate the process and the realize that this call makes no sense
|
---|
| 2051 | * since we'll notify the host when a process terminates anyway and
|
---|
| 2052 | * hopefully don't need any additional encouragement.
|
---|
| 2053 | */
|
---|
[58029] | 2054 | PVBOXSERVICECTRLPROCESS pProcess = VGSvcGstCtrlSessionRetainProcess(pSession, uPID);
|
---|
[47545] | 2055 | if (pProcess)
|
---|
[44963] | 2056 | {
|
---|
[47545] | 2057 | rc = VERR_NOT_IMPLEMENTED; /** @todo */
|
---|
[58029] | 2058 | VGSvcGstCtrlProcessRelease(pProcess);
|
---|
[44963] | 2059 | }
|
---|
[47545] | 2060 | else
|
---|
| 2061 | rc = VERR_NOT_FOUND;
|
---|
[44963] | 2062 | }
|
---|
[75824] | 2063 | else
|
---|
| 2064 | {
|
---|
| 2065 | VGSvcError("Error fetching parameters for process wait request: %Rrc\n", rc);
|
---|
| 2066 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 2067 | }
|
---|
[44963] | 2068 | return rc;
|
---|
| 2069 | }
|
---|
| 2070 |
|
---|
| 2071 |
|
---|
[98526] | 2072 | #ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
|
---|
[99262] | 2073 | static int vgsvcGstCtrlSessionHandleFsQueryInfo(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 2074 | {
|
---|
| 2075 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 2076 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 2077 |
|
---|
| 2078 | /*
|
---|
| 2079 | * Retrieve the request.
|
---|
| 2080 | */
|
---|
| 2081 | char szPath[RTPATH_MAX];
|
---|
| 2082 | int rc = VbglR3GuestCtrlFsGetQueryInfo(pHostCtx, szPath, sizeof(szPath));
|
---|
| 2083 | if (RT_SUCCESS(rc))
|
---|
| 2084 | {
|
---|
| 2085 | GSTCTLFSINFO fsInfo;
|
---|
| 2086 | RT_ZERO(fsInfo);
|
---|
| 2087 |
|
---|
| 2088 | /* Query as much as we can; ignore any errors and continue. */
|
---|
| 2089 | int rc2 = RTFsQuerySizes(szPath, (RTFOFF *)&fsInfo.cbTotalSize, (RTFOFF *)&fsInfo.cbFree,
|
---|
| 2090 | &fsInfo.cbBlockSize, &fsInfo.cbSectorSize);
|
---|
| 2091 | if (RT_FAILURE(rc2))
|
---|
| 2092 | VGSvcError("Error calling RTFsQuerySizes() for fsqueryinfo operation: %Rrc\n", rc2);
|
---|
| 2093 |
|
---|
| 2094 | RTFSPROPERTIES fsProps;
|
---|
| 2095 | rc2 = RTFsQueryProperties(szPath, &fsProps);
|
---|
| 2096 | if (RT_SUCCESS(rc2))
|
---|
| 2097 | {
|
---|
| 2098 | /* Regular (status) flags. */
|
---|
| 2099 | fsInfo.cMaxComponent = fsProps.cbMaxComponent;
|
---|
| 2100 | if (fsProps.fRemote)
|
---|
| 2101 | fsInfo.fFlags |= GSTCTLFSINFO_F_IS_REMOTE;
|
---|
| 2102 | if (fsProps.fCaseSensitive)
|
---|
| 2103 | fsInfo.fFlags |= GSTCTLFSINFO_F_IS_CASE_SENSITIVE;
|
---|
| 2104 | if (fsProps.fReadOnly)
|
---|
| 2105 | fsInfo.fFlags |= GSTCTLFSINFO_F_IS_READ_ONLY;
|
---|
| 2106 | if (fsProps.fCompressed)
|
---|
| 2107 | fsInfo.fFlags |= GSTCTLFSINFO_F_IS_COMPRESSED;
|
---|
| 2108 |
|
---|
| 2109 | /* Feature flags. */
|
---|
| 2110 | if (fsProps.fSupportsUnicode)
|
---|
| 2111 | fsInfo.fFeatures |= GSTCTLFSINFO_FEATURE_F_UNICODE;
|
---|
| 2112 | if (fsProps.fFileCompression)
|
---|
| 2113 | fsInfo.fFeatures |= GSTCTLFSINFO_FEATURE_F_FILE_COMPRESSION;
|
---|
| 2114 | }
|
---|
| 2115 | else
|
---|
| 2116 | VGSvcError("Error calling RTFsQueryProperties() for fsqueryinfo operation: %Rrc\n", rc2);
|
---|
| 2117 |
|
---|
| 2118 | rc2 = RTFsQuerySerial(szPath, &fsInfo.uSerialNumber);
|
---|
| 2119 | if (RT_FAILURE(rc2))
|
---|
| 2120 | VGSvcError("Error calling RTFsQuerySerial() for fsqueryinfo operation: %Rrc\n", rc2);
|
---|
| 2121 |
|
---|
| 2122 | #if 0 /** @todo Enable as soon as RTFsQueryLabel() is implemented. */
|
---|
| 2123 | rc2 = RTFsQueryLabel(szPath, fsInfo.szLabel, sizeof(fsInfo.szLabel));
|
---|
| 2124 | if (RT_FAILURE(rc2))
|
---|
| 2125 | VGSvcError("Error calling RTFsQueryLabel() for fsqueryinfo operation: %Rrc\n", rc2);
|
---|
| 2126 | #endif
|
---|
| 2127 |
|
---|
| 2128 | RTFSTYPE enmFsType;
|
---|
| 2129 | rc2 = RTFsQueryType(szPath, &enmFsType);
|
---|
| 2130 | if (RT_SUCCESS(rc2))
|
---|
| 2131 | {
|
---|
| 2132 | if (RTStrPrintf2(fsInfo.szName, sizeof(fsInfo.szName), "%s", RTFsTypeName(enmFsType)) <= 0)
|
---|
| 2133 | VGSvcError("Error printing type returned by RTFsQueryType()\n");
|
---|
| 2134 | }
|
---|
| 2135 | else
|
---|
| 2136 | VGSvcError("Error calling RTFsQueryType() for fsqueryinfo operation: %Rrc\n", rc2);
|
---|
| 2137 |
|
---|
| 2138 | #if 0 /** @todo Enable as soon as RTFsQueryMountpoint() is implemented. */
|
---|
| 2139 | char szMountpoint[RTPATH_MAX];
|
---|
| 2140 | rc2 = RTFsQueryMountpoint(szPath, szMountpoint, sizeof(szMountpoint));
|
---|
| 2141 | if (RT_SUCCESS(rc2))
|
---|
| 2142 | {
|
---|
| 2143 | #error "Implement me"
|
---|
| 2144 | }
|
---|
| 2145 | else
|
---|
| 2146 | VGSvcError("Error calling RTFsQueryMountpoint() for fsqueryinfo operation: %Rrc\n", rc2);
|
---|
| 2147 | #endif
|
---|
| 2148 |
|
---|
| 2149 | if (RT_SUCCESS(rc))
|
---|
| 2150 | {
|
---|
| 2151 | VGSvcVerbose(3, "cbTotalSize=%RU64, cbFree=%RU64, cbBlockSize=%RU32, cbSectorSize=%RU32, fFlags=%#x, fFeatures=%#x\n",
|
---|
| 2152 | fsInfo.cbTotalSize, fsInfo.cbFree, fsInfo.cbBlockSize, fsInfo.cbSectorSize,
|
---|
| 2153 | fsInfo.fFlags, fsInfo.fFeatures);
|
---|
| 2154 | VGSvcVerbose(3, "szName=%s, szLabel=%s\n", fsInfo.szName, fsInfo.szLabel);
|
---|
| 2155 | }
|
---|
| 2156 |
|
---|
| 2157 | uint32_t const cbFsInfo = sizeof(GSTCTLFSINFO); /** @todo Needs tweaking as soon as we resolve the mountpoint above. */
|
---|
| 2158 |
|
---|
| 2159 | rc2 = VbglR3GuestCtrlFsCbQueryInfo(pHostCtx, rc, &fsInfo, cbFsInfo);
|
---|
| 2160 | if (RT_FAILURE(rc2))
|
---|
| 2161 | {
|
---|
| 2162 | VGSvcError("Failed to reply to fsobjquerinfo request %Rrc, rc=%Rrc\n", rc, rc2);
|
---|
| 2163 | if (RT_SUCCESS(rc))
|
---|
| 2164 | rc = rc2;
|
---|
| 2165 | }
|
---|
| 2166 | }
|
---|
| 2167 | else
|
---|
| 2168 | {
|
---|
| 2169 | VGSvcError("Error fetching parameters for fsqueryinfo operation: %Rrc\n", rc);
|
---|
| 2170 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 2171 | }
|
---|
| 2172 | return rc;
|
---|
| 2173 | }
|
---|
| 2174 |
|
---|
[99256] | 2175 | static int vgsvcGstCtrlSessionHandleFsObjQueryInfo(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
[98526] | 2176 | {
|
---|
| 2177 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 2178 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 2179 |
|
---|
| 2180 | /*
|
---|
| 2181 | * Retrieve the request.
|
---|
| 2182 | */
|
---|
| 2183 | char szPath[RTPATH_MAX];
|
---|
| 2184 | GSTCTLFSOBJATTRADD enmAttrAdd;
|
---|
| 2185 | uint32_t fFlags;
|
---|
| 2186 | RTFSOBJINFO objInfoRuntime;
|
---|
| 2187 |
|
---|
[99256] | 2188 | int rc = VbglR3GuestCtrlFsObjGetQueryInfo(pHostCtx, szPath, sizeof(szPath), &enmAttrAdd, &fFlags);
|
---|
[98526] | 2189 | if (RT_SUCCESS(rc))
|
---|
| 2190 | {
|
---|
[98665] | 2191 | uint32_t fFlagsRuntime = 0;
|
---|
| 2192 |
|
---|
[98709] | 2193 | if (!(fFlags & ~GSTCTL_PATH_F_VALID_MASK))
|
---|
[98526] | 2194 | {
|
---|
[98709] | 2195 | if (fFlags & GSTCTL_PATH_F_ON_LINK)
|
---|
[98526] | 2196 | fFlagsRuntime |= RTPATH_F_ON_LINK;
|
---|
[98709] | 2197 | if (fFlags & GSTCTL_PATH_F_FOLLOW_LINK)
|
---|
[98526] | 2198 | fFlagsRuntime |= RTPATH_F_FOLLOW_LINK;
|
---|
[98709] | 2199 | if (fFlags & GSTCTL_PATH_F_NO_SYMLINKS)
|
---|
[98526] | 2200 | fFlagsRuntime |= RTPATH_F_NO_SYMLINKS;
|
---|
| 2201 |
|
---|
[98665] | 2202 | if (!RTPATH_F_IS_VALID(fFlagsRuntime, 0))
|
---|
| 2203 | rc = VERR_INVALID_PARAMETER;
|
---|
| 2204 | }
|
---|
| 2205 | else
|
---|
| 2206 | rc = VERR_INVALID_PARAMETER;
|
---|
| 2207 |
|
---|
| 2208 | if (RT_FAILURE(rc))
|
---|
[99256] | 2209 | VGSvcError("Invalid fsobjqueryinfo flags: %#x (%#x)\n", fFlags, fFlagsRuntime);
|
---|
[98665] | 2210 |
|
---|
| 2211 | if (RT_SUCCESS(rc))
|
---|
| 2212 | {
|
---|
[98526] | 2213 | #define CASE_ATTR_ADD_VAL(a_Val) \
|
---|
| 2214 | case GSTCTL##a_Val: enmAttrRuntime = RT##a_Val; break;
|
---|
| 2215 |
|
---|
| 2216 | RTFSOBJATTRADD enmAttrRuntime;
|
---|
| 2217 | switch (enmAttrAdd)
|
---|
| 2218 | {
|
---|
| 2219 | CASE_ATTR_ADD_VAL(FSOBJATTRADD_NOTHING);
|
---|
| 2220 | CASE_ATTR_ADD_VAL(FSOBJATTRADD_UNIX);
|
---|
| 2221 | CASE_ATTR_ADD_VAL(FSOBJATTRADD_UNIX_OWNER);
|
---|
| 2222 | CASE_ATTR_ADD_VAL(FSOBJATTRADD_UNIX_GROUP);
|
---|
| 2223 | CASE_ATTR_ADD_VAL(FSOBJATTRADD_EASIZE);
|
---|
| 2224 | default:
|
---|
| 2225 | enmAttrRuntime = RTFSOBJATTRADD_NOTHING;
|
---|
| 2226 | break;
|
---|
| 2227 | }
|
---|
| 2228 |
|
---|
| 2229 | #undef CASE_ATTR_ADD_VAL
|
---|
| 2230 |
|
---|
| 2231 | /*
|
---|
| 2232 | * For now we ASSUME that RTFSOBJINFO == GSTCTLFSOBJINFO, which implies that we simply can cast RTFSOBJINFO
|
---|
| 2233 | * to GSTCTLFSOBJINFO. This might change in the future, however, so be extra cautious here.
|
---|
| 2234 | *
|
---|
| 2235 | * Ditto for RTFSOBJATTR == GSTCTLFSOBJATTR.
|
---|
| 2236 | */
|
---|
| 2237 | AssertCompileSize(objInfoRuntime, sizeof(GSTCTLFSOBJINFO));
|
---|
| 2238 | AssertCompile (RT_OFFSETOF(GSTCTLFSOBJINFO, cbObject) == RT_OFFSETOF(GSTCTLFSOBJINFO, cbObject));
|
---|
| 2239 | AssertCompile (RT_OFFSETOF(GSTCTLFSOBJINFO, Attr) == RT_OFFSETOF(GSTCTLFSOBJINFO, Attr));
|
---|
| 2240 | AssertCompileSize(RTFSOBJATTR, sizeof(GSTCTLFSOBJATTR));
|
---|
| 2241 |
|
---|
| 2242 | rc = RTPathQueryInfoEx(szPath, &objInfoRuntime, enmAttrRuntime, fFlagsRuntime);
|
---|
| 2243 | }
|
---|
| 2244 |
|
---|
| 2245 | PGSTCTLFSOBJINFO pObjInfo = (PGSTCTLFSOBJINFO)&objInfoRuntime;
|
---|
| 2246 |
|
---|
[98817] | 2247 | const char *pszUser = VGSvcIdCacheGetUidName(&pSession->UidCache, pObjInfo->Attr.u.Unix.uid, szPath, NULL /* pszRelativeTo */);
|
---|
| 2248 | const char *pszGroup = VGSvcIdCacheGetGidName(&pSession->GidCache, pObjInfo->Attr.u.Unix.gid, szPath, NULL /* pszRelativeTo */);
|
---|
[98709] | 2249 |
|
---|
[99257] | 2250 | int rc2 = VbglR3GuestCtrlFsObjCbQueryInfoEx(pHostCtx, rc, pObjInfo, pszUser, pszGroup);
|
---|
[98526] | 2251 | if (RT_FAILURE(rc2))
|
---|
| 2252 | {
|
---|
[99256] | 2253 | VGSvcError("Failed to reply to fsobjquerinfo request %Rrc, rc=%Rrc\n", rc, rc2);
|
---|
[98526] | 2254 | if (RT_SUCCESS(rc))
|
---|
| 2255 | rc = rc2;
|
---|
| 2256 | }
|
---|
| 2257 | }
|
---|
| 2258 | else
|
---|
| 2259 | {
|
---|
[99256] | 2260 | VGSvcError("Error fetching parameters for fsobjqueryinfo operation: %Rrc\n", rc);
|
---|
[98526] | 2261 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 2262 | }
|
---|
| 2263 | return rc;
|
---|
| 2264 | }
|
---|
| 2265 |
|
---|
| 2266 |
|
---|
| 2267 | static int vgsvcGstCtrlSessionHandleFsCreateTemp(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
|
---|
| 2268 | {
|
---|
| 2269 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 2270 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
| 2271 |
|
---|
| 2272 | /*
|
---|
| 2273 | * Retrieve the request.
|
---|
| 2274 | */
|
---|
| 2275 | char szTemplate[RTPATH_MAX];
|
---|
| 2276 | char szPath[RTPATH_MAX];
|
---|
| 2277 | uint32_t fFlags = GSTCTL_CREATETEMP_F_NONE;
|
---|
| 2278 | RTFMODE fMode = 0700;
|
---|
| 2279 | int rc = VbglR3GuestCtrlFsGetCreateTemp(pHostCtx, szTemplate, sizeof(szTemplate), szPath, sizeof(szPath), &fFlags, &fMode);
|
---|
| 2280 | if (RT_SUCCESS(rc))
|
---|
| 2281 | {
|
---|
| 2282 | if (!(fFlags & ~GSTCTL_CREATETEMP_F_VALID_MASK))
|
---|
| 2283 | {
|
---|
[98789] | 2284 | const char *pszWhat = fFlags & GSTCTL_CREATETEMP_F_DIRECTORY ? "directory" : "file";
|
---|
[98526] | 2285 |
|
---|
[98789] | 2286 | /* Validate that the template is as IPRT requires (asserted by IPRT). */
|
---|
| 2287 | if ( RTPathHasPath(szTemplate)
|
---|
| 2288 | || ( !strstr(szTemplate, "XXX")
|
---|
| 2289 | && szTemplate[strlen(szTemplate) - 1] != 'X'))
|
---|
[98526] | 2290 | {
|
---|
[98789] | 2291 | VGSvcError("createtemp: Template '%s' should contain a file name with no path and at least three consecutive 'X' characters or ending in 'X'\n",
|
---|
| 2292 | szTemplate);
|
---|
| 2293 | rc = VERR_INVALID_PARAMETER;
|
---|
[98526] | 2294 | }
|
---|
[98789] | 2295 |
|
---|
| 2296 | if ( RT_SUCCESS(rc)
|
---|
| 2297 | && szPath[0] != '\0' && !RTPathStartsWithRoot(szPath))
|
---|
[98526] | 2298 | {
|
---|
[98789] | 2299 | VGSvcError("createtemp: Path '%s' must be absolute\n", szPath);
|
---|
| 2300 | rc = VERR_INVALID_PARAMETER;
|
---|
| 2301 | }
|
---|
| 2302 |
|
---|
| 2303 | if (RT_SUCCESS(rc))
|
---|
| 2304 | {
|
---|
| 2305 | char szTemplateWithPath[RTPATH_MAX] = "";
|
---|
| 2306 | if (szPath[0] != '\0')
|
---|
| 2307 | {
|
---|
| 2308 | rc = RTStrCopy(szTemplateWithPath, sizeof(szTemplateWithPath), szPath);
|
---|
| 2309 | if (RT_FAILURE(rc))
|
---|
| 2310 | {
|
---|
| 2311 | VGSvcError("createtemp: Path '%s' too long\n", szPath);
|
---|
| 2312 | rc = VERR_INVALID_PARAMETER;
|
---|
| 2313 | }
|
---|
| 2314 | }
|
---|
[98526] | 2315 | else
|
---|
[98789] | 2316 | {
|
---|
| 2317 | rc = RTPathTemp(szTemplateWithPath, sizeof(szTemplateWithPath));
|
---|
| 2318 | if (RT_FAILURE(rc))
|
---|
| 2319 | {
|
---|
| 2320 | VGSvcError("createtemp: Failed to get the temporary directory (%Rrc)", rc);
|
---|
| 2321 | rc = VERR_INVALID_PARAMETER;
|
---|
| 2322 | }
|
---|
| 2323 | }
|
---|
| 2324 |
|
---|
| 2325 | if (RT_SUCCESS(rc))
|
---|
| 2326 | {
|
---|
| 2327 | rc = RTPathAppend(szTemplateWithPath, sizeof(szTemplateWithPath), szTemplate);
|
---|
| 2328 | if (RT_FAILURE(rc))
|
---|
| 2329 | {
|
---|
| 2330 | VGSvcError("createtemp: Template '%s' too long for path\n", szTemplate);
|
---|
| 2331 | rc = VERR_INVALID_PARAMETER;
|
---|
| 2332 | }
|
---|
| 2333 | else
|
---|
| 2334 | {
|
---|
| 2335 | bool const fSecure = RT_BOOL(fFlags & GSTCTL_CREATETEMP_F_SECURE);
|
---|
| 2336 | if (fFlags & GSTCTL_CREATETEMP_F_DIRECTORY)
|
---|
| 2337 | {
|
---|
| 2338 | if (fSecure)
|
---|
| 2339 | rc = RTDirCreateTempSecure(szTemplateWithPath); /* File mode is fixed to 0700. */
|
---|
| 2340 | else
|
---|
| 2341 | rc = RTDirCreateTemp(szTemplate, fMode);
|
---|
| 2342 | }
|
---|
| 2343 | else /* File */
|
---|
| 2344 | {
|
---|
| 2345 | if (fSecure)
|
---|
| 2346 | rc = RTFileCreateTempSecure(szTemplateWithPath); /* File mode is fixed to 0700. */
|
---|
| 2347 | else
|
---|
| 2348 | rc = RTFileCreateTemp(szTemplate, fMode);
|
---|
| 2349 | }
|
---|
| 2350 |
|
---|
| 2351 | VGSvcVerbose(3, "Creating temporary %s (szTemplate='%s', fFlags=%#x, fMode=%#x) -> rc=%Rrc\n",
|
---|
| 2352 | pszWhat, szTemplate, fFlags, fMode, rc);
|
---|
| 2353 | }
|
---|
| 2354 | }
|
---|
[98526] | 2355 | }
|
---|
| 2356 | }
|
---|
| 2357 | else
|
---|
| 2358 | {
|
---|
| 2359 | VGSvcError("Invalid temporary directory/file creation flags: %#x\n", fFlags);
|
---|
| 2360 | rc = VERR_NOT_SUPPORTED;
|
---|
| 2361 | }
|
---|
| 2362 |
|
---|
| 2363 | /*
|
---|
| 2364 | * Report result back to host.
|
---|
| 2365 | */
|
---|
| 2366 | int rc2 = VbglR3GuestCtrlFsCbCreateTemp(pHostCtx, rc, szTemplate);
|
---|
| 2367 | if (RT_FAILURE(rc2))
|
---|
| 2368 | {
|
---|
| 2369 | VGSvcError("Failed to report temporary file/directory creation status, rc=%Rrc\n", rc2);
|
---|
| 2370 | if (RT_SUCCESS(rc))
|
---|
| 2371 | rc = rc2;
|
---|
| 2372 | }
|
---|
| 2373 | }
|
---|
| 2374 | else
|
---|
| 2375 | {
|
---|
| 2376 | VGSvcError("Error fetching parameters for file/directory creation operation: %Rrc\n", rc);
|
---|
| 2377 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
|
---|
| 2378 | }
|
---|
[98789] | 2379 | VGSvcVerbose(3, "Creating temporary file/directory returned rc=%Rrc\n", rc);
|
---|
[98526] | 2380 | return rc;
|
---|
| 2381 | }
|
---|
| 2382 | #endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
|
---|
| 2383 |
|
---|
| 2384 |
|
---|
[58029] | 2385 | int VGSvcGstCtrlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
|
---|
[75824] | 2386 | void **ppvScratchBuf, uint32_t *pcbScratchBuf, volatile bool *pfShutdown)
|
---|
[44963] | 2387 | {
|
---|
| 2388 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 2389 | AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
|
---|
[75824] | 2390 | AssertPtrReturn(*ppvScratchBuf, VERR_INVALID_POINTER);
|
---|
[44963] | 2391 | AssertPtrReturn(pfShutdown, VERR_INVALID_POINTER);
|
---|
| 2392 |
|
---|
[58029] | 2393 |
|
---|
| 2394 | /*
|
---|
[45697] | 2395 | * Only anonymous sessions (that is, sessions which run with local
|
---|
[57659] | 2396 | * service privileges) or spawned session processes can do certain
|
---|
[45697] | 2397 | * operations.
|
---|
| 2398 | */
|
---|
[58029] | 2399 | bool const fImpersonated = RT_BOOL(pSession->fFlags & ( VBOXSERVICECTRLSESSION_FLAG_SPAWN
|
---|
| 2400 | | VBOXSERVICECTRLSESSION_FLAG_ANONYMOUS));
|
---|
[71405] | 2401 | int rc = VERR_NOT_SUPPORTED; /* Play safe by default. */
|
---|
| 2402 |
|
---|
[44963] | 2403 | switch (uMsg)
|
---|
| 2404 | {
|
---|
[76958] | 2405 | case HOST_MSG_SESSION_CLOSE:
|
---|
[57659] | 2406 | /* Shutdown (this spawn). */
|
---|
[58029] | 2407 | rc = VGSvcGstCtrlSessionClose(pSession);
|
---|
[44963] | 2408 | *pfShutdown = true; /* Shutdown in any case. */
|
---|
| 2409 | break;
|
---|
| 2410 |
|
---|
[76958] | 2411 | case HOST_MSG_EXEC_CMD:
|
---|
[58029] | 2412 | rc = vgsvcGstCtrlSessionHandleProcExec(pSession, pHostCtx);
|
---|
[44963] | 2413 | break;
|
---|
| 2414 |
|
---|
[76958] | 2415 | case HOST_MSG_EXEC_SET_INPUT:
|
---|
[75824] | 2416 | rc = vgsvcGstCtrlSessionHandleProcInput(pSession, pHostCtx, ppvScratchBuf, pcbScratchBuf);
|
---|
[44963] | 2417 | break;
|
---|
| 2418 |
|
---|
[76958] | 2419 | case HOST_MSG_EXEC_GET_OUTPUT:
|
---|
[58029] | 2420 | rc = vgsvcGstCtrlSessionHandleProcOutput(pSession, pHostCtx);
|
---|
[44963] | 2421 | break;
|
---|
| 2422 |
|
---|
[76958] | 2423 | case HOST_MSG_EXEC_TERMINATE:
|
---|
[58029] | 2424 | rc = vgsvcGstCtrlSessionHandleProcTerminate(pSession, pHostCtx);
|
---|
[44963] | 2425 | break;
|
---|
| 2426 |
|
---|
[76958] | 2427 | case HOST_MSG_EXEC_WAIT_FOR:
|
---|
[58029] | 2428 | rc = vgsvcGstCtrlSessionHandleProcWaitFor(pSession, pHostCtx);
|
---|
[44963] | 2429 | break;
|
---|
| 2430 |
|
---|
[98526] | 2431 | #ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
|
---|
[99253] | 2432 | case HOST_MSG_FS_OBJ_QUERY_INFO:
|
---|
[98526] | 2433 | if (fImpersonated)
|
---|
[99256] | 2434 | rc = vgsvcGstCtrlSessionHandleFsObjQueryInfo(pSession, pHostCtx);
|
---|
[98526] | 2435 | break;
|
---|
| 2436 |
|
---|
| 2437 | case HOST_MSG_FS_CREATE_TEMP:
|
---|
| 2438 | if (fImpersonated)
|
---|
| 2439 | rc = vgsvcGstCtrlSessionHandleFsCreateTemp(pSession, pHostCtx);
|
---|
| 2440 | break;
|
---|
[99262] | 2441 |
|
---|
| 2442 | case HOST_MSG_FS_QUERY_INFO:
|
---|
| 2443 | if (fImpersonated)
|
---|
| 2444 | rc = vgsvcGstCtrlSessionHandleFsQueryInfo(pSession, pHostCtx);
|
---|
| 2445 | break;
|
---|
[98526] | 2446 | #endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
|
---|
| 2447 |
|
---|
[76958] | 2448 | case HOST_MSG_FILE_OPEN:
|
---|
[58029] | 2449 | if (fImpersonated)
|
---|
| 2450 | rc = vgsvcGstCtrlSessionHandleFileOpen(pSession, pHostCtx);
|
---|
[44963] | 2451 | break;
|
---|
| 2452 |
|
---|
[76958] | 2453 | case HOST_MSG_FILE_CLOSE:
|
---|
[58029] | 2454 | if (fImpersonated)
|
---|
| 2455 | rc = vgsvcGstCtrlSessionHandleFileClose(pSession, pHostCtx);
|
---|
[44963] | 2456 | break;
|
---|
| 2457 |
|
---|
[76958] | 2458 | case HOST_MSG_FILE_READ:
|
---|
[58029] | 2459 | if (fImpersonated)
|
---|
[75824] | 2460 | rc = vgsvcGstCtrlSessionHandleFileRead(pSession, pHostCtx, ppvScratchBuf, pcbScratchBuf);
|
---|
[44963] | 2461 | break;
|
---|
| 2462 |
|
---|
[76958] | 2463 | case HOST_MSG_FILE_READ_AT:
|
---|
[58029] | 2464 | if (fImpersonated)
|
---|
[75824] | 2465 | rc = vgsvcGstCtrlSessionHandleFileReadAt(pSession, pHostCtx, ppvScratchBuf, pcbScratchBuf);
|
---|
[44963] | 2466 | break;
|
---|
| 2467 |
|
---|
[76958] | 2468 | case HOST_MSG_FILE_WRITE:
|
---|
[58029] | 2469 | if (fImpersonated)
|
---|
[75824] | 2470 | rc = vgsvcGstCtrlSessionHandleFileWrite(pSession, pHostCtx, ppvScratchBuf, pcbScratchBuf);
|
---|
[44963] | 2471 | break;
|
---|
| 2472 |
|
---|
[76958] | 2473 | case HOST_MSG_FILE_WRITE_AT:
|
---|
[58029] | 2474 | if (fImpersonated)
|
---|
[75824] | 2475 | rc = vgsvcGstCtrlSessionHandleFileWriteAt(pSession, pHostCtx, ppvScratchBuf, pcbScratchBuf);
|
---|
[44963] | 2476 | break;
|
---|
| 2477 |
|
---|
[76958] | 2478 | case HOST_MSG_FILE_SEEK:
|
---|
[58029] | 2479 | if (fImpersonated)
|
---|
| 2480 | rc = vgsvcGstCtrlSessionHandleFileSeek(pSession, pHostCtx);
|
---|
[44963] | 2481 | break;
|
---|
| 2482 |
|
---|
[76958] | 2483 | case HOST_MSG_FILE_TELL:
|
---|
[58029] | 2484 | if (fImpersonated)
|
---|
| 2485 | rc = vgsvcGstCtrlSessionHandleFileTell(pSession, pHostCtx);
|
---|
[44963] | 2486 | break;
|
---|
| 2487 |
|
---|
[79287] | 2488 | case HOST_MSG_FILE_SET_SIZE:
|
---|
| 2489 | if (fImpersonated)
|
---|
| 2490 | rc = vgsvcGstCtrlSessionHandleFileSetSize(pSession, pHostCtx);
|
---|
| 2491 | break;
|
---|
| 2492 |
|
---|
[98526] | 2493 | #ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
|
---|
| 2494 | case HOST_MSG_FILE_REMOVE:
|
---|
| 2495 | if (fImpersonated)
|
---|
| 2496 | rc = vgsvcGstCtrlSessionHandleFileRemove(pSession, pHostCtx);
|
---|
| 2497 | break;
|
---|
| 2498 |
|
---|
| 2499 | case HOST_MSG_DIR_OPEN:
|
---|
| 2500 | if (fImpersonated)
|
---|
| 2501 | rc = vgsvcGstCtrlSessionHandleDirOpen(pSession, pHostCtx);
|
---|
| 2502 | break;
|
---|
| 2503 |
|
---|
| 2504 | case HOST_MSG_DIR_CLOSE:
|
---|
| 2505 | if (fImpersonated)
|
---|
| 2506 | rc = vgsvcGstCtrlSessionHandleDirClose(pSession, pHostCtx);
|
---|
| 2507 | break;
|
---|
| 2508 |
|
---|
| 2509 | case HOST_MSG_DIR_READ:
|
---|
| 2510 | if (fImpersonated)
|
---|
| 2511 | rc = vgsvcGstCtrlSessionHandleDirRead(pSession, pHostCtx);
|
---|
| 2512 | break;
|
---|
| 2513 |
|
---|
| 2514 | case HOST_MSG_DIR_REWIND:
|
---|
| 2515 | if (fImpersonated)
|
---|
| 2516 | rc = vgsvcGstCtrlSessionHandleDirRewind(pSession, pHostCtx);
|
---|
| 2517 | break;
|
---|
| 2518 |
|
---|
| 2519 | case HOST_MSG_DIR_CREATE:
|
---|
| 2520 | if (fImpersonated)
|
---|
| 2521 | rc = vgsvcGstCtrlSessionHandleDirCreate(pSession, pHostCtx);
|
---|
| 2522 | break;
|
---|
[99085] | 2523 |
|
---|
| 2524 | case HOST_MSG_DIR_LIST:
|
---|
| 2525 | if (fImpersonated)
|
---|
| 2526 | rc = vgsvcGstCtrlSessionHandleDirList(pSession, pHostCtx);
|
---|
| 2527 | break;
|
---|
[98526] | 2528 | #endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
|
---|
| 2529 |
|
---|
| 2530 | case HOST_MSG_DIR_REMOVE:
|
---|
| 2531 | if (fImpersonated)
|
---|
| 2532 | rc = vgsvcGstCtrlSessionHandleDirRemove(pSession, pHostCtx);
|
---|
| 2533 | break;
|
---|
| 2534 |
|
---|
[76958] | 2535 | case HOST_MSG_PATH_RENAME:
|
---|
[58029] | 2536 | if (fImpersonated)
|
---|
| 2537 | rc = vgsvcGstCtrlSessionHandlePathRename(pSession, pHostCtx);
|
---|
[49349] | 2538 | break;
|
---|
| 2539 |
|
---|
[76958] | 2540 | case HOST_MSG_PATH_USER_DOCUMENTS:
|
---|
[71314] | 2541 | if (fImpersonated)
|
---|
| 2542 | rc = vgsvcGstCtrlSessionHandlePathUserDocuments(pSession, pHostCtx);
|
---|
| 2543 | break;
|
---|
| 2544 |
|
---|
[76958] | 2545 | case HOST_MSG_PATH_USER_HOME:
|
---|
[71314] | 2546 | if (fImpersonated)
|
---|
| 2547 | rc = vgsvcGstCtrlSessionHandlePathUserHome(pSession, pHostCtx);
|
---|
| 2548 | break;
|
---|
| 2549 |
|
---|
[102654] | 2550 | case HOST_MSG_MOUNT_POINTS:
|
---|
| 2551 | if (fImpersonated)
|
---|
| 2552 | rc = vgsvcGstCtrlSessionHandleMountPoints(pSession, pHostCtx);
|
---|
| 2553 | break;
|
---|
| 2554 |
|
---|
[84548] | 2555 | case HOST_MSG_SHUTDOWN:
|
---|
| 2556 | rc = vgsvcGstCtrlSessionHandleShutdown(pSession, pHostCtx);
|
---|
| 2557 | break;
|
---|
| 2558 |
|
---|
[71405] | 2559 | default: /* Not supported, see next code block. */
|
---|
[44963] | 2560 | break;
|
---|
| 2561 | }
|
---|
[75824] | 2562 | if (RT_SUCCESS(rc))
|
---|
| 2563 | { /* likely */ }
|
---|
| 2564 | else if (rc != VERR_NOT_SUPPORTED) /* Note: Reply to host must must be sent by above handler. */
|
---|
[98526] | 2565 | VGSvcError("Error while handling message %s (%#x, cParms=%RU32), rc=%Rrc\n",
|
---|
| 2566 | GstCtrlHostMsgtoStr((eHostMsg)uMsg), uMsg, pHostCtx->uNumParms, rc);
|
---|
[75824] | 2567 | else
|
---|
[71405] | 2568 | {
|
---|
[75824] | 2569 | /* We must skip and notify host here as best we can... */
|
---|
[75895] | 2570 | VGSvcVerbose(1, "Unsupported message (uMsg=%RU32, cParms=%RU32) from host, skipping\n", uMsg, pHostCtx->uNumParms);
|
---|
[75824] | 2571 | if (VbglR3GuestCtrlSupportsOptimizations(pHostCtx->uClientID))
|
---|
| 2572 | VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, VERR_NOT_SUPPORTED, uMsg);
|
---|
| 2573 | else
|
---|
| 2574 | VbglR3GuestCtrlMsgSkipOld(pHostCtx->uClientID);
|
---|
[75895] | 2575 | rc = VINF_SUCCESS;
|
---|
[71405] | 2576 | }
|
---|
| 2577 |
|
---|
[44963] | 2578 | return rc;
|
---|
| 2579 | }
|
---|
| 2580 |
|
---|
| 2581 |
|
---|
| 2582 | /**
|
---|
[57659] | 2583 | * Thread main routine for a spawned guest session process.
|
---|
[75807] | 2584 | *
|
---|
[57659] | 2585 | * This thread runs in the main executable to control the spawned session process.
|
---|
[44935] | 2586 | *
|
---|
[58029] | 2587 | * @returns VBox status code.
|
---|
| 2588 | * @param hThreadSelf Thread handle.
|
---|
| 2589 | * @param pvUser Pointer to a VBOXSERVICECTRLSESSIONTHREAD structure.
|
---|
[44935] | 2590 | *
|
---|
| 2591 | */
|
---|
[58029] | 2592 | static DECLCALLBACK(int) vgsvcGstCtrlSessionThread(RTTHREAD hThreadSelf, void *pvUser)
|
---|
[44935] | 2593 | {
|
---|
[45010] | 2594 | PVBOXSERVICECTRLSESSIONTHREAD pThread = (PVBOXSERVICECTRLSESSIONTHREAD)pvUser;
|
---|
| 2595 | AssertPtrReturn(pThread, VERR_INVALID_POINTER);
|
---|
[44935] | 2596 |
|
---|
[84147] | 2597 | uint32_t const idSession = pThread->pStartupInfo->uSessionID;
|
---|
[75807] | 2598 | uint32_t const idClient = g_idControlSvcClient;
|
---|
| 2599 | VGSvcVerbose(3, "Session ID=%RU32 thread running\n", idSession);
|
---|
[44935] | 2600 |
|
---|
[47695] | 2601 | /* Let caller know that we're done initializing, regardless of the result. */
|
---|
[58029] | 2602 | int rc2 = RTThreadUserSignal(hThreadSelf);
|
---|
[47695] | 2603 | AssertRC(rc2);
|
---|
| 2604 |
|
---|
[75807] | 2605 | /*
|
---|
| 2606 | * Wait for the child process to stop or the shutdown flag to be signalled.
|
---|
| 2607 | */
|
---|
| 2608 | RTPROCSTATUS ProcessStatus = { 0, RTPROCEXITREASON_NORMAL };
|
---|
| 2609 | bool fProcessAlive = true;
|
---|
| 2610 | bool fSessionCancelled = VbglR3GuestCtrlSupportsOptimizations(g_idControlSvcClient);
|
---|
| 2611 | uint32_t cMsShutdownTimeout = 30 * 1000; /** @todo Make this configurable. Later. */
|
---|
| 2612 | uint64_t msShutdownStart = 0;
|
---|
| 2613 | uint64_t const msStart = RTTimeMilliTS();
|
---|
| 2614 | size_t offSecretKey = 0;
|
---|
| 2615 | int rcWait;
|
---|
[62850] | 2616 | for (;;)
|
---|
[44935] | 2617 | {
|
---|
[75807] | 2618 | /* Secret key feeding. */
|
---|
| 2619 | if (offSecretKey < sizeof(pThread->abKey))
|
---|
| 2620 | {
|
---|
| 2621 | size_t cbWritten = 0;
|
---|
| 2622 | rc2 = RTPipeWrite(pThread->hKeyPipe, &pThread->abKey[offSecretKey], sizeof(pThread->abKey) - offSecretKey, &cbWritten);
|
---|
| 2623 | if (RT_SUCCESS(rc2))
|
---|
| 2624 | offSecretKey += cbWritten;
|
---|
| 2625 | }
|
---|
| 2626 |
|
---|
| 2627 | /* Poll child process status. */
|
---|
[62850] | 2628 | rcWait = RTProcWaitNoResume(pThread->hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
|
---|
| 2629 | if ( rcWait == VINF_SUCCESS
|
---|
| 2630 | || rcWait == VERR_PROCESS_NOT_FOUND)
|
---|
[44935] | 2631 | {
|
---|
[62850] | 2632 | fProcessAlive = false;
|
---|
| 2633 | break;
|
---|
| 2634 | }
|
---|
[75719] | 2635 | AssertMsgBreak(rcWait == VERR_PROCESS_RUNNING || rcWait == VERR_INTERRUPTED,
|
---|
[62850] | 2636 | ("Got unexpected rc=%Rrc while waiting for session process termination\n", rcWait));
|
---|
[58029] | 2637 |
|
---|
[75807] | 2638 | /* Shutting down? */
|
---|
[62850] | 2639 | if (ASMAtomicReadBool(&pThread->fShutdown))
|
---|
| 2640 | {
|
---|
[75807] | 2641 | if (!msShutdownStart)
|
---|
[44935] | 2642 | {
|
---|
[62850] | 2643 | VGSvcVerbose(3, "Notifying guest session process (PID=%RU32, session ID=%RU32) ...\n",
|
---|
[75807] | 2644 | pThread->hProcess, idSession);
|
---|
[45010] | 2645 |
|
---|
[62850] | 2646 | VBGLR3GUESTCTRLCMDCTX hostCtx =
|
---|
[45010] | 2647 | {
|
---|
[75736] | 2648 | /* .idClient = */ idClient,
|
---|
[75807] | 2649 | /* .idContext = */ VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(idSession),
|
---|
[84147] | 2650 | /* .uProtocol = */ pThread->pStartupInfo->uProtocol,
|
---|
[62850] | 2651 | /* .cParams = */ 2
|
---|
| 2652 | };
|
---|
[75807] | 2653 | rc2 = VbglR3GuestCtrlSessionClose(&hostCtx, 0 /* fFlags */);
|
---|
| 2654 | if (RT_FAILURE(rc2))
|
---|
[62850] | 2655 | {
|
---|
| 2656 | VGSvcError("Unable to notify guest session process (PID=%RU32, session ID=%RU32), rc=%Rrc\n",
|
---|
[75807] | 2657 | pThread->hProcess, idSession, rc2);
|
---|
[49349] | 2658 |
|
---|
[75807] | 2659 | if (rc2 == VERR_NOT_SUPPORTED)
|
---|
[58029] | 2660 | {
|
---|
[62850] | 2661 | /* Terminate guest session process in case it's not supported by a too old host. */
|
---|
[75807] | 2662 | rc2 = RTProcTerminate(pThread->hProcess);
|
---|
[62850] | 2663 | VGSvcVerbose(3, "Terminating guest session process (PID=%RU32) ended with rc=%Rrc\n",
|
---|
[75807] | 2664 | pThread->hProcess, rc2);
|
---|
[49349] | 2665 | }
|
---|
[62850] | 2666 | break;
|
---|
| 2667 | }
|
---|
[49349] | 2668 |
|
---|
[75807] | 2669 | VGSvcVerbose(3, "Guest session ID=%RU32 thread was asked to terminate, waiting for session process to exit (%RU32 ms timeout) ...\n",
|
---|
| 2670 | idSession, cMsShutdownTimeout);
|
---|
| 2671 | msShutdownStart = RTTimeMilliTS();
|
---|
[62850] | 2672 | continue; /* Don't waste time on waiting. */
|
---|
[45010] | 2673 | }
|
---|
[75807] | 2674 | if (RTTimeMilliTS() - msShutdownStart > cMsShutdownTimeout)
|
---|
[62850] | 2675 | {
|
---|
[75807] | 2676 | VGSvcVerbose(3, "Guest session ID=%RU32 process did not shut down within time\n", idSession);
|
---|
[62850] | 2677 | break;
|
---|
| 2678 | }
|
---|
[44935] | 2679 | }
|
---|
| 2680 |
|
---|
[75807] | 2681 | /* Cancel the prepared session stuff after 30 seconds. */
|
---|
| 2682 | if ( !fSessionCancelled
|
---|
| 2683 | && RTTimeMilliTS() - msStart >= 30000)
|
---|
| 2684 | {
|
---|
| 2685 | VbglR3GuestCtrlSessionCancelPrepared(g_idControlSvcClient, idSession);
|
---|
| 2686 | fSessionCancelled = true;
|
---|
| 2687 | }
|
---|
| 2688 |
|
---|
| 2689 | /** @todo r=bird: This 100ms sleep is _extremely_ sucky! */
|
---|
[62850] | 2690 | RTThreadSleep(100); /* Wait a bit. */
|
---|
| 2691 | }
|
---|
| 2692 |
|
---|
[75807] | 2693 | if (!fSessionCancelled)
|
---|
| 2694 | VbglR3GuestCtrlSessionCancelPrepared(g_idControlSvcClient, idSession);
|
---|
| 2695 |
|
---|
[62850] | 2696 | if (!fProcessAlive)
|
---|
| 2697 | {
|
---|
| 2698 | VGSvcVerbose(2, "Guest session process (ID=%RU32) terminated with rc=%Rrc, reason=%d, status=%d\n",
|
---|
[75807] | 2699 | idSession, rcWait, ProcessStatus.enmReason, ProcessStatus.iStatus);
|
---|
[62850] | 2700 | if (ProcessStatus.iStatus == RTEXITCODE_INIT)
|
---|
[45010] | 2701 | {
|
---|
[75807] | 2702 | VGSvcError("Guest session process (ID=%RU32) failed to initialize. Here some hints:\n", idSession);
|
---|
[62850] | 2703 | VGSvcError("- Is logging enabled and the output directory is read-only by the guest session user?\n");
|
---|
| 2704 | /** @todo Add more here. */
|
---|
[45010] | 2705 | }
|
---|
[44935] | 2706 | }
|
---|
| 2707 |
|
---|
[45010] | 2708 | uint32_t uSessionStatus = GUEST_SESSION_NOTIFYTYPE_UNDEFINED;
|
---|
[92987] | 2709 | int32_t iSessionResult = VINF_SUCCESS;
|
---|
[45010] | 2710 |
|
---|
| 2711 | if (fProcessAlive)
|
---|
| 2712 | {
|
---|
| 2713 | for (int i = 0; i < 3; i++)
|
---|
| 2714 | {
|
---|
[83438] | 2715 | if (i)
|
---|
| 2716 | RTThreadSleep(3000);
|
---|
| 2717 |
|
---|
[75807] | 2718 | VGSvcVerbose(2, "Guest session ID=%RU32 process still alive, killing attempt %d/3\n", idSession, i + 1);
|
---|
[45010] | 2719 |
|
---|
[75807] | 2720 | rc2 = RTProcTerminate(pThread->hProcess);
|
---|
| 2721 | if (RT_SUCCESS(rc2))
|
---|
[45010] | 2722 | break;
|
---|
| 2723 | }
|
---|
| 2724 |
|
---|
[75807] | 2725 | VGSvcVerbose(2, "Guest session ID=%RU32 process termination resulted in rc=%Rrc\n", idSession, rc2);
|
---|
| 2726 | uSessionStatus = RT_SUCCESS(rc2) ? GUEST_SESSION_NOTIFYTYPE_TOK : GUEST_SESSION_NOTIFYTYPE_TOA;
|
---|
[45010] | 2727 | }
|
---|
[58029] | 2728 | else if (RT_SUCCESS(rcWait))
|
---|
[45010] | 2729 | {
|
---|
[58029] | 2730 | switch (ProcessStatus.enmReason)
|
---|
[45010] | 2731 | {
|
---|
[58029] | 2732 | case RTPROCEXITREASON_NORMAL:
|
---|
| 2733 | uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN;
|
---|
[92987] | 2734 | iSessionResult = ProcessStatus.iStatus; /* Report back the session's exit code. */
|
---|
[58029] | 2735 | break;
|
---|
[45010] | 2736 |
|
---|
[58029] | 2737 | case RTPROCEXITREASON_ABEND:
|
---|
| 2738 | uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA;
|
---|
[92987] | 2739 | /* iSessionResult is undefined (0). */
|
---|
[58029] | 2740 | break;
|
---|
[45010] | 2741 |
|
---|
[58029] | 2742 | case RTPROCEXITREASON_SIGNAL:
|
---|
| 2743 | uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TES;
|
---|
[92987] | 2744 | iSessionResult = ProcessStatus.iStatus; /* Report back the signal number. */
|
---|
[58029] | 2745 | break;
|
---|
[45010] | 2746 |
|
---|
[58029] | 2747 | default:
|
---|
| 2748 | AssertMsgFailed(("Unhandled process termination reason (%d)\n", ProcessStatus.enmReason));
|
---|
| 2749 | uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA;
|
---|
| 2750 | break;
|
---|
[45010] | 2751 | }
|
---|
| 2752 | }
|
---|
[58029] | 2753 | else
|
---|
| 2754 | {
|
---|
[75807] | 2755 | /* If we didn't find the guest process anymore, just assume it terminated normally. */
|
---|
[58029] | 2756 | uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN;
|
---|
| 2757 | }
|
---|
[45010] | 2758 |
|
---|
[83554] | 2759 | /* Make sure to set stopped state before we let the host know. */
|
---|
| 2760 | ASMAtomicWriteBool(&pThread->fStopped, true);
|
---|
[45010] | 2761 |
|
---|
[83554] | 2762 | /* Report final status, regardless if we failed to wait above, so that the host knows what's going on. */
|
---|
[92988] | 2763 | VGSvcVerbose(3, "Reporting final status %RU32 of session ID=%RU32\n", uSessionStatus, idSession);
|
---|
[45010] | 2764 | Assert(uSessionStatus != GUEST_SESSION_NOTIFYTYPE_UNDEFINED);
|
---|
[83554] | 2765 |
|
---|
[83555] | 2766 | VBGLR3GUESTCTRLCMDCTX ctx = { idClient, VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(idSession),
|
---|
| 2767 | 0 /* uProtocol, unused */, 0 /* uNumParms, unused */ };
|
---|
[92987] | 2768 | rc2 = VbglR3GuestCtrlSessionNotify(&ctx, uSessionStatus, iSessionResult);
|
---|
[45010] | 2769 | if (RT_FAILURE(rc2))
|
---|
[83554] | 2770 | VGSvcError("Reporting final status of session ID=%RU32 failed with rc=%Rrc\n", idSession, rc2);
|
---|
[45010] | 2771 |
|
---|
[92987] | 2772 | VGSvcVerbose(3, "Thread for session ID=%RU32 ended with sessionStatus=%#x (%RU32), sessionRc=%#x (%Rrc)\n",
|
---|
| 2773 | idSession, uSessionStatus, uSessionStatus, iSessionResult, iSessionResult);
|
---|
[83554] | 2774 |
|
---|
[75807] | 2775 | return VINF_SUCCESS;
|
---|
| 2776 | }
|
---|
[45010] | 2777 |
|
---|
[75807] | 2778 | /**
|
---|
| 2779 | * Reads the secret key the parent VBoxService instance passed us and pass it
|
---|
| 2780 | * along as a authentication token to the host service.
|
---|
| 2781 | *
|
---|
| 2782 | * For older hosts, this sets up the message filtering.
|
---|
| 2783 | *
|
---|
| 2784 | * @returns VBox status code.
|
---|
| 2785 | * @param idClient The HGCM client ID.
|
---|
| 2786 | * @param idSession The session ID.
|
---|
| 2787 | */
|
---|
| 2788 | static int vgsvcGstCtrlSessionReadKeyAndAccept(uint32_t idClient, uint32_t idSession)
|
---|
| 2789 | {
|
---|
| 2790 | /*
|
---|
| 2791 | * Read it.
|
---|
| 2792 | */
|
---|
| 2793 | RTHANDLE Handle;
|
---|
[86414] | 2794 | int rc = RTHandleGetStandard(RTHANDLESTD_INPUT, true /*fLeaveOpen*/, &Handle);
|
---|
[75807] | 2795 | if (RT_SUCCESS(rc))
|
---|
| 2796 | {
|
---|
| 2797 | if (Handle.enmType == RTHANDLETYPE_PIPE)
|
---|
| 2798 | {
|
---|
| 2799 | uint8_t abSecretKey[RT_SIZEOFMEMB(VBOXSERVICECTRLSESSIONTHREAD, abKey)];
|
---|
| 2800 | rc = RTPipeReadBlocking(Handle.u.hPipe, abSecretKey, sizeof(abSecretKey), NULL);
|
---|
| 2801 | if (RT_SUCCESS(rc))
|
---|
| 2802 | {
|
---|
| 2803 | VGSvcVerbose(3, "Got secret key from standard input.\n");
|
---|
| 2804 |
|
---|
| 2805 | /*
|
---|
| 2806 | * Do the accepting, if appropriate.
|
---|
| 2807 | */
|
---|
| 2808 | if (g_fControlSupportsOptimizations)
|
---|
| 2809 | {
|
---|
| 2810 | rc = VbglR3GuestCtrlSessionAccept(idClient, idSession, abSecretKey, sizeof(abSecretKey));
|
---|
| 2811 | if (RT_SUCCESS(rc))
|
---|
[75858] | 2812 | VGSvcVerbose(3, "Session %u accepted (client ID %u)\n", idClient, idSession);
|
---|
[75807] | 2813 | else
|
---|
[75858] | 2814 | VGSvcError("Failed to accept session %u (client ID %u): %Rrc\n", idClient, idSession, rc);
|
---|
[75807] | 2815 | }
|
---|
| 2816 | else
|
---|
| 2817 | {
|
---|
| 2818 | /* For legacy hosts, we do the filtering thingy. */
|
---|
| 2819 | rc = VbglR3GuestCtrlMsgFilterSet(idClient, VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(idSession),
|
---|
| 2820 | VBOX_GUESTCTRL_FILTER_BY_SESSION(idSession), 0);
|
---|
| 2821 | if (RT_SUCCESS(rc))
|
---|
[75858] | 2822 | VGSvcVerbose(3, "Session %u filtering successfully enabled\n", idSession);
|
---|
[75807] | 2823 | else
|
---|
| 2824 | VGSvcError("Failed to set session filter: %Rrc\n", rc);
|
---|
| 2825 | }
|
---|
| 2826 | }
|
---|
| 2827 | else
|
---|
| 2828 | VGSvcError("Error reading secret key from standard input: %Rrc\n", rc);
|
---|
| 2829 | }
|
---|
| 2830 | else
|
---|
| 2831 | {
|
---|
| 2832 | VGSvcError("Standard input is not a pipe!\n");
|
---|
| 2833 | rc = VERR_INVALID_HANDLE;
|
---|
| 2834 | }
|
---|
| 2835 | RTHandleClose(&Handle);
|
---|
| 2836 | }
|
---|
| 2837 | else
|
---|
| 2838 | VGSvcError("RTHandleGetStandard failed on standard input: %Rrc\n", rc);
|
---|
[44935] | 2839 | return rc;
|
---|
| 2840 | }
|
---|
| 2841 |
|
---|
[75736] | 2842 | /**
|
---|
[84209] | 2843 | * Invalidates a guest session by updating all it's internal parameters like host features and stuff.
|
---|
| 2844 | *
|
---|
| 2845 | * @param pSession Session to invalidate.
|
---|
| 2846 | * @param idClient Client ID to use.
|
---|
| 2847 | */
|
---|
| 2848 | static void vgsvcGstCtrlSessionInvalidate(PVBOXSERVICECTRLSESSION pSession, uint32_t idClient)
|
---|
| 2849 | {
|
---|
| 2850 | RT_NOREF(pSession);
|
---|
| 2851 |
|
---|
| 2852 | VGSvcVerbose(1, "Invalidating session %RU32 (client ID=%RU32)\n", idClient, pSession->StartupInfo.uSessionID);
|
---|
| 2853 |
|
---|
| 2854 | int rc2 = VbglR3GuestCtrlQueryFeatures(idClient, &g_fControlHostFeatures0);
|
---|
| 2855 | if (RT_SUCCESS(rc2)) /* Querying host features is not fatal -- do not use rc here. */
|
---|
| 2856 | {
|
---|
| 2857 | VGSvcVerbose(1, "g_fControlHostFeatures0=%#x\n", g_fControlHostFeatures0);
|
---|
| 2858 | }
|
---|
| 2859 | else
|
---|
| 2860 | VGSvcVerbose(1, "Querying host features failed with %Rrc\n", rc2);
|
---|
| 2861 | }
|
---|
| 2862 |
|
---|
| 2863 | /**
|
---|
[75736] | 2864 | * Main message handler for the guest control session process.
|
---|
| 2865 | *
|
---|
| 2866 | * @returns exit code.
|
---|
| 2867 | * @param pSession Pointer to g_Session.
|
---|
| 2868 | * @thread main.
|
---|
| 2869 | */
|
---|
[58029] | 2870 | static RTEXITCODE vgsvcGstCtrlSessionSpawnWorker(PVBOXSERVICECTRLSESSION pSession)
|
---|
[44863] | 2871 | {
|
---|
[45010] | 2872 | AssertPtrReturn(pSession, RTEXITCODE_FAILURE);
|
---|
[58029] | 2873 | VGSvcVerbose(0, "Hi, this is guest session ID=%RU32\n", pSession->StartupInfo.uSessionID);
|
---|
[44935] | 2874 |
|
---|
[75736] | 2875 | /*
|
---|
| 2876 | * Connect to the host service.
|
---|
| 2877 | */
|
---|
| 2878 | uint32_t idClient;
|
---|
| 2879 | int rc = VbglR3GuestCtrlConnect(&idClient);
|
---|
| 2880 | if (RT_FAILURE(rc))
|
---|
| 2881 | return VGSvcError("Error connecting to guest control service, rc=%Rrc\n", rc);
|
---|
[75807] | 2882 | g_fControlSupportsOptimizations = VbglR3GuestCtrlSupportsOptimizations(idClient);
|
---|
[75858] | 2883 | g_idControlSvcClient = idClient;
|
---|
[44935] | 2884 |
|
---|
[84209] | 2885 | VGSvcVerbose(1, "Using client ID=%RU32\n", idClient);
|
---|
[83508] | 2886 |
|
---|
[84209] | 2887 | vgsvcGstCtrlSessionInvalidate(pSession, idClient);
|
---|
| 2888 |
|
---|
[75807] | 2889 | rc = vgsvcGstCtrlSessionReadKeyAndAccept(idClient, pSession->StartupInfo.uSessionID);
|
---|
| 2890 | if (RT_SUCCESS(rc))
|
---|
[75727] | 2891 | {
|
---|
[49349] | 2892 | /*
|
---|
[75736] | 2893 | * Report started status.
|
---|
| 2894 | * If session status cannot be posted to the host for some reason, bail out.
|
---|
[49349] | 2895 | */
|
---|
[83553] | 2896 | VBGLR3GUESTCTRLCMDCTX ctx = { idClient, VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(pSession->StartupInfo.uSessionID),
|
---|
| 2897 | 0 /* uProtocol, unused */, 0 /* uNumParms, unused */ };
|
---|
[75736] | 2898 | rc = VbglR3GuestCtrlSessionNotify(&ctx, GUEST_SESSION_NOTIFYTYPE_STARTED, VINF_SUCCESS);
|
---|
[49349] | 2899 | if (RT_SUCCESS(rc))
|
---|
[75736] | 2900 | {
|
---|
| 2901 | /*
|
---|
[76958] | 2902 | * Allocate a scratch buffer for messages which also send payload data with them.
|
---|
[75824] | 2903 | * This buffer may grow if the host sends us larger chunks of data.
|
---|
[75736] | 2904 | */
|
---|
| 2905 | uint32_t cbScratchBuf = _64K;
|
---|
[75824] | 2906 | void *pvScratchBuf = RTMemAlloc(cbScratchBuf);
|
---|
[75736] | 2907 | if (pvScratchBuf)
|
---|
| 2908 | {
|
---|
[83441] | 2909 | int cFailedMsgPeeks = 0;
|
---|
| 2910 |
|
---|
[75736] | 2911 | /*
|
---|
| 2912 | * Message processing loop.
|
---|
| 2913 | */
|
---|
| 2914 | VBGLR3GUESTCTRLCMDCTX CtxHost = { idClient, 0 /* Context ID */, pSession->StartupInfo.uProtocol, 0 };
|
---|
| 2915 | for (;;)
|
---|
| 2916 | {
|
---|
| 2917 | VGSvcVerbose(3, "Waiting for host msg ...\n");
|
---|
| 2918 | uint32_t uMsg = 0;
|
---|
[75853] | 2919 | rc = VbglR3GuestCtrlMsgPeekWait(idClient, &uMsg, &CtxHost.uNumParms, NULL);
|
---|
[75807] | 2920 | if (RT_SUCCESS(rc))
|
---|
[75736] | 2921 | {
|
---|
[75824] | 2922 | VGSvcVerbose(4, "Msg=%RU32 (%RU32 parms) retrieved (%Rrc)\n", uMsg, CtxHost.uNumParms, rc);
|
---|
[49349] | 2923 |
|
---|
[75736] | 2924 | /*
|
---|
[75824] | 2925 | * Pass it on to the session handler.
|
---|
[75736] | 2926 | * Note! Only when handling HOST_SESSION_CLOSE is the rc used.
|
---|
| 2927 | */
|
---|
| 2928 | bool fShutdown = false;
|
---|
[75824] | 2929 | rc = VGSvcGstCtrlSessionHandler(pSession, uMsg, &CtxHost, &pvScratchBuf, &cbScratchBuf, &fShutdown);
|
---|
[75736] | 2930 | if (fShutdown)
|
---|
| 2931 | break;
|
---|
[83441] | 2932 |
|
---|
| 2933 | cFailedMsgPeeks = 0;
|
---|
| 2934 |
|
---|
| 2935 | /* Let others run (guests are often single CPU) ... */
|
---|
| 2936 | RTThreadYield();
|
---|
[75736] | 2937 | }
|
---|
[84209] | 2938 | /*
|
---|
| 2939 | * Handle restore notification from host. All the context IDs (sessions,
|
---|
| 2940 | * files, proceses, etc) are invalidated by a VM restore and must be closed.
|
---|
| 2941 | */
|
---|
| 2942 | else if (rc == VERR_VM_RESTORED)
|
---|
| 2943 | {
|
---|
[95505] | 2944 | VGSvcVerbose(1, "The VM session ID changed (i.e. restored), closing stale session %RU32\n",
|
---|
| 2945 | pSession->StartupInfo.uSessionID);
|
---|
[84209] | 2946 |
|
---|
[95505] | 2947 | /* We currently don't serialize guest sessions, guest processes and other guest control objects
|
---|
| 2948 | * within saved states. So just close this session and report success to the parent process.
|
---|
| 2949 | *
|
---|
| 2950 | * Note: Not notifying the host here is intentional, as it wouldn't have any information
|
---|
| 2951 | * about what to do with it.
|
---|
| 2952 | */
|
---|
| 2953 | rc = VINF_SUCCESS; /* Report success as exit code. */
|
---|
| 2954 | break;
|
---|
[84209] | 2955 | }
|
---|
[83441] | 2956 | else
|
---|
| 2957 | {
|
---|
| 2958 | VGSvcVerbose(1, "Getting host message failed with %Rrc\n", rc);
|
---|
[44863] | 2959 |
|
---|
[83441] | 2960 | if (cFailedMsgPeeks++ == 3)
|
---|
| 2961 | break;
|
---|
| 2962 |
|
---|
| 2963 | RTThreadSleep(3 * RT_MS_1SEC);
|
---|
| 2964 |
|
---|
| 2965 | /** @todo Shouldn't we have a plan for handling connection loss and such? */
|
---|
| 2966 | }
|
---|
[75736] | 2967 | }
|
---|
[44863] | 2968 |
|
---|
[75736] | 2969 | /*
|
---|
| 2970 | * Shutdown.
|
---|
| 2971 | */
|
---|
| 2972 | RTMemFree(pvScratchBuf);
|
---|
[44963] | 2973 | }
|
---|
[75736] | 2974 | else
|
---|
| 2975 | rc = VERR_NO_MEMORY;
|
---|
[44863] | 2976 |
|
---|
[75736] | 2977 | VGSvcVerbose(0, "Session %RU32 ended\n", pSession->StartupInfo.uSessionID);
|
---|
[44963] | 2978 | }
|
---|
[75736] | 2979 | else
|
---|
| 2980 | VGSvcError("Reporting session ID=%RU32 started status failed with rc=%Rrc\n", pSession->StartupInfo.uSessionID, rc);
|
---|
[44963] | 2981 | }
|
---|
[75736] | 2982 | else
|
---|
| 2983 | VGSvcError("Setting message filterAdd=0x%x failed with rc=%Rrc\n", pSession->StartupInfo.uSessionID, rc);
|
---|
[44863] | 2984 |
|
---|
[75736] | 2985 | VGSvcVerbose(3, "Disconnecting client ID=%RU32 ...\n", idClient);
|
---|
| 2986 | VbglR3GuestCtrlDisconnect(idClient);
|
---|
[75858] | 2987 | g_idControlSvcClient = 0;
|
---|
[44863] | 2988 |
|
---|
[58029] | 2989 | VGSvcVerbose(3, "Session worker returned with rc=%Rrc\n", rc);
|
---|
[44963] | 2990 | return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
|
---|
| 2991 | }
|
---|
[44863] | 2992 |
|
---|
| 2993 |
|
---|
[44963] | 2994 | /**
|
---|
[58029] | 2995 | * Finds a (formerly) started guest process given by its PID and increases its
|
---|
| 2996 | * reference count.
|
---|
[44963] | 2997 | *
|
---|
[58029] | 2998 | * Must be decreased by the caller with VGSvcGstCtrlProcessRelease().
|
---|
| 2999 | *
|
---|
| 3000 | * @returns Guest process if found, otherwise NULL.
|
---|
| 3001 | * @param pSession Pointer to guest session where to search process in.
|
---|
| 3002 | * @param uPID PID to search for.
|
---|
| 3003 | *
|
---|
| 3004 | * @note This does *not lock the process!
|
---|
[44963] | 3005 | */
|
---|
[58029] | 3006 | PVBOXSERVICECTRLPROCESS VGSvcGstCtrlSessionRetainProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID)
|
---|
[44963] | 3007 | {
|
---|
| 3008 | AssertPtrReturn(pSession, NULL);
|
---|
[44863] | 3009 |
|
---|
[45415] | 3010 | PVBOXSERVICECTRLPROCESS pProcess = NULL;
|
---|
| 3011 | int rc = RTCritSectEnter(&pSession->CritSect);
|
---|
[44963] | 3012 | if (RT_SUCCESS(rc))
|
---|
| 3013 | {
|
---|
[45415] | 3014 | PVBOXSERVICECTRLPROCESS pCurProcess;
|
---|
[47545] | 3015 | RTListForEach(&pSession->lstProcesses, pCurProcess, VBOXSERVICECTRLPROCESS, Node)
|
---|
[44963] | 3016 | {
|
---|
[45415] | 3017 | if (pCurProcess->uPID == uPID)
|
---|
[44963] | 3018 | {
|
---|
[45415] | 3019 | rc = RTCritSectEnter(&pCurProcess->CritSect);
|
---|
[44963] | 3020 | if (RT_SUCCESS(rc))
|
---|
[45697] | 3021 | {
|
---|
| 3022 | pCurProcess->cRefs++;
|
---|
| 3023 | rc = RTCritSectLeave(&pCurProcess->CritSect);
|
---|
| 3024 | AssertRC(rc);
|
---|
| 3025 | }
|
---|
| 3026 |
|
---|
| 3027 | if (RT_SUCCESS(rc))
|
---|
[45415] | 3028 | pProcess = pCurProcess;
|
---|
[44963] | 3029 | break;
|
---|
| 3030 | }
|
---|
| 3031 | }
|
---|
[44863] | 3032 |
|
---|
[45697] | 3033 | rc = RTCritSectLeave(&pSession->CritSect);
|
---|
| 3034 | AssertRC(rc);
|
---|
[44963] | 3035 | }
|
---|
| 3036 |
|
---|
[45415] | 3037 | return pProcess;
|
---|
[44963] | 3038 | }
|
---|
| 3039 |
|
---|
| 3040 |
|
---|
[58029] | 3041 | int VGSvcGstCtrlSessionClose(PVBOXSERVICECTRLSESSION pSession)
|
---|
[44963] | 3042 | {
|
---|
| 3043 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 3044 |
|
---|
[58029] | 3045 | VGSvcVerbose(0, "Session %RU32 is about to close ...\n", pSession->StartupInfo.uSessionID);
|
---|
[44963] | 3046 |
|
---|
[45415] | 3047 | int rc = RTCritSectEnter(&pSession->CritSect);
|
---|
| 3048 | if (RT_SUCCESS(rc))
|
---|
| 3049 | {
|
---|
| 3050 | /*
|
---|
| 3051 | * Close all guest processes.
|
---|
| 3052 | */
|
---|
[58029] | 3053 | VGSvcVerbose(0, "Stopping all guest processes ...\n");
|
---|
[45010] | 3054 |
|
---|
[45415] | 3055 | /* Signal all guest processes in the active list that we want to shutdown. */
|
---|
| 3056 | PVBOXSERVICECTRLPROCESS pProcess;
|
---|
[47545] | 3057 | RTListForEach(&pSession->lstProcesses, pProcess, VBOXSERVICECTRLPROCESS, Node)
|
---|
[58029] | 3058 | VGSvcGstCtrlProcessStop(pProcess);
|
---|
[45010] | 3059 |
|
---|
[83286] | 3060 | VGSvcVerbose(1, "%RU32 guest processes were signalled to stop\n", pSession->cProcesses);
|
---|
[45604] | 3061 |
|
---|
[45415] | 3062 | /* Wait for all active threads to shutdown and destroy the active thread list. */
|
---|
[83595] | 3063 | PVBOXSERVICECTRLPROCESS pProcessNext;
|
---|
| 3064 | RTListForEachSafe(&pSession->lstProcesses, pProcess, pProcessNext, VBOXSERVICECTRLPROCESS, Node)
|
---|
[45415] | 3065 | {
|
---|
[83595] | 3066 | int rc3 = RTCritSectLeave(&pSession->CritSect);
|
---|
| 3067 | AssertRC(rc3);
|
---|
[44963] | 3068 |
|
---|
[83595] | 3069 | int rc2 = VGSvcGstCtrlProcessWait(pProcess, 30 * 1000 /* Wait 30 seconds max. */, NULL /* rc */);
|
---|
[45415] | 3070 |
|
---|
[83595] | 3071 | rc3 = RTCritSectEnter(&pSession->CritSect);
|
---|
[47545] | 3072 | AssertRC(rc3);
|
---|
[45415] | 3073 |
|
---|
[47545] | 3074 | if (RT_SUCCESS(rc2))
|
---|
[83595] | 3075 | {
|
---|
| 3076 | rc2 = vgsvcGstCtrlSessionProcessRemoveInternal(pSession, pProcess);
|
---|
| 3077 | if (RT_SUCCESS(rc2))
|
---|
| 3078 | {
|
---|
| 3079 | VGSvcGstCtrlProcessFree(pProcess);
|
---|
| 3080 | pProcess = NULL;
|
---|
| 3081 | }
|
---|
| 3082 | }
|
---|
[44963] | 3083 | }
|
---|
| 3084 |
|
---|
[83595] | 3085 | AssertMsg(pSession->cProcesses == 0,
|
---|
| 3086 | ("Session process list still contains %RU32 when it should not\n", pSession->cProcesses));
|
---|
[47545] | 3087 | AssertMsg(RTListIsEmpty(&pSession->lstProcesses),
|
---|
[83595] | 3088 | ("Session process list is not empty when it should\n"));
|
---|
[47545] | 3089 |
|
---|
[45415] | 3090 | /*
|
---|
| 3091 | * Close all left guest files.
|
---|
| 3092 | */
|
---|
[58029] | 3093 | VGSvcVerbose(0, "Closing all guest files ...\n");
|
---|
[45604] | 3094 |
|
---|
[83595] | 3095 | PVBOXSERVICECTRLFILE pFile, pFileNext;
|
---|
| 3096 | RTListForEachSafe(&pSession->lstFiles, pFile, pFileNext, VBOXSERVICECTRLFILE, Node)
|
---|
[45415] | 3097 | {
|
---|
[83595] | 3098 | int rc2 = vgsvcGstCtrlSessionFileFree(pFile);
|
---|
[45415] | 3099 | if (RT_FAILURE(rc2))
|
---|
| 3100 | {
|
---|
[84148] | 3101 | VGSvcError("Unable to close file '%s'; rc=%Rrc\n", pFile->pszName, rc2);
|
---|
[45415] | 3102 | if (RT_SUCCESS(rc))
|
---|
| 3103 | rc = rc2;
|
---|
| 3104 | /* Keep going. */
|
---|
| 3105 | }
|
---|
[44963] | 3106 |
|
---|
[83595] | 3107 | pFile = NULL; /* To make it obvious. */
|
---|
[45010] | 3108 | }
|
---|
| 3109 |
|
---|
[98526] | 3110 | #ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
|
---|
| 3111 | AssertMsg(pSession->cDirs == 0,
|
---|
| 3112 | ("Session directory list still contains %RU32 when it should not\n", pSession->cDirs));
|
---|
| 3113 | AssertMsg(RTListIsEmpty(&pSession->lstDirs),
|
---|
| 3114 | ("Session directory list is not empty when it should\n"));
|
---|
| 3115 | #endif
|
---|
[83595] | 3116 | AssertMsg(pSession->cFiles == 0,
|
---|
| 3117 | ("Session file list still contains %RU32 when it should not\n", pSession->cFiles));
|
---|
| 3118 | AssertMsg(RTListIsEmpty(&pSession->lstFiles),
|
---|
| 3119 | ("Session file list is not empty when it should\n"));
|
---|
[45010] | 3120 |
|
---|
[45415] | 3121 | int rc2 = RTCritSectLeave(&pSession->CritSect);
|
---|
| 3122 | if (RT_SUCCESS(rc))
|
---|
| 3123 | rc = rc2;
|
---|
[45010] | 3124 | }
|
---|
| 3125 |
|
---|
[44963] | 3126 | return rc;
|
---|
| 3127 | }
|
---|
| 3128 |
|
---|
| 3129 |
|
---|
[58029] | 3130 | int VGSvcGstCtrlSessionDestroy(PVBOXSERVICECTRLSESSION pSession)
|
---|
[44963] | 3131 | {
|
---|
| 3132 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 3133 |
|
---|
[58029] | 3134 | int rc = VGSvcGstCtrlSessionClose(pSession);
|
---|
[44963] | 3135 |
|
---|
| 3136 | /* Destroy critical section. */
|
---|
[45415] | 3137 | RTCritSectDelete(&pSession->CritSect);
|
---|
[44963] | 3138 |
|
---|
| 3139 | return rc;
|
---|
| 3140 | }
|
---|
| 3141 |
|
---|
| 3142 |
|
---|
[58029] | 3143 | int VGSvcGstCtrlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t fFlags)
|
---|
[44963] | 3144 | {
|
---|
| 3145 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 3146 |
|
---|
[47545] | 3147 | RTListInit(&pSession->lstProcesses);
|
---|
[98526] | 3148 | #ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
|
---|
| 3149 | RTListInit(&pSession->lstDirs);
|
---|
| 3150 | #endif
|
---|
[44963] | 3151 | RTListInit(&pSession->lstFiles);
|
---|
| 3152 |
|
---|
[83286] | 3153 | pSession->cProcesses = 0;
|
---|
| 3154 | pSession->cFiles = 0;
|
---|
| 3155 |
|
---|
[57659] | 3156 | pSession->fFlags = fFlags;
|
---|
[44963] | 3157 |
|
---|
[98824] | 3158 | #ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
|
---|
[98817] | 3159 | RT_ZERO(pSession->UidCache);
|
---|
| 3160 | RT_ZERO(pSession->GidCache);
|
---|
[98824] | 3161 | #endif
|
---|
| 3162 |
|
---|
[44963] | 3163 | /* Init critical section for protecting the thread lists. */
|
---|
[45415] | 3164 | int rc = RTCritSectInit(&pSession->CritSect);
|
---|
[44963] | 3165 | AssertRC(rc);
|
---|
| 3166 |
|
---|
| 3167 | return rc;
|
---|
| 3168 | }
|
---|
| 3169 |
|
---|
| 3170 |
|
---|
| 3171 | /**
|
---|
[47545] | 3172 | * Adds a guest process to a session's process list.
|
---|
[44963] | 3173 | *
|
---|
[58029] | 3174 | * @return VBox status code.
|
---|
[47545] | 3175 | * @param pSession Guest session to add process to.
|
---|
| 3176 | * @param pProcess Guest process to add.
|
---|
[44963] | 3177 | */
|
---|
[58029] | 3178 | int VGSvcGstCtrlSessionProcessAdd(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess)
|
---|
[44963] | 3179 | {
|
---|
| 3180 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
[45010] | 3181 | AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
|
---|
[44963] | 3182 |
|
---|
[45415] | 3183 | int rc = RTCritSectEnter(&pSession->CritSect);
|
---|
[44963] | 3184 | if (RT_SUCCESS(rc))
|
---|
| 3185 | {
|
---|
[83286] | 3186 | VGSvcVerbose(3, "Adding process (PID %RU32) to session ID=%RU32\n", pProcess->uPID, pSession->StartupInfo.uSessionID);
|
---|
[44963] | 3187 |
|
---|
[47545] | 3188 | /* Add process to session list. */
|
---|
[58029] | 3189 | RTListAppend(&pSession->lstProcesses, &pProcess->Node);
|
---|
[44963] | 3190 |
|
---|
[83286] | 3191 | pSession->cProcesses++;
|
---|
| 3192 | VGSvcVerbose(3, "Now session ID=%RU32 has %RU32 processes total\n",
|
---|
| 3193 | pSession->StartupInfo.uSessionID, pSession->cProcesses);
|
---|
| 3194 |
|
---|
[47545] | 3195 | int rc2 = RTCritSectLeave(&pSession->CritSect);
|
---|
| 3196 | if (RT_SUCCESS(rc))
|
---|
| 3197 | rc = rc2;
|
---|
| 3198 | }
|
---|
[44963] | 3199 |
|
---|
[47545] | 3200 | return VINF_SUCCESS;
|
---|
| 3201 | }
|
---|
[44963] | 3202 |
|
---|
[83595] | 3203 | /**
|
---|
| 3204 | * Removes a guest process from a session's process list.
|
---|
| 3205 | * Internal version, does not do locking.
|
---|
| 3206 | *
|
---|
| 3207 | * @return VBox status code.
|
---|
| 3208 | * @param pSession Guest session to remove process from.
|
---|
| 3209 | * @param pProcess Guest process to remove.
|
---|
| 3210 | */
|
---|
| 3211 | static int vgsvcGstCtrlSessionProcessRemoveInternal(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess)
|
---|
| 3212 | {
|
---|
| 3213 | VGSvcVerbose(3, "Removing process (PID %RU32) from session ID=%RU32\n", pProcess->uPID, pSession->StartupInfo.uSessionID);
|
---|
| 3214 | AssertReturn(pProcess->cRefs == 0, VERR_WRONG_ORDER);
|
---|
[44963] | 3215 |
|
---|
[83595] | 3216 | RTListNodeRemove(&pProcess->Node);
|
---|
| 3217 |
|
---|
| 3218 | AssertReturn(pSession->cProcesses, VERR_WRONG_ORDER);
|
---|
| 3219 | pSession->cProcesses--;
|
---|
| 3220 | VGSvcVerbose(3, "Now session ID=%RU32 has %RU32 processes total\n",
|
---|
| 3221 | pSession->StartupInfo.uSessionID, pSession->cProcesses);
|
---|
| 3222 |
|
---|
| 3223 | return VINF_SUCCESS;
|
---|
| 3224 | }
|
---|
| 3225 |
|
---|
[47545] | 3226 | /**
|
---|
| 3227 | * Removes a guest process from a session's process list.
|
---|
| 3228 | *
|
---|
[58029] | 3229 | * @return VBox status code.
|
---|
[47545] | 3230 | * @param pSession Guest session to remove process from.
|
---|
| 3231 | * @param pProcess Guest process to remove.
|
---|
| 3232 | */
|
---|
[58029] | 3233 | int VGSvcGstCtrlSessionProcessRemove(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess)
|
---|
[47545] | 3234 | {
|
---|
| 3235 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 3236 | AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
|
---|
[44963] | 3237 |
|
---|
[47545] | 3238 | int rc = RTCritSectEnter(&pSession->CritSect);
|
---|
| 3239 | if (RT_SUCCESS(rc))
|
---|
| 3240 | {
|
---|
[83595] | 3241 | rc = vgsvcGstCtrlSessionProcessRemoveInternal(pSession, pProcess);
|
---|
[44963] | 3242 |
|
---|
[45415] | 3243 | int rc2 = RTCritSectLeave(&pSession->CritSect);
|
---|
[44963] | 3244 | if (RT_SUCCESS(rc))
|
---|
| 3245 | rc = rc2;
|
---|
| 3246 | }
|
---|
| 3247 |
|
---|
[83286] | 3248 | return rc;
|
---|
[44963] | 3249 | }
|
---|
| 3250 |
|
---|
| 3251 |
|
---|
| 3252 | /**
|
---|
| 3253 | * Determines whether starting a new guest process according to the
|
---|
| 3254 | * maximum number of concurrent guest processes defined is allowed or not.
|
---|
| 3255 | *
|
---|
[58029] | 3256 | * @return VBox status code.
|
---|
[58089] | 3257 | * @param pSession The guest session.
|
---|
[83286] | 3258 | * @param pfAllowed \c True if starting (another) guest process
|
---|
| 3259 | * is allowed, \c false if not.
|
---|
[44963] | 3260 | */
|
---|
[83286] | 3261 | int VGSvcGstCtrlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pfAllowed)
|
---|
[44963] | 3262 | {
|
---|
| 3263 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
[83286] | 3264 | AssertPtrReturn(pfAllowed, VERR_INVALID_POINTER);
|
---|
[44963] | 3265 |
|
---|
[45415] | 3266 | int rc = RTCritSectEnter(&pSession->CritSect);
|
---|
[44963] | 3267 | if (RT_SUCCESS(rc))
|
---|
| 3268 | {
|
---|
| 3269 | /*
|
---|
| 3270 | * Check if we're respecting our memory policy by checking
|
---|
| 3271 | * how many guest processes are started and served already.
|
---|
| 3272 | */
|
---|
| 3273 | bool fLimitReached = false;
|
---|
| 3274 | if (pSession->uProcsMaxKept) /* If we allow unlimited processes (=0), take a shortcut. */
|
---|
| 3275 | {
|
---|
[83286] | 3276 | VGSvcVerbose(3, "Maximum kept guest processes set to %RU32, acurrent=%RU32\n",
|
---|
| 3277 | pSession->uProcsMaxKept, pSession->cProcesses);
|
---|
[44963] | 3278 |
|
---|
[83286] | 3279 | int32_t iProcsLeft = (pSession->uProcsMaxKept - pSession->cProcesses - 1);
|
---|
[44963] | 3280 | if (iProcsLeft < 0)
|
---|
| 3281 | {
|
---|
[83286] | 3282 | VGSvcVerbose(3, "Maximum running guest processes reached (%RU32)\n", pSession->uProcsMaxKept);
|
---|
[44963] | 3283 | fLimitReached = true;
|
---|
| 3284 | }
|
---|
| 3285 | }
|
---|
| 3286 |
|
---|
[83286] | 3287 | *pfAllowed = !fLimitReached;
|
---|
[44963] | 3288 |
|
---|
[45415] | 3289 | int rc2 = RTCritSectLeave(&pSession->CritSect);
|
---|
[44963] | 3290 | if (RT_SUCCESS(rc))
|
---|
| 3291 | rc = rc2;
|
---|
| 3292 | }
|
---|
| 3293 |
|
---|
| 3294 | return rc;
|
---|
| 3295 | }
|
---|
| 3296 |
|
---|
| 3297 |
|
---|
| 3298 | /**
|
---|
[83286] | 3299 | * Cleans up stopped and no longer used processes.
|
---|
| 3300 | *
|
---|
| 3301 | * This will free and remove processes from the session's process list.
|
---|
| 3302 | *
|
---|
| 3303 | * @returns VBox status code.
|
---|
| 3304 | * @param pSession Session to clean up processes for.
|
---|
| 3305 | */
|
---|
| 3306 | static int vgsvcGstCtrlSessionCleanupProcesses(const PVBOXSERVICECTRLSESSION pSession)
|
---|
| 3307 | {
|
---|
| 3308 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 3309 |
|
---|
| 3310 | VGSvcVerbose(3, "Cleaning up stopped processes for session %RU32 ...\n", pSession->StartupInfo.uSessionID);
|
---|
| 3311 |
|
---|
| 3312 | int rc2 = RTCritSectEnter(&pSession->CritSect);
|
---|
| 3313 | AssertRC(rc2);
|
---|
| 3314 |
|
---|
| 3315 | int rc = VINF_SUCCESS;
|
---|
| 3316 |
|
---|
| 3317 | PVBOXSERVICECTRLPROCESS pCurProcess, pNextProcess;
|
---|
| 3318 | RTListForEachSafe(&pSession->lstProcesses, pCurProcess, pNextProcess, VBOXSERVICECTRLPROCESS, Node)
|
---|
| 3319 | {
|
---|
| 3320 | if (ASMAtomicReadBool(&pCurProcess->fStopped))
|
---|
| 3321 | {
|
---|
| 3322 | rc2 = RTCritSectLeave(&pSession->CritSect);
|
---|
| 3323 | AssertRC(rc2);
|
---|
| 3324 |
|
---|
| 3325 | rc = VGSvcGstCtrlProcessWait(pCurProcess, 30 * 1000 /* Wait 30 seconds max. */, NULL /* rc */);
|
---|
| 3326 | if (RT_SUCCESS(rc))
|
---|
| 3327 | {
|
---|
| 3328 | VGSvcGstCtrlSessionProcessRemove(pSession, pCurProcess);
|
---|
| 3329 | VGSvcGstCtrlProcessFree(pCurProcess);
|
---|
| 3330 | }
|
---|
| 3331 |
|
---|
| 3332 | rc2 = RTCritSectEnter(&pSession->CritSect);
|
---|
| 3333 | AssertRC(rc2);
|
---|
| 3334 |
|
---|
| 3335 | /* If failed, try next time we're being called. */
|
---|
| 3336 | }
|
---|
| 3337 | }
|
---|
| 3338 |
|
---|
| 3339 | rc2 = RTCritSectLeave(&pSession->CritSect);
|
---|
| 3340 | AssertRC(rc2);
|
---|
| 3341 |
|
---|
| 3342 | if (RT_FAILURE(rc))
|
---|
| 3343 | VGSvcError("Cleaning up stopped processes for session %RU32 failed with %Rrc\n", pSession->StartupInfo.uSessionID, rc);
|
---|
| 3344 |
|
---|
| 3345 | return rc;
|
---|
| 3346 | }
|
---|
| 3347 |
|
---|
| 3348 |
|
---|
| 3349 | /**
|
---|
[57962] | 3350 | * Creates the process for a guest session.
|
---|
| 3351 | *
|
---|
[58029] | 3352 | * @return VBox status code.
|
---|
[57962] | 3353 | * @param pSessionStartupInfo Session startup info.
|
---|
| 3354 | * @param pSessionThread The session thread under construction.
|
---|
| 3355 | * @param uCtrlSessionThread The session thread debug ordinal.
|
---|
| 3356 | */
|
---|
[84215] | 3357 | static int vgsvcVGSvcGstCtrlSessionThreadCreateProcess(const PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pSessionStartupInfo,
|
---|
[58029] | 3358 | PVBOXSERVICECTRLSESSIONTHREAD pSessionThread, uint32_t uCtrlSessionThread)
|
---|
[57962] | 3359 | {
|
---|
[71320] | 3360 | RT_NOREF(uCtrlSessionThread);
|
---|
[62850] | 3361 |
|
---|
[57962] | 3362 | /*
|
---|
| 3363 | * Is this an anonymous session? Anonymous sessions run with the same
|
---|
| 3364 | * privileges as the main VBoxService executable.
|
---|
| 3365 | */
|
---|
[84147] | 3366 | bool const fAnonymous = pSessionThread->pStartupInfo->pszUser
|
---|
| 3367 | && pSessionThread->pStartupInfo->pszUser[0] == '\0';
|
---|
[57962] | 3368 | if (fAnonymous)
|
---|
| 3369 | {
|
---|
[84147] | 3370 | Assert(!strlen(pSessionThread->pStartupInfo->pszPassword));
|
---|
| 3371 | Assert(!strlen(pSessionThread->pStartupInfo->pszDomain));
|
---|
[57962] | 3372 |
|
---|
[58029] | 3373 | VGSvcVerbose(3, "New anonymous guest session ID=%RU32 created, fFlags=%x, using protocol %RU32\n",
|
---|
| 3374 | pSessionStartupInfo->uSessionID,
|
---|
| 3375 | pSessionStartupInfo->fFlags,
|
---|
| 3376 | pSessionStartupInfo->uProtocol);
|
---|
[57962] | 3377 | }
|
---|
| 3378 | else
|
---|
| 3379 | {
|
---|
[58029] | 3380 | VGSvcVerbose(3, "Spawning new guest session ID=%RU32, szUser=%s, szPassword=%s, szDomain=%s, fFlags=%x, using protocol %RU32\n",
|
---|
| 3381 | pSessionStartupInfo->uSessionID,
|
---|
[84147] | 3382 | pSessionStartupInfo->pszUser,
|
---|
[57962] | 3383 | #ifdef DEBUG
|
---|
[84147] | 3384 | pSessionStartupInfo->pszPassword,
|
---|
[57962] | 3385 | #else
|
---|
[58029] | 3386 | "XXX", /* Never show passwords in release mode. */
|
---|
[57962] | 3387 | #endif
|
---|
[84147] | 3388 | pSessionStartupInfo->pszDomain,
|
---|
[58029] | 3389 | pSessionStartupInfo->fFlags,
|
---|
| 3390 | pSessionStartupInfo->uProtocol);
|
---|
[57962] | 3391 | }
|
---|
| 3392 |
|
---|
| 3393 | /*
|
---|
| 3394 | * Spawn a child process for doing the actual session handling.
|
---|
| 3395 | * Start by assembling the argument list.
|
---|
| 3396 | */
|
---|
| 3397 | char szExeName[RTPATH_MAX];
|
---|
| 3398 | char *pszExeName = RTProcGetExecutablePath(szExeName, sizeof(szExeName));
|
---|
[84731] | 3399 | AssertPtrReturn(pszExeName, VERR_FILENAME_TOO_LONG);
|
---|
[57962] | 3400 |
|
---|
[75807] | 3401 | char szParmSessionID[32];
|
---|
[84147] | 3402 | RTStrPrintf(szParmSessionID, sizeof(szParmSessionID), "--session-id=%RU32", pSessionThread->pStartupInfo->uSessionID);
|
---|
[75807] | 3403 |
|
---|
| 3404 | char szParmSessionProto[32];
|
---|
| 3405 | RTStrPrintf(szParmSessionProto, sizeof(szParmSessionProto), "--session-proto=%RU32",
|
---|
[84147] | 3406 | pSessionThread->pStartupInfo->uProtocol);
|
---|
[57962] | 3407 | #ifdef DEBUG
|
---|
[75807] | 3408 | char szParmThreadId[32];
|
---|
| 3409 | RTStrPrintf(szParmThreadId, sizeof(szParmThreadId), "--thread-id=%RU32", uCtrlSessionThread);
|
---|
[57962] | 3410 | #endif
|
---|
[75807] | 3411 | unsigned idxArg = 0; /* Next index in argument vector. */
|
---|
| 3412 | char const *apszArgs[24];
|
---|
[57962] | 3413 |
|
---|
[75807] | 3414 | apszArgs[idxArg++] = pszExeName;
|
---|
[92662] | 3415 | #ifdef VBOXSERVICE_ARG1_UTF8_ARGV
|
---|
| 3416 | apszArgs[idxArg++] = VBOXSERVICE_ARG1_UTF8_ARGV; Assert(idxArg == 2);
|
---|
| 3417 | #endif
|
---|
[75807] | 3418 | apszArgs[idxArg++] = "guestsession";
|
---|
| 3419 | apszArgs[idxArg++] = szParmSessionID;
|
---|
| 3420 | apszArgs[idxArg++] = szParmSessionProto;
|
---|
[57962] | 3421 | #ifdef DEBUG
|
---|
[75807] | 3422 | apszArgs[idxArg++] = szParmThreadId;
|
---|
[57962] | 3423 | #endif
|
---|
[75807] | 3424 | if (!fAnonymous) /* Do we need to pass a user name? */
|
---|
| 3425 | {
|
---|
| 3426 | apszArgs[idxArg++] = "--user";
|
---|
[84147] | 3427 | apszArgs[idxArg++] = pSessionThread->pStartupInfo->pszUser;
|
---|
[59134] | 3428 |
|
---|
[84147] | 3429 | if (strlen(pSessionThread->pStartupInfo->pszDomain))
|
---|
[57962] | 3430 | {
|
---|
[75807] | 3431 | apszArgs[idxArg++] = "--domain";
|
---|
[84147] | 3432 | apszArgs[idxArg++] = pSessionThread->pStartupInfo->pszDomain;
|
---|
[57962] | 3433 | }
|
---|
[75807] | 3434 | }
|
---|
[57962] | 3435 |
|
---|
[75807] | 3436 | /* Add same verbose flags as parent process. */
|
---|
| 3437 | char szParmVerbose[32];
|
---|
| 3438 | if (g_cVerbosity > 0)
|
---|
| 3439 | {
|
---|
| 3440 | unsigned cVs = RT_MIN(g_cVerbosity, RT_ELEMENTS(szParmVerbose) - 2);
|
---|
| 3441 | szParmVerbose[0] = '-';
|
---|
| 3442 | memset(&szParmVerbose[1], 'v', cVs);
|
---|
| 3443 | szParmVerbose[1 + cVs] = '\0';
|
---|
| 3444 | apszArgs[idxArg++] = szParmVerbose;
|
---|
| 3445 | }
|
---|
| 3446 |
|
---|
| 3447 | /* Add log file handling. Each session will have an own
|
---|
| 3448 | * log file, naming based on the parent log file. */
|
---|
| 3449 | char szParmLogFile[sizeof(g_szLogFile) + 128];
|
---|
| 3450 | if (g_szLogFile[0])
|
---|
| 3451 | {
|
---|
| 3452 | const char *pszSuffix = RTPathSuffix(g_szLogFile);
|
---|
| 3453 | if (!pszSuffix)
|
---|
| 3454 | pszSuffix = strchr(g_szLogFile, '\0');
|
---|
| 3455 | size_t cchBase = pszSuffix - g_szLogFile;
|
---|
[83612] | 3456 |
|
---|
| 3457 | RTTIMESPEC Now;
|
---|
| 3458 | RTTimeNow(&Now);
|
---|
| 3459 | char szTime[64];
|
---|
| 3460 | RTTimeSpecToString(&Now, szTime, sizeof(szTime));
|
---|
| 3461 |
|
---|
| 3462 | /* Replace out characters not allowed on Windows platforms, put in by RTTimeSpecToString(). */
|
---|
| 3463 | static const RTUNICP s_uszValidRangePairs[] =
|
---|
| 3464 | {
|
---|
| 3465 | ' ', ' ',
|
---|
| 3466 | '(', ')',
|
---|
| 3467 | '-', '.',
|
---|
| 3468 | '0', '9',
|
---|
| 3469 | 'A', 'Z',
|
---|
| 3470 | 'a', 'z',
|
---|
| 3471 | '_', '_',
|
---|
| 3472 | 0xa0, 0xd7af,
|
---|
| 3473 | '\0'
|
---|
| 3474 | };
|
---|
| 3475 | ssize_t cReplaced = RTStrPurgeComplementSet(szTime, s_uszValidRangePairs, '_' /* chReplacement */);
|
---|
| 3476 | AssertReturn(cReplaced, VERR_INVALID_UTF8_ENCODING);
|
---|
| 3477 |
|
---|
[57962] | 3478 | #ifndef DEBUG
|
---|
[83612] | 3479 | RTStrPrintf(szParmLogFile, sizeof(szParmLogFile), "%.*s-%RU32-%s-%s%s",
|
---|
[84147] | 3480 | cchBase, g_szLogFile, pSessionStartupInfo->uSessionID, pSessionStartupInfo->pszUser, szTime, pszSuffix);
|
---|
[57962] | 3481 | #else
|
---|
[83612] | 3482 | RTStrPrintf(szParmLogFile, sizeof(szParmLogFile), "%.*s-%RU32-%RU32-%s-%s%s",
|
---|
[75807] | 3483 | cchBase, g_szLogFile, pSessionStartupInfo->uSessionID, uCtrlSessionThread,
|
---|
[84147] | 3484 | pSessionStartupInfo->pszUser, szTime, pszSuffix);
|
---|
[57962] | 3485 | #endif
|
---|
[75807] | 3486 | apszArgs[idxArg++] = "--logfile";
|
---|
| 3487 | apszArgs[idxArg++] = szParmLogFile;
|
---|
| 3488 | }
|
---|
[57962] | 3489 |
|
---|
| 3490 | #ifdef DEBUG
|
---|
[75807] | 3491 | if (g_Session.fFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT)
|
---|
| 3492 | apszArgs[idxArg++] = "--dump-stdout";
|
---|
| 3493 | if (g_Session.fFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR)
|
---|
| 3494 | apszArgs[idxArg++] = "--dump-stderr";
|
---|
[57962] | 3495 | #endif
|
---|
[75807] | 3496 | apszArgs[idxArg] = NULL;
|
---|
| 3497 | Assert(idxArg < RT_ELEMENTS(apszArgs));
|
---|
[57962] | 3498 |
|
---|
[75807] | 3499 | if (g_cVerbosity > 3)
|
---|
| 3500 | {
|
---|
| 3501 | VGSvcVerbose(4, "Spawning parameters:\n");
|
---|
| 3502 | for (idxArg = 0; apszArgs[idxArg]; idxArg++)
|
---|
[75890] | 3503 | VGSvcVerbose(4, " %s\n", apszArgs[idxArg]);
|
---|
[75807] | 3504 | }
|
---|
[57962] | 3505 |
|
---|
[75807] | 3506 | /*
|
---|
| 3507 | * Flags.
|
---|
| 3508 | */
|
---|
[92674] | 3509 | uint32_t const fProcCreate = RTPROC_FLAGS_PROFILE
|
---|
[75807] | 3510 | #ifdef RT_OS_WINDOWS
|
---|
[92674] | 3511 | | RTPROC_FLAGS_SERVICE
|
---|
| 3512 | | RTPROC_FLAGS_HIDDEN
|
---|
[57962] | 3513 | #endif
|
---|
[92674] | 3514 | | VBOXSERVICE_PROC_F_UTF8_ARGV;
|
---|
[57962] | 3515 |
|
---|
[75807] | 3516 | /*
|
---|
| 3517 | * Configure standard handles.
|
---|
| 3518 | */
|
---|
| 3519 | RTHANDLE hStdIn;
|
---|
| 3520 | int rc = RTPipeCreate(&hStdIn.u.hPipe, &pSessionThread->hKeyPipe, RTPIPE_C_INHERIT_READ);
|
---|
| 3521 | if (RT_SUCCESS(rc))
|
---|
| 3522 | {
|
---|
| 3523 | hStdIn.enmType = RTHANDLETYPE_PIPE;
|
---|
| 3524 |
|
---|
| 3525 | RTHANDLE hStdOutAndErr;
|
---|
| 3526 | rc = RTFileOpenBitBucket(&hStdOutAndErr.u.hFile, RTFILE_O_WRITE);
|
---|
[57962] | 3527 | if (RT_SUCCESS(rc))
|
---|
| 3528 | {
|
---|
[75807] | 3529 | hStdOutAndErr.enmType = RTHANDLETYPE_FILE;
|
---|
| 3530 |
|
---|
| 3531 | /*
|
---|
| 3532 | * Windows: If a domain name is given, construct an UPN (User Principle Name)
|
---|
| 3533 | * with the domain name built-in, e.g. "joedoe@example.com".
|
---|
| 3534 | */
|
---|
[84147] | 3535 | const char *pszUser = pSessionThread->pStartupInfo->pszUser;
|
---|
[75807] | 3536 | #ifdef RT_OS_WINDOWS
|
---|
| 3537 | char *pszUserUPN = NULL;
|
---|
[84147] | 3538 | if (pSessionThread->pStartupInfo->pszDomain[0])
|
---|
[57962] | 3539 | {
|
---|
[75807] | 3540 | int cchbUserUPN = RTStrAPrintf(&pszUserUPN, "%s@%s",
|
---|
[84147] | 3541 | pSessionThread->pStartupInfo->pszUser,
|
---|
| 3542 | pSessionThread->pStartupInfo->pszDomain);
|
---|
[75807] | 3543 | if (cchbUserUPN > 0)
|
---|
[57962] | 3544 | {
|
---|
[75807] | 3545 | pszUser = pszUserUPN;
|
---|
| 3546 | VGSvcVerbose(3, "Using UPN: %s\n", pszUserUPN);
|
---|
[57962] | 3547 | }
|
---|
[75807] | 3548 | else
|
---|
| 3549 | rc = VERR_NO_STR_MEMORY;
|
---|
[57962] | 3550 | }
|
---|
| 3551 | if (RT_SUCCESS(rc))
|
---|
[75807] | 3552 | #endif
|
---|
[57962] | 3553 | {
|
---|
[92611] | 3554 | /*
|
---|
[75807] | 3555 | * Finally, create the process.
|
---|
| 3556 | */
|
---|
[92674] | 3557 | rc = RTProcCreateEx(pszExeName, apszArgs, RTENV_DEFAULT, fProcCreate,
|
---|
[75807] | 3558 | &hStdIn, &hStdOutAndErr, &hStdOutAndErr,
|
---|
| 3559 | !fAnonymous ? pszUser : NULL,
|
---|
[84147] | 3560 | !fAnonymous ? pSessionThread->pStartupInfo->pszPassword : NULL,
|
---|
[80569] | 3561 | NULL /*pvExtraData*/,
|
---|
[75807] | 3562 | &pSessionThread->hProcess);
|
---|
[57962] | 3563 | }
|
---|
[75807] | 3564 | #ifdef RT_OS_WINDOWS
|
---|
| 3565 | RTStrFree(pszUserUPN);
|
---|
| 3566 | #endif
|
---|
| 3567 | RTFileClose(hStdOutAndErr.u.hFile);
|
---|
[57962] | 3568 | }
|
---|
[75807] | 3569 |
|
---|
| 3570 | RTPipeClose(hStdIn.u.hPipe);
|
---|
[57962] | 3571 | }
|
---|
| 3572 | return rc;
|
---|
| 3573 | }
|
---|
| 3574 |
|
---|
| 3575 |
|
---|
| 3576 | /**
|
---|
[55578] | 3577 | * Creates a guest session.
|
---|
[44863] | 3578 | *
|
---|
[55578] | 3579 | * This will spawn a new VBoxService.exe instance under behalf of the given user
|
---|
| 3580 | * which then will act as a session host. On successful open, the session will
|
---|
| 3581 | * be added to the given session thread list.
|
---|
| 3582 | *
|
---|
[58029] | 3583 | * @return VBox status code.
|
---|
[44963] | 3584 | * @param pList Which list to use to store the session thread in.
|
---|
[44863] | 3585 | * @param pSessionStartupInfo Session startup info.
|
---|
[44963] | 3586 | * @param ppSessionThread Returns newly created session thread on success.
|
---|
[44863] | 3587 | * Optional.
|
---|
| 3588 | */
|
---|
[84215] | 3589 | int VGSvcGstCtrlSessionThreadCreate(PRTLISTANCHOR pList, const PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pSessionStartupInfo,
|
---|
[58029] | 3590 | PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread)
|
---|
[44863] | 3591 | {
|
---|
[44963] | 3592 | AssertPtrReturn(pList, VERR_INVALID_POINTER);
|
---|
[44863] | 3593 | AssertPtrReturn(pSessionStartupInfo, VERR_INVALID_POINTER);
|
---|
[44963] | 3594 | /* ppSessionThread is optional. */
|
---|
[44863] | 3595 |
|
---|
[57961] | 3596 | #ifdef VBOX_STRICT
|
---|
[44863] | 3597 | /* Check for existing session in debug mode. Should never happen because of
|
---|
| 3598 | * Main consistency. */
|
---|
[57961] | 3599 | PVBOXSERVICECTRLSESSIONTHREAD pSessionCur;
|
---|
[44963] | 3600 | RTListForEach(pList, pSessionCur, VBOXSERVICECTRLSESSIONTHREAD, Node)
|
---|
[44863] | 3601 | {
|
---|
[83554] | 3602 | AssertMsgReturn( pSessionCur->fStopped == true
|
---|
[84147] | 3603 | || pSessionCur->pStartupInfo->uSessionID != pSessionStartupInfo->uSessionID,
|
---|
[83554] | 3604 | ("Guest session thread ID=%RU32 already exists (fStopped=%RTbool)\n",
|
---|
[84147] | 3605 | pSessionCur->pStartupInfo->uSessionID, pSessionCur->fStopped), VERR_ALREADY_EXISTS);
|
---|
[44863] | 3606 | }
|
---|
| 3607 | #endif
|
---|
| 3608 |
|
---|
[45415] | 3609 | /* Static counter to help tracking session thread <-> process relations. */
|
---|
| 3610 | static uint32_t s_uCtrlSessionThread = 0;
|
---|
| 3611 |
|
---|
[57961] | 3612 | /*
|
---|
| 3613 | * Allocate and initialize the session thread structure.
|
---|
| 3614 | */
|
---|
[75807] | 3615 | int rc;
|
---|
[57962] | 3616 | PVBOXSERVICECTRLSESSIONTHREAD pSessionThread = (PVBOXSERVICECTRLSESSIONTHREAD)RTMemAllocZ(sizeof(*pSessionThread));
|
---|
[45415] | 3617 | if (pSessionThread)
|
---|
[44863] | 3618 | {
|
---|
[75807] | 3619 | //pSessionThread->fShutdown = false;
|
---|
| 3620 | //pSessionThread->fStarted = false;
|
---|
| 3621 | //pSessionThread->fStopped = false;
|
---|
| 3622 | pSessionThread->hKeyPipe = NIL_RTPIPE;
|
---|
| 3623 | pSessionThread->Thread = NIL_RTTHREAD;
|
---|
| 3624 | pSessionThread->hProcess = NIL_RTPROCESS;
|
---|
| 3625 |
|
---|
[84147] | 3626 | /* Duplicate startup info. */
|
---|
[84215] | 3627 | pSessionThread->pStartupInfo = VbglR3GuestCtrlSessionStartupInfoDup(pSessionStartupInfo);
|
---|
[84147] | 3628 | AssertPtrReturn(pSessionThread->pStartupInfo, VERR_NO_MEMORY);
|
---|
[44863] | 3629 |
|
---|
[75807] | 3630 | /* Generate the secret key. */
|
---|
| 3631 | RTRandBytes(pSessionThread->abKey, sizeof(pSessionThread->abKey));
|
---|
[44935] | 3632 |
|
---|
[45415] | 3633 | rc = RTCritSectInit(&pSessionThread->CritSect);
|
---|
[57962] | 3634 | AssertRC(rc);
|
---|
| 3635 | if (RT_SUCCESS(rc))
|
---|
[44863] | 3636 | {
|
---|
[57800] | 3637 | /*
|
---|
[75807] | 3638 | * Give the session key to the host so it can validate the client.
|
---|
[57800] | 3639 | */
|
---|
[75807] | 3640 | if (VbglR3GuestCtrlSupportsOptimizations(g_idControlSvcClient))
|
---|
| 3641 | {
|
---|
| 3642 | for (uint32_t i = 0; i < 10; i++)
|
---|
| 3643 | {
|
---|
| 3644 | rc = VbglR3GuestCtrlSessionPrepare(g_idControlSvcClient, pSessionStartupInfo->uSessionID,
|
---|
| 3645 | pSessionThread->abKey, sizeof(pSessionThread->abKey));
|
---|
| 3646 | if (rc != VERR_OUT_OF_RESOURCES)
|
---|
| 3647 | break;
|
---|
| 3648 | RTThreadSleep(100);
|
---|
| 3649 | }
|
---|
| 3650 | }
|
---|
[57659] | 3651 | if (RT_SUCCESS(rc))
|
---|
| 3652 | {
|
---|
[83421] | 3653 | s_uCtrlSessionThread++;
|
---|
| 3654 |
|
---|
[57962] | 3655 | /*
|
---|
[75807] | 3656 | * Start the session child process.
|
---|
[57962] | 3657 | */
|
---|
[75807] | 3658 | rc = vgsvcVGSvcGstCtrlSessionThreadCreateProcess(pSessionStartupInfo, pSessionThread, s_uCtrlSessionThread);
|
---|
[44863] | 3659 | if (RT_SUCCESS(rc))
|
---|
| 3660 | {
|
---|
[75807] | 3661 | /*
|
---|
| 3662 | * Start the session thread.
|
---|
| 3663 | */
|
---|
| 3664 | rc = RTThreadCreateF(&pSessionThread->Thread, vgsvcGstCtrlSessionThread, pSessionThread /*pvUser*/, 0 /*cbStack*/,
|
---|
[83421] | 3665 | RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "gctls%RU32", s_uCtrlSessionThread);
|
---|
[75807] | 3666 | if (RT_SUCCESS(rc))
|
---|
[44863] | 3667 | {
|
---|
[75807] | 3668 | /* Wait for the thread to initialize. */
|
---|
| 3669 | rc = RTThreadUserWait(pSessionThread->Thread, RT_MS_1MIN);
|
---|
| 3670 | if ( RT_SUCCESS(rc)
|
---|
| 3671 | && !ASMAtomicReadBool(&pSessionThread->fShutdown))
|
---|
| 3672 | {
|
---|
[84147] | 3673 | VGSvcVerbose(2, "Thread for session ID=%RU32 started\n", pSessionThread->pStartupInfo->uSessionID);
|
---|
[57659] | 3674 |
|
---|
[75807] | 3675 | ASMAtomicXchgBool(&pSessionThread->fStarted, true);
|
---|
[57659] | 3676 |
|
---|
[75807] | 3677 | /* Add session to list. */
|
---|
| 3678 | RTListAppend(pList, &pSessionThread->Node);
|
---|
| 3679 | if (ppSessionThread) /* Return session if wanted. */
|
---|
| 3680 | *ppSessionThread = pSessionThread;
|
---|
| 3681 | return VINF_SUCCESS;
|
---|
| 3682 | }
|
---|
| 3683 |
|
---|
| 3684 | /*
|
---|
| 3685 | * Bail out.
|
---|
| 3686 | */
|
---|
| 3687 | VGSvcError("Thread for session ID=%RU32 failed to start, rc=%Rrc\n",
|
---|
[84147] | 3688 | pSessionThread->pStartupInfo->uSessionID, rc);
|
---|
[75807] | 3689 | if (RT_SUCCESS_NP(rc))
|
---|
| 3690 | rc = VERR_CANT_CREATE; /** @todo Find a better rc. */
|
---|
[57659] | 3691 | }
|
---|
[75807] | 3692 | else
|
---|
| 3693 | VGSvcError("Creating session thread failed, rc=%Rrc\n", rc);
|
---|
[57659] | 3694 |
|
---|
[75807] | 3695 | RTProcTerminate(pSessionThread->hProcess);
|
---|
| 3696 | uint32_t cMsWait = 1;
|
---|
| 3697 | while ( RTProcWait(pSessionThread->hProcess, RTPROCWAIT_FLAGS_NOBLOCK, NULL) == VERR_PROCESS_RUNNING
|
---|
| 3698 | && cMsWait <= 9) /* 1023 ms */
|
---|
| 3699 | {
|
---|
| 3700 | RTThreadSleep(cMsWait);
|
---|
| 3701 | cMsWait <<= 1;
|
---|
| 3702 | }
|
---|
[44935] | 3703 | }
|
---|
[57962] | 3704 |
|
---|
[75807] | 3705 | if (VbglR3GuestCtrlSupportsOptimizations(g_idControlSvcClient))
|
---|
| 3706 | VbglR3GuestCtrlSessionCancelPrepared(g_idControlSvcClient, pSessionStartupInfo->uSessionID);
|
---|
[44935] | 3707 | }
|
---|
[75807] | 3708 | else
|
---|
| 3709 | VGSvcVerbose(3, "VbglR3GuestCtrlSessionPrepare failed: %Rrc\n", rc);
|
---|
| 3710 | RTPipeClose(pSessionThread->hKeyPipe);
|
---|
| 3711 | pSessionThread->hKeyPipe = NIL_RTPIPE;
|
---|
[57962] | 3712 | RTCritSectDelete(&pSessionThread->CritSect);
|
---|
[44863] | 3713 | }
|
---|
[57962] | 3714 | RTMemFree(pSessionThread);
|
---|
[44863] | 3715 | }
|
---|
| 3716 | else
|
---|
| 3717 | rc = VERR_NO_MEMORY;
|
---|
| 3718 |
|
---|
[58029] | 3719 | VGSvcVerbose(3, "Spawning session thread returned returned rc=%Rrc\n", rc);
|
---|
[44863] | 3720 | return rc;
|
---|
| 3721 | }
|
---|
| 3722 |
|
---|
| 3723 |
|
---|
| 3724 | /**
|
---|
[45415] | 3725 | * Waits for a formerly opened guest session process to close.
|
---|
[44863] | 3726 | *
|
---|
[58029] | 3727 | * @return VBox status code.
|
---|
[45415] | 3728 | * @param pThread Guest session thread to wait for.
|
---|
| 3729 | * @param uTimeoutMS Waiting timeout (in ms).
|
---|
[58029] | 3730 | * @param fFlags Closing flags.
|
---|
[44863] | 3731 | */
|
---|
[103149] | 3732 | static int VGSvcGstCtrlSessionThreadWait(PVBOXSERVICECTRLSESSIONTHREAD pThread, uint32_t uTimeoutMS, uint32_t fFlags)
|
---|
[44863] | 3733 | {
|
---|
[71320] | 3734 | RT_NOREF(fFlags);
|
---|
[45010] | 3735 | AssertPtrReturn(pThread, VERR_INVALID_POINTER);
|
---|
| 3736 | /** @todo Validate closing flags. */
|
---|
[44863] | 3737 |
|
---|
[58029] | 3738 | AssertMsgReturn(pThread->Thread != NIL_RTTHREAD,
|
---|
| 3739 | ("Guest session thread of session %p does not exist when it should\n", pThread),
|
---|
| 3740 | VERR_NOT_FOUND);
|
---|
[45010] | 3741 |
|
---|
[44935] | 3742 | int rc = VINF_SUCCESS;
|
---|
| 3743 |
|
---|
[45415] | 3744 | /*
|
---|
[57659] | 3745 | * The spawned session process should have received the same closing request,
|
---|
[45604] | 3746 | * so just wait for the process to close.
|
---|
[45415] | 3747 | */
|
---|
[45010] | 3748 | if (ASMAtomicReadBool(&pThread->fStarted))
|
---|
[44935] | 3749 | {
|
---|
[45010] | 3750 | /* Ask the thread to shutdown. */
|
---|
| 3751 | ASMAtomicXchgBool(&pThread->fShutdown, true);
|
---|
[44935] | 3752 |
|
---|
[58029] | 3753 | VGSvcVerbose(3, "Waiting for session thread ID=%RU32 to close (%RU32ms) ...\n",
|
---|
[84147] | 3754 | pThread->pStartupInfo->uSessionID, uTimeoutMS);
|
---|
[44935] | 3755 |
|
---|
| 3756 | int rcThread;
|
---|
[45415] | 3757 | rc = RTThreadWait(pThread->Thread, uTimeoutMS, &rcThread);
|
---|
[58029] | 3758 | if (RT_SUCCESS(rc))
|
---|
[83554] | 3759 | {
|
---|
| 3760 | AssertMsg(pThread->fStopped, ("Thread of session ID=%RU32 not in stopped state when it should\n",
|
---|
[84147] | 3761 | pThread->pStartupInfo->uSessionID));
|
---|
[83554] | 3762 |
|
---|
[84147] | 3763 | VGSvcVerbose(3, "Session thread ID=%RU32 ended with rc=%Rrc\n", pThread->pStartupInfo->uSessionID, rcThread);
|
---|
[83554] | 3764 | }
|
---|
[44935] | 3765 | else
|
---|
[84147] | 3766 | VGSvcError("Waiting for session thread ID=%RU32 to close failed with rc=%Rrc\n", pThread->pStartupInfo->uSessionID, rc);
|
---|
[45415] | 3767 | }
|
---|
[83554] | 3768 | else
|
---|
[84147] | 3769 | VGSvcVerbose(3, "Thread for session ID=%RU32 not in started state, skipping wait\n", pThread->pStartupInfo->uSessionID);
|
---|
[44935] | 3770 |
|
---|
[83554] | 3771 | LogFlowFuncLeaveRC(rc);
|
---|
[45415] | 3772 | return rc;
|
---|
| 3773 | }
|
---|
[44935] | 3774 |
|
---|
[45415] | 3775 | /**
|
---|
| 3776 | * Waits for the specified session thread to end and remove
|
---|
| 3777 | * it from the session thread list.
|
---|
| 3778 | *
|
---|
[58029] | 3779 | * @return VBox status code.
|
---|
[45415] | 3780 | * @param pThread Session thread to destroy.
|
---|
[58029] | 3781 | * @param fFlags Closing flags.
|
---|
[45415] | 3782 | */
|
---|
[58029] | 3783 | int VGSvcGstCtrlSessionThreadDestroy(PVBOXSERVICECTRLSESSIONTHREAD pThread, uint32_t fFlags)
|
---|
[45415] | 3784 | {
|
---|
| 3785 | AssertPtrReturn(pThread, VERR_INVALID_POINTER);
|
---|
[84147] | 3786 | AssertPtrReturn(pThread->pStartupInfo, VERR_WRONG_ORDER);
|
---|
[44935] | 3787 |
|
---|
[84147] | 3788 | const uint32_t uSessionID = pThread->pStartupInfo->uSessionID;
|
---|
[83554] | 3789 |
|
---|
| 3790 | VGSvcVerbose(3, "Destroying session ID=%RU32 ...\n", uSessionID);
|
---|
| 3791 |
|
---|
[58029] | 3792 | int rc = VGSvcGstCtrlSessionThreadWait(pThread, 5 * 60 * 1000 /* 5 minutes timeout */, fFlags);
|
---|
[83554] | 3793 | if (RT_SUCCESS(rc))
|
---|
| 3794 | {
|
---|
[84215] | 3795 | VbglR3GuestCtrlSessionStartupInfoFree(pThread->pStartupInfo);
|
---|
[84147] | 3796 | pThread->pStartupInfo = NULL;
|
---|
| 3797 |
|
---|
[95518] | 3798 | RTPipeClose(pThread->hKeyPipe);
|
---|
| 3799 | pThread->hKeyPipe = NIL_RTPIPE;
|
---|
| 3800 |
|
---|
| 3801 | RTCritSectDelete(&pThread->CritSect);
|
---|
| 3802 |
|
---|
[83554] | 3803 | /* Remove session from list and destroy object. */
|
---|
| 3804 | RTListNodeRemove(&pThread->Node);
|
---|
[44935] | 3805 |
|
---|
[83554] | 3806 | RTMemFree(pThread);
|
---|
| 3807 | pThread = NULL;
|
---|
| 3808 | }
|
---|
[47695] | 3809 |
|
---|
[83554] | 3810 | VGSvcVerbose(3, "Destroyed session ID=%RU32 with %Rrc\n", uSessionID, rc);
|
---|
[44935] | 3811 | return rc;
|
---|
[44863] | 3812 | }
|
---|
| 3813 |
|
---|
| 3814 | /**
|
---|
[55580] | 3815 | * Close all open guest session threads.
|
---|
[44863] | 3816 | *
|
---|
[55580] | 3817 | * @note Caller is responsible for locking!
|
---|
| 3818 | *
|
---|
[58029] | 3819 | * @return VBox status code.
|
---|
[44963] | 3820 | * @param pList Which list to close the session threads for.
|
---|
[58029] | 3821 | * @param fFlags Closing flags.
|
---|
[44863] | 3822 | */
|
---|
[58029] | 3823 | int VGSvcGstCtrlSessionThreadDestroyAll(PRTLISTANCHOR pList, uint32_t fFlags)
|
---|
[44863] | 3824 | {
|
---|
[44963] | 3825 | AssertPtrReturn(pList, VERR_INVALID_POINTER);
|
---|
| 3826 |
|
---|
[44863] | 3827 | int rc = VINF_SUCCESS;
|
---|
| 3828 |
|
---|
[49349] | 3829 | /*int rc = VbglR3GuestCtrlClose
|
---|
| 3830 | if (RT_FAILURE(rc))
|
---|
[58029] | 3831 | VGSvcError("Cancelling pending waits failed; rc=%Rrc\n", rc);*/
|
---|
[49349] | 3832 |
|
---|
[57659] | 3833 | PVBOXSERVICECTRLSESSIONTHREAD pSessIt;
|
---|
| 3834 | PVBOXSERVICECTRLSESSIONTHREAD pSessItNext;
|
---|
| 3835 | RTListForEachSafe(pList, pSessIt, pSessItNext, VBOXSERVICECTRLSESSIONTHREAD, Node)
|
---|
[44863] | 3836 | {
|
---|
[58029] | 3837 | int rc2 = VGSvcGstCtrlSessionThreadDestroy(pSessIt, fFlags);
|
---|
[45415] | 3838 | if (RT_FAILURE(rc2))
|
---|
[44863] | 3839 | {
|
---|
[58029] | 3840 | VGSvcError("Closing session thread '%s' failed with rc=%Rrc\n", RTThreadGetName(pSessIt->Thread), rc2);
|
---|
[45415] | 3841 | if (RT_SUCCESS(rc))
|
---|
| 3842 | rc = rc2;
|
---|
[44863] | 3843 | /* Keep going. */
|
---|
| 3844 | }
|
---|
[44935] | 3845 | }
|
---|
| 3846 |
|
---|
[58029] | 3847 | VGSvcVerbose(4, "Destroying guest session threads ended with %Rrc\n", rc);
|
---|
[44935] | 3848 | return rc;
|
---|
| 3849 | }
|
---|
| 3850 |
|
---|
[58029] | 3851 |
|
---|
| 3852 | /**
|
---|
| 3853 | * Main function for the session process.
|
---|
| 3854 | *
|
---|
| 3855 | * @returns exit code.
|
---|
| 3856 | * @param argc Argument count.
|
---|
| 3857 | * @param argv Argument vector (UTF-8).
|
---|
| 3858 | */
|
---|
| 3859 | RTEXITCODE VGSvcGstCtrlSessionSpawnInit(int argc, char **argv)
|
---|
[44863] | 3860 | {
|
---|
| 3861 | static const RTGETOPTDEF s_aOptions[] =
|
---|
| 3862 | {
|
---|
[59145] | 3863 | { "--domain", VBOXSERVICESESSIONOPT_DOMAIN, RTGETOPT_REQ_STRING },
|
---|
[47551] | 3864 | #ifdef DEBUG
|
---|
| 3865 | { "--dump-stdout", VBOXSERVICESESSIONOPT_DUMP_STDOUT, RTGETOPT_REQ_NOTHING },
|
---|
| 3866 | { "--dump-stderr", VBOXSERVICESESSIONOPT_DUMP_STDERR, RTGETOPT_REQ_NOTHING },
|
---|
| 3867 | #endif
|
---|
[44863] | 3868 | { "--logfile", VBOXSERVICESESSIONOPT_LOG_FILE, RTGETOPT_REQ_STRING },
|
---|
[45415] | 3869 | { "--user", VBOXSERVICESESSIONOPT_USERNAME, RTGETOPT_REQ_STRING },
|
---|
[44863] | 3870 | { "--session-id", VBOXSERVICESESSIONOPT_SESSION_ID, RTGETOPT_REQ_UINT32 },
|
---|
| 3871 | { "--session-proto", VBOXSERVICESESSIONOPT_SESSION_PROTO, RTGETOPT_REQ_UINT32 },
|
---|
[45415] | 3872 | #ifdef DEBUG
|
---|
| 3873 | { "--thread-id", VBOXSERVICESESSIONOPT_THREAD_ID, RTGETOPT_REQ_UINT32 },
|
---|
| 3874 | #endif /* DEBUG */
|
---|
[44863] | 3875 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
|
---|
| 3876 | };
|
---|
| 3877 |
|
---|
| 3878 | RTGETOPTSTATE GetState;
|
---|
| 3879 | RTGetOptInit(&GetState, argc, argv,
|
---|
| 3880 | s_aOptions, RT_ELEMENTS(s_aOptions),
|
---|
| 3881 | 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
| 3882 |
|
---|
[58029] | 3883 | uint32_t fSession = VBOXSERVICECTRLSESSION_FLAG_SPAWN;
|
---|
[44963] | 3884 |
|
---|
[47551] | 3885 | /* Protocol and session ID must be specified explicitly. */
|
---|
| 3886 | g_Session.StartupInfo.uProtocol = UINT32_MAX;
|
---|
| 3887 | g_Session.StartupInfo.uSessionID = UINT32_MAX;
|
---|
[45010] | 3888 |
|
---|
[75720] | 3889 | int ch;
|
---|
| 3890 | RTGETOPTUNION ValueUnion;
|
---|
[55580] | 3891 | while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
|
---|
[44863] | 3892 | {
|
---|
| 3893 | /* For options that require an argument, ValueUnion has received the value. */
|
---|
| 3894 | switch (ch)
|
---|
| 3895 | {
|
---|
[59145] | 3896 | case VBOXSERVICESESSIONOPT_DOMAIN:
|
---|
| 3897 | /* Information not needed right now, skip. */
|
---|
[44863] | 3898 | break;
|
---|
[47551] | 3899 | #ifdef DEBUG
|
---|
| 3900 | case VBOXSERVICESESSIONOPT_DUMP_STDOUT:
|
---|
[58029] | 3901 | fSession |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT;
|
---|
[47551] | 3902 | break;
|
---|
[44863] | 3903 |
|
---|
[47551] | 3904 | case VBOXSERVICESESSIONOPT_DUMP_STDERR:
|
---|
[58029] | 3905 | fSession |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR;
|
---|
[47551] | 3906 | break;
|
---|
| 3907 | #endif
|
---|
[44863] | 3908 | case VBOXSERVICESESSIONOPT_SESSION_ID:
|
---|
[44963] | 3909 | g_Session.StartupInfo.uSessionID = ValueUnion.u32;
|
---|
[44863] | 3910 | break;
|
---|
| 3911 |
|
---|
| 3912 | case VBOXSERVICESESSIONOPT_SESSION_PROTO:
|
---|
[44963] | 3913 | g_Session.StartupInfo.uProtocol = ValueUnion.u32;
|
---|
[44863] | 3914 | break;
|
---|
[49349] | 3915 | #ifdef DEBUG
|
---|
[45415] | 3916 | case VBOXSERVICESESSIONOPT_THREAD_ID:
|
---|
[55580] | 3917 | /* Not handled. Mainly for processs listing. */
|
---|
[45415] | 3918 | break;
|
---|
[49349] | 3919 | #endif
|
---|
[59145] | 3920 | case VBOXSERVICESESSIONOPT_LOG_FILE:
|
---|
| 3921 | {
|
---|
| 3922 | int rc = RTStrCopy(g_szLogFile, sizeof(g_szLogFile), ValueUnion.psz);
|
---|
| 3923 | if (RT_FAILURE(rc))
|
---|
| 3924 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error copying log file name: %Rrc", rc);
|
---|
| 3925 | break;
|
---|
| 3926 | }
|
---|
| 3927 |
|
---|
| 3928 | case VBOXSERVICESESSIONOPT_USERNAME:
|
---|
| 3929 | /* Information not needed right now, skip. */
|
---|
| 3930 | break;
|
---|
| 3931 |
|
---|
[44863] | 3932 | /** @todo Implement help? */
|
---|
| 3933 |
|
---|
| 3934 | case 'v':
|
---|
| 3935 | g_cVerbosity++;
|
---|
| 3936 | break;
|
---|
| 3937 |
|
---|
| 3938 | case VINF_GETOPT_NOT_OPTION:
|
---|
[83409] | 3939 | {
|
---|
| 3940 | if (!RTStrICmp(ValueUnion.psz, VBOXSERVICECTRLSESSION_GETOPT_PREFIX))
|
---|
| 3941 | break;
|
---|
| 3942 | /* else fall through and bail out. */
|
---|
| 3943 | RT_FALL_THROUGH();
|
---|
| 3944 | }
|
---|
[44863] | 3945 | default:
|
---|
[83409] | 3946 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'", ValueUnion.psz);
|
---|
[44863] | 3947 | }
|
---|
| 3948 | }
|
---|
| 3949 |
|
---|
[55580] | 3950 | /* Check that we've got all the required options. */
|
---|
[44963] | 3951 | if (g_Session.StartupInfo.uProtocol == UINT32_MAX)
|
---|
| 3952 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No protocol version specified");
|
---|
| 3953 |
|
---|
| 3954 | if (g_Session.StartupInfo.uSessionID == UINT32_MAX)
|
---|
[44863] | 3955 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No session ID specified");
|
---|
| 3956 |
|
---|
[47551] | 3957 | /* Init the session object. */
|
---|
[58029] | 3958 | int rc = VGSvcGstCtrlSessionInit(&g_Session, fSession);
|
---|
[47551] | 3959 | if (RT_FAILURE(rc))
|
---|
[50051] | 3960 | return RTMsgErrorExit(RTEXITCODE_INIT, "Failed to initialize session object, rc=%Rrc\n", rc);
|
---|
[47551] | 3961 |
|
---|
[58029] | 3962 | rc = VGSvcLogCreate(g_szLogFile[0] ? g_szLogFile : NULL);
|
---|
[44863] | 3963 | if (RT_FAILURE(rc))
|
---|
[58029] | 3964 | return RTMsgErrorExit(RTEXITCODE_INIT, "Failed to create log file '%s', rc=%Rrc\n",
|
---|
[55580] | 3965 | g_szLogFile[0] ? g_szLogFile : "<None>", rc);
|
---|
[44863] | 3966 |
|
---|
[58029] | 3967 | RTEXITCODE rcExit = vgsvcGstCtrlSessionSpawnWorker(&g_Session);
|
---|
[44863] | 3968 |
|
---|
[58029] | 3969 | VGSvcLogDestroy();
|
---|
[44863] | 3970 | return rcExit;
|
---|
| 3971 | }
|
---|
| 3972 |
|
---|