VirtualBox

source: vbox/trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h@ 84648

Last change on this file since 84648 was 84648, checked in by vboxsync, 5 years ago

Guest Control/Main: Big guest error information revamp, to show more information about the actual context in which an error occurred. bugref:9320

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.4 KB
Line 
1/* $Id: GuestCtrlImplPrivate.h 84648 2020-06-03 08:11:04Z vboxsync $ */
2/** @file
3 * Internal helpers/structures for guest control functionality.
4 */
5
6/*
7 * Copyright (C) 2011-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef MAIN_INCLUDED_GuestCtrlImplPrivate_h
19#define MAIN_INCLUDED_GuestCtrlImplPrivate_h
20#ifndef RT_WITHOUT_PRAGMA_ONCE
21# pragma once
22#endif
23
24#include "ConsoleImpl.h"
25#include "Global.h"
26
27#include <iprt/asm.h>
28#include <iprt/env.h>
29#include <iprt/semaphore.h>
30#include <iprt/cpp/utils.h>
31
32#include <VBox/com/com.h>
33#include <VBox/com/ErrorInfo.h>
34#include <VBox/com/string.h>
35#include <VBox/com/VirtualBox.h>
36#include <VBox/err.h> /* VERR_GSTCTL_GUEST_ERROR */
37
38#include <map>
39#include <vector>
40
41using namespace com;
42
43#ifdef VBOX_WITH_GUEST_CONTROL
44# include <VBox/GuestHost/GuestControl.h>
45# include <VBox/HostServices/GuestControlSvc.h>
46using namespace guestControl;
47#endif
48
49/** Vector holding a process' CPU affinity. */
50typedef std::vector <LONG> ProcessAffinity;
51/** Vector holding process startup arguments. */
52typedef std::vector <Utf8Str> ProcessArguments;
53
54class GuestProcessStreamBlock;
55class GuestSession;
56
57
58/**
59 * Simple structure mantaining guest credentials.
60 */
61struct GuestCredentials
62{
63 Utf8Str mUser;
64 Utf8Str mPassword;
65 Utf8Str mDomain;
66};
67
68
69/**
70 * Wrapper around the RTEnv API, unusable base class.
71 *
72 * @remarks Feel free to elevate this class to iprt/cpp/env.h as RTCEnv.
73 */
74class GuestEnvironmentBase
75{
76public:
77 /**
78 * Default constructor.
79 *
80 * The user must invoke one of the init methods before using the object.
81 */
82 GuestEnvironmentBase(void)
83 : m_hEnv(NIL_RTENV)
84 , m_cRefs(1)
85 , m_fFlags(0)
86 { }
87
88 /**
89 * Destructor.
90 */
91 virtual ~GuestEnvironmentBase(void)
92 {
93 Assert(m_cRefs <= 1);
94 int rc = RTEnvDestroy(m_hEnv); AssertRC(rc);
95 m_hEnv = NIL_RTENV;
96 }
97
98 /**
99 * Retains a reference to this object.
100 * @returns New reference count.
101 * @remarks Sharing an object is currently only safe if no changes are made to
102 * it because RTENV does not yet implement any locking. For the only
103 * purpose we need this, implementing IGuestProcess::environment by
104 * using IGuestSession::environmentBase, that's fine as the session
105 * base environment is immutable.
106 */
107 uint32_t retain(void)
108 {
109 uint32_t cRefs = ASMAtomicIncU32(&m_cRefs);
110 Assert(cRefs > 1); Assert(cRefs < _1M);
111 return cRefs;
112
113 }
114 /** Useful shortcut. */
115 uint32_t retainConst(void) const { return unconst(this)->retain(); }
116
117 /**
118 * Releases a reference to this object, deleting the object when reaching zero.
119 * @returns New reference count.
120 */
121 uint32_t release(void)
122 {
123 uint32_t cRefs = ASMAtomicDecU32(&m_cRefs);
124 Assert(cRefs < _1M);
125 if (cRefs == 0)
126 delete this;
127 return cRefs;
128 }
129
130 /** Useful shortcut. */
131 uint32_t releaseConst(void) const { return unconst(this)->retain(); }
132
133 /**
134 * Checks if the environment has been successfully initialized or not.
135 *
136 * @returns @c true if initialized, @c false if not.
137 */
138 bool isInitialized(void) const
139 {
140 return m_hEnv != NIL_RTENV;
141 }
142
143 /**
144 * Returns the variable count.
145 * @return Number of variables.
146 * @sa RTEnvCountEx
147 */
148 uint32_t count(void) const
149 {
150 return RTEnvCountEx(m_hEnv);
151 }
152
153 /**
154 * Deletes the environment change record entirely.
155 *
156 * The count() method will return zero after this call.
157 *
158 * @sa RTEnvReset
159 */
160 void reset(void)
161 {
162 int rc = RTEnvReset(m_hEnv);
163 AssertRC(rc);
164 }
165
166 /**
167 * Exports the environment change block as an array of putenv style strings.
168 *
169 *
170 * @returns VINF_SUCCESS or VERR_NO_MEMORY.
171 * @param pArray The output array.
172 */
173 int queryPutEnvArray(std::vector<com::Utf8Str> *pArray) const
174 {
175 uint32_t cVars = RTEnvCountEx(m_hEnv);
176 try
177 {
178 pArray->resize(cVars);
179 for (uint32_t iVar = 0; iVar < cVars; iVar++)
180 {
181 const char *psz = RTEnvGetByIndexRawEx(m_hEnv, iVar);
182 AssertReturn(psz, VERR_INTERNAL_ERROR_3); /* someone is racing us! */
183 (*pArray)[iVar] = psz;
184 }
185 return VINF_SUCCESS;
186 }
187 catch (std::bad_alloc &)
188 {
189 return VERR_NO_MEMORY;
190 }
191 }
192
193 /**
194 * Applies an array of putenv style strings.
195 *
196 * @returns IPRT status code.
197 * @param rArray The array with the putenv style strings.
198 * @param pidxError Where to return the index causing trouble on
199 * failure. Optional.
200 * @sa RTEnvPutEx
201 */
202 int applyPutEnvArray(const std::vector<com::Utf8Str> &rArray, size_t *pidxError = NULL)
203 {
204 size_t const cArray = rArray.size();
205 for (size_t i = 0; i < cArray; i++)
206 {
207 int rc = RTEnvPutEx(m_hEnv, rArray[i].c_str());
208 if (RT_FAILURE(rc))
209 {
210 if (pidxError)
211 *pidxError = i;
212 return rc;
213 }
214 }
215 return VINF_SUCCESS;
216 }
217
218 /**
219 * Applies the changes from another environment to this.
220 *
221 * @returns IPRT status code.
222 * @param rChanges Reference to an environment which variables will be
223 * imported and, if it's a change record, schedule
224 * variable unsets will be applied.
225 * @sa RTEnvApplyChanges
226 */
227 int applyChanges(const GuestEnvironmentBase &rChanges)
228 {
229 return RTEnvApplyChanges(m_hEnv, rChanges.m_hEnv);
230 }
231
232 /**
233 * See RTEnvQueryUtf8Block for details.
234 * @returns IPRT status code.
235 * @param ppszzBlock Where to return the block pointer.
236 * @param pcbBlock Where to optionally return the block size.
237 * @sa RTEnvQueryUtf8Block
238 */
239 int queryUtf8Block(char **ppszzBlock, size_t *pcbBlock)
240 {
241 return RTEnvQueryUtf8Block(m_hEnv, true /*fSorted*/, ppszzBlock, pcbBlock);
242 }
243
244 /**
245 * Frees what queryUtf8Block returned, NULL ignored.
246 * @sa RTEnvFreeUtf8Block
247 */
248 static void freeUtf8Block(char *pszzBlock)
249 {
250 return RTEnvFreeUtf8Block(pszzBlock);
251 }
252
253 /**
254 * Applies a block on the format returned by queryUtf8Block.
255 *
256 * @returns IPRT status code.
257 * @param pszzBlock Pointer to the block.
258 * @param cbBlock The size of the block.
259 * @param fNoEqualMeansUnset Whether the lack of a '=' (equal) sign in a
260 * string means it should be unset (@c true), or if
261 * it means the variable should be defined with an
262 * empty value (@c false, the default).
263 * @todo move this to RTEnv!
264 */
265 int copyUtf8Block(const char *pszzBlock, size_t cbBlock, bool fNoEqualMeansUnset = false)
266 {
267 int rc = VINF_SUCCESS;
268 while (cbBlock > 0 && *pszzBlock != '\0')
269 {
270 const char *pszEnd = (const char *)memchr(pszzBlock, '\0', cbBlock);
271 if (!pszEnd)
272 return VERR_BUFFER_UNDERFLOW;
273 int rc2;
274 if (fNoEqualMeansUnset || strchr(pszzBlock, '='))
275 rc2 = RTEnvPutEx(m_hEnv, pszzBlock);
276 else
277 rc2 = RTEnvSetEx(m_hEnv, pszzBlock, "");
278 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
279 rc = rc2;
280
281 /* Advance. */
282 cbBlock -= pszEnd - pszzBlock;
283 if (cbBlock < 2)
284 return VERR_BUFFER_UNDERFLOW;
285 cbBlock--;
286 pszzBlock = pszEnd + 1;
287 }
288
289 /* The remainder must be zero padded. */
290 if (RT_SUCCESS(rc))
291 {
292 if (ASMMemIsZero(pszzBlock, cbBlock))
293 return VINF_SUCCESS;
294 return VERR_TOO_MUCH_DATA;
295 }
296 return rc;
297 }
298
299 /**
300 * Get an environment variable.
301 *
302 * @returns IPRT status code.
303 * @param rName The variable name.
304 * @param pValue Where to return the value.
305 * @sa RTEnvGetEx
306 */
307 int getVariable(const com::Utf8Str &rName, com::Utf8Str *pValue) const
308 {
309 size_t cchNeeded;
310 int rc = RTEnvGetEx(m_hEnv, rName.c_str(), NULL, 0, &cchNeeded);
311 if ( RT_SUCCESS(rc)
312 || rc == VERR_BUFFER_OVERFLOW)
313 {
314 try
315 {
316 pValue->reserve(cchNeeded + 1);
317 rc = RTEnvGetEx(m_hEnv, rName.c_str(), pValue->mutableRaw(), pValue->capacity(), NULL);
318 pValue->jolt();
319 }
320 catch (std::bad_alloc &)
321 {
322 rc = VERR_NO_STR_MEMORY;
323 }
324 }
325 return rc;
326 }
327
328 /**
329 * Checks if the given variable exists.
330 *
331 * @returns @c true if it exists, @c false if not or if it's an scheduled unset
332 * in a environment change record.
333 * @param rName The variable name.
334 * @sa RTEnvExistEx
335 */
336 bool doesVariableExist(const com::Utf8Str &rName) const
337 {
338 return RTEnvExistEx(m_hEnv, rName.c_str());
339 }
340
341 /**
342 * Set an environment variable.
343 *
344 * @returns IPRT status code.
345 * @param rName The variable name.
346 * @param rValue The value of the variable.
347 * @sa RTEnvSetEx
348 */
349 int setVariable(const com::Utf8Str &rName, const com::Utf8Str &rValue)
350 {
351 return RTEnvSetEx(m_hEnv, rName.c_str(), rValue.c_str());
352 }
353
354 /**
355 * Unset an environment variable.
356 *
357 * @returns IPRT status code.
358 * @param rName The variable name.
359 * @sa RTEnvUnsetEx
360 */
361 int unsetVariable(const com::Utf8Str &rName)
362 {
363 return RTEnvUnsetEx(m_hEnv, rName.c_str());
364 }
365
366protected:
367 /**
368 * Copy constructor.
369 * @throws HRESULT
370 */
371 GuestEnvironmentBase(const GuestEnvironmentBase &rThat, bool fChangeRecord, uint32_t fFlags = 0)
372 : m_hEnv(NIL_RTENV)
373 , m_cRefs(1)
374 , m_fFlags(fFlags)
375 {
376 int rc = cloneCommon(rThat, fChangeRecord);
377 if (RT_FAILURE(rc))
378 throw (Global::vboxStatusCodeToCOM(rc));
379 }
380
381 /**
382 * Common clone/copy method with type conversion abilities.
383 *
384 * @returns IPRT status code.
385 * @param rThat The object to clone.
386 * @param fChangeRecord Whether the this instance is a change record (true)
387 * or normal (false) environment.
388 */
389 int cloneCommon(const GuestEnvironmentBase &rThat, bool fChangeRecord)
390 {
391 int rc = VINF_SUCCESS;
392 RTENV hNewEnv = NIL_RTENV;
393 if (rThat.m_hEnv != NIL_RTENV)
394 {
395 /*
396 * Clone it.
397 */
398 if (RTEnvIsChangeRecord(rThat.m_hEnv) == fChangeRecord)
399 rc = RTEnvClone(&hNewEnv, rThat.m_hEnv);
400 else
401 {
402 /* Need to type convert it. */
403 if (fChangeRecord)
404 rc = RTEnvCreateChangeRecordEx(&hNewEnv, rThat.m_fFlags);
405 else
406 rc = RTEnvCreateEx(&hNewEnv, rThat.m_fFlags);
407 if (RT_SUCCESS(rc))
408 {
409 rc = RTEnvApplyChanges(hNewEnv, rThat.m_hEnv);
410 if (RT_FAILURE(rc))
411 RTEnvDestroy(hNewEnv);
412 }
413 }
414 }
415 else
416 {
417 /*
418 * Create an empty one so the object works smoothly.
419 * (Relevant for GuestProcessStartupInfo and internal commands.)
420 */
421 if (fChangeRecord)
422 rc = RTEnvCreateChangeRecordEx(&hNewEnv, rThat.m_fFlags);
423 else
424 rc = RTEnvCreateEx(&hNewEnv, rThat.m_fFlags);
425 }
426 if (RT_SUCCESS(rc))
427 {
428 RTEnvDestroy(m_hEnv);
429 m_hEnv = hNewEnv;
430 m_fFlags = rThat.m_fFlags;
431 }
432 return rc;
433 }
434
435
436 /** The environment change record. */
437 RTENV m_hEnv;
438 /** Reference counter. */
439 uint32_t volatile m_cRefs;
440 /** RTENV_CREATE_F_XXX. */
441 uint32_t m_fFlags;
442};
443
444class GuestEnvironmentChanges;
445
446
447/**
448 * Wrapper around the RTEnv API for a normal environment.
449 */
450class GuestEnvironment : public GuestEnvironmentBase
451{
452public:
453 /**
454 * Default constructor.
455 *
456 * The user must invoke one of the init methods before using the object.
457 */
458 GuestEnvironment(void)
459 : GuestEnvironmentBase()
460 { }
461
462 /**
463 * Copy operator.
464 * @param rThat The object to copy.
465 * @throws HRESULT
466 */
467 GuestEnvironment(const GuestEnvironment &rThat)
468 : GuestEnvironmentBase(rThat, false /*fChangeRecord*/)
469 { }
470
471 /**
472 * Copy operator.
473 * @param rThat The object to copy.
474 * @throws HRESULT
475 */
476 GuestEnvironment(const GuestEnvironmentBase &rThat)
477 : GuestEnvironmentBase(rThat, false /*fChangeRecord*/)
478 { }
479
480 /**
481 * Initialize this as a normal environment block.
482 * @returns IPRT status code.
483 * @param fFlags RTENV_CREATE_F_XXX
484 */
485 int initNormal(uint32_t fFlags)
486 {
487 AssertReturn(m_hEnv == NIL_RTENV, VERR_WRONG_ORDER);
488 m_fFlags = fFlags;
489 return RTEnvCreateEx(&m_hEnv, fFlags);
490 }
491
492 /**
493 * Replaces this environemnt with that in @a rThat.
494 *
495 * @returns IPRT status code
496 * @param rThat The environment to copy. If it's a different type
497 * we'll convert the data to a normal environment block.
498 */
499 int copy(const GuestEnvironmentBase &rThat)
500 {
501 return cloneCommon(rThat, false /*fChangeRecord*/);
502 }
503
504 /**
505 * @copydoc copy()
506 */
507 GuestEnvironment &operator=(const GuestEnvironmentBase &rThat)
508 {
509 int rc = copy(rThat);
510 if (RT_FAILURE(rc))
511 throw (Global::vboxStatusCodeToCOM(rc));
512 return *this;
513 }
514
515 /** @copydoc copy() */
516 GuestEnvironment &operator=(const GuestEnvironment &rThat)
517 { return operator=((const GuestEnvironmentBase &)rThat); }
518
519 /** @copydoc copy() */
520 GuestEnvironment &operator=(const GuestEnvironmentChanges &rThat)
521 { return operator=((const GuestEnvironmentBase &)rThat); }
522
523};
524
525
526/**
527 * Wrapper around the RTEnv API for a environment change record.
528 *
529 * This class is used as a record of changes to be applied to a different
530 * environment block (in VBoxService before launching a new process).
531 */
532class GuestEnvironmentChanges : public GuestEnvironmentBase
533{
534public:
535 /**
536 * Default constructor.
537 *
538 * The user must invoke one of the init methods before using the object.
539 */
540 GuestEnvironmentChanges(void)
541 : GuestEnvironmentBase()
542 { }
543
544 /**
545 * Copy operator.
546 * @param rThat The object to copy.
547 * @throws HRESULT
548 */
549 GuestEnvironmentChanges(const GuestEnvironmentChanges &rThat)
550 : GuestEnvironmentBase(rThat, true /*fChangeRecord*/)
551 { }
552
553 /**
554 * Copy operator.
555 * @param rThat The object to copy.
556 * @throws HRESULT
557 */
558 GuestEnvironmentChanges(const GuestEnvironmentBase &rThat)
559 : GuestEnvironmentBase(rThat, true /*fChangeRecord*/)
560 { }
561
562 /**
563 * Initialize this as a environment change record.
564 * @returns IPRT status code.
565 * @param fFlags RTENV_CREATE_F_XXX
566 */
567 int initChangeRecord(uint32_t fFlags)
568 {
569 AssertReturn(m_hEnv == NIL_RTENV, VERR_WRONG_ORDER);
570 m_fFlags = fFlags;
571 return RTEnvCreateChangeRecordEx(&m_hEnv, fFlags);
572 }
573
574 /**
575 * Replaces this environemnt with that in @a rThat.
576 *
577 * @returns IPRT status code
578 * @param rThat The environment to copy. If it's a different type
579 * we'll convert the data to a set of changes.
580 */
581 int copy(const GuestEnvironmentBase &rThat)
582 {
583 return cloneCommon(rThat, true /*fChangeRecord*/);
584 }
585
586 /**
587 * @copydoc copy()
588 */
589 GuestEnvironmentChanges &operator=(const GuestEnvironmentBase &rThat)
590 {
591 int rc = copy(rThat);
592 if (RT_FAILURE(rc))
593 throw (Global::vboxStatusCodeToCOM(rc));
594 return *this;
595 }
596
597 /** @copydoc copy() */
598 GuestEnvironmentChanges &operator=(const GuestEnvironmentChanges &rThat)
599 { return operator=((const GuestEnvironmentBase &)rThat); }
600
601 /** @copydoc copy() */
602 GuestEnvironmentChanges &operator=(const GuestEnvironment &rThat)
603 { return operator=((const GuestEnvironmentBase &)rThat); }
604};
605
606/**
607 * Class for keeping guest error information.
608 */
609class GuestErrorInfo
610{
611public:
612
613 /**
614 * Enumeration for specifying the guest error type.
615 */
616 enum Type
617 {
618 /** Guest error is anonymous. Avoid this. */
619 Type_Anonymous = 0,
620 /** Guest error is from a guest session. */
621 Type_Session,
622 /** Guest error is from a guest process. */
623 Type_Process,
624 /** Guest error is from a guest file object. */
625 Type_File,
626 /** Guest error is from a guest directory object. */
627 Type_Directory,
628 /** Guest error is from a the built-in toolbox "vbox_cat" command. */
629 Type_ToolCat,
630 /** Guest error is from a the built-in toolbox "vbox_ls" command. */
631 Type_ToolLs,
632 /** Guest error is from a the built-in toolbox "vbox_rm" command. */
633 Type_ToolRm,
634 /** Guest error is from a the built-in toolbox "vbox_mkdir" command. */
635 Type_ToolMkDir,
636 /** Guest error is from a the built-in toolbox "vbox_mktemp" command. */
637 Type_ToolMkTemp,
638 /** Guest error is from a the built-in toolbox "vbox_stat" command. */
639 Type_ToolStat,
640 /** The usual 32-bit hack. */
641 Type_32BIT_HACK = 0x7fffffff
642 };
643
644 /**
645 * Initialization constructor.
646 *
647 * @param eType Error type to use.
648 * @param rc IPRT-style rc to use.
649 * @param pcszWhat Subject to use.
650 */
651 GuestErrorInfo(GuestErrorInfo::Type eType, int rc, const char *pcszWhat)
652 {
653 int rc2 = setV(eType, rc, pcszWhat);
654 if (RT_FAILURE(rc2))
655 throw rc2;
656 }
657
658 /**
659 * Returns the (IPRT-style) rc of this error.
660 *
661 * @returns VBox status code.
662 */
663 int getRc(void) const { return mRc; }
664
665 /**
666 * Returns the type of this error.
667 *
668 * @returns Error type.
669 */
670 Type getType(void) const { return mType; }
671
672 /**
673 * Returns the subject of this error.
674 *
675 * @returns Subject as a string.
676 */
677 Utf8Str getWhat(void) const { return mWhat; }
678
679 /**
680 * Sets the error information using a variable arguments list (va_list).
681 *
682 * @returns VBox status code.
683 * @param eType Error type to use.
684 * @param rc IPRT-style rc to use.
685 * @param pcszWhat Subject to use.
686 */
687 int setV(GuestErrorInfo::Type eType, int rc, const char *pcszWhat)
688 {
689 mType = eType;
690 mRc = rc;
691 mWhat = pcszWhat;
692
693 return VINF_SUCCESS;
694 }
695
696protected:
697
698 /** Error type. */
699 Type mType;
700 /** IPRT-style error code. */
701 int mRc;
702 /** Subject string related to this error. */
703 Utf8Str mWhat;
704};
705
706/**
707 * Structure for keeping all the relevant guest directory
708 * information around.
709 */
710struct GuestDirectoryOpenInfo
711{
712 GuestDirectoryOpenInfo(void)
713 : mFlags(0) { }
714
715 /** The directory path. */
716 Utf8Str mPath;
717 /** Then open filter. */
718 Utf8Str mFilter;
719 /** Opening flags. */
720 uint32_t mFlags;
721};
722
723
724/**
725 * Structure for keeping all the relevant guest file
726 * information around.
727 */
728struct GuestFileOpenInfo
729{
730 GuestFileOpenInfo(void)
731 : mAccessMode((FileAccessMode_T)0)
732 , mOpenAction((FileOpenAction_T)0)
733 , mSharingMode((FileSharingMode_T)0)
734 , mCreationMode(0)
735 , mfOpenEx(0) { }
736
737 /**
738 * Validates a file open info.
739 *
740 * @returns \c true if valid, \c false if not.
741 */
742 bool IsValid(void) const
743 {
744 if (mfOpenEx) /** @todo Open flags not implemented yet. */
745 return false;
746
747 switch (mOpenAction)
748 {
749 case FileOpenAction_OpenExisting:
750 break;
751 case FileOpenAction_OpenOrCreate:
752 break;
753 case FileOpenAction_CreateNew:
754 break;
755 case FileOpenAction_CreateOrReplace:
756 break;
757 case FileOpenAction_OpenExistingTruncated:
758 {
759 if ( mAccessMode == FileAccessMode_ReadOnly
760 || mAccessMode == FileAccessMode_AppendOnly
761 || mAccessMode == FileAccessMode_AppendRead)
762 return false;
763 break;
764 }
765 case FileOpenAction_AppendOrCreate: /* Deprecated, do not use. */
766 break;
767 default:
768 AssertFailedReturn(false);
769 break;
770 }
771
772 return true; /** @todo Do we need more checks here? */
773 }
774
775 /** The filename. */
776 Utf8Str mFilename;
777 /** The file access mode. */
778 FileAccessMode_T mAccessMode;
779 /** The file open action. */
780 FileOpenAction_T mOpenAction;
781 /** The file sharing mode. */
782 FileSharingMode_T mSharingMode;
783 /** Octal creation mode. */
784 uint32_t mCreationMode;
785 /** Extended open flags (currently none defined). */
786 uint32_t mfOpenEx;
787};
788
789
790/**
791 * Structure representing information of a
792 * file system object.
793 */
794struct GuestFsObjData
795{
796 GuestFsObjData(void)
797 : mType(FsObjType_Unknown)
798 , mObjectSize(0)
799 , mAllocatedSize(0)
800 , mAccessTime(0)
801 , mBirthTime(0)
802 , mChangeTime(0)
803 , mModificationTime(0)
804 , mUID(0)
805 , mGID(0)
806 , mNodeID(0)
807 , mNodeIDDevice(0)
808 , mNumHardLinks(0)
809 , mDeviceNumber(0)
810 , mGenerationID(0)
811 , mUserFlags(0) { }
812
813 /** @name Helper functions to extract the data from a certin VBoxService tool's guest stream block.
814 * @{ */
815 int FromLs(const GuestProcessStreamBlock &strmBlk, bool fLong);
816 int FromStat(const GuestProcessStreamBlock &strmBlk);
817 int FromMkTemp(const GuestProcessStreamBlock &strmBlk);
818 /** @} */
819
820 /** @name Static helper functions to work with time from stream block keys.
821 * @{ */
822 static PRTTIMESPEC TimeSpecFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey, PRTTIMESPEC pTimeSpec);
823 static int64_t UnixEpochNsFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey);
824 /** @} */
825
826 /** @name helper functions to work with IPRT stuff.
827 * @{ */
828 RTFMODE GetFileMode(void) const;
829 /** @} */
830
831 Utf8Str mName;
832 FsObjType_T mType;
833 Utf8Str mFileAttrs;
834 int64_t mObjectSize;
835 int64_t mAllocatedSize;
836 int64_t mAccessTime;
837 int64_t mBirthTime;
838 int64_t mChangeTime;
839 int64_t mModificationTime;
840 Utf8Str mUserName;
841 int32_t mUID;
842 int32_t mGID;
843 Utf8Str mGroupName;
844 Utf8Str mACL;
845 int64_t mNodeID;
846 uint32_t mNodeIDDevice;
847 uint32_t mNumHardLinks;
848 uint32_t mDeviceNumber;
849 uint32_t mGenerationID;
850 uint32_t mUserFlags;
851};
852
853
854/**
855 * Structure for keeping all the relevant guest session
856 * startup parameters around.
857 */
858class GuestSessionStartupInfo
859{
860public:
861
862 GuestSessionStartupInfo(void)
863 : mID(UINT32_MAX)
864 , mIsInternal(false /* Non-internal session */)
865 , mOpenTimeoutMS(30 * 1000 /* 30s opening timeout */)
866 , mOpenFlags(0 /* No opening flags set */) { }
867
868 /** The session's friendly name. Optional. */
869 Utf8Str mName;
870 /** The session's unique ID. Used to encode a context ID.
871 * UINT32_MAX if not initialized. */
872 uint32_t mID;
873 /** Flag indicating if this is an internal session
874 * or not. Internal session are not accessible by
875 * public API clients. */
876 bool mIsInternal;
877 /** Timeout (in ms) used for opening the session. */
878 uint32_t mOpenTimeoutMS;
879 /** Session opening flags. */
880 uint32_t mOpenFlags;
881};
882
883
884/**
885 * Structure for keeping all the relevant guest process
886 * startup parameters around.
887 */
888class GuestProcessStartupInfo
889{
890public:
891
892 GuestProcessStartupInfo(void)
893 : mFlags(ProcessCreateFlag_None)
894 , mTimeoutMS(UINT32_MAX /* No timeout by default */)
895 , mPriority(ProcessPriority_Default)
896 , mAffinity(0) { }
897
898 /** The process' friendly name. */
899 Utf8Str mName;
900 /** The executable. */
901 Utf8Str mExecutable;
902 /** Arguments vector (starting with argument \#0). */
903 ProcessArguments mArguments;
904 /** The process environment change record. */
905 GuestEnvironmentChanges mEnvironmentChanges;
906 /** Process creation flags. */
907 uint32_t mFlags;
908 /** Timeout (in ms) the process is allowed to run.
909 * Specify UINT32_MAX if no timeout (unlimited run time) is given. */
910 ULONG mTimeoutMS;
911 /** Process priority. */
912 ProcessPriority_T mPriority;
913 /** Process affinity. At the moment we
914 * only support 64 VCPUs. API and
915 * guest can do more already! */
916 uint64_t mAffinity;
917};
918
919
920/**
921 * Class representing the "value" side of a "key=value" pair.
922 */
923class GuestProcessStreamValue
924{
925public:
926
927 GuestProcessStreamValue(void) { }
928 GuestProcessStreamValue(const char *pszValue)
929 : mValue(pszValue) {}
930
931 GuestProcessStreamValue(const GuestProcessStreamValue& aThat)
932 : mValue(aThat.mValue) { }
933
934 /** Copy assignment operator. */
935 GuestProcessStreamValue &operator=(GuestProcessStreamValue const &a_rThat) RT_NOEXCEPT
936 {
937 mValue = a_rThat.mValue;
938
939 return *this;
940 }
941
942 Utf8Str mValue;
943};
944
945/** Map containing "key=value" pairs of a guest process stream. */
946typedef std::pair< Utf8Str, GuestProcessStreamValue > GuestCtrlStreamPair;
947typedef std::map < Utf8Str, GuestProcessStreamValue > GuestCtrlStreamPairMap;
948typedef std::map < Utf8Str, GuestProcessStreamValue >::iterator GuestCtrlStreamPairMapIter;
949typedef std::map < Utf8Str, GuestProcessStreamValue >::const_iterator GuestCtrlStreamPairMapIterConst;
950
951/**
952 * Class representing a block of stream pairs (key=value). Each block in a raw guest
953 * output stream is separated by "\0\0", each pair is separated by "\0". The overall
954 * end of a guest stream is marked by "\0\0\0\0".
955 */
956class GuestProcessStreamBlock
957{
958public:
959
960 GuestProcessStreamBlock(void);
961
962 virtual ~GuestProcessStreamBlock(void);
963
964public:
965
966 void Clear(void);
967
968#ifdef DEBUG
969 void DumpToLog(void) const;
970#endif
971
972 const char *GetString(const char *pszKey) const;
973 size_t GetCount(void) const;
974 int GetRc(void) const;
975 int GetInt64Ex(const char *pszKey, int64_t *piVal) const;
976 int64_t GetInt64(const char *pszKey) const;
977 int GetUInt32Ex(const char *pszKey, uint32_t *puVal) const;
978 uint32_t GetUInt32(const char *pszKey, uint32_t uDefault = 0) const;
979 int32_t GetInt32(const char *pszKey, int32_t iDefault = 0) const;
980
981 bool IsEmpty(void) { return mPairs.empty(); }
982
983 int SetValue(const char *pszKey, const char *pszValue);
984
985protected:
986
987 GuestCtrlStreamPairMap mPairs;
988};
989
990/** Vector containing multiple allocated stream pair objects. */
991typedef std::vector< GuestProcessStreamBlock > GuestCtrlStreamObjects;
992typedef std::vector< GuestProcessStreamBlock >::iterator GuestCtrlStreamObjectsIter;
993typedef std::vector< GuestProcessStreamBlock >::const_iterator GuestCtrlStreamObjectsIterConst;
994
995/**
996 * Class for parsing machine-readable guest process output by VBoxService'
997 * toolbox commands ("vbox_ls", "vbox_stat" etc), aka "guest stream".
998 */
999class GuestProcessStream
1000{
1001
1002public:
1003
1004 GuestProcessStream();
1005
1006 virtual ~GuestProcessStream();
1007
1008public:
1009
1010 int AddData(const BYTE *pbData, size_t cbData);
1011
1012 void Destroy();
1013
1014#ifdef DEBUG
1015 void Dump(const char *pszFile);
1016#endif
1017
1018 size_t GetOffset() { return m_offBuffer; }
1019
1020 size_t GetSize() { return m_cbUsed; }
1021
1022 int ParseBlock(GuestProcessStreamBlock &streamBlock);
1023
1024protected:
1025
1026 /** Currently allocated size of internal stream buffer. */
1027 size_t m_cbAllocated;
1028 /** Currently used size at m_offBuffer. */
1029 size_t m_cbUsed;
1030 /** Current byte offset within the internal stream buffer. */
1031 size_t m_offBuffer;
1032 /** Internal stream buffer. */
1033 BYTE *m_pbBuffer;
1034};
1035
1036class Guest;
1037class Progress;
1038
1039class GuestWaitEventPayload
1040{
1041
1042public:
1043
1044 GuestWaitEventPayload(void)
1045 : uType(0),
1046 cbData(0),
1047 pvData(NULL) { }
1048
1049 GuestWaitEventPayload(uint32_t uTypePayload,
1050 const void *pvPayload, uint32_t cbPayload)
1051 : uType(0),
1052 cbData(0),
1053 pvData(NULL)
1054 {
1055 int rc = copyFrom(uTypePayload, pvPayload, cbPayload);
1056 if (RT_FAILURE(rc))
1057 throw rc;
1058 }
1059
1060 virtual ~GuestWaitEventPayload(void)
1061 {
1062 Clear();
1063 }
1064
1065 GuestWaitEventPayload& operator=(const GuestWaitEventPayload &that)
1066 {
1067 CopyFromDeep(that);
1068 return *this;
1069 }
1070
1071public:
1072
1073 void Clear(void)
1074 {
1075 if (pvData)
1076 {
1077 Assert(cbData);
1078 RTMemFree(pvData);
1079 cbData = 0;
1080 pvData = NULL;
1081 }
1082 uType = 0;
1083 }
1084
1085 int CopyFromDeep(const GuestWaitEventPayload &payload)
1086 {
1087 return copyFrom(payload.uType, payload.pvData, payload.cbData);
1088 }
1089
1090 const void* Raw(void) const { return pvData; }
1091
1092 size_t Size(void) const { return cbData; }
1093
1094 uint32_t Type(void) const { return uType; }
1095
1096 void* MutableRaw(void) { return pvData; }
1097
1098 Utf8Str ToString(void)
1099 {
1100 const char *pszStr = (const char *)pvData;
1101 size_t cbStr = cbData;
1102
1103 if (RT_FAILURE(RTStrValidateEncodingEx(pszStr, cbStr,
1104 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED | RTSTR_VALIDATE_ENCODING_EXACT_LENGTH)))
1105 {
1106 AssertFailed();
1107 return "";
1108 }
1109
1110 return Utf8Str(pszStr, cbStr);
1111 }
1112
1113protected:
1114
1115 int copyFrom(uint32_t uTypePayload, const void *pvPayload, uint32_t cbPayload)
1116 {
1117 if (cbPayload > _64K) /* Paranoia. */
1118 return VERR_TOO_MUCH_DATA;
1119
1120 Clear();
1121
1122 int rc = VINF_SUCCESS;
1123
1124 if (cbPayload)
1125 {
1126 pvData = RTMemAlloc(cbPayload);
1127 if (pvData)
1128 {
1129 uType = uTypePayload;
1130
1131 memcpy(pvData, pvPayload, cbPayload);
1132 cbData = cbPayload;
1133 }
1134 else
1135 rc = VERR_NO_MEMORY;
1136 }
1137 else
1138 {
1139 uType = uTypePayload;
1140
1141 pvData = NULL;
1142 cbData = 0;
1143 }
1144
1145 return rc;
1146 }
1147
1148protected:
1149
1150 /** Type of payload. */
1151 uint32_t uType;
1152 /** Size (in bytes) of payload. */
1153 uint32_t cbData;
1154 /** Pointer to actual payload data. */
1155 void *pvData;
1156};
1157
1158class GuestWaitEventBase
1159{
1160
1161protected:
1162
1163 GuestWaitEventBase(void);
1164 virtual ~GuestWaitEventBase(void);
1165
1166public:
1167
1168 uint32_t ContextID(void) { return mCID; };
1169 int GuestResult(void) { return mGuestRc; }
1170 int Result(void) { return mRc; }
1171 GuestWaitEventPayload & Payload(void) { return mPayload; }
1172 int SignalInternal(int rc, int guestRc, const GuestWaitEventPayload *pPayload);
1173 int Wait(RTMSINTERVAL uTimeoutMS);
1174
1175protected:
1176
1177 int Init(uint32_t uCID);
1178
1179protected:
1180
1181 /* Shutdown indicator. */
1182 bool mfAborted;
1183 /* Associated context ID (CID). */
1184 uint32_t mCID;
1185 /** The event semaphore for triggering
1186 * the actual event. */
1187 RTSEMEVENT mEventSem;
1188 /** The event's overall result. If
1189 * set to VERR_GSTCTL_GUEST_ERROR,
1190 * mGuestRc will contain the actual
1191 * error code from the guest side. */
1192 int mRc;
1193 /** The event'S overall result from the
1194 * guest side. If used, mRc must be
1195 * set to VERR_GSTCTL_GUEST_ERROR. */
1196 int mGuestRc;
1197 /** The event's payload data. Optional. */
1198 GuestWaitEventPayload mPayload;
1199};
1200
1201/** List of public guest event types. */
1202typedef std::list < VBoxEventType_T > GuestEventTypes;
1203
1204class GuestWaitEvent : public GuestWaitEventBase
1205{
1206
1207public:
1208
1209 GuestWaitEvent(void);
1210 virtual ~GuestWaitEvent(void);
1211
1212public:
1213
1214 int Init(uint32_t uCID);
1215 int Init(uint32_t uCID, const GuestEventTypes &lstEvents);
1216 int Cancel(void);
1217 const ComPtr<IEvent> Event(void) { return mEvent; }
1218 bool HasGuestError(void) const { return mRc == VERR_GSTCTL_GUEST_ERROR; }
1219 int GetGuestError(void) const { return mGuestRc; }
1220 int SignalExternal(IEvent *pEvent);
1221 const GuestEventTypes &Types(void) { return mEventTypes; }
1222 size_t TypeCount(void) { return mEventTypes.size(); }
1223
1224protected:
1225
1226 /** List of public event types this event should
1227 * be signalled on. Optional. */
1228 GuestEventTypes mEventTypes;
1229 /** Pointer to the actual public event, if any. */
1230 ComPtr<IEvent> mEvent;
1231};
1232/** Map of pointers to guest events. The primary key
1233 * contains the context ID. */
1234typedef std::map < uint32_t, GuestWaitEvent* > GuestWaitEvents;
1235/** Map of wait events per public guest event. Nice for
1236 * faster lookups when signalling a whole event group. */
1237typedef std::map < VBoxEventType_T, GuestWaitEvents > GuestEventGroup;
1238
1239class GuestBase
1240{
1241
1242public:
1243
1244 GuestBase(void);
1245 virtual ~GuestBase(void);
1246
1247public:
1248
1249 /** Signals a wait event using a public guest event; also used for
1250 * for external event listeners. */
1251 int signalWaitEvent(VBoxEventType_T aType, IEvent *aEvent);
1252 /** Signals a wait event using a guest rc. */
1253 int signalWaitEventInternal(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, int guestRc, const GuestWaitEventPayload *pPayload);
1254 /** Signals a wait event without letting public guest events know,
1255 * extended director's cut version. */
1256 int signalWaitEventInternalEx(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, int rc, int guestRc, const GuestWaitEventPayload *pPayload);
1257
1258public:
1259
1260 int baseInit(void);
1261 void baseUninit(void);
1262 int cancelWaitEvents(void);
1263 int dispatchGeneric(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb);
1264 int generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID);
1265 int registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID, GuestWaitEvent **ppEvent);
1266 int registerWaitEventEx(uint32_t uSessionID, uint32_t uObjectID, const GuestEventTypes &lstEvents, GuestWaitEvent **ppEvent);
1267 int unregisterWaitEvent(GuestWaitEvent *pEvent);
1268 int waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, VBoxEventType_T *pType, IEvent **ppEvent);
1269
1270#ifndef VBOX_GUESTCTRL_TEST_CASE
1271 HRESULT setErrorExternal(VirtualBoxBase *pInterface, const Utf8Str &strAction, const GuestErrorInfo &guestErrorInfo);
1272#endif
1273
1274public:
1275
1276 static FsObjType_T fileModeToFsObjType(RTFMODE fMode);
1277 static Utf8Str getErrorAsString(const GuestErrorInfo &guestErrorInfo);
1278
1279protected:
1280
1281 /** Pointer to the console object. Needed
1282 * for HGCM (VMMDev) communication. */
1283 Console *mConsole;
1284 /** The next context ID counter component for this object. */
1285 uint32_t mNextContextID;
1286 /** Local listener for handling the waiting events
1287 * internally. */
1288 ComPtr<IEventListener> mLocalListener;
1289 /** Critical section for wait events access. */
1290 RTCRITSECT mWaitEventCritSect;
1291 /** Map of registered wait events per event group. */
1292 GuestEventGroup mWaitEventGroups;
1293 /** Map of registered wait events. */
1294 GuestWaitEvents mWaitEvents;
1295};
1296
1297/**
1298 * Virtual class (interface) for guest objects (processes, files, ...) --
1299 * contains all per-object callback management.
1300 */
1301class GuestObject : public GuestBase
1302{
1303 friend class GuestSession;
1304
1305public:
1306
1307 GuestObject(void);
1308 virtual ~GuestObject(void);
1309
1310public:
1311
1312 ULONG getObjectID(void) { return mObjectID; }
1313
1314protected:
1315
1316 /**
1317 * Called by IGuestSession when the session status has been changed.
1318 *
1319 * @returns VBox status code.
1320 * @param enmSessionStatus New session status.
1321 */
1322 virtual int i_onSessionStatusChange(GuestSessionStatus_T enmSessionStatus) = 0;
1323
1324 /**
1325 * Called by IGuestSession right before this object gets
1326 * unregistered (removed) from the public object list.
1327 */
1328 virtual int i_onUnregister(void) = 0;
1329
1330 /** Callback dispatcher -- must be implemented by the actual object. */
1331 virtual int i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) = 0;
1332
1333protected:
1334
1335 int bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID);
1336 int registerWaitEvent(const GuestEventTypes &lstEvents, GuestWaitEvent **ppEvent);
1337 int sendMessage(uint32_t uFunction, uint32_t cParms, PVBOXHGCMSVCPARM paParms);
1338
1339protected:
1340
1341 /** @name Common parameters for all derived objects. They have their own
1342 * mData structure to keep their specific data around.
1343 * @{ */
1344 /** Pointer to parent session. Per definition
1345 * this objects *always* lives shorter than the
1346 * parent.
1347 * @todo r=bird: When wanting to use mSession in the
1348 * IGuestProcess::getEnvironment() implementation I wanted to access
1349 * GuestSession::mData::mpBaseEnvironment. Seeing the comment in
1350 * GuestProcess::terminate() saying:
1351 * "Now only API clients still can hold references to it."
1352 * and recalling seeing similar things in VirtualBox.xidl or some such place,
1353 * I'm wondering how this "per definition" behavior is enforced. Is there any
1354 * GuestProcess:uninit() call or similar magic that invalidates objects that
1355 * GuestSession loses track of in place like GuestProcess::terminate() that I've
1356 * failed to spot?
1357 *
1358 * Please enlighten me.
1359 */
1360 GuestSession *mSession;
1361 /** The object ID -- must be unique for each guest
1362 * object and is encoded into the context ID. Must
1363 * be set manually when initializing the object.
1364 *
1365 * For guest processes this is the internal PID,
1366 * for guest files this is the internal file ID. */
1367 uint32_t mObjectID;
1368 /** @} */
1369};
1370#endif /* !MAIN_INCLUDED_GuestCtrlImplPrivate_h */
1371
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette