1 | /* $Id: VBoxServiceControlSession.cpp 44869 2013-02-28 15:42:02Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VBoxServiceControlSession - Guest session handling. Also handles
|
---|
4 | * the forked session processes.
|
---|
5 | */
|
---|
6 |
|
---|
7 | /*
|
---|
8 | * Copyright (C) 2013 Oracle Corporation
|
---|
9 | *
|
---|
10 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
11 | * available from http://www.virtualbox.org. This file is free software;
|
---|
12 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
13 | * General Public License (GPL) as published by the Free Software
|
---|
14 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
15 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
16 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
17 | */
|
---|
18 |
|
---|
19 |
|
---|
20 | /*******************************************************************************
|
---|
21 | * Header Files *
|
---|
22 | *******************************************************************************/
|
---|
23 | #include <iprt/assert.h>
|
---|
24 | #include <iprt/env.h>
|
---|
25 | #include <iprt/file.h>
|
---|
26 | #include <iprt/getopt.h>
|
---|
27 | #include <iprt/handle.h>
|
---|
28 | #include <iprt/mem.h>
|
---|
29 | #include <iprt/message.h>
|
---|
30 | #include <iprt/path.h>
|
---|
31 | #include <iprt/pipe.h>
|
---|
32 | #include <iprt/poll.h>
|
---|
33 | #include <iprt/process.h>
|
---|
34 |
|
---|
35 | #include "VBoxServiceInternal.h"
|
---|
36 | #include "VBoxServiceUtils.h"
|
---|
37 | #include "VBoxServiceControl.h"
|
---|
38 |
|
---|
39 | using namespace guestControl;
|
---|
40 |
|
---|
41 | /** List of guest control sessions (VBOXSERVICECTRLSESSION). */
|
---|
42 | extern RTLISTANCHOR g_lstControlSessions;
|
---|
43 | extern int VBoxServiceLogCreate(const char *pszLogFile);
|
---|
44 | extern void VBoxServiceLogDestroy(void);
|
---|
45 |
|
---|
46 | /*******************************************************************************
|
---|
47 | * Internal Functions *
|
---|
48 | *******************************************************************************/
|
---|
49 | static int gstcntlSessionFileDestroy(PVBOXSERVICECTRLFILE pFile);
|
---|
50 | static int gstcntlSessionForkShutdown(uint32_t uClientId, uint32_t cParms);
|
---|
51 | static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(uint32_t uHandle);
|
---|
52 | static int gstcntlSessionHandleFileOpen(uint32_t uClientId, uint32_t cParms);
|
---|
53 | static int gstcntlSessionHandleFileClose(uint32_t uClientId, uint32_t cParms);
|
---|
54 | static int gstcntlSessionHandleFileRead(uint32_t uClientId, uint32_t cParms);
|
---|
55 | static int gstcntlSessionHandleFileWrite(uint32_t uClientId, uint32_t cParms, void *pvScratchBuf, size_t cbScratchBuf);
|
---|
56 | static int gstcntlSessionHandleFileSeek(uint32_t uClientId, uint32_t cParms);
|
---|
57 | static int gstcntlSessionHandleFileTell(uint32_t uClientId, uint32_t cParms);
|
---|
58 |
|
---|
59 | /** The session ID of the forked session process. */
|
---|
60 | static uint32_t g_uSessionID = UINT32_MAX;
|
---|
61 | /** The session HGCM protocol of the forked session process. */
|
---|
62 | static uint32_t g_uSessionProto = 1; /* Use the legacy protocol by default (< VBox 4.3). */
|
---|
63 | /** List of guest control files (VBOXSERVICECTRLFILE). */
|
---|
64 | static RTLISTANCHOR g_lstSessionFiles;
|
---|
65 |
|
---|
66 | /** Generic option indices for session fork arguments. */
|
---|
67 | enum
|
---|
68 | {
|
---|
69 | VBOXSERVICESESSIONOPT_LOG_FILE = 1000,
|
---|
70 | VBOXSERVICESESSIONOPT_USERNAME,
|
---|
71 | VBOXSERVICESESSIONOPT_SESSION_ID,
|
---|
72 | VBOXSERVICESESSIONOPT_SESSION_PROTO
|
---|
73 | };
|
---|
74 |
|
---|
75 |
|
---|
76 | static int gstcntlSessionFileDestroy(PVBOXSERVICECTRLFILE pFile)
|
---|
77 | {
|
---|
78 | AssertPtrReturn(pFile, VERR_INVALID_POINTER);
|
---|
79 |
|
---|
80 | int rc = RTFileClose(pFile->hFile);
|
---|
81 | if (RT_SUCCESS(rc))
|
---|
82 | {
|
---|
83 | /* Remove file entry in any case. */
|
---|
84 | RTListNodeRemove(&pFile->Node);
|
---|
85 | /* Destroy this object. */
|
---|
86 | RTMemFree(pFile);
|
---|
87 | }
|
---|
88 |
|
---|
89 | return rc;
|
---|
90 | }
|
---|
91 |
|
---|
92 |
|
---|
93 | static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(uint32_t uHandle)
|
---|
94 | {
|
---|
95 | PVBOXSERVICECTRLFILE pFileCur = NULL;
|
---|
96 | /** @todo Use a map later! */
|
---|
97 | RTListForEach(&g_lstSessionFiles, pFileCur, VBOXSERVICECTRLFILE, Node)
|
---|
98 | {
|
---|
99 | if (pFileCur->uHandle == uHandle)
|
---|
100 | return pFileCur;
|
---|
101 | }
|
---|
102 |
|
---|
103 | return NULL;
|
---|
104 | }
|
---|
105 |
|
---|
106 |
|
---|
107 | static int gstcntlSessionHandleFileOpen(uint32_t uClientId, uint32_t cParms)
|
---|
108 | {
|
---|
109 | char szFile[RTPATH_MAX];
|
---|
110 | char szOpenMode[64];
|
---|
111 | char szDisposition[64];
|
---|
112 | uint32_t uCreationMode = 0;
|
---|
113 | uint64_t uOffset = 0;
|
---|
114 |
|
---|
115 | uint32_t uHandle = 0;
|
---|
116 | VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
|
---|
117 | int rc = VbglR3GuestCtrlFileGetOpen(&ctx,
|
---|
118 | /* File to open. */
|
---|
119 | szFile, sizeof(szFile),
|
---|
120 | /* Open mode. */
|
---|
121 | szOpenMode, sizeof(szOpenMode),
|
---|
122 | /* Disposition. */
|
---|
123 | szDisposition, sizeof(szDisposition),
|
---|
124 | /* Creation mode. */
|
---|
125 | &uCreationMode,
|
---|
126 | /* Offset. */
|
---|
127 | &uOffset);
|
---|
128 | if (RT_SUCCESS(rc))
|
---|
129 | {
|
---|
130 | PVBOXSERVICECTRLFILE pFile = (PVBOXSERVICECTRLFILE)RTMemAlloc(sizeof(VBOXSERVICECTRLFILE));
|
---|
131 | if (pFile)
|
---|
132 | {
|
---|
133 | if (!RTStrPrintf(pFile->szName, sizeof(pFile->szName), "%s", szFile))
|
---|
134 | rc = VERR_BUFFER_OVERFLOW;
|
---|
135 |
|
---|
136 | if (RT_SUCCESS(rc))
|
---|
137 | {
|
---|
138 | uint64_t fFlags = RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE; /** @todo Modes! */
|
---|
139 | rc = RTFileOpen(&pFile->hFile, pFile->szName, fFlags);
|
---|
140 | if ( RT_SUCCESS(rc)
|
---|
141 | && uOffset)
|
---|
142 | {
|
---|
143 | /* Seeking is optional. */
|
---|
144 | int rc2 = RTFileSeek(pFile->hFile, (int64_t)uOffset, RTFILE_SEEK_BEGIN, NULL /* Current offset */);
|
---|
145 | if (RT_FAILURE(rc2))
|
---|
146 | VBoxServiceVerbose(3, "[File %s]: Seeking to offset %RU64 failed; rc=%Rrc\n",
|
---|
147 | pFile->szName, uOffset, rc);
|
---|
148 | }
|
---|
149 | else
|
---|
150 | VBoxServiceVerbose(3, "[File %s]: Opening failed; rc=%Rrc\n",
|
---|
151 | pFile->szName, rc);
|
---|
152 | }
|
---|
153 |
|
---|
154 | if (RT_SUCCESS(rc))
|
---|
155 | {
|
---|
156 | uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(ctx.uContextID);
|
---|
157 | pFile->uHandle = uHandle;
|
---|
158 | /* rc = */ RTListAppend(&g_lstSessionFiles, &pFile->Node);
|
---|
159 |
|
---|
160 | VBoxServiceVerbose(3, "[File %s]: Opened (ID=%RU32)\n",
|
---|
161 | pFile->szName, pFile->uHandle);
|
---|
162 | }
|
---|
163 |
|
---|
164 | if (RT_FAILURE(rc))
|
---|
165 | RTMemFree(pFile);
|
---|
166 | }
|
---|
167 | else
|
---|
168 | rc = VERR_NO_MEMORY;
|
---|
169 |
|
---|
170 | /* Report back in any case. */
|
---|
171 | CALLBACKPAYLOAD_FILE_NOTFIY_OPEN cplOpen = { rc, uHandle };
|
---|
172 | int rc2 = VbglR3GuestCtrlFileNotify(uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_OPEN,
|
---|
173 | &cplOpen, sizeof(cplOpen));
|
---|
174 | if (RT_FAILURE(rc2))
|
---|
175 | VBoxServiceError("[File %s]: Failed to report file open status, rc=%Rrc\n",
|
---|
176 | szFile, rc2);
|
---|
177 | if (RT_SUCCESS(rc))
|
---|
178 | rc = rc2;
|
---|
179 | }
|
---|
180 |
|
---|
181 | return rc;
|
---|
182 | }
|
---|
183 |
|
---|
184 |
|
---|
185 | static int gstcntlSessionHandleFileClose(uint32_t uClientId, uint32_t cParms)
|
---|
186 | {
|
---|
187 | uint32_t uHandle;
|
---|
188 |
|
---|
189 | VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
|
---|
190 | int rc = VbglR3GuestCtrlFileGetClose(&ctx, &uHandle /* File handle to close */);
|
---|
191 | if (RT_SUCCESS(rc))
|
---|
192 | {
|
---|
193 | PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
|
---|
194 | if (pFile)
|
---|
195 | {
|
---|
196 | rc = gstcntlSessionFileDestroy(pFile);
|
---|
197 | }
|
---|
198 | else
|
---|
199 | rc = VERR_NOT_FOUND;
|
---|
200 |
|
---|
201 | /* Report back in any case. */
|
---|
202 | CALLBACKPAYLOAD_FILE_NOTFIY_CLOSE cplClose = { rc };
|
---|
203 | int rc2 = VbglR3GuestCtrlFileNotify(uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_CLOSE,
|
---|
204 | &cplClose, sizeof(cplClose));
|
---|
205 | if (RT_FAILURE(rc2))
|
---|
206 | VBoxServiceError("Failed to report file close status, rc=%Rrc\n", rc2);
|
---|
207 | if (RT_SUCCESS(rc))
|
---|
208 | rc = rc2;
|
---|
209 | }
|
---|
210 | return rc;
|
---|
211 | }
|
---|
212 |
|
---|
213 |
|
---|
214 | static int gstcntlSessionHandleFileRead(uint32_t uClientId, uint32_t cParms,
|
---|
215 | void *pvScratchBuf, size_t cbScratchBuf)
|
---|
216 | {
|
---|
217 | uint32_t uHandle;
|
---|
218 | uint32_t cbToRead;
|
---|
219 |
|
---|
220 | VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
|
---|
221 | int rc = VbglR3GuestCtrlFileGetRead(&ctx, &uHandle, &cbToRead);
|
---|
222 | if (RT_SUCCESS(rc))
|
---|
223 | {
|
---|
224 | void *pvDataRead = pvScratchBuf;
|
---|
225 | size_t cbRead = 0;
|
---|
226 |
|
---|
227 | PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
|
---|
228 | if (pFile)
|
---|
229 | {
|
---|
230 | if (cbToRead)
|
---|
231 | {
|
---|
232 | if (cbToRead > cbScratchBuf)
|
---|
233 | {
|
---|
234 | pvDataRead = RTMemAlloc(cbToRead);
|
---|
235 | if (!pvDataRead)
|
---|
236 | rc = VERR_NO_MEMORY;
|
---|
237 | }
|
---|
238 |
|
---|
239 | if (RT_LIKELY(RT_SUCCESS(rc)))
|
---|
240 | rc = RTFileRead(pFile->hFile, pvDataRead, cbToRead, &cbRead);
|
---|
241 | }
|
---|
242 | else
|
---|
243 | rc = VERR_BUFFER_UNDERFLOW;
|
---|
244 | }
|
---|
245 | else
|
---|
246 | rc = VERR_NOT_FOUND;
|
---|
247 |
|
---|
248 | /* Report back in any case. */
|
---|
249 | CALLBACKPAYLOAD_FILE_NOTFIY_READ cplRead = { rc, cbRead, pvDataRead };
|
---|
250 | int rc2 = VbglR3GuestCtrlFileNotify(uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_READ,
|
---|
251 | &cplRead, sizeof(cplRead));
|
---|
252 | if ( cbToRead > cbScratchBuf
|
---|
253 | && pvDataRead)
|
---|
254 | RTMemFree(pvDataRead);
|
---|
255 |
|
---|
256 | if (RT_FAILURE(rc2))
|
---|
257 | VBoxServiceError("Failed to report file read status, rc=%Rrc\n", rc2);
|
---|
258 | if (RT_SUCCESS(rc))
|
---|
259 | rc = rc2;
|
---|
260 | }
|
---|
261 | return rc;
|
---|
262 | }
|
---|
263 |
|
---|
264 |
|
---|
265 | static int gstcntlSessionHandleFileReadAt(uint32_t uClientId, uint32_t cParms,
|
---|
266 | void *pvScratchBuf, size_t cbScratchBuf)
|
---|
267 | {
|
---|
268 | uint32_t uHandle;
|
---|
269 | uint32_t cbToRead; int64_t iOffset;
|
---|
270 |
|
---|
271 | VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
|
---|
272 | int rc = VbglR3GuestCtrlFileGetReadAt(&ctx, &uHandle, &cbToRead, (uint64_t*)&iOffset);
|
---|
273 | if (RT_SUCCESS(rc))
|
---|
274 | {
|
---|
275 | void *pvDataRead = pvScratchBuf;
|
---|
276 | size_t cbRead = 0;
|
---|
277 |
|
---|
278 | PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
|
---|
279 | if (pFile)
|
---|
280 | {
|
---|
281 | if (cbToRead)
|
---|
282 | {
|
---|
283 | if (cbToRead > cbScratchBuf)
|
---|
284 | {
|
---|
285 | pvDataRead = RTMemAlloc(cbToRead);
|
---|
286 | if (!pvDataRead)
|
---|
287 | rc = VERR_NO_MEMORY;
|
---|
288 | }
|
---|
289 |
|
---|
290 | if (RT_LIKELY(RT_SUCCESS(rc)))
|
---|
291 | rc = RTFileReadAt(pFile->hFile, iOffset, pvDataRead, cbToRead, &cbRead);
|
---|
292 | }
|
---|
293 | else
|
---|
294 | rc = VERR_BUFFER_UNDERFLOW;
|
---|
295 | }
|
---|
296 | else
|
---|
297 | rc = VERR_NOT_FOUND;
|
---|
298 |
|
---|
299 | /* Report back in any case. */
|
---|
300 | CALLBACKPAYLOAD_FILE_NOTFIY_READ cplRead = { rc, cbRead, pvDataRead };
|
---|
301 | int rc2 = VbglR3GuestCtrlFileNotify(uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_READ,
|
---|
302 | &cplRead, sizeof(cplRead));
|
---|
303 | if ( cbToRead > cbScratchBuf
|
---|
304 | && pvDataRead)
|
---|
305 | RTMemFree(pvDataRead);
|
---|
306 |
|
---|
307 | if (RT_FAILURE(rc2))
|
---|
308 | VBoxServiceError("Failed to report file read status, rc=%Rrc\n", rc2);
|
---|
309 | if (RT_SUCCESS(rc))
|
---|
310 | rc = rc2;
|
---|
311 | }
|
---|
312 | return rc;
|
---|
313 | }
|
---|
314 |
|
---|
315 |
|
---|
316 | static int gstcntlSessionHandleFileWrite(uint32_t uClientId, uint32_t cParms,
|
---|
317 | void *pvScratchBuf, size_t cbScratchBuf)
|
---|
318 | {
|
---|
319 | AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
|
---|
320 | AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);
|
---|
321 |
|
---|
322 | uint32_t uHandle;
|
---|
323 | uint32_t cbToWrite;
|
---|
324 |
|
---|
325 | VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
|
---|
326 | int rc = VbglR3GuestCtrlFileGetWrite(&ctx, &uHandle,
|
---|
327 | pvScratchBuf, cbScratchBuf,
|
---|
328 | &cbToWrite);
|
---|
329 | if (RT_SUCCESS(rc))
|
---|
330 | {
|
---|
331 | size_t cbWritten = 0;
|
---|
332 | PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
|
---|
333 | if (pFile)
|
---|
334 | {
|
---|
335 | rc = RTFileWrite(pFile->hFile, pvScratchBuf, cbScratchBuf, &cbWritten);
|
---|
336 | }
|
---|
337 | else
|
---|
338 | rc = VERR_NOT_FOUND;
|
---|
339 |
|
---|
340 | /* Report back in any case. */
|
---|
341 | CALLBACKPAYLOAD_FILE_NOTFIY_WRITE cplWrite = { rc, (uint32_t)cbWritten };
|
---|
342 | int rc2 = VbglR3GuestCtrlFileNotify(uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_WRITE,
|
---|
343 | &cplWrite, sizeof(cplWrite));
|
---|
344 | if (RT_FAILURE(rc2))
|
---|
345 | VBoxServiceError("Failed to report file write status, rc=%Rrc\n", rc2);
|
---|
346 | if (RT_SUCCESS(rc))
|
---|
347 | rc = rc2;
|
---|
348 | }
|
---|
349 | return rc;
|
---|
350 | }
|
---|
351 |
|
---|
352 |
|
---|
353 | static int gstcntlSessionHandleFileWriteAt(uint32_t uClientId, uint32_t cParms,
|
---|
354 | void *pvScratchBuf, size_t cbScratchBuf)
|
---|
355 | {
|
---|
356 | AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);
|
---|
357 | AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);
|
---|
358 |
|
---|
359 | uint32_t uHandle;
|
---|
360 | uint32_t cbToWrite; int64_t iOffset;
|
---|
361 |
|
---|
362 | VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
|
---|
363 | int rc = VbglR3GuestCtrlFileGetWriteAt(&ctx, &uHandle,
|
---|
364 | pvScratchBuf, cbScratchBuf,
|
---|
365 | &cbToWrite, (uint64_t*)&iOffset);
|
---|
366 | if (RT_SUCCESS(rc))
|
---|
367 | {
|
---|
368 | size_t cbWritten = 0;
|
---|
369 | PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
|
---|
370 | if (pFile)
|
---|
371 | {
|
---|
372 | rc = RTFileWriteAt(pFile->hFile, iOffset,
|
---|
373 | pvScratchBuf, cbScratchBuf, &cbWritten);
|
---|
374 | }
|
---|
375 | else
|
---|
376 | rc = VERR_NOT_FOUND;
|
---|
377 |
|
---|
378 | /* Report back in any case. */
|
---|
379 | CALLBACKPAYLOAD_FILE_NOTFIY_WRITE cplWrite = { rc, (uint32_t)cbWritten };
|
---|
380 | int rc2 = VbglR3GuestCtrlFileNotify(uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_WRITE,
|
---|
381 | &cplWrite, sizeof(cplWrite));
|
---|
382 | if (RT_FAILURE(rc2))
|
---|
383 | VBoxServiceError("Failed to report file write status, rc=%Rrc\n", rc2);
|
---|
384 | if (RT_SUCCESS(rc))
|
---|
385 | rc = rc2;
|
---|
386 | }
|
---|
387 | return rc;
|
---|
388 | }
|
---|
389 |
|
---|
390 |
|
---|
391 | static int gstcntlSessionHandleFileSeek(uint32_t uClientId, uint32_t cParms)
|
---|
392 | {
|
---|
393 | uint32_t uHandle;
|
---|
394 | uint32_t uSeekMethod;
|
---|
395 | uint64_t uOffset; /* Will be converted to int64_t. */
|
---|
396 |
|
---|
397 | uint64_t uOffsetActual = 0;
|
---|
398 |
|
---|
399 | VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
|
---|
400 | int rc = VbglR3GuestCtrlFileGetSeek(&ctx, &uHandle,
|
---|
401 | &uSeekMethod, &uOffset);
|
---|
402 | if (RT_SUCCESS(rc))
|
---|
403 | {
|
---|
404 | PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
|
---|
405 | if (pFile)
|
---|
406 | {
|
---|
407 | unsigned uSeekMethodIPRT;
|
---|
408 | switch (uSeekMethod)
|
---|
409 | {
|
---|
410 | case GUEST_FILE_SEEKTYPE_BEGIN:
|
---|
411 | uSeekMethodIPRT = RTFILE_SEEK_BEGIN;
|
---|
412 | break;
|
---|
413 |
|
---|
414 | case GUEST_FILE_SEEKTYPE_CURRENT:
|
---|
415 | uSeekMethodIPRT = RTFILE_SEEK_CURRENT;
|
---|
416 | break;
|
---|
417 |
|
---|
418 | case GUEST_FILE_SEEKTYPE_END:
|
---|
419 | uSeekMethodIPRT = RTFILE_SEEK_END;
|
---|
420 | break;
|
---|
421 |
|
---|
422 | default:
|
---|
423 | rc = VERR_NOT_SUPPORTED;
|
---|
424 | break;
|
---|
425 | }
|
---|
426 |
|
---|
427 | if (RT_SUCCESS(rc))
|
---|
428 | rc = RTFileSeek(pFile->hFile, (int64_t)uOffset,
|
---|
429 | uSeekMethodIPRT, &uOffsetActual);
|
---|
430 | }
|
---|
431 | else
|
---|
432 | rc = VERR_NOT_FOUND;
|
---|
433 |
|
---|
434 | /* Report back in any case. */
|
---|
435 | CALLBACKPAYLOAD_FILE_NOTFIY_SEEK cplSeek = { rc, uOffsetActual };
|
---|
436 | int rc2 = VbglR3GuestCtrlFileNotify(uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_SEEK,
|
---|
437 | &cplSeek, sizeof(cplSeek));
|
---|
438 | if (RT_FAILURE(rc2))
|
---|
439 | VBoxServiceError("Failed to report file seek status, rc=%Rrc\n", rc2);
|
---|
440 | if (RT_SUCCESS(rc))
|
---|
441 | rc = rc2;
|
---|
442 | }
|
---|
443 | return rc;
|
---|
444 | }
|
---|
445 |
|
---|
446 |
|
---|
447 | static int gstcntlSessionHandleFileTell(uint32_t uClientId, uint32_t cParms)
|
---|
448 | {
|
---|
449 | uint32_t uHandle;
|
---|
450 | uint64_t uOffsetActual = 0;
|
---|
451 |
|
---|
452 | VBGLR3GUESTCTRLHOSTCTX ctx = { uClientId, cParms };
|
---|
453 | int rc = VbglR3GuestCtrlFileGetTell(&ctx, &uHandle);
|
---|
454 | if (RT_SUCCESS(rc))
|
---|
455 | {
|
---|
456 | PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(uHandle);
|
---|
457 | if (pFile)
|
---|
458 | {
|
---|
459 | uOffsetActual = RTFileTell(pFile->hFile);
|
---|
460 | }
|
---|
461 | else
|
---|
462 | rc = VERR_NOT_FOUND;
|
---|
463 |
|
---|
464 | /* Report back in any case. */
|
---|
465 | CALLBACKPAYLOAD_FILE_NOTFIY_TELL cplTell = { rc, uOffsetActual };
|
---|
466 | int rc2 = VbglR3GuestCtrlFileNotify(uClientId, ctx.uContextID, GUEST_FILE_NOTIFYTYPE_TELL,
|
---|
467 | &cplTell, sizeof(cplTell));
|
---|
468 | if (RT_FAILURE(rc2))
|
---|
469 | VBoxServiceError("Failed to report file tell status, rc=%Rrc\n", rc2);
|
---|
470 | if (RT_SUCCESS(rc))
|
---|
471 | rc = rc2;
|
---|
472 | }
|
---|
473 | return rc;
|
---|
474 | }
|
---|
475 |
|
---|
476 |
|
---|
477 | RTEXITCODE gstcntlSessionWorker(void)
|
---|
478 | {
|
---|
479 | bool fSessionFilter = true;
|
---|
480 |
|
---|
481 | uint32_t uClientID;
|
---|
482 | int rc = VbglR3GuestCtrlConnect(&uClientID);
|
---|
483 | if (RT_SUCCESS(rc))
|
---|
484 | {
|
---|
485 | /* Set session filter. */
|
---|
486 | uint32_t uFilterAdd = VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(g_uSessionID);
|
---|
487 |
|
---|
488 | rc = VbglR3GuestCtrlMsgSetFilter(uClientID, uFilterAdd, 0 /* Filter remove */);
|
---|
489 | if ( RT_FAILURE(rc)
|
---|
490 | && rc == VERR_NOT_SUPPORTED)
|
---|
491 | {
|
---|
492 | /* No session filter available. Skip. */
|
---|
493 | fSessionFilter = false;
|
---|
494 |
|
---|
495 | rc = VINF_SUCCESS;
|
---|
496 | }
|
---|
497 | }
|
---|
498 |
|
---|
499 | /* Allocate a scratch buffer for commands which also send
|
---|
500 | * payload data with them. */
|
---|
501 | uint32_t cbScratchBuf = _64K; /** @todo Make buffer size configurable via guest properties/argv! */
|
---|
502 | AssertReturn(RT_IS_POWER_OF_TWO(cbScratchBuf), RTEXITCODE_FAILURE);
|
---|
503 | uint8_t *pvScratchBuf = NULL;
|
---|
504 |
|
---|
505 | if (RT_SUCCESS(rc))
|
---|
506 | {
|
---|
507 | RTListInit(&g_lstSessionFiles);
|
---|
508 | pvScratchBuf = (uint8_t*)RTMemAlloc(cbScratchBuf);
|
---|
509 | if (!pvScratchBuf)
|
---|
510 | rc = VERR_NO_MEMORY;
|
---|
511 | }
|
---|
512 |
|
---|
513 | if (RT_SUCCESS(rc))
|
---|
514 | {
|
---|
515 | bool fShutdown = false;
|
---|
516 |
|
---|
517 | for (;;)
|
---|
518 | {
|
---|
519 | VBoxServiceVerbose(3, "Waiting for host msg ...\n");
|
---|
520 | uint32_t uMsg = 0;
|
---|
521 | uint32_t cParms = 0;
|
---|
522 | rc = VbglR3GuestCtrlMsgWaitFor(uClientID, &uMsg, &cParms);
|
---|
523 | if (rc == VERR_TOO_MUCH_DATA)
|
---|
524 | {
|
---|
525 | VBoxServiceVerbose(4, "Message requires %RU32 parameters, but only 2 supplied -- retrying request (no error!)...\n", cParms);
|
---|
526 | rc = VINF_SUCCESS; /* Try to get "real" message in next block below. */
|
---|
527 | }
|
---|
528 | else if (RT_FAILURE(rc))
|
---|
529 | VBoxServiceVerbose(3, "Getting host message failed with %Rrc\n", rc); /* VERR_GEN_IO_FAILURE seems to be normal if ran into timeout. */
|
---|
530 | if (RT_SUCCESS(rc))
|
---|
531 | {
|
---|
532 | VBoxServiceVerbose(3, "Msg=%RU32 (%RU32 parms) retrieved\n", uMsg, cParms);
|
---|
533 | }
|
---|
534 |
|
---|
535 | VBoxServiceVerbose(3, "Msg=%RU32 (%RU32 parms) retrieved\n", uMsg, cParms);
|
---|
536 |
|
---|
537 | /** @todo Guest session ID change detection? */
|
---|
538 |
|
---|
539 | switch (uMsg)
|
---|
540 | {
|
---|
541 | case HOST_CANCEL_PENDING_WAITS:
|
---|
542 | /* Fall thru is intentional. */
|
---|
543 | case HOST_SESSION_CLOSE:
|
---|
544 | /* Shutdown this fork. */
|
---|
545 | rc = gstcntlSessionForkShutdown(uClientID, cParms);
|
---|
546 | fShutdown = true; /* Shutdown in any case. */
|
---|
547 | break;
|
---|
548 |
|
---|
549 | case HOST_FILE_OPEN:
|
---|
550 | rc = gstcntlSessionHandleFileOpen(uClientID, cParms);
|
---|
551 | break;
|
---|
552 |
|
---|
553 | case HOST_FILE_CLOSE:
|
---|
554 | rc = gstcntlSessionHandleFileClose(uClientID, cParms);
|
---|
555 | break;
|
---|
556 |
|
---|
557 | case HOST_FILE_READ:
|
---|
558 | rc = gstcntlSessionHandleFileRead(uClientID, cParms,
|
---|
559 | pvScratchBuf, cbScratchBuf);
|
---|
560 | break;
|
---|
561 |
|
---|
562 | case HOST_FILE_READ_AT:
|
---|
563 | rc = gstcntlSessionHandleFileReadAt(uClientID, cParms,
|
---|
564 | pvScratchBuf, cbScratchBuf);
|
---|
565 | break;
|
---|
566 |
|
---|
567 | case HOST_FILE_WRITE:
|
---|
568 | rc = gstcntlSessionHandleFileWrite(uClientID, cParms,
|
---|
569 | pvScratchBuf, cbScratchBuf);
|
---|
570 | break;
|
---|
571 |
|
---|
572 | case HOST_FILE_WRITE_AT:
|
---|
573 | rc = gstcntlSessionHandleFileWriteAt(uClientID, cParms,
|
---|
574 | pvScratchBuf, cbScratchBuf);
|
---|
575 | break;
|
---|
576 |
|
---|
577 | case HOST_FILE_SEEK:
|
---|
578 | rc = gstcntlSessionHandleFileSeek(uClientID, cParms);
|
---|
579 | break;
|
---|
580 |
|
---|
581 | case HOST_FILE_TELL:
|
---|
582 | rc = gstcntlSessionHandleFileTell(uClientID, cParms);
|
---|
583 | break;
|
---|
584 |
|
---|
585 | default:
|
---|
586 | VBoxServiceVerbose(3, "Unsupported message from host, uMsg=%RU32, cParms=%RU32\n",
|
---|
587 | uMsg, cParms);
|
---|
588 | /* Don't terminate here; just wait for the next message. */
|
---|
589 | break;
|
---|
590 | }
|
---|
591 |
|
---|
592 | if (fShutdown)
|
---|
593 | break;
|
---|
594 | }
|
---|
595 | }
|
---|
596 |
|
---|
597 | VBoxServiceVerbose(0, "Session %RU32 ended\n", g_uSessionID);
|
---|
598 |
|
---|
599 | if (pvScratchBuf)
|
---|
600 | RTMemFree(pvScratchBuf);
|
---|
601 |
|
---|
602 | VBoxServiceVerbose(3, "Disconnecting client ID=%RU32 ...\n", uClientID);
|
---|
603 | VbglR3GuestCtrlDisconnect(uClientID);
|
---|
604 |
|
---|
605 | VBoxServiceVerbose(3, "Session worker returned with rc=%Rrc\n", rc);
|
---|
606 | return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
|
---|
607 | }
|
---|
608 |
|
---|
609 |
|
---|
610 | /**
|
---|
611 | * Creates a guest session. This will spawn a new VBoxService.exe instance under
|
---|
612 | * behalf of the given user which then will act as a session host.
|
---|
613 | *
|
---|
614 | * @return IPRT status code.
|
---|
615 | * @param pSessionStartupInfo Session startup info.
|
---|
616 | * @param pNode Returns newly created session node on success.
|
---|
617 | * Optional.
|
---|
618 | */
|
---|
619 | int GstCntlSessionOpen(const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo,
|
---|
620 | PRTLISTNODE pNode)
|
---|
621 | {
|
---|
622 | AssertPtrReturn(pSessionStartupInfo, VERR_INVALID_POINTER);
|
---|
623 | /* pNode is optional. */
|
---|
624 |
|
---|
625 | #ifdef DEBUG
|
---|
626 | PVBOXSERVICECTRLSESSION pSessionCur;
|
---|
627 | /* Check for existing session in debug mode. Should never happen because of
|
---|
628 | * Main consistency. */
|
---|
629 | RTListForEach(&g_lstControlSessions, pSessionCur, VBOXSERVICECTRLSESSION, Node)
|
---|
630 | {
|
---|
631 | if (pSessionCur->StartupInfo.uSessionID == pSessionStartupInfo->uSessionID)
|
---|
632 | {
|
---|
633 | AssertMsgFailed(("Guest session %RU32 (%p) already exists when it should not\n",
|
---|
634 | pSessionCur->StartupInfo.uSessionID, pSessionCur));
|
---|
635 | return VERR_ALREADY_EXISTS;
|
---|
636 | }
|
---|
637 | }
|
---|
638 | #endif
|
---|
639 | int rc = VINF_SUCCESS;
|
---|
640 |
|
---|
641 | PVBOXSERVICECTRLSESSION pSession = (PVBOXSERVICECTRLSESSION)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSION));
|
---|
642 | if (pSession)
|
---|
643 | {
|
---|
644 | /* Copy over session startup info. */
|
---|
645 | memcpy(&pSession->StartupInfo, pSessionStartupInfo, sizeof(VBOXSERVICECTRLSESSIONSTARTUPINFO));
|
---|
646 |
|
---|
647 | VBoxServiceVerbose(3, "Forking new guest session szUser=%s, szPassword=%s, szDomain=%s, uFlags=%x, using protocol %RU32\n",
|
---|
648 | pSessionStartupInfo->szUser,
|
---|
649 | #ifdef DEBUG
|
---|
650 | pSessionStartupInfo->szPassword,
|
---|
651 | #else
|
---|
652 | "XXX", /* Never show passwords in release mode. */
|
---|
653 | #endif
|
---|
654 | pSessionStartupInfo->szDomain,
|
---|
655 | pSessionStartupInfo->uFlags,
|
---|
656 | pSessionStartupInfo->uProtocol);
|
---|
657 |
|
---|
658 | rc = RTCritSectInit(&pSession->CritSect);
|
---|
659 | AssertRC(rc);
|
---|
660 |
|
---|
661 | /* Fork child doing the actual session handling. */
|
---|
662 | char szExeName[RTPATH_MAX];
|
---|
663 | char *pszExeName = RTProcGetExecutablePath(szExeName, sizeof(szExeName));
|
---|
664 | if (pszExeName)
|
---|
665 | {
|
---|
666 | char szParmUserName[GUESTPROCESS_MAX_USER_LEN + 32];
|
---|
667 | if (!RTStrPrintf(szParmUserName, sizeof(szParmUserName), "--username=%s", pSession->StartupInfo.szUser))
|
---|
668 | rc = VERR_BUFFER_OVERFLOW;
|
---|
669 | char szParmSessionID[32];
|
---|
670 | if (RT_SUCCESS(rc) && !RTStrPrintf(szParmSessionID, sizeof(szParmSessionID), "--session-id=%RU32",
|
---|
671 | pSession->StartupInfo.uSessionID))
|
---|
672 | {
|
---|
673 | rc = VERR_BUFFER_OVERFLOW;
|
---|
674 | }
|
---|
675 | char szParmSessionProto[32];
|
---|
676 | if (RT_SUCCESS(rc) && !RTStrPrintf(szParmSessionProto, sizeof(szParmSessionProto), "--session-proto=%RU32",
|
---|
677 | pSession->StartupInfo.uProtocol))
|
---|
678 | {
|
---|
679 | rc = VERR_BUFFER_OVERFLOW;
|
---|
680 | }
|
---|
681 |
|
---|
682 | if (RT_SUCCESS(rc))
|
---|
683 | {
|
---|
684 | int iOptIdx = 0; /* Current index in argument vector. */
|
---|
685 |
|
---|
686 | char const *papszArgs[8];
|
---|
687 | papszArgs[iOptIdx++] = pszExeName;
|
---|
688 | papszArgs[iOptIdx++] = "guestsession";
|
---|
689 | papszArgs[iOptIdx++] = szParmSessionID;
|
---|
690 | papszArgs[iOptIdx++] = szParmSessionProto;
|
---|
691 | papszArgs[iOptIdx++] = szParmUserName;
|
---|
692 |
|
---|
693 | /* Add same verbose flags as parent process. */
|
---|
694 | int rc2 = VINF_SUCCESS;
|
---|
695 | char szParmVerbose[32] = { 0 };
|
---|
696 | for (int i = 0; i < g_cVerbosity && RT_SUCCESS(rc2); i++)
|
---|
697 | {
|
---|
698 | if (i == 0)
|
---|
699 | rc2 = RTStrCat(szParmVerbose, sizeof(szParmVerbose), "-");
|
---|
700 | if (RT_FAILURE(rc2))
|
---|
701 | break;
|
---|
702 | rc2 = RTStrCat(szParmVerbose, sizeof(szParmVerbose), "v");
|
---|
703 | }
|
---|
704 | if (RT_SUCCESS(rc2))
|
---|
705 | papszArgs[iOptIdx++] = szParmVerbose;
|
---|
706 |
|
---|
707 | /* Add log file handling. Each session will have an own
|
---|
708 | * log file, naming based on the parent log file. */
|
---|
709 | char szParmLogFile[RTPATH_MAX];
|
---|
710 | if ( RT_SUCCESS(rc2)
|
---|
711 | && strlen(g_szLogFile))
|
---|
712 | {
|
---|
713 | char *pszLogFile = RTStrDup(g_szLogFile);
|
---|
714 | if (pszLogFile)
|
---|
715 | {
|
---|
716 | char *pszLogExt = NULL;
|
---|
717 | if (RTPathHasExt(pszLogFile))
|
---|
718 | pszLogExt = RTStrDup(RTPathExt(pszLogFile));
|
---|
719 | RTPathStripExt(pszLogFile);
|
---|
720 | char *pszLogSuffix;
|
---|
721 | if (RTStrAPrintf(&pszLogSuffix, "-%RU32-%s",
|
---|
722 | pSessionStartupInfo->uSessionID,
|
---|
723 | pSessionStartupInfo->szUser) < 0)
|
---|
724 | {
|
---|
725 | rc2 = VERR_NO_MEMORY;
|
---|
726 | }
|
---|
727 | else
|
---|
728 | {
|
---|
729 | rc2 = RTStrAAppend(&pszLogFile, pszLogSuffix);
|
---|
730 | if (RT_SUCCESS(rc2) && pszLogExt)
|
---|
731 | rc2 = RTStrAAppend(&pszLogFile, pszLogExt);
|
---|
732 | if (RT_SUCCESS(rc2))
|
---|
733 | {
|
---|
734 | if (!RTStrPrintf(szParmLogFile, sizeof(szParmLogFile),
|
---|
735 | "--logfile %s", pszLogFile))
|
---|
736 | {
|
---|
737 | rc2 = VERR_BUFFER_OVERFLOW;
|
---|
738 | }
|
---|
739 | }
|
---|
740 | RTStrFree(pszLogSuffix);
|
---|
741 | }
|
---|
742 | if (RT_FAILURE(rc2))
|
---|
743 | VBoxServiceError("Error building session logfile string for session %RU32 (user %s), rc=%Rrc\n",
|
---|
744 | pSessionStartupInfo->uSessionID, pSessionStartupInfo->szUser, rc2);
|
---|
745 | if (pszLogExt)
|
---|
746 | RTStrFree(pszLogExt);
|
---|
747 | RTStrFree(pszLogFile);
|
---|
748 | }
|
---|
749 | if (RT_SUCCESS(rc2))
|
---|
750 | papszArgs[iOptIdx++] = szParmLogFile;
|
---|
751 | papszArgs[iOptIdx++] = NULL;
|
---|
752 | }
|
---|
753 | else
|
---|
754 | papszArgs[iOptIdx++] = NULL;
|
---|
755 |
|
---|
756 | if (g_cVerbosity > 3)
|
---|
757 | {
|
---|
758 | VBoxServiceVerbose(4, "Forking parameters:\n");
|
---|
759 |
|
---|
760 | iOptIdx = 0;
|
---|
761 | while (papszArgs[iOptIdx])
|
---|
762 | VBoxServiceVerbose(4, "\t%s\n", papszArgs[iOptIdx++]);
|
---|
763 | }
|
---|
764 |
|
---|
765 | uint32_t uProcFlags = RTPROC_FLAGS_SERVICE
|
---|
766 | | RTPROC_FLAGS_HIDDEN; /** @todo More flags from startup info? */
|
---|
767 |
|
---|
768 | #if 0 /* Pipe handling not needed (yet). */
|
---|
769 | /* Setup pipes. */
|
---|
770 | rc = GstcntlProcessSetupPipe("|", 0 /*STDIN_FILENO*/,
|
---|
771 | &pSession->StdIn.hChild, &pSession->StdIn.phChild, &pSession->hStdInW);
|
---|
772 | if (RT_SUCCESS(rc))
|
---|
773 | {
|
---|
774 | rc = GstcntlProcessSetupPipe("|", 1 /*STDOUT_FILENO*/,
|
---|
775 | &pSession->StdOut.hChild, &pSession->StdOut.phChild, &pSession->hStdOutR);
|
---|
776 | if (RT_SUCCESS(rc))
|
---|
777 | {
|
---|
778 | rc = GstcntlProcessSetupPipe("|", 2 /*STDERR_FILENO*/,
|
---|
779 | &pSession->StdErr.hChild, &pSession->StdErr.phChild, &pSession->hStdErrR);
|
---|
780 | if (RT_SUCCESS(rc))
|
---|
781 | {
|
---|
782 | rc = RTPollSetCreate(&pSession->hPollSet);
|
---|
783 | if (RT_SUCCESS(rc))
|
---|
784 | rc = RTPollSetAddPipe(pSession->hPollSet, pSession->hStdInW, RTPOLL_EVT_ERROR,
|
---|
785 | VBOXSERVICECTRLPIPEID_STDIN);
|
---|
786 | if (RT_SUCCESS(rc))
|
---|
787 | rc = RTPollSetAddPipe(pSession->hPollSet, pSession->hStdOutR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
|
---|
788 | VBOXSERVICECTRLPIPEID_STDOUT);
|
---|
789 | if (RT_SUCCESS(rc))
|
---|
790 | rc = RTPollSetAddPipe(pSession->hPollSet, pSession->hStdErrR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
|
---|
791 | VBOXSERVICECTRLPIPEID_STDERR);
|
---|
792 | }
|
---|
793 |
|
---|
794 | if (RT_SUCCESS(rc))
|
---|
795 | {
|
---|
796 | /* Fork the thing. */
|
---|
797 | /** @todo Do we need a custom environment block? */
|
---|
798 | rc = RTProcCreateEx(pszExeName, papszArgs, RTENV_DEFAULT, uProcFlags,
|
---|
799 | pSession->StdIn.phChild, pSession->StdOut.phChild, pSession->StdErr.phChild,
|
---|
800 | pSession->StartupInfo.szUser,
|
---|
801 | pSession->StartupInfo.szPassword,
|
---|
802 | &pSession->hProcess);
|
---|
803 | }
|
---|
804 |
|
---|
805 | if (RT_SUCCESS(rc))
|
---|
806 | {
|
---|
807 | /*
|
---|
808 | * Close the child ends of any pipes and redirected files.
|
---|
809 | */
|
---|
810 | int rc2 = RTHandleClose(pSession->StdIn.phChild); AssertRC(rc2);
|
---|
811 | pSession->StdIn.phChild = NULL;
|
---|
812 | rc2 = RTHandleClose(pSession->StdOut.phChild); AssertRC(rc2);
|
---|
813 | pSession->StdOut.phChild = NULL;
|
---|
814 | rc2 = RTHandleClose(pSession->StdErr.phChild); AssertRC(rc2);
|
---|
815 | pSession->StdErr.phChild = NULL;
|
---|
816 | }
|
---|
817 | }
|
---|
818 | }
|
---|
819 | #else
|
---|
820 | /** @todo Do we need a custom environment block? */
|
---|
821 | rc = RTProcCreateEx(pszExeName, papszArgs, RTENV_DEFAULT, uProcFlags,
|
---|
822 | NULL /* StdIn */, NULL /* StdOut */, NULL /* StdErr */,
|
---|
823 | pSession->StartupInfo.szUser,
|
---|
824 | pSession->StartupInfo.szPassword,
|
---|
825 | &pSession->hProcess);
|
---|
826 | #endif
|
---|
827 | }
|
---|
828 | }
|
---|
829 | else
|
---|
830 | rc = VERR_FILE_NOT_FOUND;
|
---|
831 |
|
---|
832 | if (RT_SUCCESS(rc))
|
---|
833 | {
|
---|
834 | /* Add session to list. */
|
---|
835 | /* rc = */ RTListAppend(&g_lstControlSessions, &pSession->Node);
|
---|
836 | if (pNode) /* Return node if wanted. */
|
---|
837 | pNode = &pSession->Node;
|
---|
838 | }
|
---|
839 | else
|
---|
840 | {
|
---|
841 | RTMemFree(pSession);
|
---|
842 | }
|
---|
843 | }
|
---|
844 | else
|
---|
845 | rc = VERR_NO_MEMORY;
|
---|
846 |
|
---|
847 | VBoxServiceVerbose(3, "Forking returned returned rc=%Rrc\n", rc);
|
---|
848 | return rc;
|
---|
849 | }
|
---|
850 |
|
---|
851 |
|
---|
852 | /**
|
---|
853 | * Closes a formerly opened guest session.
|
---|
854 | *
|
---|
855 | * @return IPRT status code.
|
---|
856 | * @param pSession Guest session to close.
|
---|
857 | * @param uFlags Termination flags.
|
---|
858 | */
|
---|
859 | int GstCntlSessionClose(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags)
|
---|
860 | {
|
---|
861 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
862 |
|
---|
863 | /** @todo Implement session termination. */
|
---|
864 | return VERR_NOT_IMPLEMENTED;
|
---|
865 | }
|
---|
866 |
|
---|
867 |
|
---|
868 | /**
|
---|
869 | * Close all formerly opened guest sessions.
|
---|
870 | *
|
---|
871 | * @return IPRT status code.
|
---|
872 | * @param uFlags Termination flags.
|
---|
873 | */
|
---|
874 | int GstCntlSessionCloseAll(uint32_t uFlags)
|
---|
875 | {
|
---|
876 | int rc = VINF_SUCCESS;
|
---|
877 |
|
---|
878 | VBoxServiceVerbose(3, "GstCntlSessionCloseAll\n");
|
---|
879 |
|
---|
880 | PVBOXSERVICECTRLSESSION pSessionCur;
|
---|
881 | RTListForEach(&g_lstControlSessions, pSessionCur, VBOXSERVICECTRLSESSION, Node)
|
---|
882 | {
|
---|
883 | int rc2 = GstCntlSessionClose(pSessionCur, uFlags);
|
---|
884 | if (RT_SUCCESS(rc))
|
---|
885 | {
|
---|
886 | rc = rc2;
|
---|
887 | /* Keep going. */
|
---|
888 | }
|
---|
889 | }
|
---|
890 |
|
---|
891 | return rc;
|
---|
892 | }
|
---|
893 |
|
---|
894 |
|
---|
895 | RTEXITCODE VBoxServiceControlSessionForkInit(int argc, char **argv)
|
---|
896 | {
|
---|
897 | static const RTGETOPTDEF s_aOptions[] =
|
---|
898 | {
|
---|
899 | { "--logfile", VBOXSERVICESESSIONOPT_LOG_FILE, RTGETOPT_REQ_STRING },
|
---|
900 | { "--username", VBOXSERVICESESSIONOPT_USERNAME, RTGETOPT_REQ_STRING },
|
---|
901 | { "--session-id", VBOXSERVICESESSIONOPT_SESSION_ID, RTGETOPT_REQ_UINT32 },
|
---|
902 | { "--session-proto", VBOXSERVICESESSIONOPT_SESSION_PROTO, RTGETOPT_REQ_UINT32 },
|
---|
903 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
|
---|
904 | };
|
---|
905 |
|
---|
906 | int ch;
|
---|
907 | RTGETOPTUNION ValueUnion;
|
---|
908 | RTGETOPTSTATE GetState;
|
---|
909 | RTGetOptInit(&GetState, argc, argv,
|
---|
910 | s_aOptions, RT_ELEMENTS(s_aOptions),
|
---|
911 | 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
912 |
|
---|
913 | int rc = VINF_SUCCESS;
|
---|
914 |
|
---|
915 | while ( (ch = RTGetOpt(&GetState, &ValueUnion))
|
---|
916 | && RT_SUCCESS(rc))
|
---|
917 | {
|
---|
918 | /* For options that require an argument, ValueUnion has received the value. */
|
---|
919 | switch (ch)
|
---|
920 | {
|
---|
921 | case VBOXSERVICESESSIONOPT_LOG_FILE:
|
---|
922 | if (!RTStrPrintf(g_szLogFile, sizeof(g_szLogFile), "%s", ValueUnion.psz))
|
---|
923 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unable to set logfile name to '%s'",
|
---|
924 | ValueUnion.psz);
|
---|
925 | break;
|
---|
926 |
|
---|
927 | case VBOXSERVICESESSIONOPT_USERNAME:
|
---|
928 | /** @todo. */
|
---|
929 | break;
|
---|
930 |
|
---|
931 | case VBOXSERVICESESSIONOPT_SESSION_ID:
|
---|
932 | g_uSessionID = ValueUnion.u32;
|
---|
933 | break;
|
---|
934 |
|
---|
935 | case VBOXSERVICESESSIONOPT_SESSION_PROTO:
|
---|
936 | g_uSessionProto = ValueUnion.u32;
|
---|
937 | break;
|
---|
938 |
|
---|
939 | /** @todo Implement help? */
|
---|
940 |
|
---|
941 | case 'v':
|
---|
942 | g_cVerbosity++;
|
---|
943 | break;
|
---|
944 |
|
---|
945 | case VINF_GETOPT_NOT_OPTION:
|
---|
946 | /* Ignore; might be "guestsession" main command. */
|
---|
947 | break;
|
---|
948 |
|
---|
949 | default:
|
---|
950 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown command '%s'", ValueUnion.psz);
|
---|
951 | break; /* Never reached. */
|
---|
952 | }
|
---|
953 | }
|
---|
954 |
|
---|
955 | if (RT_FAILURE(rc))
|
---|
956 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Initialization failed with rc=%Rrc", rc);
|
---|
957 |
|
---|
958 | if (g_uSessionID == UINT32_MAX)
|
---|
959 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No session ID specified");
|
---|
960 |
|
---|
961 | rc = VBoxServiceLogCreate(strlen(g_szLogFile) ? g_szLogFile : NULL);
|
---|
962 | if (RT_FAILURE(rc))
|
---|
963 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log (%s, %Rrc)",
|
---|
964 | strlen(g_szLogFile) ? g_szLogFile : "<None>", rc);
|
---|
965 |
|
---|
966 | RTEXITCODE rcExit = gstcntlSessionWorker();
|
---|
967 |
|
---|
968 | VBoxServiceLogDestroy();
|
---|
969 | return rcExit;
|
---|
970 | }
|
---|
971 |
|
---|
972 | static int gstcntlSessionForkShutdown(uint32_t uClientId, uint32_t cParms)
|
---|
973 | {
|
---|
974 | VBoxServiceVerbose(0, "Session %RU32 is going to shutdown ...\n", g_uSessionID);
|
---|
975 |
|
---|
976 | /* Close all left guest files. */
|
---|
977 | PVBOXSERVICECTRLFILE pFile;
|
---|
978 | pFile = RTListGetFirst(&g_lstSessionFiles, VBOXSERVICECTRLFILE, Node);
|
---|
979 | while (pFile)
|
---|
980 | {
|
---|
981 | PVBOXSERVICECTRLFILE pNext = RTListNodeGetNext(&pFile->Node, VBOXSERVICECTRLFILE, Node);
|
---|
982 | bool fLast = RTListNodeIsLast(&g_lstSessionFiles, &pFile->Node);
|
---|
983 |
|
---|
984 | int rc2 = gstcntlSessionFileDestroy(pFile);
|
---|
985 | if (RT_FAILURE(rc2))
|
---|
986 | {
|
---|
987 | VBoxServiceError("Unable to close file \"%s\"; rc=%Rrc\n",
|
---|
988 | pFile->szName, rc2);
|
---|
989 | /* Keep going. */
|
---|
990 | }
|
---|
991 |
|
---|
992 | if (fLast)
|
---|
993 | break;
|
---|
994 |
|
---|
995 | pFile = pNext;
|
---|
996 | }
|
---|
997 |
|
---|
998 | AssertMsg(RTListIsEmpty(&g_lstSessionFiles),
|
---|
999 | ("Guest file list still contains entries when it should not\n"));
|
---|
1000 |
|
---|
1001 | /** @todo Add guest process termination here. Later. */
|
---|
1002 |
|
---|
1003 | return VINF_SUCCESS; /** @todo */
|
---|
1004 | }
|
---|
1005 |
|
---|