Changeset 49165 in vbox for trunk/src/VBox/Frontends/VBoxManage
- Timestamp:
- Oct 17, 2013 2:48:13 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 90036
- Location:
- trunk/src/VBox/Frontends/VBoxManage
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/Makefile.kmk
r48406 r49165 5 5 6 6 # 7 # Copyright (C) 2006-201 2Oracle Corporation7 # Copyright (C) 2006-2013 Oracle Corporation 8 8 # 9 9 # This file is part of VirtualBox Open Source Edition (OSE), as … … 45 45 VBoxManageDisk.cpp \ 46 46 $(if $(VBOX_WITH_GUEST_CONTROL),VBoxManageGuestCtrl.cpp) \ 47 $(if $(VBOX_WITH_GUEST_CONTROL),VBoxManageGuestCtrlListener.cpp) \ 47 48 $(if $(VBOX_WITH_GUEST_PROPS),VBoxManageGuestProp.cpp) \ 48 49 VBoxManageHelp.cpp \ -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r48014 r49165 21 21 *******************************************************************************/ 22 22 #include "VBoxManage.h" 23 #include "VBoxManageGuestCtrl.h" 23 24 24 25 #ifndef VBOX_ONLY_DOCS … … 62 63 using namespace com; 63 64 64 /** @todo Move this into a helper module. */65 static const char *ctrlFileStatusToText(FileStatus_T enmStatus);66 static const char *ctrlProcessStatusToText(ProcessStatus_T enmStatus);67 static const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus);68 69 class GuestFileEventListener;70 typedef ListenerImpl<GuestFileEventListener> GuestFileEventListenerImpl;71 VBOX_LISTENER_DECLARE(GuestFileEventListenerImpl)72 73 class GuestProcessEventListener;74 typedef ListenerImpl<GuestProcessEventListener> GuestProcessEventListenerImpl;75 VBOX_LISTENER_DECLARE(GuestProcessEventListenerImpl)76 77 class GuestSessionEventListener;78 typedef ListenerImpl<GuestSessionEventListener> GuestSessionEventListenerImpl;79 VBOX_LISTENER_DECLARE(GuestSessionEventListenerImpl)80 81 /** Simple statistics class for binding locally82 * held data to a specific guest object. */83 class GuestEventStats84 {85 86 public:87 88 GuestEventStats(void)89 : uLastUpdatedMS(RTTimeMilliTS())90 {91 }92 93 /** @todo Make this more a class than a structure. */94 public:95 96 uint64_t uLastUpdatedMS;97 };98 99 class GuestFileStats : public GuestEventStats100 {101 102 public:103 104 GuestFileStats(void) { }105 106 GuestFileStats(ComObjPtr<GuestFileEventListenerImpl> pListenerImpl)107 : mListener(pListenerImpl)108 {109 }110 111 public: /** @todo */112 113 ComObjPtr<GuestFileEventListenerImpl> mListener;114 };115 116 class GuestProcStats : public GuestEventStats117 {118 119 public:120 121 GuestProcStats(void) { }122 123 GuestProcStats(ComObjPtr<GuestProcessEventListenerImpl> pListenerImpl)124 : mListener(pListenerImpl)125 {126 }127 128 public: /** @todo */129 130 ComObjPtr<GuestProcessEventListenerImpl> mListener;131 };132 133 class GuestSessionStats : public GuestEventStats134 {135 136 public:137 138 GuestSessionStats(void) { }139 140 GuestSessionStats(ComObjPtr<GuestSessionEventListenerImpl> pListenerImpl)141 : mListener(pListenerImpl)142 {143 }144 145 public: /** @todo */146 147 ComObjPtr<GuestSessionEventListenerImpl> mListener;148 };149 150 /** Map containing all watched guest files. */151 typedef std::map< ComPtr<IGuestFile>, GuestFileStats > GuestEventFiles;152 /** Map containing all watched guest processes. */153 typedef std::map< ComPtr<IGuestProcess>, GuestProcStats > GuestEventProcs;154 /** Map containing all watched guest sessions. */155 typedef std::map< ComPtr<IGuestSession>, GuestSessionStats > GuestEventSessions;156 157 class GuestListenerBase158 {159 public:160 161 GuestListenerBase(void)162 : mfVerbose(false)163 {164 }165 166 virtual ~GuestListenerBase(void)167 {168 }169 170 HRESULT init(bool fVerbose = false)171 {172 mfVerbose = fVerbose;173 return S_OK;174 }175 176 protected:177 178 /** Verbose flag. */179 bool mfVerbose;180 };181 182 /**183 * Handler for guest process events.184 */185 class GuestFileEventListener : public GuestListenerBase186 {187 public:188 189 GuestFileEventListener(void)190 {191 }192 193 virtual ~GuestFileEventListener(void)194 {195 }196 197 void uninit(void)198 {199 200 }201 202 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)203 {204 switch (aType)205 {206 case VBoxEventType_OnGuestFileStateChanged:207 {208 HRESULT rc;209 do210 {211 ComPtr<IGuestFileStateChangedEvent> pEvent = aEvent;212 Assert(!pEvent.isNull());213 214 ComPtr<IGuestFile> pProcess;215 CHECK_ERROR_BREAK(pEvent, COMGETTER(File)(pProcess.asOutParam()));216 AssertBreak(!pProcess.isNull());217 FileStatus_T fileSts;218 CHECK_ERROR_BREAK(pEvent, COMGETTER(Status)(&fileSts));219 Bstr strPath;220 CHECK_ERROR_BREAK(pProcess, COMGETTER(FileName)(strPath.asOutParam()));221 ULONG uID;222 CHECK_ERROR_BREAK(pProcess, COMGETTER(Id)(&uID));223 224 RTPrintf("File ID=%RU32 \"%s\" changed status to [%s]\n",225 uID, Utf8Str(strPath).c_str(),226 ctrlFileStatusToText(fileSts));227 228 } while (0);229 break;230 }231 232 default:233 AssertFailed();234 }235 236 return S_OK;237 }238 239 protected:240 241 };242 243 /**244 * Handler for guest process events.245 */246 class GuestProcessEventListener : public GuestListenerBase247 {248 public:249 250 GuestProcessEventListener(void)251 {252 }253 254 virtual ~GuestProcessEventListener(void)255 {256 }257 258 void uninit(void)259 {260 261 }262 263 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)264 {265 switch (aType)266 {267 case VBoxEventType_OnGuestProcessStateChanged:268 {269 HRESULT rc;270 do271 {272 ComPtr<IGuestProcessStateChangedEvent> pEvent = aEvent;273 Assert(!pEvent.isNull());274 275 ComPtr<IGuestProcess> pProcess;276 CHECK_ERROR_BREAK(pEvent, COMGETTER(Process)(pProcess.asOutParam()));277 AssertBreak(!pProcess.isNull());278 ProcessStatus_T procSts;279 CHECK_ERROR_BREAK(pEvent, COMGETTER(Status)(&procSts));280 Bstr strPath;281 CHECK_ERROR_BREAK(pProcess, COMGETTER(ExecutablePath)(strPath.asOutParam()));282 ULONG uPID;283 CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));284 285 RTPrintf("Process PID=%RU32 \"%s\" changed status to [%s]\n",286 uPID, Utf8Str(strPath).c_str(),287 ctrlProcessStatusToText(procSts));288 289 } while (0);290 break;291 }292 293 default:294 AssertFailed();295 }296 297 return S_OK;298 }299 300 protected:301 302 };303 304 /**305 * Handler for guest session events.306 */307 class GuestSessionEventListener : public GuestListenerBase308 {309 public:310 311 GuestSessionEventListener(void)312 {313 }314 315 virtual ~GuestSessionEventListener(void)316 {317 }318 319 void uninit(void)320 {321 GuestEventProcs::iterator itProc = mProcs.begin();322 while (itProc != mProcs.end())323 {324 if (!itProc->first.isNull())325 {326 HRESULT rc;327 do328 {329 /* Listener unregistration. */330 ComPtr<IEventSource> pES;331 CHECK_ERROR_BREAK(itProc->first, COMGETTER(EventSource)(pES.asOutParam()));332 if (!pES.isNull())333 CHECK_ERROR_BREAK(pES, UnregisterListener(itProc->second.mListener));334 } while (0);335 itProc->first->Release();336 }337 338 itProc++;339 }340 mProcs.clear();341 342 GuestEventFiles::iterator itFile = mFiles.begin();343 while (itFile != mFiles.end())344 {345 if (!itFile->first.isNull())346 {347 HRESULT rc;348 do349 {350 /* Listener unregistration. */351 ComPtr<IEventSource> pES;352 CHECK_ERROR_BREAK(itFile->first, COMGETTER(EventSource)(pES.asOutParam()));353 if (!pES.isNull())354 CHECK_ERROR_BREAK(pES, UnregisterListener(itFile->second.mListener));355 } while (0);356 itFile->first->Release();357 }358 359 itFile++;360 }361 mFiles.clear();362 }363 364 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)365 {366 switch (aType)367 {368 case VBoxEventType_OnGuestFileRegistered:369 {370 HRESULT rc;371 do372 {373 ComPtr<IGuestFileRegisteredEvent> pEvent = aEvent;374 Assert(!pEvent.isNull());375 376 ComPtr<IGuestFile> pFile;377 CHECK_ERROR_BREAK(pEvent, COMGETTER(File)(pFile.asOutParam()));378 AssertBreak(!pFile.isNull());379 BOOL fRegistered;380 CHECK_ERROR_BREAK(pEvent, COMGETTER(Registered)(&fRegistered));381 Bstr strPath;382 CHECK_ERROR_BREAK(pFile, COMGETTER(FileName)(strPath.asOutParam()));383 384 RTPrintf("File \"%s\" %s\n",385 Utf8Str(strPath).c_str(),386 fRegistered ? "registered" : "unregistered");387 if (fRegistered)388 {389 if (mfVerbose)390 RTPrintf("Registering ...\n");391 392 /* Register for IGuestFile events. */393 ComObjPtr<GuestFileEventListenerImpl> pListener;394 pListener.createObject();395 CHECK_ERROR_BREAK(pListener, init(new GuestFileEventListener()));396 397 ComPtr<IEventSource> es;398 CHECK_ERROR_BREAK(pFile, COMGETTER(EventSource)(es.asOutParam()));399 com::SafeArray<VBoxEventType_T> eventTypes;400 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);401 CHECK_ERROR_BREAK(es, RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes),402 true /* Active listener */));403 404 GuestFileStats fileStats(pListener);405 mFiles[pFile] = fileStats;406 }407 else408 {409 GuestEventFiles::iterator itFile = mFiles.find(pFile);410 if (itFile != mFiles.end())411 {412 if (mfVerbose)413 RTPrintf("Unregistering file ...\n");414 415 if (!itFile->first.isNull())416 {417 /* Listener unregistration. */418 ComPtr<IEventSource> pES;419 CHECK_ERROR(itFile->first, COMGETTER(EventSource)(pES.asOutParam()));420 if (!pES.isNull())421 CHECK_ERROR(pES, UnregisterListener(itFile->second.mListener));422 itFile->first->Release();423 }424 425 mFiles.erase(itFile);426 }427 }428 429 } while (0);430 break;431 }432 433 case VBoxEventType_OnGuestProcessRegistered:434 {435 HRESULT rc;436 do437 {438 ComPtr<IGuestProcessRegisteredEvent> pEvent = aEvent;439 Assert(!pEvent.isNull());440 441 ComPtr<IGuestProcess> pProcess;442 CHECK_ERROR_BREAK(pEvent, COMGETTER(Process)(pProcess.asOutParam()));443 AssertBreak(!pProcess.isNull());444 BOOL fRegistered;445 CHECK_ERROR_BREAK(pEvent, COMGETTER(Registered)(&fRegistered));446 Bstr strPath;447 CHECK_ERROR_BREAK(pProcess, COMGETTER(ExecutablePath)(strPath.asOutParam()));448 449 RTPrintf("Process \"%s\" %s\n",450 Utf8Str(strPath).c_str(),451 fRegistered ? "registered" : "unregistered");452 if (fRegistered)453 {454 if (mfVerbose)455 RTPrintf("Registering ...\n");456 457 /* Register for IGuestProcess events. */458 ComObjPtr<GuestProcessEventListenerImpl> pListener;459 pListener.createObject();460 CHECK_ERROR_BREAK(pListener, init(new GuestProcessEventListener()));461 462 ComPtr<IEventSource> es;463 CHECK_ERROR_BREAK(pProcess, COMGETTER(EventSource)(es.asOutParam()));464 com::SafeArray<VBoxEventType_T> eventTypes;465 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);466 CHECK_ERROR_BREAK(es, RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes),467 true /* Active listener */));468 469 GuestProcStats procStats(pListener);470 mProcs[pProcess] = procStats;471 }472 else473 {474 GuestEventProcs::iterator itProc = mProcs.find(pProcess);475 if (itProc != mProcs.end())476 {477 if (mfVerbose)478 RTPrintf("Unregistering process ...\n");479 480 if (!itProc->first.isNull())481 {482 /* Listener unregistration. */483 ComPtr<IEventSource> pES;484 CHECK_ERROR(itProc->first, COMGETTER(EventSource)(pES.asOutParam()));485 if (!pES.isNull())486 CHECK_ERROR(pES, UnregisterListener(itProc->second.mListener));487 itProc->first->Release();488 }489 490 mProcs.erase(itProc);491 }492 }493 494 } while (0);495 break;496 }497 498 case VBoxEventType_OnGuestSessionStateChanged:499 {500 HRESULT rc;501 do502 {503 ComPtr<IGuestSessionStateChangedEvent> pEvent = aEvent;504 Assert(!pEvent.isNull());505 ComPtr<IGuestSession> pSession;506 CHECK_ERROR_BREAK(pEvent, COMGETTER(Session)(pSession.asOutParam()));507 AssertBreak(!pSession.isNull());508 509 GuestSessionStatus_T sessSts;510 CHECK_ERROR_BREAK(pSession, COMGETTER(Status)(&sessSts));511 ULONG uID;512 CHECK_ERROR_BREAK(pSession, COMGETTER(Id)(&uID));513 Bstr strName;514 CHECK_ERROR_BREAK(pSession, COMGETTER(Name)(strName.asOutParam()));515 516 RTPrintf("Session ID=%RU32 \"%s\" changed status to [%s]\n",517 uID, Utf8Str(strName).c_str(),518 ctrlSessionStatusToText(sessSts));519 520 } while (0);521 break;522 }523 524 default:525 AssertFailed();526 }527 528 return S_OK;529 }530 531 protected:532 533 GuestEventFiles mFiles;534 GuestEventProcs mProcs;535 };536 537 /**538 * Handler for guest events.539 */540 class GuestEventListener : public GuestListenerBase541 {542 public:543 GuestEventListener(void)544 {545 }546 547 virtual ~GuestEventListener(void)548 {549 }550 551 void uninit(void)552 {553 GuestEventSessions::iterator itSession = mSessions.begin();554 while (itSession != mSessions.end())555 {556 if (!itSession->first.isNull())557 {558 HRESULT rc;559 do560 {561 /* Listener unregistration. */562 ComPtr<IEventSource> pES;563 CHECK_ERROR_BREAK(itSession->first, COMGETTER(EventSource)(pES.asOutParam()));564 if (!pES.isNull())565 CHECK_ERROR_BREAK(pES, UnregisterListener(itSession->second.mListener));566 567 } while (0);568 itSession->first->Release();569 }570 571 itSession++;572 }573 mSessions.clear();574 }575 576 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)577 {578 switch (aType)579 {580 case VBoxEventType_OnGuestSessionRegistered:581 {582 HRESULT rc;583 do584 {585 ComPtr<IGuestSessionRegisteredEvent> pEvent = aEvent;586 Assert(!pEvent.isNull());587 588 ComPtr<IGuestSession> pSession;589 CHECK_ERROR_BREAK(pEvent, COMGETTER(Session)(pSession.asOutParam()));590 AssertBreak(!pSession.isNull());591 BOOL fRegistered;592 CHECK_ERROR_BREAK(pEvent, COMGETTER(Registered)(&fRegistered));593 Bstr strName;594 CHECK_ERROR_BREAK(pSession, COMGETTER(Name)(strName.asOutParam()));595 ULONG uID;596 CHECK_ERROR_BREAK(pSession, COMGETTER(Id)(&uID));597 598 RTPrintf("Session ID=%RU32 \"%s\" %s\n",599 uID, Utf8Str(strName).c_str(),600 fRegistered ? "registered" : "unregistered");601 if (fRegistered)602 {603 if (mfVerbose)604 RTPrintf("Registering ...\n");605 606 /* Register for IGuestSession events. */607 ComObjPtr<GuestSessionEventListenerImpl> pListener;608 pListener.createObject();609 CHECK_ERROR_BREAK(pListener, init(new GuestSessionEventListener()));610 611 ComPtr<IEventSource> es;612 CHECK_ERROR_BREAK(pSession, COMGETTER(EventSource)(es.asOutParam()));613 com::SafeArray<VBoxEventType_T> eventTypes;614 eventTypes.push_back(VBoxEventType_OnGuestFileRegistered);615 eventTypes.push_back(VBoxEventType_OnGuestProcessRegistered);616 CHECK_ERROR_BREAK(es, RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes),617 true /* Active listener */));618 619 GuestSessionStats sessionStats(pListener);620 mSessions[pSession] = sessionStats;621 }622 else623 {624 GuestEventSessions::iterator itSession = mSessions.find(pSession);625 if (itSession != mSessions.end())626 {627 if (mfVerbose)628 RTPrintf("Unregistering ...\n");629 630 if (!itSession->first.isNull())631 {632 /* Listener unregistration. */633 ComPtr<IEventSource> pES;634 CHECK_ERROR_BREAK(itSession->first, COMGETTER(EventSource)(pES.asOutParam()));635 if (!pES.isNull())636 CHECK_ERROR_BREAK(pES, UnregisterListener(itSession->second.mListener));637 itSession->first->Release();638 }639 640 mSessions.erase(itSession);641 }642 }643 644 } while (0);645 break;646 }647 648 default:649 AssertFailed();650 }651 652 return S_OK;653 }654 655 protected:656 657 GuestEventSessions mSessions;658 };659 typedef ListenerImpl<GuestEventListener> GuestEventListenerImpl;660 VBOX_LISTENER_DECLARE(GuestEventListenerImpl)661 662 65 /** Set by the signal handler. */ 663 66 static volatile bool g_fGuestCtrlCanceled = false; … … 666 69 static ComPtr<IGuestSession> g_pGuestSession; 667 70 71 /** 72 * Command context flags. 73 */ 74 /** No flags set. */ 75 #define CTLCMDCTX_FLAGS_NONE 0 76 /** Don't install a signal handler (CTRL+C trap). */ 77 #define CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER RT_BIT(0) 78 /** No guest session needed. */ 79 #define CTLCMDCTX_FLAGS_SESSION_ANONYMOUS RT_BIT(1) 80 /** Detach the guest session. That is, don't close the 81 * guest session automatically on exit. */ 82 #define CTLCMDCTX_FLAGS_SESSION_DETACH RT_BIT(2) 83 84 /** 85 * Context for handling a specific command. 86 */ 87 typedef struct GCTLCMDCTX 88 { 89 HandlerArg handlerArg; 90 /** Command-specific argument count. */ 91 int iArgc; 92 /** Command-specific argument vector. */ 93 char **ppaArgv; 94 /** First argv to start parsing with. */ 95 int iFirstArgc; 96 /** Command context flags. */ 97 uint32_t uFlags; 98 /** Verbose flag. */ 99 bool fVerbose; 100 /** User name. */ 101 Utf8Str strUsername; 102 /** Password. */ 103 Utf8Str strPassword; 104 /** Domain. */ 105 Utf8Str strDomain; 106 /** Pointer to the IGuest interface. */ 107 ComPtr<IGuest> pGuest; 108 /** Pointer to the to be used guest session. */ 109 ComPtr<IGuestSession> pGuestSession; 110 111 } GCTLCMDCTX, *PGCTLCMDCTX; 112 113 typedef struct GCTLCMD 114 { 115 /** 116 * Actual command handler callback. 117 * 118 * @param pCtx Pointer to command context to use. 119 */ 120 DECLR3CALLBACKMEMBER(RTEXITCODE, pfnHandler, (PGCTLCMDCTX pCtx)); 121 122 } GCTLCMD, *PGCTLCMD; 123 668 124 typedef struct COPYCONTEXT 669 125 { 670 COPYCONTEXT() : fVerbose(false), fDryRun(false), fHostToGuest(false) 671 { 672 } 673 126 COPYCONTEXT() 127 : fDryRun(false), 128 fHostToGuest(false) 129 { 130 } 131 132 PGCTLCMDCTX pCmdCtx; 674 133 ComPtr<IGuestSession> pGuestSession; 675 bool fVerbose;676 134 bool fDryRun; 677 135 bool fHostToGuest; 136 678 137 } COPYCONTEXT, *PCOPYCONTEXT; 679 138 … … 772 231 }; 773 232 233 /* 234 * Common getopt definitions, starting at 1000. 235 * Specific command definitions will start all at 2000. 236 */ 237 enum GETOPTDEF_COMMON 238 { 239 GETOPTDEF_COMMON_PASSWORD = 1000 240 }; 241 774 242 /** 775 243 * RTGetOpt-IDs for the guest execution control command line. … … 782 250 GETOPTDEF_EXEC_DOS2UNIX, 783 251 GETOPTDEF_EXEC_UNIX2DOS, 784 GETOPTDEF_EXEC_PASSWORD,785 252 GETOPTDEF_EXEC_WAITFOREXIT, 786 253 GETOPTDEF_EXEC_WAITFORSTDOUT, … … 792 259 GETOPTDEF_COPY_DRYRUN = 1000, 793 260 GETOPTDEF_COPY_FOLLOW, 794 GETOPTDEF_COPY_PASSWORD,795 261 GETOPTDEF_COPY_TARGETDIR 796 262 }; … … 798 264 enum GETOPTDEF_MKDIR 799 265 { 800 GETOPTDEF_MKDIR_PASSWORD = 1000801 266 }; 802 267 268 enum GETOPTDEF_RM 269 { 270 }; 271 272 enum GETOPTDEF_RMDIR 273 { 274 GETOPTDEF_RMDIR_RECURSIVE = 2000 275 }; 276 803 277 enum GETOPTDEF_SESSIONCLOSE 804 278 { 805 GETOPTDEF_SESSIONCLOSE_ALL = 1000279 GETOPTDEF_SESSIONCLOSE_ALL = 2000 806 280 }; 807 281 808 282 enum GETOPTDEF_STAT 809 283 { 810 GETOPTDEF_STAT_PASSWORD = 1000811 284 }; 812 285 … … 854 327 " [--domain <domain>] [--verbose]\n" 855 328 " [--parents] [--mode <mode>]\n" 329 "\n" 330 " removedir[ectory]|rmdir|rm\n" 331 " <guest directory>... --username <name>\n" 332 " [--passwordfile <file> | --password <password>]\n" 333 " [--domain <domain>] [--verbose]\n" 334 " [--recursive|-R|-r]\n" 335 "\n" 336 " removefile|rm\n" 337 " <guest file>... --username <name>\n" 338 " [--passwordfile <file> | --password <password>]\n" 339 " [--domain <domain>] [--verbose]\n" 856 340 "\n" 857 341 " createtemp[orary]|mktemp\n" … … 983 467 * string. 984 468 */ 985 staticconst char *ctrlProcessStatusToText(ProcessStatus_T enmStatus)469 const char *ctrlProcessStatusToText(ProcessStatus_T enmStatus) 986 470 { 987 471 switch (enmStatus) … … 1066 550 * string. 1067 551 */ 1068 staticconst char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus)552 const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus) 1069 553 { 1070 554 switch (enmStatus) … … 1096 580 * string. 1097 581 */ 1098 staticconst char *ctrlFileStatusToText(FileStatus_T enmStatus)582 const char *ctrlFileStatusToText(FileStatus_T enmStatus) 1099 583 { 1100 584 switch (enmStatus) … … 1173 657 /** 1174 658 * Un-initializes the VM after guest control usage. 659 * @param pCmdCtx Pointer to command context. 660 * @param uFlags Command context flags. 1175 661 */ 1176 static void ctrlUninitVM(HandlerArg *pArg) 1177 { 1178 AssertPtrReturnVoid(pArg); 1179 if (pArg->session) 1180 pArg->session->UnlockMachine(); 662 static void ctrlUninitVM(PGCTLCMDCTX pCtx, uint32_t uFlags) 663 { 664 AssertPtrReturnVoid(pCtx); 665 666 if (!(pCtx->uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER)) 667 ctrlSignalHandlerUninstall(); 668 669 HRESULT rc; 670 671 do 672 { 673 if (!pCtx->pGuestSession.isNull()) 674 { 675 if ( !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS) 676 && !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH)) 677 { 678 if (pCtx->fVerbose) 679 RTPrintf("Closing guest session ...\n"); 680 681 CHECK_ERROR(pCtx->pGuestSession, Close()); 682 /* Keep going - don't break here. Try to unlock the 683 * machine down below. */ 684 } 685 else if (pCtx->fVerbose) 686 RTPrintf("Guest session detached\n"); 687 } 688 689 if (pCtx->handlerArg.session) 690 CHECK_ERROR(pCtx->handlerArg.session, UnlockMachine()); 691 692 } while (0); 693 694 for (int i = 0; i < pCtx->iArgc; i++) 695 RTStrFree(pCtx->ppaArgv[i]); 696 RTMemFree(pCtx->ppaArgv); 1181 697 } 1182 698 … … 1185 701 * 1186 702 * That is, checks whether it's up and running, if it can be locked (shared 1187 * only) and returns a valid IGuest pointer on success. 703 * only) and returns a valid IGuest pointer on success. Also, it does some 704 * basic command line processing and opens a guest session, if required. 1188 705 * 1189 * @return IPRTstatus code.1190 * @param pArg Ourcommand line argument structure.1191 * @param p szNameOrId The VM's name or UUID.1192 * @param pGuest Where to return the IGuest interface pointer.706 * @return RTEXITCODE status code. 707 * @param pArg Pointer to command line argument structure. 708 * @param pCmdCtx Pointer to command context. 709 * @param uFlags Command context flags. 1193 710 */ 1194 static int ctrlInitVM(HandlerArg *pArg, const char *pszNameOrId, ComPtr<IGuest> *pGuest) 1195 { 1196 AssertPtrReturn(pArg, VERR_INVALID_PARAMETER); 1197 AssertPtrReturn(pszNameOrId, VERR_INVALID_PARAMETER); 711 static RTEXITCODE ctrlInitVM(HandlerArg *pArg, 712 PGCTLCMDCTX pCtx, uint32_t uFlags) 713 { 714 AssertPtrReturn(pArg, RTEXITCODE_FAILURE); 715 AssertReturn(pArg->argc > 1, RTEXITCODE_FAILURE); 716 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 717 718 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 719 720 const char *pszNameOrId = pArg->argv[0]; 721 const char *pszCmd = pArg->argv[1]; 1198 722 1199 723 /* Lookup VM. */ … … 1203 727 CHECK_ERROR(pArg->virtualBox, FindMachine(Bstr(pszNameOrId).raw(), 1204 728 machine.asOutParam())); 1205 if (FAILED(rc)) 1206 return VERR_NOT_FOUND; 1207 1208 /* Machine is running? */ 1209 MachineState_T machineState; 1210 CHECK_ERROR_RET(machine, COMGETTER(State)(&machineState), 1); 1211 if (machineState != MachineState_Running) 1212 { 1213 RTMsgError("Machine \"%s\" is not running (currently %s)!\n", 1214 pszNameOrId, machineStateToName(machineState, false)); 1215 return VERR_VM_INVALID_VM_STATE; 1216 } 1217 1218 do 1219 { 1220 /* Open a session for the VM. */ 1221 CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared)); 1222 /* Get the associated console. */ 1223 ComPtr<IConsole> console; 1224 CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam())); 1225 /* ... and session machine. */ 1226 ComPtr<IMachine> sessionMachine; 1227 CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam())); 1228 /* Get IGuest interface. */ 1229 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest->asOutParam())); 1230 } while (0); 1231 1232 if (FAILED(rc)) 1233 ctrlUninitVM(pArg); 1234 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; 729 if (SUCCEEDED(rc)) 730 { 731 /* Machine is running? */ 732 MachineState_T machineState; 733 CHECK_ERROR(machine, COMGETTER(State)(&machineState)); 734 if ( SUCCEEDED(rc) 735 && (machineState != MachineState_Running)) 736 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine \"%s\" is not running (currently %s)!\n", 737 pszNameOrId, machineStateToName(machineState, false)); 738 } 739 else 740 rcExit = RTEXITCODE_FAILURE; 741 742 if (rcExit == RTEXITCODE_SUCCESS) 743 { 744 /* 745 * Process standard options which are served by all commands. 746 */ 747 static const RTGETOPTDEF s_aOptions[] = 748 { 749 { "--username", 'u', RTGETOPT_REQ_STRING }, 750 { "--passwordfile", 'p', RTGETOPT_REQ_STRING }, 751 { "--password", GETOPTDEF_COMMON_PASSWORD, RTGETOPT_REQ_STRING }, 752 { "--domain", 'd', RTGETOPT_REQ_STRING }, 753 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 754 }; 755 756 /* 757 * Allocate per-command argv. This then only contains the specific arguments 758 * the command needs. 759 */ 760 pCtx->ppaArgv = (char**)RTMemAlloc(pArg->argc * sizeof(char*) + 1); 761 if (!pCtx->ppaArgv) 762 { 763 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Not enough memory for per-command argv\n"); 764 } 765 else 766 { 767 pCtx->iArgc = 0; 768 769 int ch; 770 RTGETOPTUNION ValueUnion; 771 RTGETOPTSTATE GetState; 772 RTGetOptInit(&GetState, pArg->argc, pArg->argv, 773 s_aOptions, RT_ELEMENTS(s_aOptions), 774 2, /* Skip VM name and guest control command */ 775 RTGETOPTINIT_FLAGS_OPTS_FIRST); 776 777 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 778 && (rcExit == RTEXITCODE_SUCCESS)) 779 { 780 /* For options that require an argument, ValueUnion has received the value. */ 781 switch (ch) 782 { 783 case 'u': /* User name */ 784 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 785 pCtx->strUsername = ValueUnion.psz; 786 break; 787 788 case GETOPTDEF_COMMON_PASSWORD: /* Password */ 789 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 790 { 791 if (pCtx->strPassword.isEmpty()) 792 pCtx->strPassword = ValueUnion.psz; 793 } 794 break; 795 796 case 'p': /* Password file */ 797 { 798 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 799 rcExit = readPasswordFile(ValueUnion.psz, &pCtx->strPassword); 800 break; 801 } 802 803 case 'd': /* domain */ 804 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 805 pCtx->strDomain = ValueUnion.psz; 806 break; 807 808 case 'v': /* Verbose */ 809 pCtx->fVerbose = true; 810 break; 811 812 case VINF_GETOPT_NOT_OPTION: 813 /* Fall through is intentional. */ 814 default: 815 { 816 Assert(GetState.iNext); 817 char *pszArg = RTStrDup(pArg->argv[GetState.iNext - 1]); 818 if (!pszArg) 819 { 820 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, 821 "Not enough memory for command line handling\n"); 822 break; 823 } 824 pCtx->ppaArgv[pCtx->iArgc] = pszArg; 825 pCtx->iArgc++; 826 break; 827 } 828 829 } /* switch */ 830 } /* while RTGetOpt */ 831 } 832 } 833 834 /* 835 * Check for mandatory stuff. 836 */ 837 if (rcExit == RTEXITCODE_SUCCESS) 838 { 839 #if 0 840 RTPrintf("argc=%d\n", pCtx->iArgc); 841 for (int i = 0; i < pCtx->iArgc; i++) 842 RTPrintf("argv[%d]=%s\n", i, pCtx->ppaArgv[i]); 843 #endif 844 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 845 { 846 if (pCtx->strUsername.isEmpty()) 847 rcExit = errorSyntax(USAGE_GUESTCONTROL, "No user name specified!"); 848 } 849 } 850 851 if (rcExit == RTEXITCODE_SUCCESS) 852 { 853 /* 854 * Build up a reasonable guest session name. Useful for identifying 855 * a specific session when listing / searching for them. 856 */ 857 char *pszSessionName; 858 if (0 >= RTStrAPrintf(&pszSessionName, 859 "[%RU32] VBoxManage Guest Control [%s] - %s", 860 RTProcSelf(), pszNameOrId, pszCmd)) 861 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name\n"); 862 863 do 864 { 865 /* Open a session for the VM. */ 866 CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared)); 867 /* Get the associated console. */ 868 ComPtr<IConsole> console; 869 CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam())); 870 /* ... and session machine. */ 871 ComPtr<IMachine> sessionMachine; 872 CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam())); 873 /* Get IGuest interface. */ 874 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pCtx->pGuest.asOutParam())); 875 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 876 { 877 if (pCtx->fVerbose) 878 RTPrintf("Opening guest session as user '%s' ...\n", pCtx->strUsername.c_str()); 879 880 /* Open a guest session. */ 881 Assert(!pCtx->pGuest.isNull()); 882 CHECK_ERROR_BREAK(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(), 883 Bstr(pCtx->strPassword).raw(), 884 Bstr(pCtx->strDomain).raw(), 885 Bstr(pszSessionName).raw(), 886 pCtx->pGuestSession.asOutParam())); 887 } 888 889 if (!(uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER)) 890 ctrlSignalHandlerInstall(); 891 892 } while (0); 893 894 if (FAILED(rc)) 895 rcExit = RTEXITCODE_FAILURE; 896 897 RTStrFree(pszSessionName); 898 } 899 900 if (rcExit == RTEXITCODE_SUCCESS) 901 { 902 pCtx->handlerArg = *pArg; 903 pCtx->uFlags = uFlags; 904 } 905 else /* Clean up on failure. */ 906 ctrlUninitVM(pCtx, uFlags); 907 908 return rcExit; 1235 909 } 1236 910 … … 1330 1004 } 1331 1005 1332 /* <Missing documentation> */ 1333 static RTEXITCODE handleCtrlProcessExec(ComPtr<IGuest> pGuest, HandlerArg *pArg) 1334 { 1335 AssertPtrReturn(pArg, RTEXITCODE_SYNTAX); 1006 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExec(PGCTLCMDCTX pCtx) 1007 { 1008 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 1336 1009 1337 1010 /* … … 1346 1019 { "--image", 'i', RTGETOPT_REQ_STRING }, 1347 1020 { "--no-profile", GETOPTDEF_EXEC_NO_PROFILE, RTGETOPT_REQ_NOTHING }, 1348 { "--username", 'u', RTGETOPT_REQ_STRING },1349 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },1350 { "--password", GETOPTDEF_EXEC_PASSWORD, RTGETOPT_REQ_STRING },1351 { "--domain", 'd', RTGETOPT_REQ_STRING },1352 1021 { "--timeout", 't', RTGETOPT_REQ_UINT32 }, 1353 1022 { "--unix2dos", GETOPTDEF_EXEC_UNIX2DOS, RTGETOPT_REQ_NOTHING }, 1354 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },1355 1023 { "--wait-exit", GETOPTDEF_EXEC_WAITFOREXIT, RTGETOPT_REQ_NOTHING }, 1356 1024 { "--wait-stdout", GETOPTDEF_EXEC_WAITFORSTDOUT, RTGETOPT_REQ_NOTHING }, … … 1361 1029 RTGETOPTUNION ValueUnion; 1362 1030 RTGETOPTSTATE GetState; 1363 RTGetOptInit(&GetState, p Arg->argc, pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);1031 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, 0); 1364 1032 1365 1033 Utf8Str strCmd; … … 1368 1036 com::SafeArray<IN_BSTR> aArgs; 1369 1037 com::SafeArray<IN_BSTR> aEnv; 1370 Utf8Str strUsername;1371 Utf8Str strPassword;1372 Utf8Str strDomain;1373 1038 RTMSINTERVAL cMsTimeout = 0; 1374 1039 OUTPUTTYPE eOutputType = OUTPUTTYPE_UNDEFINED; 1375 1040 bool fDetached = true; 1376 bool fVerbose = false;1377 1041 int vrc = VINF_SUCCESS; 1378 1042 … … 1424 1088 /** @todo Add a hidden flag. */ 1425 1089 1426 case 'u': /* User name */1427 strUsername = ValueUnion.psz;1428 break;1429 1430 case GETOPTDEF_EXEC_PASSWORD: /* Password */1431 strPassword = ValueUnion.psz;1432 break;1433 1434 case 'p': /* Password file */1435 {1436 RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);1437 if (rcExit != RTEXITCODE_SUCCESS)1438 return rcExit;1439 break;1440 }1441 1442 case 'd': /* domain */1443 strDomain = ValueUnion.psz;1444 break;1445 1446 1090 case 't': /* Timeout */ 1447 1091 cMsTimeout = ValueUnion.u32; … … 1454 1098 break; 1455 1099 1456 case 'v': /* Verbose */1457 fVerbose = true;1458 break;1459 1460 1100 case GETOPTDEF_EXEC_WAITFOREXIT: 1461 1101 aWaitFlags.push_back(ProcessWaitForFlag_Terminate); … … 1476 1116 1477 1117 case VINF_GETOPT_NOT_OPTION: 1478 {1479 1118 if (aArgs.size() == 0 && strCmd.isEmpty()) 1480 1119 strCmd = ValueUnion.psz; … … 1482 1121 aArgs.push_back(Bstr(ValueUnion.psz).raw()); 1483 1122 break; 1484 }1485 1123 1486 1124 default: 1487 1125 return RTGetOptPrintError(ch, &ValueUnion); 1126 break; 1488 1127 1489 1128 } /* switch */ … … 1500 1139 if (strCmd.isEmpty()) 1501 1140 return errorSyntax(USAGE_GUESTCONTROL, "No command to execute specified!"); 1502 1503 if (strUsername.isEmpty())1504 return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");1505 1141 1506 1142 /** @todo Any output conversion not supported yet! */ … … 1508 1144 return errorSyntax(USAGE_GUESTCONTROL, "Output conversion not implemented yet!"); 1509 1145 1510 ctrlSignalHandlerInstall();1511 1512 /*1513 * Start with the real work.1514 */1515 HRESULT rc = S_OK;1516 if (fVerbose)1517 RTPrintf("Opening guest session as user '%s' ...\n", strUsername.c_str());1518 1519 1146 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 1520 1521 /** @todo This eventually needs a bit of revamping so that a valid session gets passed 1522 * into this function already so that we don't need to mess around with closing 1523 * the session all over the places below again. Later. */ 1147 HRESULT rc; 1524 1148 1525 1149 try … … 1527 1151 do 1528 1152 { 1529 Utf8Str strVBoxManage;1530 strVBoxManage.printf("VBoxManage Guest Control (PID %RU32)", RTProcSelf());1531 1532 CHECK_ERROR_BREAK(pGuest, CreateSession(Bstr(strUsername).raw(),1533 Bstr(strPassword).raw(),1534 Bstr(strDomain).raw(),1535 Bstr(strVBoxManage).raw(),1536 g_pGuestSession.asOutParam()));1537 1538 1153 /* Adjust process creation flags if we don't want to wait for process termination. */ 1539 1154 if (fDetached) … … 1546 1161 * Wait for guest session to start. 1547 1162 */ 1548 if ( fVerbose)1163 if (pCtx->fVerbose) 1549 1164 { 1550 1165 if (cMsTimeout == 0) … … 1566 1181 || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported) 1567 1182 { 1568 if ( fVerbose)1183 if (pCtx->fVerbose) 1569 1184 RTPrintf("Guest session (ID %RU32) has been started\n", uSessionID); 1570 1185 } … … 1575 1190 } 1576 1191 1577 if ( fVerbose)1192 if (pCtx->fVerbose) 1578 1193 { 1579 1194 if (cMsTimeout == 0) … … 1621 1236 ULONG uPID = 0; 1622 1237 CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID)); 1623 if ( fVerbose)1238 if (pCtx->fVerbose) 1624 1239 { 1625 1240 RTPrintf("Process '%s' (PID %RU32) started\n", … … 1708 1323 LONG exitCode; 1709 1324 CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&exitCode)); 1710 if ( fVerbose)1325 if (pCtx->fVerbose) 1711 1326 RTPrintf("Exit code=%u (Status=%u [%s])\n", 1712 1327 exitCode, procStatus, ctrlProcessStatusToText(procStatus)); … … 1714 1329 rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCode(procStatus, exitCode); 1715 1330 } 1716 else if ( fVerbose)1331 else if (pCtx->fVerbose) 1717 1332 RTPrintf("Process now is in status [%s]\n", ctrlProcessStatusToText(procStatus)); 1718 1333 } 1719 1334 else 1720 1335 { 1721 if ( fVerbose)1336 if (pCtx->fVerbose) 1722 1337 RTPrintf("Process execution aborted!\n"); 1723 1338 … … 1731 1346 rc = E_OUTOFMEMORY; 1732 1347 } 1733 1734 ctrlSignalHandlerUninstall();1735 1348 1736 1349 bool fCloseSession = false; … … 1747 1360 fCloseSession = true; 1748 1361 1749 if ( fCloseSession 1750 && !g_pGuestSession.isNull()) 1751 { 1752 if (fVerbose) 1753 RTPrintf("Closing guest session ...\n"); 1754 rc = g_pGuestSession->Close(); 1755 } 1756 else if (!fCloseSession && fVerbose) 1757 RTPrintf("Guest session detached\n"); 1362 if (!fCloseSession) 1363 pCtx->uFlags |= CTLCMDCTX_FLAGS_SESSION_DETACH; 1758 1364 1759 1365 if ( rcExit == RTEXITCODE_SUCCESS … … 1772 1378 * 1773 1379 * @return IPRT status code. 1774 * @param pGuest Pointer to IGuest interface to use. 1775 * @param fVerbose Flag indicating if we want to run in verbose mode. 1380 * @param pCtx Pointer to command context. 1776 1381 * @param fDryRun Flag indicating if we want to run a dry run only. 1777 1382 * @param fHostToGuest Flag indicating if we want to copy from host to guest 1778 1383 * or vice versa. 1779 * @param strUsername Username of account to use on the guest side.1780 * @param strPassword Password of account to use.1781 * @param strDomain Domain of account to use.1782 1384 * @param strSessionName Session name (only for identification purposes). 1783 1385 * @param ppContext Pointer which receives the allocated copy context. 1784 1386 */ 1785 static int ctrlCopyContextCreate(IGuest *pGuest, bool fVerbose, bool fDryRun, 1786 bool fHostToGuest, const Utf8Str &strUsername, 1787 const Utf8Str &strPassword, const Utf8Str &strDomain, 1387 static int ctrlCopyContextCreate(PGCTLCMDCTX pCtx, bool fDryRun, bool fHostToGuest, 1788 1388 const Utf8Str &strSessionName, 1789 1389 PCOPYCONTEXT *ppContext) 1790 1390 { 1791 AssertPtrReturn(p Guest, VERR_INVALID_POINTER);1391 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1792 1392 1793 1393 PCOPYCONTEXT pContext = new COPYCONTEXT(); 1794 1394 AssertPtrReturn(pContext, VERR_NO_MEMORY); /**< @todo r=klaus cannot happen with new */ 1795 1395 ComPtr<IGuestSession> pGuestSession; 1796 HRESULT rc = p Guest->CreateSession(Bstr(strUsername).raw(),1797 Bstr(strPassword).raw(),1798 Bstr(strDomain).raw(),1799 Bstr(strSessionName).raw(),1800 pGuestSession.asOutParam());1396 HRESULT rc = pCtx->pGuest->CreateSession(Bstr(pCtx->strUsername).raw(), 1397 Bstr(pCtx->strPassword).raw(), 1398 Bstr(pCtx->strDomain).raw(), 1399 Bstr(strSessionName).raw(), 1400 pGuestSession.asOutParam()); 1801 1401 if (FAILED(rc)) 1802 return ctrlPrintError(p Guest, COM_IIDOF(IGuest));1803 1804 pContext-> fVerbose = fVerbose;1402 return ctrlPrintError(pCtx->pGuest, COM_IIDOF(IGuest)); 1403 1404 pContext->pCmdCtx = pCtx; 1805 1405 pContext->fDryRun = fDryRun; 1806 1406 pContext->fHostToGuest = fHostToGuest; … … 1978 1578 && fDirExists) 1979 1579 { 1980 if (pContext-> fVerbose)1580 if (pContext->pCmdCtx->fVerbose) 1981 1581 RTPrintf("Directory \"%s\" already exists\n", pszDir); 1982 1582 return VINF_SUCCESS; … … 1988 1588 return vrc; 1989 1589 1990 if (pContext-> fVerbose)1590 if (pContext->pCmdCtx->fVerbose) 1991 1591 RTPrintf("Creating directory \"%s\" ...\n", pszDir); 1992 1592 … … 2164 1764 AssertReturn(!fFlags, VERR_INVALID_POINTER); /* No flags supported yet. */ 2165 1765 2166 if (pContext-> fVerbose)1766 if (pContext->pCmdCtx->fVerbose) 2167 1767 RTPrintf("Copying \"%s\" to \"%s\" ...\n", 2168 1768 pszFileSource, pszFileDest); … … 2196 1796 else 2197 1797 { 2198 if (pContext-> fVerbose)1798 if (pContext->pCmdCtx->fVerbose) 2199 1799 rc = showProgress(pProgress); 2200 1800 else … … 2239 1839 vrc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir); 2240 1840 2241 if (pContext-> fVerbose)1841 if (pContext->pCmdCtx->fVerbose) 2242 1842 RTPrintf("Processing host directory: %s\n", szCurDir); 2243 1843 … … 2284 1884 break; 2285 1885 2286 if (pContext-> fVerbose)1886 if (pContext->pCmdCtx->fVerbose) 2287 1887 RTPrintf("Directory: %s\n", DirEntry.szName); 2288 1888 … … 2328 1928 } 2329 1929 2330 if (pContext-> fVerbose)1930 if (pContext->pCmdCtx->fVerbose) 2331 1931 RTPrintf("File: %s\n", DirEntry.szName); 2332 1932 … … 2411 2011 return vrc; 2412 2012 2413 if (pContext-> fVerbose)2013 if (pContext->pCmdCtx->fVerbose) 2414 2014 RTPrintf("Processing guest directory: %s\n", szCurDir); 2415 2015 … … 2448 2048 break; 2449 2049 2450 if (pContext-> fVerbose)2050 if (pContext->pCmdCtx->fVerbose) 2451 2051 { 2452 2052 Utf8Str strDir(strName); … … 2498 2098 } 2499 2099 2500 if (pContext-> fVerbose)2100 if (pContext->pCmdCtx->fVerbose) 2501 2101 RTPrintf("File: %s\n", strFile.c_str()); 2502 2102 … … 2655 2255 } 2656 2256 2657 static RTEXITCODE handleCtrlCopy(ComPtr<IGuest> guest, HandlerArg *pArg, 2658 bool fHostToGuest) 2659 { 2660 AssertPtrReturn(pArg, RTEXITCODE_SYNTAX); 2257 static RTEXITCODE handleCtrlCopy(PGCTLCMDCTX pCtx, bool fHostToGuest) 2258 { 2259 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 2661 2260 2662 2261 /** @todo r=bird: This command isn't very unix friendly in general. mkdir … … 2678 2277 { "--dryrun", GETOPTDEF_COPY_DRYRUN, RTGETOPT_REQ_NOTHING }, 2679 2278 { "--follow", GETOPTDEF_COPY_FOLLOW, RTGETOPT_REQ_NOTHING }, 2680 { "--username", 'u', RTGETOPT_REQ_STRING },2681 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },2682 { "--password", GETOPTDEF_COPY_PASSWORD, RTGETOPT_REQ_STRING },2683 { "--domain", 'd', RTGETOPT_REQ_STRING },2684 2279 { "--recursive", 'R', RTGETOPT_REQ_NOTHING }, 2685 { "--target-directory", GETOPTDEF_COPY_TARGETDIR, RTGETOPT_REQ_STRING }, 2686 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 2280 { "--target-directory", GETOPTDEF_COPY_TARGETDIR, RTGETOPT_REQ_STRING } 2687 2281 }; 2688 2282 … … 2690 2284 RTGETOPTUNION ValueUnion; 2691 2285 RTGETOPTSTATE GetState; 2692 RTGetOptInit(&GetState, p Arg->argc, pArg->argv,2693 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);2286 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 2287 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 2694 2288 2695 2289 Utf8Str strSource; 2696 2290 Utf8Str strDest; 2697 Utf8Str strUsername;2698 Utf8Str strPassword;2699 Utf8Str strDomain;2700 2291 uint32_t fFlags = CopyFileFlag_None; 2701 bool fVerbose = false;2702 2292 bool fCopyRecursive = false; 2703 2293 bool fDryRun = false; … … 2719 2309 break; 2720 2310 2721 case 'u': /* User name */2722 strUsername = ValueUnion.psz;2723 break;2724 2725 case GETOPTDEF_COPY_PASSWORD: /* Password */2726 strPassword = ValueUnion.psz;2727 break;2728 2729 case 'p': /* Password file */2730 {2731 RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);2732 if (rcExit != RTEXITCODE_SUCCESS)2733 return rcExit;2734 break;2735 }2736 2737 case 'd': /* domain */2738 strDomain = ValueUnion.psz;2739 break;2740 2741 2311 case 'R': /* Recursive processing */ 2742 2312 fFlags |= CopyFileFlag_Recursive; … … 2745 2315 case GETOPTDEF_COPY_TARGETDIR: 2746 2316 strDest = ValueUnion.psz; 2747 break;2748 2749 case 'v': /* Verbose */2750 fVerbose = true;2751 2317 break; 2752 2318 … … 2756 2322 * --target-directory yet? Then use the current 2757 2323 * (= last) argument as destination. */ 2758 if ( pArg->argc == GetState.iNext2324 if ( pCtx->iArgc == GetState.iNext 2759 2325 && strDest.isEmpty()) 2760 2326 { … … 2771 2337 default: 2772 2338 return RTGetOptPrintError(ch, &ValueUnion); 2339 break; 2773 2340 } 2774 2341 } … … 2782 2349 "No destination specified!"); 2783 2350 2784 if (strUsername.isEmpty())2785 return errorSyntax(USAGE_GUESTCONTROL,2786 "No user name specified!");2787 2788 2351 /* 2789 2352 * Done parsing arguments, do some more preparations. 2790 2353 */ 2791 if ( fVerbose)2354 if (pCtx->fVerbose) 2792 2355 { 2793 2356 if (fHostToGuest) … … 2802 2365 * the routines need to know when handling the actual copying. */ 2803 2366 PCOPYCONTEXT pContext = NULL; 2804 vrc = ctrlCopyContextCreate(guest, fVerbose, fDryRun, fHostToGuest, 2805 strUsername, strPassword, strDomain, 2367 vrc = ctrlCopyContextCreate(pCtx, fDryRun, fHostToGuest, 2806 2368 "VBoxManage Guest Control Copy", &pContext); 2807 2369 if (RT_FAILURE(vrc)) … … 2862 2424 } 2863 2425 2864 if ( fVerbose)2426 if (pCtx->fVerbose) 2865 2427 RTPrintf("Source: %s\n", pszSource); 2866 2428 … … 2949 2511 } 2950 2512 2951 static RTEXITCODE handleCtrlCreateDirectory(ComPtr<IGuest> pGuest, HandlerArg *pArg) 2952 { 2953 AssertPtrReturn(pArg, RTEXITCODE_SYNTAX); 2513 static DECLCALLBACK(RTEXITCODE) handleCtrlCopyFrom(PGCTLCMDCTX pCtx) 2514 { 2515 return handleCtrlCopy(pCtx, false /* Guest to host */); 2516 } 2517 2518 static DECLCALLBACK(RTEXITCODE) handleCtrlCopyTo(PGCTLCMDCTX pCtx) 2519 { 2520 return handleCtrlCopy(pCtx, true /* Host to guest */); 2521 } 2522 2523 static DECLCALLBACK(RTEXITCODE) handleCtrlCreateDirectory(PGCTLCMDCTX pCtx) 2524 { 2525 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 2954 2526 2955 2527 /* … … 2962 2534 { 2963 2535 { "--mode", 'm', RTGETOPT_REQ_UINT32 }, 2964 { "--parents", 'P', RTGETOPT_REQ_NOTHING }, 2965 { "--username", 'u', RTGETOPT_REQ_STRING }, 2966 { "--passwordfile", 'p', RTGETOPT_REQ_STRING }, 2967 { "--password", GETOPTDEF_MKDIR_PASSWORD, RTGETOPT_REQ_STRING }, 2968 { "--domain", 'd', RTGETOPT_REQ_STRING }, 2969 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 2536 { "--parents", 'P', RTGETOPT_REQ_NOTHING } 2970 2537 }; 2971 2538 … … 2973 2540 RTGETOPTUNION ValueUnion; 2974 2541 RTGETOPTSTATE GetState; 2975 RTGetOptInit(&GetState, pArg->argc, pArg->argv, 2976 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST); 2977 2978 Utf8Str strUsername; 2979 Utf8Str strPassword; 2980 Utf8Str strDomain; 2542 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 2543 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 2544 2981 2545 SafeArray<DirectoryCreateFlag_T> dirCreateFlags; 2982 2546 uint32_t fDirMode = 0; /* Default mode. */ 2983 bool fVerbose = false;2984 2985 2547 DESTDIRMAP mapDirs; 2986 2548 … … 2998 2560 break; 2999 2561 3000 case 'u': /* User name */3001 strUsername = ValueUnion.psz;3002 break;3003 3004 case GETOPTDEF_MKDIR_PASSWORD: /* Password */3005 strPassword = ValueUnion.psz;3006 break;3007 3008 case 'p': /* Password file */3009 {3010 RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);3011 if (rcExit != RTEXITCODE_SUCCESS)3012 return rcExit;3013 break;3014 }3015 3016 case 'd': /* domain */3017 strDomain = ValueUnion.psz;3018 break;3019 3020 case 'v': /* Verbose */3021 fVerbose = true;3022 break;3023 3024 2562 case VINF_GETOPT_NOT_OPTION: 3025 {3026 2563 mapDirs[ValueUnion.psz]; /* Add destination directory to map. */ 3027 2564 break; 3028 }3029 2565 3030 2566 default: 3031 2567 return RTGetOptPrintError(ch, &ValueUnion); 2568 break; 3032 2569 } 3033 2570 } … … 3037 2574 return errorSyntax(USAGE_GUESTCONTROL, "No directory to create specified!"); 3038 2575 3039 if (strUsername.isEmpty())3040 return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");3041 3042 2576 /* 3043 2577 * Create the directories. 3044 2578 */ 3045 HRESULT hrc = S_OK; 3046 if (fVerbose && cDirs) 3047 RTPrintf("Creating %u directories ...\n", cDirs); 3048 3049 ComPtr<IGuestSession> pGuestSession; 3050 hrc = pGuest->CreateSession(Bstr(strUsername).raw(), 3051 Bstr(strPassword).raw(), 3052 Bstr(strDomain).raw(), 3053 Bstr("VBoxManage Guest Control MkDir").raw(), 3054 pGuestSession.asOutParam()); 3055 if (FAILED(hrc)) 3056 { 3057 ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 3058 return RTEXITCODE_FAILURE; 3059 } 2579 HRESULT rc = S_OK; 2580 if (pCtx->fVerbose && cDirs) 2581 RTPrintf("Creating %RU32 directories ...\n", cDirs); 3060 2582 3061 2583 DESTDIRMAPITER it = mapDirs.begin(); 3062 while (it != mapDirs.end()) 3063 { 3064 if (fVerbose) 2584 while ( (it != mapDirs.end()) 2585 && !g_fGuestCtrlCanceled) 2586 { 2587 if (pCtx->fVerbose) 3065 2588 RTPrintf("Creating directory \"%s\" ...\n", it->first.c_str()); 3066 2589 3067 hrc = pGuestSession->DirectoryCreate(Bstr(it->first).raw(), fDirMode, ComSafeArrayAsInParam(dirCreateFlags)); 3068 if (FAILED(hrc)) 3069 { 3070 ctrlPrintError(pGuest, COM_IIDOF(IGuestSession)); /* Return code ignored, save original rc. */ 3071 break; 3072 } 3073 2590 CHECK_ERROR_BREAK(pCtx->pGuestSession, DirectoryCreate(Bstr(it->first).raw(), 2591 fDirMode, ComSafeArrayAsInParam(dirCreateFlags))); 3074 2592 it++; 3075 2593 } 3076 2594 3077 if (!pGuestSession.isNull()) 3078 pGuestSession->Close(); 3079 3080 return FAILED(hrc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS; 3081 } 3082 3083 static RTEXITCODE handleCtrlCreateTemp(ComPtr<IGuest> pGuest, HandlerArg *pArg) 3084 { 3085 AssertPtrReturn(pArg, RTEXITCODE_SYNTAX); 2595 return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS; 2596 } 2597 2598 static DECLCALLBACK(RTEXITCODE) handleCtrlRemoveDirectory(PGCTLCMDCTX pCtx) 2599 { 2600 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3086 2601 3087 2602 /* … … 3093 2608 static const RTGETOPTDEF s_aOptions[] = 3094 2609 { 2610 { "--recursive", GETOPTDEF_RMDIR_RECURSIVE, RTGETOPT_REQ_NOTHING } 2611 }; 2612 2613 int ch; 2614 RTGETOPTUNION ValueUnion; 2615 RTGETOPTSTATE GetState; 2616 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 2617 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 2618 2619 bool fRecursive = false; 2620 DESTDIRMAP mapDirs; 2621 2622 while ((ch = RTGetOpt(&GetState, &ValueUnion))) 2623 { 2624 /* For options that require an argument, ValueUnion has received the value. */ 2625 switch (ch) 2626 { 2627 case GETOPTDEF_RMDIR_RECURSIVE: 2628 fRecursive = true; 2629 break; 2630 2631 case VINF_GETOPT_NOT_OPTION: 2632 mapDirs[ValueUnion.psz]; /* Add destination directory to map. */ 2633 break; 2634 2635 default: 2636 return RTGetOptPrintError(ch, &ValueUnion); 2637 break; 2638 } 2639 } 2640 2641 uint32_t cDirs = mapDirs.size(); 2642 if (!cDirs) 2643 return errorSyntax(USAGE_GUESTCONTROL, "No directory to remove specified!"); 2644 2645 /* 2646 * Remove the directories. 2647 */ 2648 HRESULT rc = S_OK; 2649 if (pCtx->fVerbose && cDirs) 2650 RTPrintf("Removing %RU32 directories ...\n", cDirs); 2651 2652 DESTDIRMAPITER it = mapDirs.begin(); 2653 while ( (it != mapDirs.end()) 2654 && !g_fGuestCtrlCanceled) 2655 { 2656 if (pCtx->fVerbose) 2657 RTPrintf("%s directory \"%s\" ...\n", 2658 fRecursive ? "Recursively removing" : "Removing", 2659 it->first.c_str()); 2660 try 2661 { 2662 if (fRecursive) 2663 { 2664 com::SafeArray<DirectoryRemoveRecFlag_T> aRemRecFlags; 2665 /** @todo Make flags configurable. */ 2666 aRemRecFlags.push_back(DirectoryRemoveRecFlag_ContentAndDir); 2667 2668 ComPtr<IProgress> pProgress; 2669 CHECK_ERROR_BREAK(pCtx->pGuestSession, DirectoryRemoveRecursive(Bstr(it->first).raw(), 2670 ComSafeArrayAsInParam(aRemRecFlags), 2671 pProgress.asOutParam())); 2672 if (pCtx->fVerbose) 2673 rc = showProgress(pProgress); 2674 else 2675 rc = pProgress->WaitForCompletion(-1 /* No timeout */); 2676 if (SUCCEEDED(rc)) 2677 CHECK_PROGRESS_ERROR(pProgress, ("Directory deletion failed")); 2678 } 2679 else 2680 CHECK_ERROR_BREAK(pCtx->pGuestSession, DirectoryRemove(Bstr(it->first).raw())); 2681 } 2682 catch (std::bad_alloc) 2683 { 2684 rc = E_OUTOFMEMORY; 2685 break; 2686 } 2687 2688 it++; 2689 } 2690 2691 return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS; 2692 } 2693 2694 static DECLCALLBACK(RTEXITCODE) handleCtrlRemoveFile(PGCTLCMDCTX pCtx) 2695 { 2696 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 2697 2698 /* 2699 * Parse arguments. 2700 * 2701 * Note! No direct returns here, everyone must go thru the cleanup at the 2702 * end of this function. 2703 */ 2704 static const RTGETOPTDEF s_aOptions[] = { 0 }; 2705 2706 int ch; 2707 RTGETOPTUNION ValueUnion; 2708 RTGETOPTSTATE GetState; 2709 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 2710 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 2711 2712 DESTDIRMAP mapDirs; 2713 2714 while ((ch = RTGetOpt(&GetState, &ValueUnion))) 2715 { 2716 /* For options that require an argument, ValueUnion has received the value. */ 2717 switch (ch) 2718 { 2719 case VINF_GETOPT_NOT_OPTION: 2720 mapDirs[ValueUnion.psz]; /* Add destination directory to map. */ 2721 break; 2722 2723 default: 2724 return RTGetOptPrintError(ch, &ValueUnion); 2725 break; 2726 } 2727 } 2728 2729 uint32_t cFiles = mapDirs.size(); 2730 if (!cFiles) 2731 return errorSyntax(USAGE_GUESTCONTROL, "No file to remove specified!"); 2732 2733 /* 2734 * Create the directories. 2735 */ 2736 HRESULT rc = S_OK; 2737 if (pCtx->fVerbose && cFiles) 2738 RTPrintf("Removing %RU32 file(s) ...\n", cFiles); 2739 2740 DESTDIRMAPITER it = mapDirs.begin(); 2741 while ( (it != mapDirs.end()) 2742 && !g_fGuestCtrlCanceled) 2743 { 2744 if (pCtx->fVerbose) 2745 RTPrintf("Removing file \"%s\" ...\n", it->first.c_str()); 2746 2747 CHECK_ERROR_BREAK(pCtx->pGuestSession, FileRemove(Bstr(it->first).raw())); 2748 2749 it++; 2750 } 2751 2752 return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS; 2753 } 2754 2755 static DECLCALLBACK(RTEXITCODE) handleCtrlCreateTemp(PGCTLCMDCTX pCtx) 2756 { 2757 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 2758 2759 /* 2760 * Parse arguments. 2761 * 2762 * Note! No direct returns here, everyone must go thru the cleanup at the 2763 * end of this function. 2764 */ 2765 static const RTGETOPTDEF s_aOptions[] = 2766 { 3095 2767 { "--mode", 'm', RTGETOPT_REQ_UINT32 }, 3096 2768 { "--directory", 'D', RTGETOPT_REQ_NOTHING }, 3097 2769 { "--secure", 's', RTGETOPT_REQ_NOTHING }, 3098 { "--tmpdir", 't', RTGETOPT_REQ_STRING }, 3099 { "--username", 'u', RTGETOPT_REQ_STRING }, 3100 { "--passwordfile", 'p', RTGETOPT_REQ_STRING }, 3101 { "--password", GETOPTDEF_MKDIR_PASSWORD, RTGETOPT_REQ_STRING }, 3102 { "--domain", 'd', RTGETOPT_REQ_STRING }, 3103 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 2770 { "--tmpdir", 't', RTGETOPT_REQ_STRING } 3104 2771 }; 3105 2772 … … 3107 2774 RTGETOPTUNION ValueUnion; 3108 2775 RTGETOPTSTATE GetState; 3109 RTGetOptInit(&GetState, pArg->argc, pArg->argv, 3110 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3111 3112 Utf8Str strUsername; 3113 Utf8Str strPassword; 3114 Utf8Str strDomain; 2776 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 2777 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 2778 3115 2779 Utf8Str strTemplate; 3116 2780 uint32_t fMode = 0; /* Default mode. */ … … 3118 2782 bool fSecure = false; 3119 2783 Utf8Str strTempDir; 3120 bool fVerbose = false;3121 2784 3122 2785 DESTDIRMAP mapDirs; … … 3141 2804 case 't': /* Temp directory */ 3142 2805 strTempDir = ValueUnion.psz; 3143 break;3144 3145 case 'u': /* User name */3146 strUsername = ValueUnion.psz;3147 break;3148 3149 case GETOPTDEF_MKDIR_PASSWORD: /* Password */3150 strPassword = ValueUnion.psz;3151 break;3152 3153 case 'p': /* Password file */3154 {3155 RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);3156 if (rcExit != RTEXITCODE_SUCCESS)3157 return rcExit;3158 break;3159 }3160 3161 case 'd': /* domain */3162 strDomain = ValueUnion.psz;3163 break;3164 3165 case 'v': /* Verbose */3166 fVerbose = true;3167 2806 break; 3168 2807 … … 3179 2818 default: 3180 2819 return RTGetOptPrintError(ch, &ValueUnion); 2820 break; 3181 2821 } 3182 2822 } … … 3184 2824 if (strTemplate.isEmpty()) 3185 2825 return errorSyntax(USAGE_GUESTCONTROL, "No template specified!"); 3186 3187 if (strUsername.isEmpty())3188 return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");3189 2826 3190 2827 if (!fDirectory) … … 3194 2831 * Create the directories. 3195 2832 */ 3196 HRESULT hrc = S_OK; 3197 if (fVerbose) 2833 if (pCtx->fVerbose) 3198 2834 { 3199 2835 if (fDirectory && !strTempDir.isEmpty()) … … 3211 2847 } 3212 2848 3213 ComPtr<IGuestSession> pGuestSession; 3214 hrc = pGuest->CreateSession(Bstr(strUsername).raw(), 3215 Bstr(strPassword).raw(), 3216 Bstr(strDomain).raw(), 3217 Bstr("VBoxManage Guest Control MkTemp").raw(), 3218 pGuestSession.asOutParam()); 3219 if (FAILED(hrc)) 3220 { 3221 ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 3222 return RTEXITCODE_FAILURE; 3223 } 3224 2849 HRESULT rc = S_OK; 3225 2850 if (fDirectory) 3226 2851 { 3227 2852 Bstr directory; 3228 hrc = pGuestSession->DirectoryCreateTemp(Bstr(strTemplate).raw(),3229 fMode, Bstr(strTempDir).raw(),3230 fSecure,3231 directory.asOutParam());3232 if (SUCCEEDED( hrc))2853 CHECK_ERROR(pCtx->pGuestSession, DirectoryCreateTemp(Bstr(strTemplate).raw(), 2854 fMode, Bstr(strTempDir).raw(), 2855 fSecure, 2856 directory.asOutParam())); 2857 if (SUCCEEDED(rc)) 3233 2858 RTPrintf("Directory name: %ls\n", directory.raw()); 3234 2859 } 3235 2860 // else - temporary file not yet implemented 3236 if (FAILED(hrc)) 3237 ctrlPrintError(pGuest, COM_IIDOF(IGuestSession)); /* Return code ignored, save original rc. */ 3238 3239 if (!pGuestSession.isNull()) 3240 pGuestSession->Close(); 3241 3242 return FAILED(hrc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS; 3243 } 3244 3245 static int handleCtrlStat(ComPtr<IGuest> pGuest, HandlerArg *pArg) 3246 { 3247 AssertPtrReturn(pArg, VERR_INVALID_PARAMETER); 2861 2862 return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS; 2863 } 2864 2865 static DECLCALLBACK(RTEXITCODE) handleCtrlStat(PGCTLCMDCTX pCtx) 2866 { 2867 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3248 2868 3249 2869 static const RTGETOPTDEF s_aOptions[] = … … 3252 2872 { "--file-system", 'f', RTGETOPT_REQ_NOTHING }, 3253 2873 { "--format", 'c', RTGETOPT_REQ_STRING }, 3254 { "--username", 'u', RTGETOPT_REQ_STRING }, 3255 { "--passwordfile", 'p', RTGETOPT_REQ_STRING }, 3256 { "--password", GETOPTDEF_STAT_PASSWORD, RTGETOPT_REQ_STRING }, 3257 { "--domain", 'd', RTGETOPT_REQ_STRING }, 3258 { "--terse", 't', RTGETOPT_REQ_NOTHING }, 3259 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 2874 { "--terse", 't', RTGETOPT_REQ_NOTHING } 3260 2875 }; 3261 2876 … … 3263 2878 RTGETOPTUNION ValueUnion; 3264 2879 RTGETOPTSTATE GetState; 3265 RTGetOptInit(&GetState, pArg->argc, pArg->argv, 3266 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3267 3268 Utf8Str strUsername; 3269 Utf8Str strPassword; 3270 Utf8Str strDomain; 3271 3272 bool fVerbose = false; 2880 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 2881 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 2882 3273 2883 DESTDIRMAP mapObjs; 3274 2884 3275 2885 while ((ch = RTGetOpt(&GetState, &ValueUnion))) 3276 2886 { 2887 RTPrintf("val: %s=%d\n", ValueUnion.psz, ch); 2888 3277 2889 /* For options that require an argument, ValueUnion has received the value. */ 3278 2890 switch (ch) 3279 2891 { 3280 case 'u': /* User name */3281 strUsername = ValueUnion.psz;3282 break;3283 3284 case GETOPTDEF_STAT_PASSWORD: /* Password */3285 strPassword = ValueUnion.psz;3286 break;3287 3288 case 'p': /* Password file */3289 {3290 RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);3291 if (rcExit != RTEXITCODE_SUCCESS)3292 return rcExit;3293 break;3294 }3295 3296 case 'd': /* domain */3297 strDomain = ValueUnion.psz;3298 break;3299 3300 2892 case 'L': /* Dereference */ 3301 2893 case 'f': /* File-system */ … … 3306 2898 break; /* Never reached. */ 3307 2899 3308 case 'v': /* Verbose */3309 fVerbose = true;3310 break;3311 3312 2900 case VINF_GETOPT_NOT_OPTION: 3313 {3314 2901 mapObjs[ValueUnion.psz]; /* Add element to check to map. */ 3315 2902 break; 3316 }3317 2903 3318 2904 default: 3319 2905 return RTGetOptPrintError(ch, &ValueUnion); 2906 break; 3320 2907 } 3321 2908 } … … 3325 2912 return errorSyntax(USAGE_GUESTCONTROL, "No element(s) to check specified!"); 3326 2913 3327 if (strUsername.isEmpty()) 3328 return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!"); 3329 3330 ComPtr<IGuestSession> pGuestSession; 3331 HRESULT hrc = pGuest->CreateSession(Bstr(strUsername).raw(), 3332 Bstr(strPassword).raw(), 3333 Bstr(strDomain).raw(), 3334 Bstr("VBoxManage Guest Control Stat").raw(), 3335 pGuestSession.asOutParam()); 3336 if (FAILED(hrc)) 3337 return ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 2914 HRESULT rc; 3338 2915 3339 2916 /* 3340 * Create the directories.2917 * Doing the checks. 3341 2918 */ 3342 2919 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; … … 3344 2921 while (it != mapObjs.end()) 3345 2922 { 3346 if ( fVerbose)2923 if (pCtx->fVerbose) 3347 2924 RTPrintf("Checking for element \"%s\" ...\n", it->first.c_str()); 3348 2925 3349 2926 ComPtr<IGuestFsObjInfo> pFsObjInfo; 3350 hrc =pGuestSession->FileQueryInfo(Bstr(it->first).raw(), pFsObjInfo.asOutParam());3351 if (FAILED( hrc))3352 hrc =pGuestSession->DirectoryQueryInfo(Bstr(it->first).raw(), pFsObjInfo.asOutParam());3353 3354 if (FAILED( hrc))2927 rc = pCtx->pGuestSession->FileQueryInfo(Bstr(it->first).raw(), pFsObjInfo.asOutParam()); 2928 if (FAILED(rc)) 2929 rc = pCtx->pGuestSession->DirectoryQueryInfo(Bstr(it->first).raw(), pFsObjInfo.asOutParam()); 2930 2931 if (FAILED(rc)) 3355 2932 { 3356 2933 /* If there's at least one element which does not exist on the guest, 3357 2934 * drop out with exitcode 1. */ 3358 if ( fVerbose)2935 if (pCtx->fVerbose) 3359 2936 RTPrintf("Cannot stat for element \"%s\": No such element\n", 3360 2937 it->first.c_str()); … … 3364 2941 { 3365 2942 FsObjType_T objType; 3366 hrc = pFsObjInfo->COMGETTER(Type)(&objType); 3367 if (FAILED(hrc)) 3368 return ctrlPrintError(pGuest, COM_IIDOF(IGuestFsObjInfo)); 2943 pFsObjInfo->COMGETTER(Type)(&objType); 3369 2944 switch (objType) 3370 2945 { … … 3392 2967 } 3393 2968 3394 if (!pGuestSession.isNull())3395 pGuestSession->Close();3396 3397 2969 return rcExit; 3398 2970 } 3399 2971 3400 static int handleCtrlUpdateAdditions(ComPtr<IGuest> guest, HandlerArg *pArg)3401 { 3402 AssertPtrReturn(p Arg, VERR_INVALID_PARAMETER);2972 static DECLCALLBACK(RTEXITCODE) handleCtrlUpdateAdditions(PGCTLCMDCTX pCtx) 2973 { 2974 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3403 2975 3404 2976 /* … … 3408 2980 Utf8Str strSource; 3409 2981 com::SafeArray<IN_BSTR> aArgs; 3410 bool fVerbose = false;3411 2982 bool fWaitStartOnly = false; 3412 2983 … … 3414 2985 { 3415 2986 { "--source", 's', RTGETOPT_REQ_STRING }, 3416 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },3417 2987 { "--wait-start", 'w', RTGETOPT_REQ_NOTHING } 3418 2988 }; … … 3421 2991 RTGETOPTUNION ValueUnion; 3422 2992 RTGETOPTSTATE GetState; 3423 RTGetOptInit(&GetState, p Arg->argc, pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);2993 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, 0); 3424 2994 3425 2995 int vrc = VINF_SUCCESS; … … 3433 3003 break; 3434 3004 3435 case 'v':3436 fVerbose = true;3437 break;3438 3439 3005 case 'w': 3440 3006 fWaitStartOnly = true; … … 3442 3008 3443 3009 case VINF_GETOPT_NOT_OPTION: 3444 {3445 3010 if (aArgs.size() == 0 && strSource.isEmpty()) 3446 3011 strSource = ValueUnion.psz; … … 3448 3013 aArgs.push_back(Bstr(ValueUnion.psz).raw()); 3449 3014 break; 3450 }3451 3015 3452 3016 default: 3453 3017 return RTGetOptPrintError(ch, &ValueUnion); 3454 } 3455 } 3456 3457 if (fVerbose) 3018 break; 3019 } 3020 } 3021 3022 if (pCtx->fVerbose) 3458 3023 RTPrintf("Updating Guest Additions ...\n"); 3459 3024 … … 3462 3027 { 3463 3028 ComPtr<ISystemProperties> pProperties; 3464 CHECK_ERROR_BREAK(p Arg->virtualBox, COMGETTER(SystemProperties)(pProperties.asOutParam()));3029 CHECK_ERROR_BREAK(pCtx->handlerArg.virtualBox, COMGETTER(SystemProperties)(pProperties.asOutParam())); 3465 3030 Bstr strISO; 3466 3031 CHECK_ERROR_BREAK(pProperties, COMGETTER(DefaultAdditionsISO)(strISO.asOutParam())); … … 3483 3048 if (RT_SUCCESS(vrc)) 3484 3049 { 3485 if ( fVerbose)3050 if (pCtx->fVerbose) 3486 3051 RTPrintf("Using source: %s\n", strSource.c_str()); 3487 3052 … … 3490 3055 { 3491 3056 aUpdateFlags.push_back(AdditionsUpdateFlag_WaitForUpdateStartOnly); 3492 if ( fVerbose)3057 if (pCtx->fVerbose) 3493 3058 RTPrintf("Preparing and waiting for Guest Additions installer to start ...\n"); 3494 3059 } 3495 3060 3496 3061 ComPtr<IProgress> pProgress; 3497 CHECK_ERROR( guest, UpdateGuestAdditions(Bstr(strSource).raw(),3062 CHECK_ERROR(pCtx->pGuest, UpdateGuestAdditions(Bstr(strSource).raw(), 3498 3063 ComSafeArrayAsInParam(aArgs), 3499 3064 /* Wait for whole update process to complete. */ … … 3501 3066 pProgress.asOutParam())); 3502 3067 if (FAILED(rc)) 3503 vrc = ctrlPrintError( guest, COM_IIDOF(IGuest));3068 vrc = ctrlPrintError(pCtx->pGuest, COM_IIDOF(IGuest)); 3504 3069 else 3505 3070 { 3506 if ( fVerbose)3071 if (pCtx->fVerbose) 3507 3072 rc = showProgress(pProgress); 3508 3073 else … … 3513 3078 vrc = ctrlPrintProgressError(pProgress); 3514 3079 if ( RT_SUCCESS(vrc) 3515 && fVerbose)3080 && pCtx->fVerbose) 3516 3081 { 3517 3082 RTPrintf("Guest Additions update successful\n"); … … 3523 3088 } 3524 3089 3525 static RTEXITCODE handleCtrlList(ComPtr<IGuest> guest, HandlerArg *pArg)3526 { 3527 AssertPtrReturn(p Arg, RTEXITCODE_SYNTAX);3528 3529 if (p Arg->argc < 1)3090 static DECLCALLBACK(RTEXITCODE) handleCtrlList(PGCTLCMDCTX pCtx) 3091 { 3092 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3093 3094 if (pCtx->iArgc < 1) 3530 3095 return errorSyntax(USAGE_GUESTCONTROL, "Must specify a listing category"); 3531 3096 … … 3538 3103 bool fListProcesses = false; 3539 3104 bool fListFiles = false; 3540 if ( !RTStrICmp(p Arg->argv[0], "sessions")3541 || !RTStrICmp(p Arg->argv[0], "sess"))3105 if ( !RTStrICmp(pCtx->ppaArgv[0], "sessions") 3106 || !RTStrICmp(pCtx->ppaArgv[0], "sess")) 3542 3107 fListSessions = true; 3543 else if ( !RTStrICmp(p Arg->argv[0], "processes")3544 || !RTStrICmp(p Arg->argv[0], "procs"))3108 else if ( !RTStrICmp(pCtx->ppaArgv[0], "processes") 3109 || !RTStrICmp(pCtx->ppaArgv[0], "procs")) 3545 3110 fListSessions = fListProcesses = true; /* Showing processes implies showing sessions. */ 3546 else if ( !RTStrICmp(p Arg->argv[0], "files"))3111 else if ( !RTStrICmp(pCtx->ppaArgv[0], "files")) 3547 3112 fListSessions = fListFiles = true; /* Showing files implies showing sessions. */ 3548 else if (!RTStrICmp(p Arg->argv[0], "all"))3113 else if (!RTStrICmp(pCtx->ppaArgv[0], "all")) 3549 3114 fListAll = true; 3550 3115 … … 3562 3127 3563 3128 SafeIfaceArray <IGuestSession> collSessions; 3564 CHECK_ERROR_BREAK( guest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions)));3129 CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions))); 3565 3130 size_t cSessions = collSessions.size(); 3566 3131 … … 3652 3217 } 3653 3218 else 3654 return errorSyntax(USAGE_GUESTCONTROL, "Invalid listing category '%s", p Arg->argv[0]);3219 return errorSyntax(USAGE_GUESTCONTROL, "Invalid listing category '%s", pCtx->ppaArgv[0]); 3655 3220 3656 3221 return rcExit; 3657 3222 } 3658 3223 3659 static RTEXITCODE handleCtrlProcessClose(ComPtr<IGuest> guest, HandlerArg *pArg)3660 { 3661 AssertPtrReturn(p Arg, RTEXITCODE_SYNTAX);3662 3663 if (p Arg->argc < 1)3224 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessClose(PGCTLCMDCTX pCtx) 3225 { 3226 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3227 3228 if (pCtx->iArgc < 1) 3664 3229 return errorSyntax(USAGE_GUESTCONTROL, "Must specify at least a PID to close"); 3665 3230 … … 3673 3238 { 3674 3239 { "--session-id", 'i', RTGETOPT_REQ_UINT32 }, 3675 { "--session-name", 'n', RTGETOPT_REQ_STRING }, 3676 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 3240 { "--session-name", 'n', RTGETOPT_REQ_STRING } 3677 3241 }; 3678 3242 … … 3680 3244 RTGETOPTUNION ValueUnion; 3681 3245 RTGETOPTSTATE GetState; 3682 RTGetOptInit(&GetState, p Arg->argc, pArg->argv,3683 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);3246 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 3247 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3684 3248 3685 3249 std::vector < uint32_t > vecPID; 3686 3250 ULONG ulSessionID = UINT32_MAX; 3687 3251 Utf8Str strSessionName; 3688 bool fVerbose = false;3689 3252 3690 3253 int vrc = VINF_SUCCESS; … … 3704 3267 break; 3705 3268 3706 case 'v': /* Verbose */3707 fVerbose = true;3708 break;3709 3710 3269 case VINF_GETOPT_NOT_OPTION: 3711 if (p Arg->argc == GetState.iNext)3270 if (pCtx->iArgc == GetState.iNext) 3712 3271 { 3713 3272 /* Treat every else specified as a PID to kill. */ … … 3730 3289 default: 3731 3290 return RTGetOptPrintError(ch, &ValueUnion); 3291 break; 3732 3292 } 3733 3293 } … … 3759 3319 3760 3320 SafeIfaceArray <IGuestSession> collSessions; 3761 CHECK_ERROR_BREAK( guest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions)));3321 CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions))); 3762 3322 size_t cSessions = collSessions.size(); 3763 3323 … … 3810 3370 if (fProcFound) 3811 3371 { 3812 if ( fVerbose)3372 if (pCtx->fVerbose) 3813 3373 RTPrintf("Terminating process (PID %RU32) (session ID %RU32) ...\n", 3814 3374 uPID, uID); … … 3845 3405 } 3846 3406 3847 static RTEXITCODE handleCtrlProcess(ComPtr<IGuest> guest, HandlerArg *pArg)3848 { 3849 AssertPtrReturn(p Arg, RTEXITCODE_SYNTAX);3850 3851 if (p Arg->argc < 1)3407 static DECLCALLBACK(RTEXITCODE) handleCtrlProcess(PGCTLCMDCTX pCtx) 3408 { 3409 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3410 3411 if (pCtx->iArgc < 1) 3852 3412 return errorSyntax(USAGE_GUESTCONTROL, "Must specify an action"); 3853 3413 3854 3414 /** Use RTGetOpt here when handling command line args gets more complex. */ 3855 3415 3856 HandlerArg argSub = *pArg; 3857 argSub.argc = pArg->argc - 1; /* Skip session action. */ 3858 argSub.argv = pArg->argv + 1; /* Same here. */ 3859 3860 if ( !RTStrICmp(pArg->argv[0], "close") 3861 || !RTStrICmp(pArg->argv[0], "kill") 3862 || !RTStrICmp(pArg->argv[0], "terminate")) 3863 { 3864 return handleCtrlProcessClose(guest, &argSub); 3865 } 3866 3867 return errorSyntax(USAGE_GUESTCONTROL, "Invalid process action '%s'", pArg->argv[0]); 3868 } 3869 3870 static RTEXITCODE handleCtrlSessionClose(ComPtr<IGuest> guest, HandlerArg *pArg) 3871 { 3872 AssertPtrReturn(pArg, RTEXITCODE_SYNTAX); 3873 3874 if (pArg->argc < 1) 3416 if ( !RTStrICmp(pCtx->ppaArgv[0], "close") 3417 || !RTStrICmp(pCtx->ppaArgv[0], "kill") 3418 || !RTStrICmp(pCtx->ppaArgv[0], "terminate")) 3419 { 3420 pCtx->iFirstArgc++; /* Skip process action. */ 3421 return handleCtrlProcessClose(pCtx); 3422 } 3423 3424 return errorSyntax(USAGE_GUESTCONTROL, "Invalid process action '%s'", pCtx->ppaArgv[0]); 3425 } 3426 3427 static DECLCALLBACK(RTEXITCODE) handleCtrlSessionClose(PGCTLCMDCTX pCtx) 3428 { 3429 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3430 3431 if (pCtx->iArgc < 1) 3875 3432 return errorSyntax(USAGE_GUESTCONTROL, "Must specify at least a session ID to close"); 3876 3433 … … 3885 3442 { "--all", GETOPTDEF_SESSIONCLOSE_ALL, RTGETOPT_REQ_NOTHING }, 3886 3443 { "--session-id", 'i', RTGETOPT_REQ_UINT32 }, 3887 { "--session-name", 'n', RTGETOPT_REQ_STRING }, 3888 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 3444 { "--session-name", 'n', RTGETOPT_REQ_STRING } 3889 3445 }; 3890 3446 … … 3892 3448 RTGETOPTUNION ValueUnion; 3893 3449 RTGETOPTSTATE GetState; 3894 RTGetOptInit(&GetState, p Arg->argc, pArg->argv,3895 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);3450 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 3451 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3896 3452 3897 3453 ULONG ulSessionID = UINT32_MAX; 3898 3454 Utf8Str strSessionName; 3899 bool fVerbose = false;3900 3455 3901 3456 while ((ch = RTGetOpt(&GetState, &ValueUnion))) … … 3912 3467 break; 3913 3468 3914 case 'v': /* Verbose */3915 fVerbose = true;3916 break;3917 3918 3469 case GETOPTDEF_SESSIONCLOSE_ALL: 3919 3470 strSessionName = "*"; … … 3926 3477 default: 3927 3478 return RTGetOptPrintError(ch, &ValueUnion); 3479 break; 3928 3480 } 3929 3481 } … … 3949 3501 3950 3502 SafeIfaceArray <IGuestSession> collSessions; 3951 CHECK_ERROR_BREAK( guest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions)));3503 CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions))); 3952 3504 size_t cSessions = collSessions.size(); 3953 3505 … … 3978 3530 3979 3531 Assert(!pSession.isNull()); 3980 if ( fVerbose)3532 if (pCtx->fVerbose) 3981 3533 RTPrintf("Closing guest session ID=#%RU32 \"%s\" ...\n", 3982 3534 uID, strNameUtf8.c_str()); 3983 3535 CHECK_ERROR_BREAK(pSession, Close()); 3984 if ( fVerbose)3536 if (pCtx->fVerbose) 3985 3537 RTPrintf("Guest session successfully closed\n"); 3986 3538 … … 4000 3552 } 4001 3553 4002 static RTEXITCODE handleCtrlSession(ComPtr<IGuest> guest, HandlerArg *pArg)4003 { 4004 AssertPtrReturn(p Arg, RTEXITCODE_SYNTAX);4005 4006 if (p Arg->argc < 1)3554 static DECLCALLBACK(RTEXITCODE) handleCtrlSession(PGCTLCMDCTX pCtx) 3555 { 3556 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3557 3558 if (pCtx->iArgc < 1) 4007 3559 return errorSyntax(USAGE_GUESTCONTROL, "Must specify an action"); 4008 3560 4009 3561 /** Use RTGetOpt here when handling command line args gets more complex. */ 4010 3562 4011 HandlerArg argSub = *pArg; 4012 argSub.argc = pArg->argc - 1; /* Skip session action. */ 4013 argSub.argv = pArg->argv + 1; /* Same here. */ 4014 4015 if ( !RTStrICmp(pArg->argv[0], "close") 4016 || !RTStrICmp(pArg->argv[0], "kill") 4017 || !RTStrICmp(pArg->argv[0], "terminate")) 4018 { 4019 return handleCtrlSessionClose(guest, &argSub); 4020 } 4021 4022 return errorSyntax(USAGE_GUESTCONTROL, "Invalid session action '%s'", pArg->argv[0]); 4023 } 4024 4025 static RTEXITCODE handleCtrlWatch(ComPtr<IGuest> guest, HandlerArg *pArg) 4026 { 4027 AssertPtrReturn(pArg, RTEXITCODE_SYNTAX); 3563 if ( !RTStrICmp(pCtx->ppaArgv[0], "close") 3564 || !RTStrICmp(pCtx->ppaArgv[0], "kill") 3565 || !RTStrICmp(pCtx->ppaArgv[0], "terminate")) 3566 { 3567 pCtx->iFirstArgc++; /* Skip session action. */ 3568 return handleCtrlSessionClose(pCtx); 3569 } 3570 3571 return errorSyntax(USAGE_GUESTCONTROL, "Invalid session action '%s'", pCtx->ppaArgv[0]); 3572 } 3573 3574 static DECLCALLBACK(RTEXITCODE) handleCtrlWatch(PGCTLCMDCTX pCtx) 3575 { 3576 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 4028 3577 4029 3578 /* 4030 3579 * Parse arguments. 4031 3580 */ 4032 static const RTGETOPTDEF s_aOptions[] = 4033 { 4034 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 4035 }; 3581 static const RTGETOPTDEF s_aOptions[] = { 0 }; 4036 3582 4037 3583 int ch; 4038 3584 RTGETOPTUNION ValueUnion; 4039 3585 RTGETOPTSTATE GetState; 4040 RTGetOptInit(&GetState, pArg->argc, pArg->argv, 4041 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST); 4042 4043 bool fVerbose = false; 3586 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 3587 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 4044 3588 4045 3589 while ((ch = RTGetOpt(&GetState, &ValueUnion))) … … 4048 3592 switch (ch) 4049 3593 { 4050 case 'v': /* Verbose */4051 fVerbose = true;4052 break;4053 4054 3594 case VINF_GETOPT_NOT_OPTION: 4055 3595 break; … … 4057 3597 default: 4058 3598 return RTGetOptPrintError(ch, &ValueUnion); 3599 break; 4059 3600 } 4060 3601 } … … 4076 3617 /* Register for IGuest events. */ 4077 3618 ComPtr<IEventSource> es; 4078 CHECK_ERROR_BREAK( guest, COMGETTER(EventSource)(es.asOutParam()));3619 CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(EventSource)(es.asOutParam())); 4079 3620 com::SafeArray<VBoxEventType_T> eventTypes; 4080 3621 eventTypes.push_back(VBoxEventType_OnGuestSessionRegistered); … … 4087 3628 } while (0); 4088 3629 4089 ctrlSignalHandlerInstall(); 4090 4091 if (fVerbose) 3630 if (pCtx->fVerbose) 4092 3631 RTPrintf("Waiting for events ...\n"); 4093 3632 … … 4098 3637 } 4099 3638 4100 if ( fVerbose)3639 if (pCtx->fVerbose) 4101 3640 RTPrintf("Signal caught, exiting ...\n"); 4102 4103 ctrlSignalHandlerUninstall();4104 3641 4105 3642 if (!pGuestListener.isNull()) … … 4107 3644 /* Guest callback unregistration. */ 4108 3645 ComPtr<IEventSource> pES; 4109 CHECK_ERROR( guest, COMGETTER(EventSource)(pES.asOutParam()));3646 CHECK_ERROR(pCtx->pGuest, COMGETTER(EventSource)(pES.asOutParam())); 4110 3647 if (!pES.isNull()) 4111 3648 CHECK_ERROR(pES, UnregisterListener(pGuestListener)); … … 4129 3666 int handleGuestControl(HandlerArg *pArg) 4130 3667 { 4131 AssertPtrReturn(pArg, VERR_INVALID_P ARAMETER);3668 AssertPtrReturn(pArg, VERR_INVALID_POINTER); 4132 3669 4133 3670 #ifdef DEBUG_andy_disabled … … 4136 3673 #endif 4137 3674 4138 HandlerArg arg = *pArg; 4139 arg.argc = pArg->argc - 2; /* Skip VM name and sub command. */ 4140 arg.argv = pArg->argv + 2; /* Same here. */ 4141 4142 ComPtr<IGuest> guest; 4143 int vrc = ctrlInitVM(pArg, pArg->argv[0] /* VM Name */, &guest); 4144 if (RT_SUCCESS(vrc)) 4145 { 4146 int rcExit; 4147 if (pArg->argc < 2) 4148 rcExit = errorSyntax(USAGE_GUESTCONTROL, "No sub command specified!"); 4149 else if ( !RTStrICmp(pArg->argv[1], "exec") 4150 || !RTStrICmp(pArg->argv[1], "execute")) 4151 rcExit = handleCtrlProcessExec(guest, &arg); 4152 else if (!RTStrICmp(pArg->argv[1], "copyfrom")) 4153 rcExit = handleCtrlCopy(guest, &arg, false /* Guest to host */); 4154 else if ( !RTStrICmp(pArg->argv[1], "copyto") 4155 || !RTStrICmp(pArg->argv[1], "cp")) 4156 rcExit = handleCtrlCopy(guest, &arg, true /* Host to guest */); 4157 else if ( !RTStrICmp(pArg->argv[1], "createdirectory") 4158 || !RTStrICmp(pArg->argv[1], "createdir") 4159 || !RTStrICmp(pArg->argv[1], "mkdir") 4160 || !RTStrICmp(pArg->argv[1], "md")) 4161 rcExit = handleCtrlCreateDirectory(guest, &arg); 4162 else if ( !RTStrICmp(pArg->argv[1], "createtemporary") 4163 || !RTStrICmp(pArg->argv[1], "createtemp") 4164 || !RTStrICmp(pArg->argv[1], "mktemp")) 4165 rcExit = handleCtrlCreateTemp(guest, &arg); 4166 else if ( !RTStrICmp(pArg->argv[1], "kill") /* Linux. */ 4167 || !RTStrICmp(pArg->argv[1], "pkill") /* Solaris / *BSD. */ 4168 || !RTStrICmp(pArg->argv[1], "pskill")) /* SysInternals version. */ 4169 { 4170 /** @todo What about "taskkill" on Windows? */ 4171 rcExit = handleCtrlProcessClose(guest, &arg); 4172 } 4173 /** @todo Implement "killall"? */ 4174 else if ( !RTStrICmp(pArg->argv[1], "stat")) 4175 rcExit = handleCtrlStat(guest, &arg); 4176 else if ( !RTStrICmp(pArg->argv[1], "updateadditions") 4177 || !RTStrICmp(pArg->argv[1], "updateadds")) 4178 rcExit = handleCtrlUpdateAdditions(guest, &arg); 4179 else if ( !RTStrICmp(pArg->argv[1], "list")) 4180 rcExit = handleCtrlList(guest, &arg); 4181 else if ( !RTStrICmp(pArg->argv[1], "session")) 4182 rcExit = handleCtrlSession(guest, &arg); 4183 else if ( !RTStrICmp(pArg->argv[1], "process")) 4184 rcExit = handleCtrlProcess(guest, &arg); 4185 else if ( !RTStrICmp(pArg->argv[1], "watch")) 4186 rcExit = handleCtrlWatch(guest, &arg); 4187 else 4188 rcExit = errorSyntax(USAGE_GUESTCONTROL, "Unknown sub command '%s' specified!", pArg->argv[1]); 4189 4190 ctrlUninitVM(pArg); 3675 /* pArg->argv[0] contains the VM name. */ 3676 /* pArg->argv[1] contains the guest control command. */ 3677 if (pArg->argc < 2) 3678 return errorSyntax(USAGE_GUESTCONTROL, "No sub command specified!"); 3679 3680 uint32_t uCmdCtxFlags = 0; 3681 GCTLCMD gctlCmd; 3682 if ( !RTStrICmp(pArg->argv[1], "exec") 3683 || !RTStrICmp(pArg->argv[1], "execute")) 3684 gctlCmd.pfnHandler = handleCtrlProcessExec; 3685 else if (!RTStrICmp(pArg->argv[1], "copyfrom")) 3686 gctlCmd.pfnHandler = handleCtrlCopyFrom; 3687 else if ( !RTStrICmp(pArg->argv[1], "copyto") 3688 || !RTStrICmp(pArg->argv[1], "cp")) 3689 gctlCmd.pfnHandler = handleCtrlCopyTo; 3690 else if ( !RTStrICmp(pArg->argv[1], "createdirectory") 3691 || !RTStrICmp(pArg->argv[1], "createdir") 3692 || !RTStrICmp(pArg->argv[1], "mkdir") 3693 || !RTStrICmp(pArg->argv[1], "md")) 3694 gctlCmd.pfnHandler = handleCtrlCreateDirectory; 3695 else if ( !RTStrICmp(pArg->argv[1], "removedirectory") 3696 || !RTStrICmp(pArg->argv[1], "removedir") 3697 || !RTStrICmp(pArg->argv[1], "rmdir")) 3698 gctlCmd.pfnHandler = handleCtrlRemoveDirectory; 3699 else if ( !RTStrICmp(pArg->argv[1], "rm") 3700 || !RTStrICmp(pArg->argv[1], "removefile")) 3701 gctlCmd.pfnHandler = handleCtrlRemoveFile; 3702 else if ( !RTStrICmp(pArg->argv[1], "createtemporary") 3703 || !RTStrICmp(pArg->argv[1], "createtemp") 3704 || !RTStrICmp(pArg->argv[1], "mktemp")) 3705 gctlCmd.pfnHandler = handleCtrlCreateTemp; 3706 else if ( !RTStrICmp(pArg->argv[1], "kill") /* Linux. */ 3707 || !RTStrICmp(pArg->argv[1], "pkill") /* Solaris / *BSD. */ 3708 || !RTStrICmp(pArg->argv[1], "pskill")) /* SysInternals version. */ 3709 { 3710 /** @todo What about "taskkill" on Windows? */ 3711 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 3712 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 3713 gctlCmd.pfnHandler = handleCtrlProcessClose; 3714 } 3715 /** @todo Implement "killall"? */ 3716 else if ( !RTStrICmp(pArg->argv[1], "stat")) 3717 gctlCmd.pfnHandler = handleCtrlStat; 3718 else if ( !RTStrICmp(pArg->argv[1], "updateadditions") 3719 || !RTStrICmp(pArg->argv[1], "updateadds")) 3720 { 3721 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 3722 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 3723 gctlCmd.pfnHandler = handleCtrlUpdateAdditions; 3724 } 3725 else if ( !RTStrICmp(pArg->argv[1], "list")) 3726 { 3727 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 3728 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 3729 gctlCmd.pfnHandler = handleCtrlList; 3730 } 3731 else if ( !RTStrICmp(pArg->argv[1], "session")) 3732 { 3733 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 3734 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 3735 gctlCmd.pfnHandler = handleCtrlSession; 3736 } 3737 else if ( !RTStrICmp(pArg->argv[1], "process")) 3738 { 3739 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 3740 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 3741 gctlCmd.pfnHandler = handleCtrlProcess; 3742 } 3743 else if ( !RTStrICmp(pArg->argv[1], "watch")) 3744 { 3745 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 3746 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 3747 gctlCmd.pfnHandler = handleCtrlWatch; 3748 } 3749 else 3750 return errorSyntax(USAGE_GUESTCONTROL, "Unknown sub command '%s' specified!", pArg->argv[1]); 3751 3752 GCTLCMDCTX cmdCtx; 3753 RT_ZERO(cmdCtx); 3754 3755 RTEXITCODE rcExit = ctrlInitVM(pArg, &cmdCtx, uCmdCtxFlags); 3756 if (rcExit == RTEXITCODE_SUCCESS) 3757 { 3758 /* Kick off the actual command handler. */ 3759 rcExit = gctlCmd.pfnHandler(&cmdCtx); 3760 3761 ctrlUninitVM(&cmdCtx, cmdCtx.uFlags); 4191 3762 return rcExit; 4192 3763 } 4193 return RTEXITCODE_FAILURE; 4194 } 4195 3764 3765 return rcExit; 3766 } 4196 3767 #endif /* !VBOX_ONLY_DOCS */ 4197 3768
Note:
See TracChangeset
for help on using the changeset viewer.