- Timestamp:
- May 2, 2015 8:21:33 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 99977
- Location:
- trunk/src/VBox/Frontends/VBoxManage
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h
r55535 r55604 115 115 # define USAGE_GSTCTRL_COPYFROM RT_BIT(2) 116 116 # define USAGE_GSTCTRL_COPYTO RT_BIT(3) 117 # define USAGE_GSTCTRL_ CREATEDIRRT_BIT(4)118 # define USAGE_GSTCTRL_R EMOVEDIRRT_BIT(5)119 # define USAGE_GSTCTRL_R EMOVEFILERT_BIT(6)120 # define USAGE_GSTCTRL_ RENAMERT_BIT(7)121 # define USAGE_GSTCTRL_ CREATETEMPRT_BIT(8)117 # define USAGE_GSTCTRL_MKDIR RT_BIT(4) 118 # define USAGE_GSTCTRL_RMDIR RT_BIT(5) 119 # define USAGE_GSTCTRL_RM RT_BIT(6) 120 # define USAGE_GSTCTRL_MV RT_BIT(7) 121 # define USAGE_GSTCTRL_MKTEMP RT_BIT(8) 122 122 # define USAGE_GSTCTRL_LIST RT_BIT(9) 123 # define USAGE_GSTCTRL_PROCESS RT_BIT(10) 124 # define USAGE_GSTCTRL_KILL RT_BIT(11) 125 # define USAGE_GSTCTRL_SESSION RT_BIT(12) 126 # define USAGE_GSTCTRL_STAT RT_BIT(13) 127 # define USAGE_GSTCTRL_UPDATEADDS RT_BIT(14) 128 # define USAGE_GSTCTRL_WATCH RT_BIT(15) 123 # define USAGE_GSTCTRL_CLOSEPROCESS RT_BIT(10) 124 # define USAGE_GSTCTRL_CLOSESESSION RT_BIT(11) 125 # define USAGE_GSTCTRL_STAT RT_BIT(12) 126 # define USAGE_GSTCTRL_UPDATEGA RT_BIT(13) 127 # define USAGE_GSTCTRL_WATCH RT_BIT(14) 129 128 # define USAGE_GSTCTRL_EXEC RT_BIT(31) /**< @deprecated Remember to remove. */ 130 129 #endif -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r55598 r55604 5 5 6 6 /* 7 * Copyright (C) 2010-201 3Oracle Corporation7 * Copyright (C) 2010-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 64 64 using namespace com; 65 65 66 /******************************************************************************* 67 * Defined Constants And Macros * 68 *******************************************************************************/ 69 #define GCTLCMD_COMMON_OPT_USER 999 /**< The --username option number. */ 70 #define GCTLCMD_COMMON_OPT_PASSWORD 998 /**< The --password option number. */ 71 #define GCTLCMD_COMMON_OPT_PASSWORD_FILE 997 /**< The --password-file option number. */ 72 #define GCTLCMD_COMMON_OPT_DOMAIN 996 /**< The --domain option number. */ 73 /** Common option definitions. */ 74 #define GCTLCMD_COMMON_OPTION_DEFS() \ 75 { "--username", GCTLCMD_COMMON_OPT_USER, RTGETOPT_REQ_STRING }, \ 76 { "--passwordfile", GCTLCMD_COMMON_OPT_PASSWORD_FILE,RTGETOPT_REQ_STRING }, \ 77 { "--password", GCTLCMD_COMMON_OPT_PASSWORD, RTGETOPT_REQ_STRING }, \ 78 { "--domain", GCTLCMD_COMMON_OPT_DOMAIN, RTGETOPT_REQ_STRING }, \ 79 { "--quiet", 'q', RTGETOPT_REQ_NOTHING }, \ 80 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 81 82 /** Handles common options in the typical option parsing switch. */ 83 #define GCTLCMD_COMMON_OPTION_CASES(a_pCtx, a_ch, a_pValueUnion) \ 84 case 'v': \ 85 case 'q': \ 86 case GCTLCMD_COMMON_OPT_USER: \ 87 case GCTLCMD_COMMON_OPT_DOMAIN: \ 88 case GCTLCMD_COMMON_OPT_PASSWORD: \ 89 case GCTLCMD_COMMON_OPT_PASSWORD_FILE: \ 90 { \ 91 RTEXITCODE rcExitCommon = gctlCtxSetOption(a_pCtx, a_ch, a_pValueUnion); \ 92 if (RT_UNLIKELY(rcExitCommon != RTEXITCODE_SUCCESS)) \ 93 return rcExitCommon; \ 94 } break 95 96 97 /******************************************************************************* 98 * Global Variables * 99 *******************************************************************************/ 66 100 /** Set by the signal handler when current guest control 67 101 * action shall be aborted. */ 68 102 static volatile bool g_fGuestCtrlCanceled = false; 69 103 104 105 /******************************************************************************* 106 * Structures and Typedefs * 107 *******************************************************************************/ 70 108 /** 71 109 * Listener declarations. … … 76 114 VBOX_LISTENER_DECLARE(GuestEventListenerImpl) 77 115 116 78 117 /** 79 * Command context flags. 118 * Definition of a guestcontrol command, with handler and various flags. 119 */ 120 typedef struct GCTLCMDDEF 121 { 122 /** The command name. */ 123 const char *pszName; 124 125 /** 126 * Actual command handler callback. 127 * 128 * @param pCtx Pointer to command context to use. 129 */ 130 DECLR3CALLBACKMEMBER(RTEXITCODE, pfnHandler, (struct GCTLCMDCTX *pCtx)); 131 132 /** The command usage flags. */ 133 uint32_t fCmdUsage; 134 /** Command context flags (GCTLCMDCTX_F_XXX). */ 135 uint32_t fCmdCtx; 136 } GCTLCMD; 137 /** Pointer to a const guest control command definition. */ 138 typedef GCTLCMDDEF const *PCGCTLCMDDEF; 139 140 /** @name GCTLCMDCTX_F_XXX - Command context flags. 141 * @{ 80 142 */ 81 143 /** No flags set. */ 82 #define CTLCMDCTX_FLAGS_NONE0144 #define GCTLCMDCTX_F_NONE 0 83 145 /** Don't install a signal handler (CTRL+C trap). */ 84 #define CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLERRT_BIT(0)146 #define GCTLCMDCTX_F_NO_SIGNAL_HANDLER RT_BIT(0) 85 147 /** No guest session needed. */ 86 #define CTLCMDCTX_FLAGS_SESSION_ANONYMOUS RT_BIT(1) 87 /** Detach the guest session. That is, don't close the 88 * guest session automatically on exit. */ 89 #define CTLCMDCTX_FLAGS_SESSION_DETACH RT_BIT(2) 148 #define GCTLCMDCTX_F_SESSION_ANONYMOUS RT_BIT(1) 149 /** @} */ 90 150 91 151 /** … … 94 154 typedef struct GCTLCMDCTX 95 155 { 96 HandlerArg handlerArg; 97 /** Command-specific argument count. */ 98 int iArgc; 99 /** Command-specific argument vector. */ 100 char **ppaArgv; 101 /** First argv to start parsing with. */ 102 int iFirstArgc; 103 /** Command context flags. */ 104 uint32_t uFlags; 105 /** Verbose flag. */ 106 bool fVerbose; 156 HandlerArg *pArg; 157 158 /** Pointer to the command definition. */ 159 PCGCTLCMDDEF pCmdDef; 160 /** The VM name or UUID. */ 161 const char *pszVmNameOrUuid; 162 163 /** Whether we've locked the VM session. */ 164 bool fLockedVmSession; 165 /** Whether to detach (@c true) or close the session. */ 166 bool fDetachGuestSession; 167 /** Set if we've installed the signal handler. */ 168 bool fInstalledSignalHandler; 169 /** The verbosity level. */ 170 uint32_t cVerbose; 107 171 /** User name. */ 108 172 Utf8Str strUsername; … … 120 184 } GCTLCMDCTX, *PGCTLCMDCTX; 121 185 122 typedef struct GCTLCMD123 {124 /**125 * Actual command handler callback.126 *127 * @param pCtx Pointer to command context to use.128 */129 DECLR3CALLBACKMEMBER(RTEXITCODE, pfnHandler, (PGCTLCMDCTX pCtx));130 131 } GCTLCMD, *PGCTLCMD;132 186 133 187 typedef struct COPYCONTEXT … … 220 274 221 275 222 /*223 * Common getopt definitions, starting at 1000.224 * Specific command definitions will start all at 2000.225 */226 enum GETOPTDEF_COMMON227 {228 GETOPTDEF_COMMON_PASSWORD = 1000229 };230 231 /**232 * Long option IDs for the guestcontrol run command.233 */234 enum kGstCtrlRunOpt235 {236 kGstCtrlRunOpt_IgnoreOrphanedProcesses = 1000,237 kGstCtrlRunOpt_NoProfile,238 kGstCtrlRunOpt_Dos2Unix,239 kGstCtrlRunOpt_Unix2Dos,240 kGstCtrlRunOpt_WaitForStdOut,241 kGstCtrlRunOpt_NoWaitForStdOut,242 kGstCtrlRunOpt_WaitForStdErr,243 kGstCtrlRunOpt_NoWaitForStdErr244 };245 246 276 /** 247 277 * RTGetOpt-IDs for the guest execution control command line. … … 266 296 }; 267 297 268 enum GETOPTDEF_MKDIR269 {270 };271 272 enum GETOPTDEF_RM273 {274 };275 276 enum GETOPTDEF_RMDIR277 {278 };279 280 enum GETOPTDEF_SESSIONCLOSE281 {282 GETOPTDEF_SESSIONCLOSE_ALL = 2000283 };284 285 enum GETOPTDEF_STAT286 {287 };288 298 289 299 enum kStreamTransform … … 294 304 }; 295 305 296 static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest, const char *pszDir, bool *fExists); 306 307 /******************************************************************************* 308 * Internal Functions * 309 *******************************************************************************/ 310 static int gctlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest, const char *pszDir, bool *fExists); 297 311 298 312 #endif /* VBOX_ONLY_DOCS */ 313 314 299 315 300 316 void usageGuestControl(PRTSTREAM pStrm, const char *pcszSep1, const char *pcszSep2, uint32_t uSubCmd) … … 304 320 pcszSep1, pcszSep2, 305 321 uSubCmd == ~0U ? "\n" : ""); 322 /* 0 1 2 3 4 5 6 7 8XXXXXXXXXX */ 323 /* 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */ 324 #define COMMON_OPTION_HELP \ 325 " [--username <name>] [--domain <domain>]\n" \ 326 " [--passwordfile <file> | --password <password>]\n" \ 327 " [--verbose|-v] [--quiet|-q]\n" 328 #define COMMON_OPTION_HELP_ANON \ 329 " [--verbose|-v] [--quiet|-q]\n" 306 330 if (uSubCmd & USAGE_GSTCTRL_RUN) 307 331 RTStrmPrintf(pStrm, 308 " run\n" 309 " [--image <path to executable>] --username <name>\n" 310 " [--passwordfile <file> | --password <password>]\n" 311 " [--domain <domain>] [--verbose] [--timeout <msec>]\n" 332 " run\n" COMMON_OPTION_HELP 333 " [--image <path to executable>] [--timeout <msec>]\n" 312 334 " [--putenv <NAME>[=<VALUE>]] [--unquoted-args]\n" 313 335 " [--no-wait-stdout|--wait-stdout]\n" … … 318 340 if (uSubCmd & USAGE_GSTCTRL_START) 319 341 RTStrmPrintf(pStrm, 320 " start\n" 321 " [--image <path to executable>] --username <name>\n" 322 " [--passwordfile <file> | --password <password>]\n" 323 " [--domain <domain>] [--verbose] [--timeout <msec>]\n" 342 " start\n" COMMON_OPTION_HELP 343 " [--image <path to executable>] [--timeout <msec>]\n" 324 344 " [--putenv <NAME>[=<VALUE>]] [--unquoted-args]\n" 325 " [--dos2unix] [--unix2dos]\n"326 345 " -- <program/arg0> [argument1] ... [argumentN]]\n" 327 346 "\n"); 347 /* 0 1 2 3 4 5 6 7 8XXXXXXXXXX */ 348 /* 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */ 328 349 if (uSubCmd == USAGE_GSTCTRL_EXEC) 329 350 RTStrmPrintf(pStrm, … … 339 360 if (uSubCmd & USAGE_GSTCTRL_COPYFROM) 340 361 RTStrmPrintf(pStrm, 341 " copyfrom\n" 342 " <guest source> <host dest> --username <name>\n" 343 " [--passwordfile <file> | --password <password>]\n" 344 " [--domain <domain>] [--verbose]\n" 362 " copyfrom\n" COMMON_OPTION_HELP 345 363 " [--dryrun] [--follow] [--recursive]\n" 364 " <guest source> <host dest>\n" 346 365 "\n"); 347 366 if (uSubCmd & USAGE_GSTCTRL_COPYTO) 348 367 RTStrmPrintf(pStrm, 349 " copyto|cp\n" 350 " <host source> <guest dest> --username <name>\n" 351 " [--passwordfile <file> | --password <password>]\n" 352 " [--domain <domain>] [--verbose]\n" 368 " copyto|cp\n" COMMON_OPTION_HELP 353 369 " [--dryrun] [--follow] [--recursive]\n" 370 " <host source> <guest dest> " 354 371 "\n"); 355 if (uSubCmd & USAGE_GSTCTRL_ CREATEDIR)372 if (uSubCmd & USAGE_GSTCTRL_MKDIR) 356 373 RTStrmPrintf(pStrm, 357 " createdir[ectory]|mkdir|md\n" 358 " <guest directory>... --username <name>\n" 359 " [--passwordfile <file> | --password <password>]\n" 360 " [--domain <domain>] [--verbose]\n" 374 " mkdir|md|createdir[ectory]\n" COMMON_OPTION_HELP 361 375 " [--parents] [--mode <mode>]\n" 376 " <guest directory> [...]\n" 362 377 "\n"); 363 if (uSubCmd & USAGE_GSTCTRL_R EMOVEDIR)378 if (uSubCmd & USAGE_GSTCTRL_RMDIR) 364 379 RTStrmPrintf(pStrm, 365 " removedir[ectory]|rmdir\n" 366 " <guest directory>... --username <name>\n" 367 " [--passwordfile <file> | --password <password>]\n" 368 " [--domain <domain>] [--verbose]\n" 380 " rmdir|removedir[ectory]\n" COMMON_OPTION_HELP 369 381 " [--recursive|-R|-r]\n" 382 " <guest directory> [...]\n" 370 383 "\n"); 371 if (uSubCmd & USAGE_GSTCTRL_R EMOVEFILE)384 if (uSubCmd & USAGE_GSTCTRL_RM) 372 385 RTStrmPrintf(pStrm, 373 " removefile|rm\n" 374 " <guest file>... --username <name>\n" 375 " [--passwordfile <file> | --password <password>]\n" 376 " [--domain <domain>] [--verbose]\n" 386 " removefile|rm\n" COMMON_OPTION_HELP 387 " <guest file> [...]\n" 377 388 "\n"); 378 if (uSubCmd & USAGE_GSTCTRL_ RENAME)389 if (uSubCmd & USAGE_GSTCTRL_MV) 379 390 RTStrmPrintf(pStrm, 380 " ren[ame]|mv\n" 381 " <source>... <dest> --username <name>\n" 382 " [--passwordfile <file> | --password <password>]\n" 383 " [--domain <domain>] [--verbose]\n" 391 " mv|move|ren[ame]\n" COMMON_OPTION_HELP 392 " <source> [source1 [...]] <dest>\n" 384 393 "\n"); 385 if (uSubCmd & USAGE_GSTCTRL_ CREATETEMP)394 if (uSubCmd & USAGE_GSTCTRL_MKTEMP) 386 395 RTStrmPrintf(pStrm, 387 " createtemp[orary]|mktemp\n" 388 " <template> --username <name>\n" 389 " [--passwordfile <file> | --password <password>]\n" 390 " [--directory] [--secure] [--tmpdir <directory>]\n" 391 " [--domain <domain>] [--mode <mode>] [--verbose]\n" 392 "\n"); 393 if (uSubCmd & USAGE_GSTCTRL_LIST) 394 RTStrmPrintf(pStrm, 395 " list <all|sessions|processes|files> [--verbose]\n" 396 "\n"); 397 /** @todo Add an own help group for "session" and "process" sub commands. */ 398 if (uSubCmd & USAGE_GSTCTRL_PROCESS) 399 RTStrmPrintf(pStrm, 400 " process kill --session-id <ID>\n" 401 " | --session-name <name or pattern>\n" 402 " [--verbose]\n" 403 " <PID> ... <PID n>\n" 404 "\n"); 405 if (uSubCmd & USAGE_GSTCTRL_KILL) 406 RTStrmPrintf(pStrm, 407 " [p[s]]kill --session-id <ID>\n" 408 " | --session-name <name or pattern>\n" 409 " [--verbose]\n" 410 " <PID> ... <PID n>\n" 411 "\n"); 412 if (uSubCmd & USAGE_GSTCTRL_SESSION) 413 RTStrmPrintf(pStrm, 414 " session close --session-id <ID>\n" 415 " | --session-name <name or pattern>\n" 416 " | --all\n" 417 " [--verbose]\n" 396 " mktemp|createtemp[orary]\n" COMMON_OPTION_HELP 397 " [--secure] [--mode <mode>] [--tmpdir <directory>]\n" 398 " <template>\n" 418 399 "\n"); 419 400 if (uSubCmd & USAGE_GSTCTRL_STAT) 420 401 RTStrmPrintf(pStrm, 421 " stat\n" 422 " <file>... --username <name>\n" 423 " [--passwordfile <file> | --password <password>]\n" 424 " [--domain <domain>] [--verbose]\n" 402 " stat\n" COMMON_OPTION_HELP 403 " <file> [...]\n" 425 404 "\n"); 426 if (uSubCmd & USAGE_GSTCTRL_UPDATEADDS) 405 406 /* Command not requiring authentication. */ 407 if (uSubCmd & USAGE_GSTCTRL_LIST) 427 408 RTStrmPrintf(pStrm, 428 " updateadditions\n" 429 " [--source <guest additions .ISO>] [--verbose]\n" 409 " list <all|sessions|processes|files>\n" COMMON_OPTION_HELP_ANON 410 "\n"); 411 if (uSubCmd & USAGE_GSTCTRL_CLOSEPROCESS) 412 RTStrmPrintf(pStrm, 413 " closeprocess|kill\n" COMMON_OPTION_HELP_ANON 414 " < --session-id <ID>\n" 415 " | --session-name <name or pattern>\n" 416 " <PID1> [PID1 [...]]\n" 417 "\n"); 418 if (uSubCmd & USAGE_GSTCTRL_CLOSESESSION) 419 RTStrmPrintf(pStrm, 420 " closesession\n" COMMON_OPTION_HELP_ANON 421 " < --all | --session-id <ID>\n" 422 " | --session-name <name or pattern> >\n" 423 "\n"); 424 if (uSubCmd & USAGE_GSTCTRL_UPDATEGA) 425 RTStrmPrintf(pStrm, 426 " updatega|updateguestadditions|updateadditions\n" COMMON_OPTION_HELP_ANON 427 " [--source <guest additions .ISO>]\n" 430 428 " [--wait-start]\n" 431 429 " [-- [<argument1>] ... [<argumentN>]]\n" … … 433 431 if (uSubCmd & USAGE_GSTCTRL_WATCH) 434 432 RTStrmPrintf(pStrm, 435 " watch [--verbose]\n"433 " watch\n" COMMON_OPTION_HELP_ANON 436 434 "\n"); 437 435 } … … 439 437 #ifndef VBOX_ONLY_DOCS 440 438 439 441 440 #ifdef RT_OS_WINDOWS 442 static BOOL WINAPI g uestCtrlSignalHandler(DWORD dwCtrlType)441 static BOOL WINAPI gctlSignalHandler(DWORD dwCtrlType) 443 442 { 444 443 bool fEventHandled = FALSE; … … 468 467 * unnecessary here. 469 468 */ 470 static void g uestCtrlSignalHandler(int iSignal)469 static void gctlSignalHandler(int iSignal) 471 470 { 472 471 NOREF(iSignal); … … 474 473 } 475 474 #endif 475 476 476 477 477 /** … … 479 479 * whenever the user wants to intercept the program. 480 480 * 481 ** @todo Make this handler available for all VBoxManage modules? 482 */ 483 static int ctrlSignalHandlerInstall(void) 484 { 481 * @todo Make this handler available for all VBoxManage modules? 482 */ 483 static int gctlSignalHandlerInstall(void) 484 { 485 g_fGuestCtrlCanceled = false; 486 485 487 int rc = VINF_SUCCESS; 486 488 #ifdef RT_OS_WINDOWS 487 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)g uestCtrlSignalHandler, TRUE /* Add handler */))489 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)gctlSignalHandler, TRUE /* Add handler */)) 488 490 { 489 491 rc = RTErrConvertFromWin32(GetLastError()); … … 491 493 } 492 494 #else 493 signal(SIGINT, g uestCtrlSignalHandler);495 signal(SIGINT, gctlSignalHandler); 494 496 # ifdef SIGBREAK 495 signal(SIGBREAK, g uestCtrlSignalHandler);497 signal(SIGBREAK, gctlSignalHandler); 496 498 # endif 497 499 #endif … … 499 501 } 500 502 503 501 504 /** 502 505 * Uninstalls a previously installed signal handler. 503 506 */ 504 static int ctrlSignalHandlerUninstall(void)507 static int gctlSignalHandlerUninstall(void) 505 508 { 506 509 int rc = VINF_SUCCESS; … … 520 523 } 521 524 525 522 526 /** 523 * Translates a process status to a human readable 524 * string. 525 */ 526 const char *ctrlProcessStatusToText(ProcessStatus_T enmStatus) 527 * Translates a process status to a human readable string. 528 */ 529 const char *gctlProcessStatusToText(ProcessStatus_T enmStatus) 527 530 { 528 531 switch (enmStatus) … … 556 559 } 557 560 558 const char *ctrlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult) 561 /** 562 * Translates a guest process wait result to a human readable string. 563 */ 564 const char *gctlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult) 559 565 { 560 566 switch (enmWaitResult) … … 585 591 586 592 /** 587 * Translates a guest session status to a human readable 588 * string. 589 */ 590 const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus) 593 * Translates a guest session status to a human readable string. 594 */ 595 const char *gctlGuestSessionStatusToText(GuestSessionStatus_T enmStatus) 591 596 { 592 597 switch (enmStatus) … … 615 620 616 621 /** 617 * Translates a guest file status to a human readable 618 * string. 619 */ 620 const char *ctrlFileStatusToText(FileStatus_T enmStatus) 622 * Translates a guest file status to a human readable string. 623 */ 624 const char *gctlFileStatusToText(FileStatus_T enmStatus) 621 625 { 622 626 switch (enmStatus) … … 640 644 } 641 645 642 static int ctrlPrintError(com::ErrorInfo &errorInfo)646 static int gctlPrintError(com::ErrorInfo &errorInfo) 643 647 { 644 648 if ( errorInfo.isFullAvailable() … … 660 664 } 661 665 662 static int ctrlPrintError(IUnknown *pObj, const GUID &aIID)666 static int gctlPrintError(IUnknown *pObj, const GUID &aIID) 663 667 { 664 668 com::ErrorInfo ErrInfo(pObj, aIID); 665 return ctrlPrintError(ErrInfo);666 } 667 668 static int ctrlPrintProgressError(ComPtr<IProgress> pProgress)669 return gctlPrintError(ErrInfo); 670 } 671 672 static int gctlPrintProgressError(ComPtr<IProgress> pProgress) 669 673 { 670 674 int vrc = VINF_SUCCESS; … … 682 686 { 683 687 com::ProgressErrorInfo ErrInfo(pProgress); 684 vrc = ctrlPrintError(ErrInfo);688 vrc = gctlPrintError(ErrInfo); 685 689 } 686 690 } … … 693 697 } 694 698 699 700 701 /* 702 * 703 * 704 * Guest Control Command Context 705 * Guest Control Command Context 706 * Guest Control Command Context 707 * Guest Control Command Context 708 * 709 * 710 * 711 */ 712 713 695 714 /** 715 * Initializes a guest control command context structure. 716 * 717 * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE on failure (after 718 * informing the user of course). 719 * @param pCtx The command context to init. 720 * @param pArg The handle argument package. 721 * @param pCmdDef The command definition. 722 */ 723 static RTEXITCODE gctrCmdCtxInit(PGCTLCMDCTX pCtx, HandlerArg *pArg, PCGCTLCMDDEF pCmdDef) 724 { 725 Assert(pArg->argc >= 2); 726 RT_ZERO(*pCtx); 727 pCtx->pArg = pArg; 728 pCtx->pCmdDef = pCmdDef; 729 pCtx->pszVmNameOrUuid = pArg->argv[0]; 730 731 /* 732 * The user name defaults to the host one, if we can get at it. 733 */ 734 char szUser[1024]; 735 int rc = RTProcQueryUsername(RTProcSelf(), szUser, sizeof(szUser), NULL); 736 if ( RT_SUCCESS(rc) 737 && RTStrIsValidEncoding(szUser)) /* paranoia required on posix */ 738 { 739 try 740 { 741 pCtx->strUsername = szUser; 742 } 743 catch (std::bad_alloc &) 744 { 745 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Out of memory"); 746 } 747 } 748 /* else: ignore this failure. */ 749 750 return RTEXITCODE_SUCCESS; 751 } 752 753 754 /** 755 * Worker for GCTLCMD_COMMON_OPTION_CASES. 756 * 757 * @returns RTEXITCODE_SUCCESS if the option was handled successfully. If not, 758 * an error message is printed and an appropriate failure exit code is 759 * returned. 760 * @param pCtx The guest control command context. 761 * @param ch The option char or ordinal. 762 * @param pValueUnion The option value union. 763 */ 764 static RTEXITCODE gctlCtxSetOption(PGCTLCMDCTX pCtx, int ch, PRTGETOPTUNION pValueUnion) 765 { 766 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 767 switch (ch) 768 { 769 case 'u': /* User name */ 770 if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS)) 771 pCtx->strUsername = pValueUnion->psz; 772 else 773 return errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage, 774 "The --username|-u option is not valid with this command"); 775 break; 776 777 case GCTLCMD_COMMON_OPT_PASSWORD: /* Password */ 778 if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS)) 779 { 780 if (pCtx->strPassword.isNotEmpty()) 781 RTMsgWarning("Password is given more than once."); 782 pCtx->strPassword = pValueUnion->psz; 783 } 784 else 785 return errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage, 786 "The --password option is not valid with this command"); 787 break; 788 789 case 'p': /* Password file */ 790 if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS)) 791 rcExit = readPasswordFile(pValueUnion->psz, &pCtx->strPassword); 792 else 793 return errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage, 794 "The --password-file|-p option is not valid with this command"); 795 break; 796 797 case 'd': /* domain */ 798 if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS)) 799 pCtx->strDomain = pValueUnion->psz; 800 else 801 return errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage, 802 "The --domain option is not valid with this command"); 803 break; 804 805 case 'v': /* --verbose */ 806 pCtx->cVerbose++; 807 break; 808 809 case 'q': /* --quiet */ 810 if (pCtx->cVerbose) 811 pCtx->cVerbose--; 812 break; 813 814 default: 815 AssertFatalMsgFailed(("ch=%d (%c)\n", ch, ch)); 816 } 817 return rcExit; 818 } 819 820 821 /** 822 * Initializes the VM for IGuest operation. 823 * 824 * This opens a shared session to a running VM and gets hold of IGuest. 825 * 826 * @returns RTEXITCODE_SUCCESS on success. RTEXITCODE_FAILURE and user message 827 * on failure. 828 * @param pCtx The guest control command context. 829 * GCTLCMDCTX::pGuest will be set on success. 830 */ 831 static RTEXITCODE gctlCtxInitVmSession(PGCTLCMDCTX pCtx) 832 { 833 HRESULT rc; 834 AssertPtr(pCtx); 835 AssertPtr(pCtx->pArg); 836 837 /* 838 * Find the VM and check if it's running. 839 */ 840 ComPtr<IMachine> machine; 841 CHECK_ERROR(pCtx->pArg->virtualBox, FindMachine(Bstr(pCtx->pszVmNameOrUuid).raw(), machine.asOutParam())); 842 if (SUCCEEDED(rc)) 843 { 844 MachineState_T enmMachineState; 845 CHECK_ERROR(machine, COMGETTER(State)(&enmMachineState)); 846 if ( SUCCEEDED(rc) 847 && enmMachineState == MachineState_Running) 848 { 849 /* 850 * It's running. So, open a session to it and get the IGuest interface. 851 */ 852 CHECK_ERROR(machine, LockMachine(pCtx->pArg->session, LockType_Shared)); 853 if (SUCCEEDED(rc)) 854 { 855 pCtx->fLockedVmSession = true; 856 ComPtr<IConsole> ptrConsole; 857 CHECK_ERROR(pCtx->pArg->session, COMGETTER(Console)(ptrConsole.asOutParam())); 858 if (SUCCEEDED(rc)) 859 { 860 CHECK_ERROR(ptrConsole, COMGETTER(Guest)(pCtx->pGuest.asOutParam())); 861 if (SUCCEEDED(rc)) 862 return RTEXITCODE_SUCCESS; 863 } 864 } 865 } 866 else if(SUCCEEDED(rc)) 867 RTMsgError("Machine \"%s\" is not running (currently %s)!\n", 868 pCtx->pszVmNameOrUuid, machineStateToName(enmMachineState, false)); 869 } 870 return RTEXITCODE_FAILURE; 871 } 872 873 874 /** 875 * Creates a guest session with the VM. 876 * 877 * @retval RTEXITCODE_SUCCESS on success. 878 * @retval RTEXITCODE_FAILURE and user message on failure. 879 * @param pCtx The guest control command context. 880 * GCTCMDCTX::pGuestSession and GCTLCMDCTX::uSessionID 881 * will be set. 882 */ 883 static RTEXITCODE gctlCtxInitGuestSession(PGCTLCMDCTX pCtx) 884 { 885 HRESULT rc; 886 AssertPtr(pCtx); 887 Assert(!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS)); 888 Assert(pCtx->pGuest.isNotNull()); 889 890 /* 891 * Build up a reasonable guest session name. Useful for identifying 892 * a specific session when listing / searching for them. 893 */ 894 char *pszSessionName; 895 if (RTStrAPrintf(&pszSessionName, 896 "[%RU32] VBoxManage Guest Control [%s] - %s", 897 RTProcSelf(), pCtx->pszVmNameOrUuid, pCtx->pCmdDef->pszName) < 0) 898 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name"); 899 900 /* 901 * Create a guest session. 902 */ 903 if (pCtx->cVerbose > 1) 904 RTPrintf("Creating guest session as user '%s'...\n", pCtx->strUsername.c_str()); 905 try 906 { 907 CHECK_ERROR(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(), 908 Bstr(pCtx->strPassword).raw(), 909 Bstr(pCtx->strDomain).raw(), 910 Bstr(pszSessionName).raw(), 911 pCtx->pGuestSession.asOutParam())); 912 } 913 catch (std::bad_alloc &) 914 { 915 RTMsgError("Out of memory setting up IGuest::CreateSession call"); 916 rc = E_OUTOFMEMORY; 917 } 918 if (SUCCEEDED(rc)) 919 { 920 /* 921 * Wait for guest session to start. 922 */ 923 if (pCtx->cVerbose > 1) 924 RTPrintf("Waiting for guest session to start...\n"); 925 GuestSessionWaitResult_T enmWaitResult; 926 try 927 { 928 com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags; 929 aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start); 930 CHECK_ERROR(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags), 931 /** @todo Make session handling timeouts configurable. */ 932 30 * 1000, &enmWaitResult)); 933 } 934 catch (std::bad_alloc &) 935 { 936 RTMsgError("Out of memory setting up IGuestSession::WaitForArray call"); 937 rc = E_OUTOFMEMORY; 938 } 939 if (SUCCEEDED(rc)) 940 { 941 /* The WaitFlagNotSupported result may happen with GAs older than 4.3. */ 942 if ( enmWaitResult == GuestSessionWaitResult_Start 943 || enmWaitResult == GuestSessionWaitResult_WaitFlagNotSupported) 944 { 945 /* 946 * Get the session ID and we're ready to rumble. 947 */ 948 CHECK_ERROR(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID)); 949 if (SUCCEEDED(rc)) 950 { 951 if (pCtx->cVerbose > 1) 952 RTPrintf("Successfully started guest session (ID %RU32)\n", pCtx->uSessionID); 953 RTStrFree(pszSessionName); 954 return RTEXITCODE_SUCCESS; 955 } 956 } 957 else 958 { 959 GuestSessionStatus_T enmSessionStatus; 960 CHECK_ERROR(pCtx->pGuestSession, COMGETTER(Status)(&enmSessionStatus)); 961 RTMsgError("Error starting guest session (current status is: %s)\n", 962 SUCCEEDED(rc) ? gctlGuestSessionStatusToText(enmSessionStatus) : "<unknown>"); 963 } 964 } 965 } 966 967 RTStrFree(pszSessionName); 968 return RTEXITCODE_FAILURE; 969 } 970 971 972 /** 973 * Completes the guest control context initialization after parsing arguments. 974 * 975 * Will validate common arguments, open a VM session, and if requested open a 976 * guest session and install the CTRL-C signal handler. 977 * 978 * It is good to validate all the options and arguments you can before making 979 * this call. However, the VM session, IGuest and IGuestSession interfaces are 980 * not availabe till after this call, so take care. 981 * 982 * @retval RTEXITCODE_SUCCESS on success. 983 * @retval RTEXITCODE_FAILURE and user message on failure. 984 * @param pCtx The guest control command context. 985 * GCTCMDCTX::pGuestSession and GCTLCMDCTX::uSessionID 986 * will be set. 987 */ 988 static RTEXITCODE gctlCtxPostArgParsingInit(PGCTLCMDCTX pCtx) 989 { 990 /* 991 * Check that the user name isn't empty when we need it. 992 */ 993 RTEXITCODE rcExit; 994 if ( (pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS) 995 || pCtx->strUsername.isNotEmpty()) 996 { 997 /* 998 * Open the VM session and if required, a guest session. 999 */ 1000 rcExit = gctlCtxInitVmSession(pCtx); 1001 if ( rcExit == RTEXITCODE_SUCCESS 1002 && !(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS)) 1003 rcExit = gctlCtxInitGuestSession(pCtx); 1004 if (rcExit == RTEXITCODE_SUCCESS) 1005 { 1006 /* 1007 * Install signal handler if requested (errors are ignored). 1008 */ 1009 if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_NO_SIGNAL_HANDLER)) 1010 { 1011 int rc = gctlSignalHandlerInstall(); 1012 pCtx->fInstalledSignalHandler = RT_SUCCESS(rc); 1013 } 1014 } 1015 } 1016 else 1017 rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage, "No user name specified!"); 1018 return rcExit; 1019 } 1020 1021 1022 /** 1023 * Cleans up the context when the command returns. 1024 * 1025 * This will close any open guest session, unless the DETACH flag is set. 1026 * It will also close any VM session that may be been established. Any signal 1027 * handlers we've installed will also be removed. 1028 * 696 1029 * Un-initializes the VM after guest control usage. 697 1030 * @param pCmdCtx Pointer to command context. 698 * @param uFlags Command context flags. 699 */ 700 static void ctrlUninitVM(PGCTLCMDCTX pCtx, uint32_t uFlags) 701 { 702 AssertPtrReturnVoid(pCtx); 703 704 if (!(pCtx->uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER)) 705 ctrlSignalHandlerUninstall(); 706 1031 */ 1032 static void gctlCtxTerm(PGCTLCMDCTX pCtx) 1033 { 707 1034 HRESULT rc; 708 709 do 710 { 711 if (!pCtx->pGuestSession.isNull()) 712 { 713 if ( !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS) 714 && !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH)) 715 { 716 if (pCtx->fVerbose) 717 RTPrintf("Closing guest session ...\n"); 718 719 CHECK_ERROR(pCtx->pGuestSession, Close()); 720 /* Keep going - don't break here. Try to unlock the 721 * machine down below. */ 722 } 723 else if ( (pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH) 724 && pCtx->fVerbose) 725 RTPrintf("Guest session detached\n"); 726 727 pCtx->pGuestSession.setNull(); 728 } 729 730 if (pCtx->handlerArg.session) 731 CHECK_ERROR(pCtx->handlerArg.session, UnlockMachine()); 732 733 } while (0); 734 735 for (int i = 0; i < pCtx->iArgc; i++) 736 RTStrFree(pCtx->ppaArgv[i]); 737 RTMemFree(pCtx->ppaArgv); 738 pCtx->iArgc = 0; 739 } 740 741 /** 742 * Initializes the VM for IGuest operations. 743 * 744 * That is, checks whether it's up and running, if it can be locked (shared 745 * only) and returns a valid IGuest pointer on success. Also, it does some 746 * basic command line processing and opens a guest session, if required. 747 * 748 * @return RTEXITCODE status code. 749 * @param pArg Pointer to command line argument structure. 750 * @param pCmdCtx Pointer to command context. 751 * @param uFlags Command context flags. 752 */ 753 static RTEXITCODE ctrlInitVM(HandlerArg *pArg, 754 PGCTLCMDCTX pCtx, uint32_t uFlags, uint32_t uUsage) 755 { 756 AssertPtrReturn(pArg, RTEXITCODE_FAILURE); 757 AssertReturn(pArg->argc > 1, RTEXITCODE_FAILURE); 758 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 759 760 #ifdef DEBUG_andy 761 RTPrintf("Original argv:\n"); 762 for (int i=0; i<pArg->argc;i++) 763 RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]); 764 #endif 765 766 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 767 768 const char *pszNameOrId = pArg->argv[0]; 769 const char *pszCmd = pArg->argv[1]; 770 771 /* Lookup VM. */ 772 ComPtr<IMachine> machine; 773 /* Assume it's an UUID. */ 774 HRESULT rc; 775 CHECK_ERROR(pArg->virtualBox, FindMachine(Bstr(pszNameOrId).raw(), 776 machine.asOutParam())); 777 if (SUCCEEDED(rc)) 778 { 779 /* Machine is running? */ 780 MachineState_T machineState; 781 CHECK_ERROR(machine, COMGETTER(State)(&machineState)); 782 if ( SUCCEEDED(rc) 783 && (machineState != MachineState_Running)) 784 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine \"%s\" is not running (currently %s)!\n", 785 pszNameOrId, machineStateToName(machineState, false)); 786 } 787 else 788 rcExit = RTEXITCODE_FAILURE; 789 790 if (rcExit == RTEXITCODE_SUCCESS) 791 { 792 /* 793 * Process standard options which are served by all commands. 794 */ 795 static const RTGETOPTDEF s_aOptions[] = 796 { 797 { "--username", 'u', RTGETOPT_REQ_STRING }, 798 { "--passwordfile", 'p', RTGETOPT_REQ_STRING }, 799 { "--password", GETOPTDEF_COMMON_PASSWORD, RTGETOPT_REQ_STRING }, 800 { "--domain", 'd', RTGETOPT_REQ_STRING }, 801 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 802 }; 803 804 805 806 /** @todo r=bird: This is just SOOOO hackish and fragile, especially wrt to the 807 * exec/run commands. If you don't have the full option syntax, there is no way 808 * you can safely tell an option from an option value. sigh. 809 * The way to do this is by a defines with the above s_aOptions entries, calling 810 * a common function in the default case of each option parser, and a routine to 811 * be called at the end of option parsing to open the session. */ 812 813 814 815 /* 816 * Allocate per-command argv. This then only contains the specific arguments 817 * the command needs. 818 */ 819 pCtx->ppaArgv = (char**)RTMemAlloc(pArg->argc * sizeof(char*) + 1); 820 if (!pCtx->ppaArgv) 821 { 822 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Not enough memory for per-command argv\n"); 823 } 824 else 825 { 826 pCtx->iArgc = 0; 827 828 int iArgIdx = 2; /* Skip VM name and guest control command */ 829 int ch; 830 RTGETOPTUNION ValueUnion; 831 RTGETOPTSTATE GetState; 832 RTGetOptInit(&GetState, pArg->argc, pArg->argv, 833 s_aOptions, RT_ELEMENTS(s_aOptions), 834 iArgIdx, 0); 835 836 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 837 && (rcExit == RTEXITCODE_SUCCESS)) 838 { 839 /* For options that require an argument, ValueUnion has received the value. */ 840 switch (ch) 841 { 842 case 'u': /* User name */ 843 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 844 pCtx->strUsername = ValueUnion.psz; 845 iArgIdx = GetState.iNext; 846 break; 847 848 case GETOPTDEF_COMMON_PASSWORD: /* Password */ 849 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 850 { 851 if (pCtx->strPassword.isEmpty()) 852 pCtx->strPassword = ValueUnion.psz; 853 } 854 iArgIdx = GetState.iNext; 855 break; 856 857 case 'p': /* Password file */ 858 { 859 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 860 rcExit = readPasswordFile(ValueUnion.psz, &pCtx->strPassword); 861 iArgIdx = GetState.iNext; 862 break; 863 } 864 865 case 'd': /* domain */ 866 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 867 pCtx->strDomain = ValueUnion.psz; 868 iArgIdx = GetState.iNext; 869 break; 870 871 case 'v': /* Verbose */ 872 pCtx->fVerbose = true; 873 iArgIdx = GetState.iNext; 874 break; 875 876 case 'h': /* Help */ 877 errorGetOptEx(USAGE_GUESTCONTROL, uUsage, ch, &ValueUnion); 878 return RTEXITCODE_SYNTAX; 879 880 default: 881 /* Simply skip; might be handled in a specific command 882 * handler later. */ 883 break; 884 885 } /* switch */ 886 887 int iArgDiff = GetState.iNext - iArgIdx; 888 if (iArgDiff) 889 { 890 #ifdef DEBUG_andy 891 RTPrintf("Not handled (iNext=%d, iArgsCur=%d):\n", GetState.iNext, iArgIdx); 892 #endif 893 for (int i = iArgIdx; i < GetState.iNext; i++) 894 { 895 char *pszArg = RTStrDup(pArg->argv[i]); 896 if (!pszArg) 897 { 898 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, 899 "Not enough memory for command line handling\n"); 900 break; 901 } 902 pCtx->ppaArgv[pCtx->iArgc] = pszArg; 903 pCtx->iArgc++; 904 #ifdef DEBUG_andy 905 RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]); 906 #endif 907 } 908 909 iArgIdx = GetState.iNext; 910 } 911 912 } /* while RTGetOpt */ 913 } 914 } 1035 AssertPtr(pCtx); 915 1036 916 1037 /* 917 * Check for mandatory stuff.1038 * Uninstall signal handler. 918 1039 */ 919 if (rcExit == RTEXITCODE_SUCCESS) 920 { 921 #if 0 922 RTPrintf("argc=%d\n", pCtx->iArgc); 923 for (int i = 0; i < pCtx->iArgc; i++) 924 RTPrintf("argv[%d]=%s\n", i, pCtx->ppaArgv[i]); 925 #endif 926 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 927 { 928 if (pCtx->strUsername.isEmpty()) 929 rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, uUsage, "No user name specified!"); 930 } 931 } 932 933 if (rcExit == RTEXITCODE_SUCCESS) 934 { 935 /* 936 * Build up a reasonable guest session name. Useful for identifying 937 * a specific session when listing / searching for them. 938 */ 939 char *pszSessionName; 940 if (0 >= RTStrAPrintf(&pszSessionName, 941 "[%RU32] VBoxManage Guest Control [%s] - %s", 942 RTProcSelf(), pszNameOrId, pszCmd)) 943 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name\n"); 944 945 do 946 { 947 /* Open a session for the VM. */ 948 CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared)); 949 /* Get the associated console. */ 950 ComPtr<IConsole> console; 951 CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam())); 952 /* ... and session machine. */ 953 ComPtr<IMachine> sessionMachine; 954 CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam())); 955 /* Get IGuest interface. */ 956 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pCtx->pGuest.asOutParam())); 957 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)) 958 { 959 if (pCtx->fVerbose) 960 RTPrintf("Opening guest session as user '%s' ...\n", pCtx->strUsername.c_str()); 961 962 /* Open a guest session. */ 963 Assert(!pCtx->pGuest.isNull()); 964 CHECK_ERROR_BREAK(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(), 965 Bstr(pCtx->strPassword).raw(), 966 Bstr(pCtx->strDomain).raw(), 967 Bstr(pszSessionName).raw(), 968 pCtx->pGuestSession.asOutParam())); 969 970 /* 971 * Wait for guest session to start. 972 */ 973 if (pCtx->fVerbose) 974 RTPrintf("Waiting for guest session to start ...\n"); 975 976 com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags; 977 aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start); 978 GuestSessionWaitResult_T sessionWaitResult; 979 CHECK_ERROR_BREAK(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags), 980 /** @todo Make session handling timeouts configurable. */ 981 30 * 1000, &sessionWaitResult)); 982 983 if ( sessionWaitResult == GuestSessionWaitResult_Start 984 /* Note: This might happen when Guest Additions < 4.3 are installed which don't 985 * support dedicated guest sessions. */ 986 || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported) 987 { 988 CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID)); 989 if (pCtx->fVerbose) 990 RTPrintf("Guest session (ID %RU32) has been started\n", pCtx->uSessionID); 991 } 992 else 993 { 994 GuestSessionStatus_T sessionStatus; 995 CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Status)(&sessionStatus)); 996 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error starting guest session (current status is: %s)\n", 997 ctrlSessionStatusToText(sessionStatus)); 998 break; 999 } 1000 } 1001 1002 if ( SUCCEEDED(rc) 1003 && !(uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER)) 1004 { 1005 ctrlSignalHandlerInstall(); 1006 } 1007 1008 } while (0); 1009 1010 if (FAILED(rc)) 1011 rcExit = RTEXITCODE_FAILURE; 1012 1013 RTStrFree(pszSessionName); 1014 } 1015 1016 if (rcExit == RTEXITCODE_SUCCESS) 1017 { 1018 pCtx->handlerArg = *pArg; 1019 pCtx->uFlags = uFlags; 1020 } 1021 else /* Clean up on failure. */ 1022 ctrlUninitVM(pCtx, uFlags); 1023 1024 return rcExit; 1025 } 1040 if (pCtx->fInstalledSignalHandler) 1041 { 1042 gctlSignalHandlerUninstall(); 1043 pCtx->fInstalledSignalHandler = false; 1044 } 1045 1046 /* 1047 * Close, or at least release, the guest session. 1048 */ 1049 if (pCtx->pGuestSession.isNotNull()) 1050 { 1051 if ( !(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS) 1052 && !pCtx->fDetachGuestSession) 1053 { 1054 if (pCtx->cVerbose > 1) 1055 RTPrintf("Closing guest session ...\n"); 1056 1057 CHECK_ERROR(pCtx->pGuestSession, Close()); 1058 } 1059 else if ( pCtx->fDetachGuestSession 1060 && pCtx->cVerbose > 1) 1061 RTPrintf("Guest session detached\n"); 1062 1063 pCtx->pGuestSession.setNull(); 1064 } 1065 1066 /* 1067 * Close the VM session. 1068 */ 1069 if (pCtx->fLockedVmSession) 1070 { 1071 Assert(pCtx->pArg->session.isNotNull()); 1072 CHECK_ERROR(pCtx->pArg->session, UnlockMachine()); 1073 pCtx->fLockedVmSession = false; 1074 } 1075 } 1076 1077 1078 1079 1080 1081 /* 1082 * 1083 * 1084 * Guest Control Command Handling. 1085 * Guest Control Command Handling. 1086 * Guest Control Command Handling. 1087 * Guest Control Command Handling. 1088 * Guest Control Command Handling. 1089 * 1090 * 1091 */ 1026 1092 1027 1093 … … 1044 1110 * @note The guest exit code mappings was introduced with 5.0 and the 'run' 1045 1111 * command, they are/was not supported by 'exec'. 1046 * @sa ctrlRunCalculateExitCode1112 * @sa gctlRunCalculateExitCode 1047 1113 */ 1048 1114 /** Process exited normally but with an exit code <> 0. */ … … 1079 1145 * exit codes. 1080 1146 */ 1081 static RTEXITCODE ctrlRunCalculateExitCode(ProcessStatus_T enmStatus, ULONG uExitCode, bool fReturnExitCodes)1147 static RTEXITCODE gctlRunCalculateExitCode(ProcessStatus_T enmStatus, ULONG uExitCode, bool fReturnExitCodes) 1082 1148 { 1083 1149 int vrc = RTEXITCODE_SUCCESS; … … 1134 1200 * complete. 1135 1201 */ 1136 static int ctrlRunPumpOutput(IProcess *pProcess, RTVFSIOSTREAM hVfsIosDst, ULONG uHandle, RTMSINTERVAL cMsTimeout)1202 static int gctlRunPumpOutput(IProcess *pProcess, RTVFSIOSTREAM hVfsIosDst, ULONG uHandle, RTMSINTERVAL cMsTimeout) 1137 1203 { 1138 1204 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); … … 1159 1225 } 1160 1226 else 1161 vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));1227 vrc = gctlPrintError(pProcess, COM_IIDOF(IProcess)); 1162 1228 return vrc; 1163 1229 } … … 1174 1240 * @param phVfsIos Where to return the resulting I/O stream handle. 1175 1241 */ 1176 static bool ctrlRunSetupHandle(bool fEnabled, RTHANDLESTD enmHandle, const char *pszName,1242 static bool gctlRunSetupHandle(bool fEnabled, RTHANDLESTD enmHandle, const char *pszName, 1177 1243 kStreamTransform enmTransformation, PRTVFSIOSTREAM phVfsIos) 1178 1244 { … … 1203 1269 * @param cMsTimeout Timeout value (in ms). 1204 1270 */ 1205 static RTMSINTERVAL ctrlExecGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout)1271 static RTMSINTERVAL gctlRunGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout) 1206 1272 { 1207 1273 if (!cMsTimeout || cMsTimeout == RT_INDEFINITE_WAIT) /* If no timeout specified, wait forever. */ … … 1223 1289 * @param fHelp The help flag for the command. 1224 1290 */ 1225 static RTEXITCODE handleCtrlProcessRunCommon(PGCTLCMDCTX pCtx, bool fRunCmd, uint32_t fHelp)1291 static RTEXITCODE gctlHandleRunCommon(PGCTLCMDCTX pCtx, bool fRunCmd, uint32_t fHelp) 1226 1292 { 1227 1293 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 1230 1296 * Parse arguments. 1231 1297 */ 1298 enum kGstCtrlRunOpt 1299 { 1300 kGstCtrlRunOpt_IgnoreOrphanedProcesses = 1000, 1301 kGstCtrlRunOpt_NoProfile, 1302 kGstCtrlRunOpt_Dos2Unix, 1303 kGstCtrlRunOpt_Unix2Dos, 1304 kGstCtrlRunOpt_WaitForStdOut, 1305 kGstCtrlRunOpt_NoWaitForStdOut, 1306 kGstCtrlRunOpt_WaitForStdErr, 1307 kGstCtrlRunOpt_NoWaitForStdErr 1308 }; 1232 1309 static const RTGETOPTDEF s_aOptions[] = 1233 1310 { 1311 GCTLCMD_COMMON_OPTION_DEFS() 1234 1312 { "--putenv", 'E', RTGETOPT_REQ_STRING }, 1235 1313 { "--executable", 'e', RTGETOPT_REQ_STRING }, … … 1249 1327 RTGETOPTUNION ValueUnion; 1250 1328 RTGETOPTSTATE GetState; 1251 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions),1252 pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);1329 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1330 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 1253 1331 1254 1332 com::SafeArray<ProcessCreateFlag_T> aCreateFlags; … … 1276 1354 switch (ch) 1277 1355 { 1356 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 1357 1278 1358 case 'E': 1279 1359 if ( ValueUnion.psz[0] == '\0' … … 1366 1446 { 1367 1447 aWaitFlags.push_back(ProcessWaitForFlag_Terminate); 1368 fWaitForStdOut = ctrlRunSetupHandle(fWaitForStdOut, RTHANDLESTD_OUTPUT, "stdout", enmStdOutTransform, &hVfsStdOut);1448 fWaitForStdOut = gctlRunSetupHandle(fWaitForStdOut, RTHANDLESTD_OUTPUT, "stdout", enmStdOutTransform, &hVfsStdOut); 1369 1449 if (fWaitForStdOut) 1370 1450 { … … 1372 1452 aWaitFlags.push_back(ProcessWaitForFlag_StdOut); 1373 1453 } 1374 fWaitForStdErr = ctrlRunSetupHandle(fWaitForStdErr, RTHANDLESTD_ERROR, "stderr", enmStdErrTransform, &hVfsStdErr);1454 fWaitForStdErr = gctlRunSetupHandle(fWaitForStdErr, RTHANDLESTD_ERROR, "stderr", enmStdErrTransform, &hVfsStdErr); 1375 1455 if (fWaitForStdErr) 1376 1456 { … … 1385 1465 } 1386 1466 1387 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 1467 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 1468 if (rcExit != RTEXITCODE_SUCCESS) 1469 return rcExit; 1470 1388 1471 HRESULT rc; 1389 1472 … … 1398 1481 * Create the process. 1399 1482 */ 1400 if (pCtx-> fVerbose)1483 if (pCtx->cVerbose > 1) 1401 1484 { 1402 1485 if (cMsTimeout == 0) … … 1410 1493 ComSafeArrayAsInParam(aEnv), 1411 1494 ComSafeArrayAsInParam(aCreateFlags), 1412 ctrlExecGetRemainingTime(msStart, cMsTimeout),1495 gctlRunGetRemainingTime(msStart, cMsTimeout), 1413 1496 pProcess.asOutParam())); 1414 1497 … … 1420 1503 ProcessWaitResult_T waitResult; 1421 1504 CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitStartFlags), 1422 ctrlExecGetRemainingTime(msStart, cMsTimeout), &waitResult));1505 gctlRunGetRemainingTime(msStart, cMsTimeout), &waitResult)); 1423 1506 1424 1507 ULONG uPID = 0; 1425 1508 CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID)); 1426 if (fRunCmd && pCtx-> fVerbose)1509 if (fRunCmd && pCtx->cVerbose > 1) 1427 1510 RTPrintf("Process '%s' (PID %RU32) started\n", pszImage, uPID); 1428 1511 else if (!fRunCmd) /** @todo Introduce a --quiet option for not printing this. */ … … 1446 1529 && cMsTimeLeft > 0) 1447 1530 { 1448 cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);1531 cMsTimeLeft = gctlRunGetRemainingTime(msStart, cMsTimeout); 1449 1532 CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags), 1450 1533 RT_MIN(500 /*ms*/, RT_MAX(cMsTimeLeft, 1 /*ms*/)), … … 1462 1545 break; 1463 1546 case ProcessWaitResult_Terminate: 1464 if (pCtx-> fVerbose)1547 if (pCtx->cVerbose > 1) 1465 1548 RTPrintf("Process terminated\n"); 1466 1549 /* Process terminated, we're done. */ … … 1508 1591 if (fReadStdOut) 1509 1592 { 1510 cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);1511 int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdOut, 1 /* StdOut */, cMsTimeLeft);1593 cMsTimeLeft = gctlRunGetRemainingTime(msStart, cMsTimeout); 1594 int vrc2 = gctlRunPumpOutput(pProcess, hVfsStdOut, 1 /* StdOut */, cMsTimeLeft); 1512 1595 if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc)) 1513 1596 vrc = vrc2; … … 1516 1599 if (fReadStdErr) 1517 1600 { 1518 cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);1519 int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdErr, 2 /* StdErr */, cMsTimeLeft);1601 cMsTimeLeft = gctlRunGetRemainingTime(msStart, cMsTimeout); 1602 int vrc2 = gctlRunPumpOutput(pProcess, hVfsStdErr, 2 /* StdErr */, cMsTimeLeft); 1520 1603 if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc)) 1521 1604 vrc = vrc2; … … 1537 1620 if (g_fGuestCtrlCanceled) 1538 1621 { 1539 if (pCtx-> fVerbose)1622 if (pCtx->cVerbose > 1) 1540 1623 RTPrintf("Process execution aborted!\n"); 1541 1624 rcExit = EXITCODEEXEC_CANCELED; … … 1543 1626 else if (fCompletedStartCmd) 1544 1627 { 1545 if (pCtx-> fVerbose)1628 if (pCtx->cVerbose > 1) 1546 1629 RTPrintf("Process successfully started!\n"); 1547 1630 rcExit = RTEXITCODE_SUCCESS; … … 1557 1640 LONG lExitCode; 1558 1641 CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&lExitCode)); 1559 if (pCtx-> fVerbose)1642 if (pCtx->cVerbose > 1) 1560 1643 RTPrintf("Exit code=%u (Status=%u [%s])\n", 1561 lExitCode, procStatus, ctrlProcessStatusToText(procStatus));1562 1563 rcExit = ctrlRunCalculateExitCode(procStatus, lExitCode, true /*fReturnExitCodes*/);1644 lExitCode, procStatus, gctlProcessStatusToText(procStatus)); 1645 1646 rcExit = gctlRunCalculateExitCode(procStatus, lExitCode, true /*fReturnExitCodes*/); 1564 1647 } 1565 1648 else if ( procStatus == ProcessStatus_TimedOutKilled 1566 1649 || procStatus == ProcessStatus_TimedOutAbnormally) 1567 1650 { 1568 if (pCtx-> fVerbose)1651 if (pCtx->cVerbose > 1) 1569 1652 RTPrintf("Process timed out (guest side) and\n", 1570 1653 procStatus == ProcessStatus_TimedOutAbnormally … … 1574 1657 else 1575 1658 { 1576 if (pCtx-> fVerbose)1577 RTPrintf("Process now is in status [%s] (unexpected)\n", ctrlProcessStatusToText(procStatus));1659 if (pCtx->cVerbose > 1) 1660 RTPrintf("Process now is in status [%s] (unexpected)\n", gctlProcessStatusToText(procStatus)); 1578 1661 rcExit = RTEXITCODE_FAILURE; 1579 1662 } … … 1581 1664 else if (RT_FAILURE_NP(vrc)) 1582 1665 { 1583 if (pCtx-> fVerbose)1666 if (pCtx->cVerbose > 1) 1584 1667 RTPrintf("Process monitor loop quit with vrc=%Rrc\n", vrc); 1585 1668 rcExit = RTEXITCODE_FAILURE; … … 1587 1670 else 1588 1671 { 1589 if (pCtx-> fVerbose)1672 if (pCtx->cVerbose > 1) 1590 1673 RTPrintf("Process monitor loop timed out\n"); 1591 1674 rcExit = EXITCODEEXEC_TIMEOUT; … … 1609 1692 */ 1610 1693 if (!fRunCmd && SUCCEEDED(rc) && !g_fGuestCtrlCanceled) 1611 pCtx-> uFlags |= CTLCMDCTX_FLAGS_SESSION_DETACH;1694 pCtx->fDetachGuestSession = true; 1612 1695 1613 1696 /* Make sure we return failure on failure. */ … … 1618 1701 1619 1702 1620 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessRun(PGCTLCMDCTX pCtx)1621 { 1622 return handleCtrlProcessRunCommon(pCtx, true /*fRunCmd*/, USAGE_GSTCTRL_RUN);1623 } 1624 1625 1626 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessStart(PGCTLCMDCTX pCtx)1627 { 1628 return handleCtrlProcessRunCommon(pCtx, false /*fRunCmd*/, USAGE_GSTCTRL_START);1703 static DECLCALLBACK(RTEXITCODE) gctlHandleRun(PGCTLCMDCTX pCtx) 1704 { 1705 return gctlHandleRunCommon(pCtx, true /*fRunCmd*/, USAGE_GSTCTRL_RUN); 1706 } 1707 1708 1709 static DECLCALLBACK(RTEXITCODE) gctlHandleStart(PGCTLCMDCTX pCtx) 1710 { 1711 return gctlHandleRunCommon(pCtx, false /*fRunCmd*/, USAGE_GSTCTRL_START); 1629 1712 } 1630 1713 … … 1749 1832 } 1750 1833 else 1751 vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));1834 vrc = gctlPrintError(pProcess, COM_IIDOF(IProcess)); 1752 1835 return vrc; 1753 1836 } 1754 1837 1755 1838 1756 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExecDeprecated(PGCTLCMDCTX pCtx)1839 static DECLCALLBACK(RTEXITCODE) gctlHandleProcessExecDeprecated(PGCTLCMDCTX pCtx) 1757 1840 { 1758 1841 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 1763 1846 static const RTGETOPTDEF s_aOptions[] = 1764 1847 { 1848 GCTLCMD_COMMON_OPTION_DEFS() 1765 1849 { "--dos2unix", GETOPTDEF_EXEC_DOS2UNIX, RTGETOPT_REQ_NOTHING }, 1766 1850 { "--environment", 'e', RTGETOPT_REQ_STRING }, … … 1771 1855 { "--timeout", 't', RTGETOPT_REQ_UINT32 }, 1772 1856 { "--unix2dos", GETOPTDEF_EXEC_UNIX2DOS, RTGETOPT_REQ_NOTHING }, 1773 { "--unquoted-args", ' u', RTGETOPT_REQ_NOTHING },1857 { "--unquoted-args", 'U', RTGETOPT_REQ_NOTHING }, 1774 1858 { "--wait-exit", GETOPTDEF_EXEC_WAITFOREXIT, RTGETOPT_REQ_NOTHING }, 1775 1859 { "--wait-stdout", GETOPTDEF_EXEC_WAITFORSTDOUT, RTGETOPT_REQ_NOTHING }, … … 1777 1861 }; 1778 1862 1779 #ifdef DEBUG_andy1780 RTPrintf("first=%d\n", pCtx->iFirstArgc);1781 for (int i=0; i<pCtx->iArgc;i++)1782 RTPrintf("\targv[%d]=%s\n", i, pCtx->ppaArgv[i]);1783 #endif1784 1785 1863 int ch; 1786 1864 RTGETOPTUNION ValueUnion; 1787 1865 RTGETOPTSTATE GetState; 1788 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions),1789 pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);1866 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1867 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 1790 1868 1791 1869 Utf8Str strCmd; … … 1811 1889 switch (ch) 1812 1890 { 1891 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 1892 1813 1893 case 'e': /* Environment */ 1814 1894 { … … 1839 1919 break; 1840 1920 1841 case ' u':1921 case 'U': 1842 1922 aCreateFlags.push_back(ProcessCreateFlag_UnquotedArguments); 1843 1923 break; … … 1907 1987 "No command to execute specified!"); 1908 1988 1909 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 1989 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 1990 if (rcExit != RTEXITCODE_SUCCESS) 1991 return rcExit; 1992 1910 1993 HRESULT rc; 1911 1994 … … 1921 2004 uint64_t u64StartMS = RTTimeMilliTS(); 1922 2005 1923 if (pCtx-> fVerbose)2006 if (pCtx->cVerbose > 1) 1924 2007 { 1925 2008 if (cMsTimeout == 0) … … 1937 2020 ComSafeArrayAsInParam(aEnv), 1938 2021 ComSafeArrayAsInParam(aCreateFlags), 1939 ctrlExecGetRemainingTime(u64StartMS, cMsTimeout),2022 gctlRunGetRemainingTime(u64StartMS, cMsTimeout), 1940 2023 pProcess.asOutParam())); 1941 2024 … … 1948 2031 ProcessWaitResult_T waitResult; 1949 2032 CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitStartFlags), 1950 ctrlExecGetRemainingTime(u64StartMS, cMsTimeout), &waitResult));2033 gctlRunGetRemainingTime(u64StartMS, cMsTimeout), &waitResult)); 1951 2034 bool fCompleted = false; 1952 2035 1953 2036 ULONG uPID = 0; 1954 2037 CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID)); 1955 if (!fDetached && pCtx-> fVerbose)2038 if (!fDetached && pCtx->cVerbose > 1) 1956 2039 { 1957 2040 RTPrintf("Process '%s' (PID %RU32) started\n", … … 1981 2064 && cMsTimeLeft != 0) 1982 2065 { 1983 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);2066 cMsTimeLeft = gctlRunGetRemainingTime(u64StartMS, cMsTimeout); 1984 2067 CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags), 1985 2068 500 /* ms */, &waitResult)); … … 2001 2084 break; 2002 2085 case ProcessWaitResult_Terminate: 2003 if (pCtx-> fVerbose)2086 if (pCtx->cVerbose > 1) 2004 2087 RTPrintf("Process terminated\n"); 2005 2088 /* Process terminated, we're done. */ … … 2028 2111 if (fReadStdOut) /* Do we need to fetch stdout data? */ 2029 2112 { 2030 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);2113 cMsTimeLeft = gctlRunGetRemainingTime(u64StartMS, cMsTimeout); 2031 2114 vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdOut, 2032 2115 1 /* StdOut */, cMsTimeLeft); … … 2036 2119 if (fReadStdErr) /* Do we need to fetch stdout data? */ 2037 2120 { 2038 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);2121 cMsTimeLeft = gctlRunGetRemainingTime(u64StartMS, cMsTimeout); 2039 2122 vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdErr, 2040 2123 2 /* StdErr */, cMsTimeLeft); … … 2071 2154 LONG exitCode; 2072 2155 CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&exitCode)); 2073 if (pCtx-> fVerbose)2156 if (pCtx->cVerbose > 1) 2074 2157 RTPrintf("Exit code=%u (Status=%u [%s])\n", 2075 exitCode, procStatus, ctrlProcessStatusToText(procStatus));2158 exitCode, procStatus, gctlProcessStatusToText(procStatus)); 2076 2159 2077 2160 rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCodeDeprecated(procStatus, exitCode); 2078 2161 } 2079 else if (pCtx-> fVerbose)2080 RTPrintf("Process now is in status [%s]\n", ctrlProcessStatusToText(procStatus));2162 else if (pCtx->cVerbose > 1) 2163 RTPrintf("Process now is in status [%s]\n", gctlProcessStatusToText(procStatus)); 2081 2164 } 2082 2165 } 2083 2166 else 2084 2167 { 2085 if (pCtx-> fVerbose)2168 if (pCtx->cVerbose > 1) 2086 2169 RTPrintf("Process execution aborted!\n"); 2087 2170 … … 2123 2206 2124 2207 if (!fCloseSession) 2125 pCtx-> uFlags |= CTLCMDCTX_FLAGS_SESSION_DETACH;2208 pCtx->fDetachGuestSession = true; 2126 2209 2127 2210 if ( rcExit == RTEXITCODE_SUCCESS … … 2139 2222 /** 2140 2223 * Creates a copy context structure which then can be used with various 2141 * guest control copy functions. Needs to be free'd with ctrlCopyContextFree().2224 * guest control copy functions. Needs to be free'd with gctlCopyContextFree(). 2142 2225 * 2143 2226 * @return IPRT status code. … … 2149 2232 * @param ppContext Pointer which receives the allocated copy context. 2150 2233 */ 2151 static int ctrlCopyContextCreate(PGCTLCMDCTX pCtx, bool fDryRun, bool fHostToGuest,2234 static int gctlCopyContextCreate(PGCTLCMDCTX pCtx, bool fDryRun, bool fHostToGuest, 2152 2235 const Utf8Str &strSessionName, 2153 2236 PCOPYCONTEXT *ppContext) … … 2179 2262 * @param pContext Pointer to copy context to free. 2180 2263 */ 2181 static void ctrlCopyContextFree(PCOPYCONTEXT pContext)2264 static void gctlCopyContextFree(PCOPYCONTEXT pContext) 2182 2265 { 2183 2266 if (pContext) … … 2199 2282 * path. Must be free'd with RTStrFree(). 2200 2283 */ 2201 static int ctrlCopyTranslatePath(const char *pszSourceRoot, const char *pszSource,2284 static int gctlCopyTranslatePath(const char *pszSourceRoot, const char *pszSource, 2202 2285 const char *pszDest, char **ppszTranslated) 2203 2286 { … … 2293 2376 2294 2377 char *pszTranslated = NULL; 2295 int iResult = ctrlCopyTranslatePath(aTests[iTest].pszSourceRoot, aTests[iTest].pszSource,2378 int iResult = gctlCopyTranslatePath(aTests[iTest].pszSourceRoot, aTests[iTest].pszSource, 2296 2379 aTests[iTest].pszDest, &pszTranslated); 2297 2380 if (iResult != aTests[iTest].iResult) … … 2326 2409 * @param pszDir Directory to create. 2327 2410 */ 2328 static int ctrlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir)2411 static int gctlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir) 2329 2412 { 2330 2413 AssertPtrReturn(pContext, VERR_INVALID_POINTER); … … 2332 2415 2333 2416 bool fDirExists; 2334 int vrc = ctrlCopyDirExists(pContext, pContext->fHostToGuest, pszDir, &fDirExists);2417 int vrc = gctlCopyDirExists(pContext, pContext->fHostToGuest, pszDir, &fDirExists); 2335 2418 if ( RT_SUCCESS(vrc) 2336 2419 && fDirExists) 2337 2420 { 2338 if (pContext->pCmdCtx-> fVerbose)2421 if (pContext->pCmdCtx->cVerbose > 1) 2339 2422 RTPrintf("Directory \"%s\" already exists\n", pszDir); 2340 2423 return VINF_SUCCESS; … … 2346 2429 return vrc; 2347 2430 2348 if (pContext->pCmdCtx-> fVerbose)2431 if (pContext->pCmdCtx->cVerbose > 1) 2349 2432 RTPrintf("Creating directory \"%s\" ...\n", pszDir); 2350 2433 … … 2359 2442 0700, ComSafeArrayAsInParam(dirCreateFlags)); 2360 2443 if (FAILED(rc)) 2361 vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));2444 vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession)); 2362 2445 } 2363 2446 else /* ... or on the host. */ … … 2381 2464 * given directory exists or not. 2382 2465 */ 2383 static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool fOnGuest,2466 static int gctlCopyDirExists(PCOPYCONTEXT pContext, bool fOnGuest, 2384 2467 const char *pszDir, bool *fExists) 2385 2468 { … … 2394 2477 HRESULT rc = pContext->pCmdCtx->pGuestSession->DirectoryExists(Bstr(pszDir).raw(), &fDirExists); 2395 2478 if (FAILED(rc)) 2396 vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));2479 vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession)); 2397 2480 else 2398 2481 *fExists = fDirExists ? true : false; … … 2413 2496 * given directory exists or not. 2414 2497 */ 2415 static int ctrlCopyDirExistsOnDest(PCOPYCONTEXT pContext, const char *pszDir,2498 static int gctlCopyDirExistsOnDest(PCOPYCONTEXT pContext, const char *pszDir, 2416 2499 bool *fExists) 2417 2500 { 2418 return ctrlCopyDirExists(pContext, pContext->fHostToGuest,2501 return gctlCopyDirExists(pContext, pContext->fHostToGuest, 2419 2502 pszDir, fExists); 2420 2503 } … … 2430 2513 * given directory exists or not. 2431 2514 */ 2432 static int ctrlCopyDirExistsOnSource(PCOPYCONTEXT pContext, const char *pszDir,2515 static int gctlCopyDirExistsOnSource(PCOPYCONTEXT pContext, const char *pszDir, 2433 2516 bool *fExists) 2434 2517 { 2435 return ctrlCopyDirExists(pContext, !pContext->fHostToGuest,2518 return gctlCopyDirExists(pContext, !pContext->fHostToGuest, 2436 2519 pszDir, fExists); 2437 2520 } … … 2448 2531 * given file exists or not. 2449 2532 */ 2450 static int ctrlCopyFileExists(PCOPYCONTEXT pContext, bool bOnGuest,2533 static int gctlCopyFileExists(PCOPYCONTEXT pContext, bool bOnGuest, 2451 2534 const char *pszFile, bool *fExists) 2452 2535 { … … 2461 2544 HRESULT rc = pContext->pCmdCtx->pGuestSession->FileExists(Bstr(pszFile).raw(), &fFileExists); 2462 2545 if (FAILED(rc)) 2463 vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));2546 vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession)); 2464 2547 else 2465 2548 *fExists = fFileExists ? true : false; … … 2480 2563 * given file exists or not. 2481 2564 */ 2482 static int ctrlCopyFileExistsOnDest(PCOPYCONTEXT pContext, const char *pszFile,2565 static int gctlCopyFileExistsOnDest(PCOPYCONTEXT pContext, const char *pszFile, 2483 2566 bool *fExists) 2484 2567 { 2485 return ctrlCopyFileExists(pContext, pContext->fHostToGuest,2568 return gctlCopyFileExists(pContext, pContext->fHostToGuest, 2486 2569 pszFile, fExists); 2487 2570 } … … 2497 2580 * given file exists or not. 2498 2581 */ 2499 static int ctrlCopyFileExistsOnSource(PCOPYCONTEXT pContext, const char *pszFile,2582 static int gctlCopyFileExistsOnSource(PCOPYCONTEXT pContext, const char *pszFile, 2500 2583 bool *fExists) 2501 2584 { 2502 return ctrlCopyFileExists(pContext, !pContext->fHostToGuest,2585 return gctlCopyFileExists(pContext, !pContext->fHostToGuest, 2503 2586 pszFile, fExists); 2504 2587 } … … 2514 2597 * to be set to 0. 2515 2598 */ 2516 static int ctrlCopyFileToDest(PCOPYCONTEXT pContext, const char *pszFileSource,2599 static int gctlCopyFileToDest(PCOPYCONTEXT pContext, const char *pszFileSource, 2517 2600 const char *pszFileDest, uint32_t fFlags) 2518 2601 { … … 2522 2605 AssertReturn(!fFlags, VERR_INVALID_POINTER); /* No flags supported yet. */ 2523 2606 2524 if (pContext->pCmdCtx-> fVerbose)2607 if (pContext->pCmdCtx->cVerbose > 1) 2525 2608 RTPrintf("Copying \"%s\" to \"%s\" ...\n", 2526 2609 pszFileSource, pszFileDest); … … 2549 2632 if (FAILED(rc)) 2550 2633 { 2551 vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));2634 vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession)); 2552 2635 } 2553 2636 else 2554 2637 { 2555 if (pContext->pCmdCtx-> fVerbose)2638 if (pContext->pCmdCtx->cVerbose > 1) 2556 2639 rc = showProgress(pProgress); 2557 2640 else … … 2559 2642 if (SUCCEEDED(rc)) 2560 2643 CHECK_PROGRESS_ERROR(pProgress, ("File copy failed")); 2561 vrc = ctrlPrintProgressError(pProgress);2644 vrc = gctlPrintProgressError(pProgress); 2562 2645 } 2563 2646 … … 2577 2660 * is needed for recursion. 2578 2661 */ 2579 static int ctrlCopyDirToGuest(PCOPYCONTEXT pContext,2662 static int gctlCopyDirToGuest(PCOPYCONTEXT pContext, 2580 2663 const char *pszSource, const char *pszFilter, 2581 2664 const char *pszDest, uint32_t fFlags, … … 2596 2679 vrc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir); 2597 2680 2598 if (pContext->pCmdCtx-> fVerbose)2681 if (pContext->pCmdCtx->cVerbose > 1) 2599 2682 RTPrintf("Processing host directory: %s\n", szCurDir); 2600 2683 … … 2641 2724 break; 2642 2725 2643 if (pContext->pCmdCtx-> fVerbose)2726 if (pContext->pCmdCtx->cVerbose > 1) 2644 2727 RTPrintf("Directory: %s\n", DirEntry.szName); 2645 2728 … … 2657 2740 if (pszNewSub) 2658 2741 { 2659 vrc = ctrlCopyDirToGuest(pContext,2742 vrc = gctlCopyDirToGuest(pContext, 2660 2743 pszSource, pszFilter, 2661 2744 pszDest, fFlags, pszNewSub); … … 2685 2768 } 2686 2769 2687 if (pContext->pCmdCtx-> fVerbose)2770 if (pContext->pCmdCtx->cVerbose > 1) 2688 2771 RTPrintf("File: %s\n", DirEntry.szName); 2689 2772 … … 2691 2774 { 2692 2775 char *pszDestDir; 2693 vrc = ctrlCopyTranslatePath(pszSource, szCurDir,2776 vrc = gctlCopyTranslatePath(pszSource, szCurDir, 2694 2777 pszDest, &pszDestDir); 2695 2778 if (RT_SUCCESS(vrc)) 2696 2779 { 2697 vrc = ctrlCopyDirCreate(pContext, pszDestDir);2780 vrc = gctlCopyDirCreate(pContext, pszDestDir); 2698 2781 RTStrFree(pszDestDir); 2699 2782 … … 2708 2791 { 2709 2792 char *pszFileDest; 2710 vrc = ctrlCopyTranslatePath(pszSource, pszFileSource,2793 vrc = gctlCopyTranslatePath(pszSource, pszFileSource, 2711 2794 pszDest, &pszFileDest); 2712 2795 if (RT_SUCCESS(vrc)) 2713 2796 { 2714 vrc = ctrlCopyFileToDest(pContext, pszFileSource,2797 vrc = gctlCopyFileToDest(pContext, pszFileSource, 2715 2798 pszFileDest, 0 /* Flags */); 2716 2799 RTStrFree(pszFileDest); … … 2746 2829 * is needed for recursion. 2747 2830 */ 2748 static int ctrlCopyDirToHost(PCOPYCONTEXT pContext,2831 static int gctlCopyDirToHost(PCOPYCONTEXT pContext, 2749 2832 const char *pszSource, const char *pszFilter, 2750 2833 const char *pszDest, uint32_t fFlags, … … 2768 2851 return vrc; 2769 2852 2770 if (pContext->pCmdCtx-> fVerbose)2853 if (pContext->pCmdCtx->cVerbose > 1) 2771 2854 RTPrintf("Processing guest directory: %s\n", szCurDir); 2772 2855 … … 2780 2863 pDirectory.asOutParam()); 2781 2864 if (FAILED(rc)) 2782 return ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));2865 return gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession)); 2783 2866 ComPtr<IFsObjInfo> dirEntry; 2784 2867 while (true) … … 2805 2888 break; 2806 2889 2807 if (pContext->pCmdCtx-> fVerbose)2890 if (pContext->pCmdCtx->cVerbose > 1) 2808 2891 { 2809 2892 Utf8Str strDir(strName); … … 2824 2907 if (pszNewSub) 2825 2908 { 2826 vrc = ctrlCopyDirToHost(pContext,2909 vrc = gctlCopyDirToHost(pContext, 2827 2910 pszSource, pszFilter, 2828 2911 pszDest, fFlags, pszNewSub); … … 2855 2938 } 2856 2939 2857 if (pContext->pCmdCtx-> fVerbose)2940 if (pContext->pCmdCtx->cVerbose > 1) 2858 2941 RTPrintf("File: %s\n", strFile.c_str()); 2859 2942 … … 2861 2944 { 2862 2945 char *pszDestDir; 2863 vrc = ctrlCopyTranslatePath(pszSource, szCurDir,2946 vrc = gctlCopyTranslatePath(pszSource, szCurDir, 2864 2947 pszDest, &pszDestDir); 2865 2948 if (RT_SUCCESS(vrc)) 2866 2949 { 2867 vrc = ctrlCopyDirCreate(pContext, pszDestDir);2950 vrc = gctlCopyDirCreate(pContext, pszDestDir); 2868 2951 RTStrFree(pszDestDir); 2869 2952 … … 2878 2961 { 2879 2962 char *pszFileDest; 2880 vrc = ctrlCopyTranslatePath(pszSource, pszFileSource,2963 vrc = gctlCopyTranslatePath(pszSource, pszFileSource, 2881 2964 pszDest, &pszFileDest); 2882 2965 if (RT_SUCCESS(vrc)) 2883 2966 { 2884 vrc = ctrlCopyFileToDest(pContext, pszFileSource,2967 vrc = gctlCopyFileToDest(pContext, pszFileSource, 2885 2968 pszFileDest, 0 /* Flags */); 2886 2969 RTStrFree(pszFileDest); … … 2920 3003 2921 3004 default: 2922 vrc = ctrlPrintError(pDirectory, COM_IIDOF(IGuestDirectory));3005 vrc = gctlPrintError(pDirectory, COM_IIDOF(IGuestDirectory)); 2923 3006 break; 2924 3007 } … … 2928 3011 if (FAILED(rc2)) 2929 3012 { 2930 int vrc2 = ctrlPrintError(pDirectory, COM_IIDOF(IGuestDirectory));3013 int vrc2 = gctlPrintError(pDirectory, COM_IIDOF(IGuestDirectory)); 2931 3014 if (RT_SUCCESS(vrc)) 2932 3015 vrc = vrc2; … … 2950 3033 * @param fFlags Copy flags, such as recursive copying. 2951 3034 */ 2952 static int ctrlCopyDirToDest(PCOPYCONTEXT pContext,3035 static int gctlCopyDirToDest(PCOPYCONTEXT pContext, 2953 3036 const char *pszSource, const char *pszFilter, 2954 3037 const char *pszDest, uint32_t fFlags) 2955 3038 { 2956 3039 if (pContext->fHostToGuest) 2957 return ctrlCopyDirToGuest(pContext, pszSource, pszFilter,3040 return gctlCopyDirToGuest(pContext, pszSource, pszFilter, 2958 3041 pszDest, fFlags, NULL /* Sub directory, only for recursion. */); 2959 return ctrlCopyDirToHost(pContext, pszSource, pszFilter,3042 return gctlCopyDirToHost(pContext, pszSource, pszFilter, 2960 3043 pszDest, fFlags, NULL /* Sub directory, only for recursion. */); 2961 3044 } … … 2967 3050 * @param pszSource Source to create source root for. 2968 3051 * @param ppszSourceRoot Pointer that receives the allocated source root. Needs 2969 * to be free'd with ctrlCopyFreeSourceRoot().2970 */ 2971 static int ctrlCopyCreateSourceRoot(const char *pszSource, char **ppszSourceRoot)3052 * to be free'd with gctlCopyFreeSourceRoot(). 3053 */ 3054 static int gctlCopyCreateSourceRoot(const char *pszSource, char **ppszSourceRoot) 2972 3055 { 2973 3056 AssertPtrReturn(pszSource, VERR_INVALID_POINTER); … … 3013 3096 * @param pszSourceRoot Source root to free. 3014 3097 */ 3015 static void ctrlCopyFreeSourceRoot(char *pszSourceRoot)3098 static void gctlCopyFreeSourceRoot(char *pszSourceRoot) 3016 3099 { 3017 3100 RTStrFree(pszSourceRoot); 3018 3101 } 3019 3102 3020 static RTEXITCODE handleCtrlCopy(PGCTLCMDCTX pCtx, bool fHostToGuest)3103 static RTEXITCODE gctlHandleCopy(PGCTLCMDCTX pCtx, bool fHostToGuest) 3021 3104 { 3022 3105 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 3038 3121 static const RTGETOPTDEF s_aOptions[] = 3039 3122 { 3123 GCTLCMD_COMMON_OPTION_DEFS() 3040 3124 { "--dryrun", GETOPTDEF_COPY_DRYRUN, RTGETOPT_REQ_NOTHING }, 3041 3125 { "--follow", GETOPTDEF_COPY_FOLLOW, RTGETOPT_REQ_NOTHING }, … … 3047 3131 RTGETOPTUNION ValueUnion; 3048 3132 RTGETOPTSTATE GetState; 3049 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv,3050 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);3133 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 3134 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3051 3135 3052 3136 Utf8Str strSource; … … 3065 3149 switch (ch) 3066 3150 { 3151 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 3152 3067 3153 case GETOPTDEF_COPY_DRYRUN: 3068 3154 fDryRun = true; … … 3086 3172 * --target-directory yet? Then use the current 3087 3173 * (= last) argument as destination. */ 3088 if ( pCtx->iArgc == GetState.iNext3174 if ( pCtx->pArg->argc == GetState.iNext 3089 3175 && strDest.isEmpty()) 3090 3176 { … … 3112 3198 "No destination specified!"); 3113 3199 3200 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 3201 if (rcExit != RTEXITCODE_SUCCESS) 3202 return rcExit; 3203 3114 3204 /* 3115 3205 * Done parsing arguments, do some more preparations. 3116 3206 */ 3117 if (pCtx-> fVerbose)3207 if (pCtx->cVerbose > 1) 3118 3208 { 3119 3209 if (fHostToGuest) … … 3128 3218 * the routines need to know when handling the actual copying. */ 3129 3219 PCOPYCONTEXT pContext = NULL; 3130 vrc = ctrlCopyContextCreate(pCtx, fDryRun, fHostToGuest,3220 vrc = gctlCopyContextCreate(pCtx, fDryRun, fHostToGuest, 3131 3221 fHostToGuest 3132 3222 ? "VBoxManage Guest Control - Copy to guest" … … 3153 3243 if (!RTPathFilename(pszDest)) 3154 3244 { 3155 vrc = ctrlCopyDirCreate(pContext, pszDest);3245 vrc = gctlCopyDirCreate(pContext, pszDest); 3156 3246 } 3157 3247 else … … 3163 3253 AssertPtr(pszDestDir); 3164 3254 RTPathStripFilename(pszDestDir); 3165 vrc = ctrlCopyDirCreate(pContext, pszDestDir);3255 vrc = gctlCopyDirCreate(pContext, pszDestDir); 3166 3256 RTStrFree(pszDestDir); 3167 3257 } … … 3182 3272 3183 3273 char *pszSourceRoot; 3184 vrc = ctrlCopyCreateSourceRoot(pszSource, &pszSourceRoot);3274 vrc = gctlCopyCreateSourceRoot(pszSource, &pszSourceRoot); 3185 3275 if (RT_FAILURE(vrc)) 3186 3276 { … … 3189 3279 } 3190 3280 3191 if (pCtx-> fVerbose)3281 if (pCtx->cVerbose > 1) 3192 3282 RTPrintf("Source: %s\n", pszSource); 3193 3283 … … 3201 3291 { 3202 3292 if (pszFilter) /* Directory with filter (so use source root w/o the actual filter). */ 3203 vrc = ctrlCopyDirExistsOnSource(pContext, pszSourceRoot, &fSourceExists);3293 vrc = gctlCopyDirExistsOnSource(pContext, pszSourceRoot, &fSourceExists); 3204 3294 else /* Regular directory without filter. */ 3205 vrc = ctrlCopyDirExistsOnSource(pContext, pszSource, &fSourceExists);3295 vrc = gctlCopyDirExistsOnSource(pContext, pszSource, &fSourceExists); 3206 3296 3207 3297 if (fSourceExists) … … 3214 3304 else 3215 3305 { 3216 vrc = ctrlCopyFileExistsOnSource(pContext, pszSource, &fSourceExists);3306 vrc = gctlCopyFileExistsOnSource(pContext, pszSource, &fSourceExists); 3217 3307 if ( RT_SUCCESS(vrc) 3218 3308 && fSourceExists) … … 3229 3319 /* Single file. */ 3230 3320 char *pszDestFile; 3231 vrc = ctrlCopyTranslatePath(pszSourceRoot, pszSource,3321 vrc = gctlCopyTranslatePath(pszSourceRoot, pszSource, 3232 3322 strDest.c_str(), &pszDestFile); 3233 3323 if (RT_SUCCESS(vrc)) 3234 3324 { 3235 vrc = ctrlCopyFileToDest(pContext, pszSource,3325 vrc = gctlCopyFileToDest(pContext, pszSource, 3236 3326 pszDestFile, 0 /* Flags */); 3237 3327 RTStrFree(pszDestFile); … … 3244 3334 { 3245 3335 /* Directory (with filter?). */ 3246 vrc = ctrlCopyDirToDest(pContext, pszSource, pszFilter,3336 vrc = gctlCopyDirToDest(pContext, pszSource, pszFilter, 3247 3337 strDest.c_str(), fFlags); 3248 3338 } 3249 3339 } 3250 3340 3251 ctrlCopyFreeSourceRoot(pszSourceRoot);3341 gctlCopyFreeSourceRoot(pszSourceRoot); 3252 3342 3253 3343 if ( RT_SUCCESS(vrc) … … 3271 3361 } 3272 3362 3273 ctrlCopyContextFree(pContext);3363 gctlCopyContextFree(pContext); 3274 3364 3275 3365 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 3276 3366 } 3277 3367 3278 static DECLCALLBACK(RTEXITCODE) handleCtrlCopyFrom(PGCTLCMDCTX pCtx)3279 { 3280 return handleCtrlCopy(pCtx, false /* Guest to host */);3281 } 3282 3283 static DECLCALLBACK(RTEXITCODE) handleCtrlCopyTo(PGCTLCMDCTX pCtx)3284 { 3285 return handleCtrlCopy(pCtx, true /* Host to guest */);3286 } 3287 3288 static DECLCALLBACK(RTEXITCODE) handleCtr lCreateDirectory(PGCTLCMDCTX pCtx)3368 static DECLCALLBACK(RTEXITCODE) gctlHandleCopyFrom(PGCTLCMDCTX pCtx) 3369 { 3370 return gctlHandleCopy(pCtx, false /* Guest to host */); 3371 } 3372 3373 static DECLCALLBACK(RTEXITCODE) gctlHandleCopyTo(PGCTLCMDCTX pCtx) 3374 { 3375 return gctlHandleCopy(pCtx, true /* Host to guest */); 3376 } 3377 3378 static DECLCALLBACK(RTEXITCODE) handleCtrtMkDir(PGCTLCMDCTX pCtx) 3289 3379 { 3290 3380 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 3292 3382 static const RTGETOPTDEF s_aOptions[] = 3293 3383 { 3384 GCTLCMD_COMMON_OPTION_DEFS() 3294 3385 { "--mode", 'm', RTGETOPT_REQ_UINT32 }, 3295 3386 { "--parents", 'P', RTGETOPT_REQ_NOTHING } … … 3299 3390 RTGETOPTUNION ValueUnion; 3300 3391 RTGETOPTSTATE GetState; 3301 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv,3302 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc,RTGETOPTINIT_FLAGS_OPTS_FIRST);3392 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 3393 RTGETOPTINIT_FLAGS_OPTS_FIRST); 3303 3394 3304 3395 SafeArray<DirectoryCreateFlag_T> dirCreateFlags; … … 3311 3402 switch (ch) 3312 3403 { 3404 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 3405 3313 3406 case 'm': /* Mode */ 3314 3407 fDirMode = ValueUnion.u32; … … 3324 3417 3325 3418 default: 3326 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ CREATEDIR, ch, &ValueUnion);3419 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKDIR, ch, &ValueUnion); 3327 3420 } 3328 3421 } … … 3330 3423 size_t cDirs = mapDirs.size(); 3331 3424 if (!cDirs) 3332 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ CREATEDIR,3425 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKDIR, 3333 3426 "No directory to create specified!"); 3427 3428 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 3429 if (rcExit != RTEXITCODE_SUCCESS) 3430 return rcExit; 3334 3431 3335 3432 /* … … 3337 3434 */ 3338 3435 HRESULT rc = S_OK; 3339 if (pCtx-> fVerbose && cDirs)3436 if (pCtx->cVerbose > 1) 3340 3437 RTPrintf("Creating %RU32 directories ...\n", cDirs); 3341 3438 … … 3344 3441 && !g_fGuestCtrlCanceled) 3345 3442 { 3346 if (pCtx-> fVerbose)3443 if (pCtx->cVerbose > 1) 3347 3444 RTPrintf("Creating directory \"%s\" ...\n", it->first.c_str()); 3348 3445 … … 3355 3452 } 3356 3453 3357 static DECLCALLBACK(RTEXITCODE) handleCtrlRemoveDirectory(PGCTLCMDCTX pCtx)3454 static DECLCALLBACK(RTEXITCODE) gctlHandleRmDir(PGCTLCMDCTX pCtx) 3358 3455 { 3359 3456 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 3361 3458 static const RTGETOPTDEF s_aOptions[] = 3362 3459 { 3460 GCTLCMD_COMMON_OPTION_DEFS() 3363 3461 { "--recursive", 'R', RTGETOPT_REQ_NOTHING } 3364 3462 }; … … 3367 3465 RTGETOPTUNION ValueUnion; 3368 3466 RTGETOPTSTATE GetState; 3369 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv,3370 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);3467 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 3468 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3371 3469 3372 3470 bool fRecursive = false; … … 3378 3476 switch (ch) 3379 3477 { 3478 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 3479 3380 3480 case 'R': 3381 3481 fRecursive = true; … … 3387 3487 3388 3488 default: 3389 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_R EMOVEDIR, ch, &ValueUnion);3489 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RMDIR, ch, &ValueUnion); 3390 3490 } 3391 3491 } … … 3393 3493 size_t cDirs = mapDirs.size(); 3394 3494 if (!cDirs) 3395 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_R EMOVEDIR,3495 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RMDIR, 3396 3496 "No directory to remove specified!"); 3497 3498 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 3499 if (rcExit != RTEXITCODE_SUCCESS) 3500 return rcExit; 3397 3501 3398 3502 /* … … 3400 3504 */ 3401 3505 HRESULT rc = S_OK; 3402 if (pCtx-> fVerbose && cDirs)3506 if (pCtx->cVerbose > 1) 3403 3507 RTPrintf("Removing %RU32 directories ...\n", cDirs); 3404 3508 … … 3407 3511 && !g_fGuestCtrlCanceled) 3408 3512 { 3409 if (pCtx-> fVerbose)3513 if (pCtx->cVerbose > 1) 3410 3514 RTPrintf("%s directory \"%s\" ...\n", 3411 3515 fRecursive ? "Recursively removing" : "Removing", … … 3423 3527 ComSafeArrayAsInParam(aRemRecFlags), 3424 3528 pProgress.asOutParam())); 3425 if (pCtx-> fVerbose)3529 if (pCtx->cVerbose > 1) 3426 3530 rc = showProgress(pProgress); 3427 3531 else … … 3447 3551 } 3448 3552 3449 static DECLCALLBACK(RTEXITCODE) handleCtrlRemoveFile(PGCTLCMDCTX pCtx)3553 static DECLCALLBACK(RTEXITCODE) gctlHandleRm(PGCTLCMDCTX pCtx) 3450 3554 { 3451 3555 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3556 3557 static const RTGETOPTDEF s_aOptions[] = 3558 { 3559 GCTLCMD_COMMON_OPTION_DEFS() 3560 }; 3452 3561 3453 3562 int ch; 3454 3563 RTGETOPTUNION ValueUnion; 3455 3564 RTGETOPTSTATE GetState; 3456 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, 3457 NULL /* s_aOptions */, 0 /* RT_ELEMENTS(s_aOptions) */, 3458 pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3565 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 3566 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3459 3567 3460 3568 DESTDIRMAP mapDirs; … … 3465 3573 switch (ch) 3466 3574 { 3575 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 3576 3467 3577 case VINF_GETOPT_NOT_OPTION: 3468 3578 mapDirs[ValueUnion.psz]; /* Add destination directory to map. */ … … 3470 3580 3471 3581 default: 3472 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_R EMOVEFILE, ch, &ValueUnion);3582 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RM, ch, &ValueUnion); 3473 3583 } 3474 3584 } … … 3476 3586 size_t cFiles = mapDirs.size(); 3477 3587 if (!cFiles) 3478 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEFILE, 3479 "No file to remove specified!"); 3588 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RM, "No file to remove specified!"); 3589 3590 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 3591 if (rcExit != RTEXITCODE_SUCCESS) 3592 return rcExit; 3480 3593 3481 3594 /* … … 3483 3596 */ 3484 3597 HRESULT rc = S_OK; 3485 if (pCtx-> fVerbose && cFiles)3598 if (pCtx->cVerbose > 1) 3486 3599 RTPrintf("Removing %RU32 file(s) ...\n", cFiles); 3487 3600 … … 3490 3603 && !g_fGuestCtrlCanceled) 3491 3604 { 3492 if (pCtx-> fVerbose)3605 if (pCtx->cVerbose > 1) 3493 3606 RTPrintf("Removing file \"%s\" ...\n", it->first.c_str()); 3494 3607 … … 3501 3614 } 3502 3615 3503 static DECLCALLBACK(RTEXITCODE) handleCtrlRename(PGCTLCMDCTX pCtx)3616 static DECLCALLBACK(RTEXITCODE) gctlHandleMv(PGCTLCMDCTX pCtx) 3504 3617 { 3505 3618 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3506 3619 3507 static const RTGETOPTDEF s_aOptions[] = { { 0 } }; 3620 static const RTGETOPTDEF s_aOptions[] = 3621 { 3622 GCTLCMD_COMMON_OPTION_DEFS() 3623 }; 3508 3624 3509 3625 int ch; 3510 3626 RTGETOPTUNION ValueUnion; 3511 3627 RTGETOPTSTATE GetState; 3512 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv,3513 NULL /*s_aOptions*/, 0 /*RT_ELEMENTS(s_aOptions)*/, pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);3628 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 3629 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3514 3630 3515 3631 int vrc = VINF_SUCCESS; … … 3531 3647 switch (ch) 3532 3648 { 3649 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 3650 3533 3651 /** @todo Implement a --dryrun command. */ 3534 3652 /** @todo Implement rename flags. */ … … 3540 3658 3541 3659 default: 3542 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ RENAME, ch, &ValueUnion);3660 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MV, ch, &ValueUnion); 3543 3661 } 3544 3662 } … … 3554 3672 size_t cSources = vecSources.size(); 3555 3673 if (!cSources) 3556 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ RENAME,3674 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MV, 3557 3675 "No source(s) to move specified!"); 3558 3676 if (cSources < 2) 3559 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ RENAME,3677 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MV, 3560 3678 "No destination specified!"); 3679 3680 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 3681 if (rcExit != RTEXITCODE_SUCCESS) 3682 return rcExit; 3561 3683 3562 3684 /* Delete last element, which now is the destination. */ … … 3577 3699 * Rename (move) the entries. 3578 3700 */ 3579 if (pCtx->fVerbose && cSources) 3580 RTPrintf("Renaming %RU32 %s ...\n", cSources, 3581 cSources > 1 3582 ? "entries" : "entry"); 3701 if (pCtx->cVerbose > 1) 3702 RTPrintf("Renaming %RU32 %s ...\n", cSources, cSources > 1 ? "entries" : "entry"); 3583 3703 3584 3704 std::vector< Utf8Str >::iterator it = vecSources.begin(); … … 3600 3720 if (FAILED(rc)) 3601 3721 { 3602 if (pCtx-> fVerbose)3722 if (pCtx->cVerbose > 1) 3603 3723 RTPrintf("Warning: Cannot stat for element \"%s\": No such element\n", 3604 3724 strCurSource.c_str()); … … 3607 3727 } 3608 3728 3609 if (pCtx-> fVerbose)3729 if (pCtx->cVerbose > 1) 3610 3730 RTPrintf("Renaming %s \"%s\" to \"%s\" ...\n", 3611 3731 fSourceIsDirectory ? "directory" : "file", … … 3635 3755 3636 3756 if ( (it != vecSources.end()) 3637 && pCtx-> fVerbose)3757 && pCtx->cVerbose > 1) 3638 3758 { 3639 3759 RTPrintf("Warning: Not all sources were renamed\n"); … … 3643 3763 } 3644 3764 3645 static DECLCALLBACK(RTEXITCODE) handleCtrlCreateTemp(PGCTLCMDCTX pCtx)3765 static DECLCALLBACK(RTEXITCODE) gctlHandleMkTemp(PGCTLCMDCTX pCtx) 3646 3766 { 3647 3767 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 3649 3769 static const RTGETOPTDEF s_aOptions[] = 3650 3770 { 3771 GCTLCMD_COMMON_OPTION_DEFS() 3651 3772 { "--mode", 'm', RTGETOPT_REQ_UINT32 }, 3652 3773 { "--directory", 'D', RTGETOPT_REQ_NOTHING }, … … 3658 3779 RTGETOPTUNION ValueUnion; 3659 3780 RTGETOPTSTATE GetState; 3660 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv,3661 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);3781 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 3782 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3662 3783 3663 3784 Utf8Str strTemplate; … … 3669 3790 DESTDIRMAP mapDirs; 3670 3791 3671 while ((ch = RTGetOpt(&GetState, &ValueUnion)) )3792 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0) 3672 3793 { 3673 3794 /* For options that require an argument, ValueUnion has received the value. */ 3674 3795 switch (ch) 3675 3796 { 3797 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 3798 3676 3799 case 'm': /* Mode */ 3677 3800 fMode = ValueUnion.u32; … … 3695 3818 strTemplate = ValueUnion.psz; 3696 3819 else 3697 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ CREATETEMP,3820 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKTEMP, 3698 3821 "More than one template specified!\n"); 3699 3822 break; … … 3701 3824 3702 3825 default: 3703 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ CREATETEMP, ch, &ValueUnion);3826 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKTEMP, ch, &ValueUnion); 3704 3827 } 3705 3828 } 3706 3829 3707 3830 if (strTemplate.isEmpty()) 3708 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ CREATETEMP,3831 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKTEMP, 3709 3832 "No template specified!"); 3710 3833 3711 3834 if (!fDirectory) 3712 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ CREATETEMP,3835 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKTEMP, 3713 3836 "Creating temporary files is currently not supported!"); 3837 3838 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 3839 if (rcExit != RTEXITCODE_SUCCESS) 3840 return rcExit; 3714 3841 3715 3842 /* 3716 3843 * Create the directories. 3717 3844 */ 3718 if (pCtx-> fVerbose)3845 if (pCtx->cVerbose > 1) 3719 3846 { 3720 3847 if (fDirectory && !strTempDir.isEmpty()) … … 3743 3870 RTPrintf("Directory name: %ls\n", directory.raw()); 3744 3871 } 3745 // else - temporary file not yet implemented 3872 else 3873 { 3874 // else - temporary file not yet implemented 3875 /** @todo implement temporary file creation (we fend it off above, no 3876 * worries). */ 3877 rc = E_FAIL; 3878 } 3746 3879 3747 3880 return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS; 3748 3881 } 3749 3882 3750 static DECLCALLBACK(RTEXITCODE) handleCtrlStat(PGCTLCMDCTX pCtx)3883 static DECLCALLBACK(RTEXITCODE) gctlHandleStat(PGCTLCMDCTX pCtx) 3751 3884 { 3752 3885 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 3754 3887 static const RTGETOPTDEF s_aOptions[] = 3755 3888 { 3889 GCTLCMD_COMMON_OPTION_DEFS() 3756 3890 { "--dereference", 'L', RTGETOPT_REQ_NOTHING }, 3757 3891 { "--file-system", 'f', RTGETOPT_REQ_NOTHING }, … … 3763 3897 RTGETOPTUNION ValueUnion; 3764 3898 RTGETOPTSTATE GetState; 3765 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv,3766 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);3899 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 3900 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3767 3901 3768 3902 DESTDIRMAP mapObjs; … … 3773 3907 switch (ch) 3774 3908 { 3909 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 3910 3775 3911 case 'L': /* Dereference */ 3776 3912 case 'f': /* File-system */ … … 3794 3930 "No element(s) to check specified!"); 3795 3931 3932 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 3933 if (rcExit != RTEXITCODE_SUCCESS) 3934 return rcExit; 3935 3796 3936 HRESULT rc; 3797 3937 … … 3799 3939 * Doing the checks. 3800 3940 */ 3801 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;3802 3941 DESTDIRMAPITER it = mapObjs.begin(); 3803 3942 while (it != mapObjs.end()) 3804 3943 { 3805 if (pCtx-> fVerbose)3944 if (pCtx->cVerbose > 1) 3806 3945 RTPrintf("Checking for element \"%s\" ...\n", it->first.c_str()); 3807 3946 … … 3815 3954 /* If there's at least one element which does not exist on the guest, 3816 3955 * drop out with exitcode 1. */ 3817 if (pCtx-> fVerbose)3956 if (pCtx->cVerbose > 1) 3818 3957 RTPrintf("Cannot stat for element \"%s\": No such element\n", 3819 3958 it->first.c_str()); … … 3852 3991 } 3853 3992 3854 static DECLCALLBACK(RTEXITCODE) handleCtrlUpdateAdditions(PGCTLCMDCTX pCtx)3993 static DECLCALLBACK(RTEXITCODE) gctlHandleUpdateAdditions(PGCTLCMDCTX pCtx) 3855 3994 { 3856 3995 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 3866 4005 static const RTGETOPTDEF s_aOptions[] = 3867 4006 { 4007 GCTLCMD_COMMON_OPTION_DEFS() 3868 4008 { "--source", 's', RTGETOPT_REQ_STRING }, 3869 4009 { "--wait-start", 'w', RTGETOPT_REQ_NOTHING } … … 3873 4013 RTGETOPTUNION ValueUnion; 3874 4014 RTGETOPTSTATE GetState; 3875 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, 0); 4015 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 4016 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 3876 4017 3877 4018 int vrc = VINF_SUCCESS; … … 3881 4022 switch (ch) 3882 4023 { 4024 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 4025 3883 4026 case 's': 3884 4027 strSource = ValueUnion.psz; … … 3897 4040 3898 4041 default: 3899 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_UPDATE ADDS, ch, &ValueUnion);3900 } 3901 } 3902 3903 if (pCtx-> fVerbose)4042 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_UPDATEGA, ch, &ValueUnion); 4043 } 4044 } 4045 4046 if (pCtx->cVerbose > 1) 3904 4047 RTPrintf("Updating Guest Additions ...\n"); 3905 4048 … … 3908 4051 { 3909 4052 ComPtr<ISystemProperties> pProperties; 3910 CHECK_ERROR_BREAK(pCtx-> handlerArg.virtualBox, COMGETTER(SystemProperties)(pProperties.asOutParam()));4053 CHECK_ERROR_BREAK(pCtx->pArg->virtualBox, COMGETTER(SystemProperties)(pProperties.asOutParam())); 3911 4054 Bstr strISO; 3912 4055 CHECK_ERROR_BREAK(pProperties, COMGETTER(DefaultAdditionsISO)(strISO.asOutParam())); … … 3929 4072 if (RT_SUCCESS(vrc)) 3930 4073 { 3931 if (pCtx-> fVerbose)4074 if (pCtx->cVerbose > 1) 3932 4075 RTPrintf("Using source: %s\n", strSource.c_str()); 4076 4077 4078 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 4079 if (rcExit != RTEXITCODE_SUCCESS) 4080 return rcExit; 4081 3933 4082 3934 4083 com::SafeArray<AdditionsUpdateFlag_T> aUpdateFlags; … … 3936 4085 { 3937 4086 aUpdateFlags.push_back(AdditionsUpdateFlag_WaitForUpdateStartOnly); 3938 if (pCtx-> fVerbose)4087 if (pCtx->cVerbose > 1) 3939 4088 RTPrintf("Preparing and waiting for Guest Additions installer to start ...\n"); 3940 4089 } … … 3947 4096 pProgress.asOutParam())); 3948 4097 if (FAILED(rc)) 3949 vrc = ctrlPrintError(pCtx->pGuest, COM_IIDOF(IGuest));4098 vrc = gctlPrintError(pCtx->pGuest, COM_IIDOF(IGuest)); 3950 4099 else 3951 4100 { 3952 if (pCtx-> fVerbose)4101 if (pCtx->cVerbose > 1) 3953 4102 rc = showProgress(pProgress); 3954 4103 else … … 3957 4106 if (SUCCEEDED(rc)) 3958 4107 CHECK_PROGRESS_ERROR(pProgress, ("Guest additions update failed")); 3959 vrc = ctrlPrintProgressError(pProgress);4108 vrc = gctlPrintProgressError(pProgress); 3960 4109 if ( RT_SUCCESS(vrc) 3961 && pCtx-> fVerbose)4110 && pCtx->cVerbose > 1) 3962 4111 { 3963 4112 RTPrintf("Guest Additions update successful\n"); … … 3969 4118 } 3970 4119 3971 static DECLCALLBACK(RTEXITCODE) handleCtrlList(PGCTLCMDCTX pCtx)4120 static DECLCALLBACK(RTEXITCODE) gctlHandleList(PGCTLCMDCTX pCtx) 3972 4121 { 3973 4122 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 3974 4123 3975 if (pCtx->iArgc < 1) 3976 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST, 3977 "Must specify a listing category"); 3978 3979 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 3980 3981 /** Use RTGetOpt here when handling command line args gets more complex. */ 3982 3983 bool fListAll = false; 3984 bool fListSessions = false; 4124 static const RTGETOPTDEF s_aOptions[] = 4125 { 4126 GCTLCMD_COMMON_OPTION_DEFS() 4127 }; 4128 4129 int ch; 4130 RTGETOPTUNION ValueUnion; 4131 RTGETOPTSTATE GetState; 4132 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 4133 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 4134 4135 bool fSeenListArg = false; 4136 bool fListAll = false; 4137 bool fListSessions = false; 3985 4138 bool fListProcesses = false; 3986 bool fListFiles = false; 3987 if ( !RTStrICmp(pCtx->ppaArgv[0], "sessions") 3988 || !RTStrICmp(pCtx->ppaArgv[0], "sess")) 3989 fListSessions = true; 3990 else if ( !RTStrICmp(pCtx->ppaArgv[0], "processes") 3991 || !RTStrICmp(pCtx->ppaArgv[0], "procs")) 3992 fListSessions = fListProcesses = true; /* Showing processes implies showing sessions. */ 3993 else if ( !RTStrICmp(pCtx->ppaArgv[0], "files")) 3994 fListSessions = fListFiles = true; /* Showing files implies showing sessions. */ 3995 else if (!RTStrICmp(pCtx->ppaArgv[0], "all")) 3996 fListAll = true; 3997 3998 /** @todo Handle "--verbose" using RTGetOpt. */ 4139 bool fListFiles = false; 4140 4141 int vrc = VINF_SUCCESS; 4142 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 4143 && RT_SUCCESS(vrc)) 4144 { 4145 switch (ch) 4146 { 4147 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 4148 4149 case VINF_GETOPT_NOT_OPTION: 4150 if ( !RTStrICmp(ValueUnion.psz, "sessions") 4151 || !RTStrICmp(ValueUnion.psz, "sess")) 4152 fListSessions = true; 4153 else if ( !RTStrICmp(ValueUnion.psz, "processes") 4154 || !RTStrICmp(ValueUnion.psz, "procs")) 4155 fListSessions = fListProcesses = true; /* Showing processes implies showing sessions. */ 4156 else if (!RTStrICmp(ValueUnion.psz, "files")) 4157 fListSessions = fListFiles = true; /* Showing files implies showing sessions. */ 4158 else if (!RTStrICmp(ValueUnion.psz, "all")) 4159 fListAll = true; 4160 else 4161 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST, 4162 "Unknown list: '%s'", ValueUnion.psz); 4163 fSeenListArg = true; 4164 break; 4165 4166 default: 4167 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_UPDATEGA, ch, &ValueUnion); 4168 } 4169 } 4170 4171 if (fSeenListArg) 4172 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST, "Missing list name"); 4173 Assert(fListAll || fListSessions); 4174 4175 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 4176 if (rcExit != RTEXITCODE_SUCCESS) 4177 return rcExit; 4178 4179 3999 4180 /** @todo Do we need a machine-readable output here as well? */ 4000 4181 4001 if ( fListAll 4002 || fListSessions) 4003 { 4004 HRESULT rc; 4005 do 4006 { 4007 size_t cTotalProcs = 0; 4008 size_t cTotalFiles = 0; 4009 4010 SafeIfaceArray <IGuestSession> collSessions; 4011 CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions))); 4012 size_t cSessions = collSessions.size(); 4013 4014 if (cSessions) 4015 { 4016 RTPrintf("Active guest sessions:\n"); 4017 4018 /** @todo Make this output a bit prettier. No time now. */ 4019 4020 for (size_t i = 0; i < cSessions; i++) 4182 HRESULT rc; 4183 size_t cTotalProcs = 0; 4184 size_t cTotalFiles = 0; 4185 4186 SafeIfaceArray <IGuestSession> collSessions; 4187 CHECK_ERROR(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions))); 4188 if (SUCCEEDED(rc)) 4189 { 4190 size_t const cSessions = collSessions.size(); 4191 if (cSessions) 4192 { 4193 RTPrintf("Active guest sessions:\n"); 4194 4195 /** @todo Make this output a bit prettier. No time now. */ 4196 4197 for (size_t i = 0; i < cSessions; i++) 4198 { 4199 ComPtr<IGuestSession> pCurSession = collSessions[i]; 4200 if (!pCurSession.isNull()) 4021 4201 { 4022 ComPtr<IGuestSession> pCurSession = collSessions[i]; 4023 if (!pCurSession.isNull()) 4202 do 4024 4203 { 4025 4204 ULONG uID; … … 4032 4211 CHECK_ERROR_BREAK(pCurSession, COMGETTER(Status)(&sessionStatus)); 4033 4212 RTPrintf("\n\tSession #%-3zu ID=%-3RU32 User=%-16ls Status=[%s] Name=%ls", 4034 i, uID, strUser.raw(), ctrlSessionStatusToText(sessionStatus), strName.raw()); 4035 4036 if ( fListAll 4037 || fListProcesses) 4213 i, uID, strUser.raw(), gctlGuestSessionStatusToText(sessionStatus), strName.raw()); 4214 } while (0); 4215 4216 if ( fListAll 4217 || fListProcesses) 4218 { 4219 SafeIfaceArray <IGuestProcess> collProcesses; 4220 CHECK_ERROR_BREAK(pCurSession, COMGETTER(Processes)(ComSafeArrayAsOutParam(collProcesses))); 4221 for (size_t a = 0; a < collProcesses.size(); a++) 4038 4222 { 4039 SafeIfaceArray <IGuestProcess> collProcesses; 4040 CHECK_ERROR_BREAK(pCurSession, COMGETTER(Processes)(ComSafeArrayAsOutParam(collProcesses))); 4041 for (size_t a = 0; a < collProcesses.size(); a++) 4223 ComPtr<IGuestProcess> pCurProcess = collProcesses[a]; 4224 if (!pCurProcess.isNull()) 4042 4225 { 4043 ComPtr<IGuestProcess> pCurProcess = collProcesses[a]; 4044 if (!pCurProcess.isNull()) 4226 do 4045 4227 { 4046 4228 ULONG uPID; … … 4052 4234 4053 4235 RTPrintf("\n\t\tProcess #%-03zu PID=%-6RU32 Status=[%s] Command=%ls", 4054 a, uPID, ctrlProcessStatusToText(procStatus), strExecPath.raw());4055 } 4236 a, uPID, gctlProcessStatusToText(procStatus), strExecPath.raw()); 4237 } while (0); 4056 4238 } 4057 4058 cTotalProcs += collProcesses.size();4059 4239 } 4060 4240 4061 if ( fListAll 4062 || fListFiles) 4241 cTotalProcs += collProcesses.size(); 4242 } 4243 4244 if ( fListAll 4245 || fListFiles) 4246 { 4247 SafeIfaceArray <IGuestFile> collFiles; 4248 CHECK_ERROR_BREAK(pCurSession, COMGETTER(Files)(ComSafeArrayAsOutParam(collFiles))); 4249 for (size_t a = 0; a < collFiles.size(); a++) 4063 4250 { 4064 SafeIfaceArray <IGuestFile> collFiles; 4065 CHECK_ERROR_BREAK(pCurSession, COMGETTER(Files)(ComSafeArrayAsOutParam(collFiles))); 4066 for (size_t a = 0; a < collFiles.size(); a++) 4251 ComPtr<IGuestFile> pCurFile = collFiles[a]; 4252 if (!pCurFile.isNull()) 4067 4253 { 4068 ComPtr<IGuestFile> pCurFile = collFiles[a]; 4069 if (!pCurFile.isNull()) 4254 do 4070 4255 { 4071 CHECK_ERROR_BREAK(pCurFile, COMGETTER(Id)(&uID)); 4256 ULONG idFile; 4257 CHECK_ERROR_BREAK(pCurFile, COMGETTER(Id)(&idFile)); 4258 Bstr strName; 4072 4259 CHECK_ERROR_BREAK(pCurFile, COMGETTER(FileName)(strName.asOutParam())); 4073 4260 FileStatus_T fileStatus; … … 4075 4262 4076 4263 RTPrintf("\n\t\tFile #%-03zu ID=%-6RU32 Status=[%s] Name=%ls", 4077 a, uID, ctrlFileStatusToText(fileStatus), strName.raw());4078 } 4264 a, idFile, gctlFileStatusToText(fileStatus), strName.raw()); 4265 } while (0); 4079 4266 } 4080 4081 cTotalFiles += collFiles.size();4082 4267 } 4268 4269 cTotalFiles += collFiles.size(); 4083 4270 } 4084 4271 } 4085 4086 RTPrintf("\n\nTotal guest sessions: %zu\n", collSessions.size()); 4087 if (fListAll || fListProcesses) 4088 RTPrintf("Total guest processes: %zu\n", cTotalProcs); 4089 if (fListAll || fListFiles) 4090 RTPrintf("Total guest files: %zu\n", cTotalFiles); 4091 } 4092 else 4093 RTPrintf("No active guest sessions found\n"); 4094 4095 } while (0); 4096 4097 if (FAILED(rc)) 4098 rcExit = RTEXITCODE_FAILURE; 4099 } 4100 else 4101 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST, 4102 "Invalid listing category '%s", pCtx->ppaArgv[0]); 4272 } 4273 4274 RTPrintf("\n\nTotal guest sessions: %zu\n", collSessions.size()); 4275 if (fListAll || fListProcesses) 4276 RTPrintf("Total guest processes: %zu\n", cTotalProcs); 4277 if (fListAll || fListFiles) 4278 RTPrintf("Total guest files: %zu\n", cTotalFiles); 4279 } 4280 else 4281 RTPrintf("No active guest sessions found\n"); 4282 } 4283 4284 if (FAILED(rc)) 4285 rcExit = RTEXITCODE_FAILURE; 4103 4286 4104 4287 return rcExit; 4105 4288 } 4106 4289 4107 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessClose(PGCTLCMDCTX pCtx)4290 static DECLCALLBACK(RTEXITCODE) gctlHandleCloseProcess(PGCTLCMDCTX pCtx) 4108 4291 { 4109 4292 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 4110 4293 4111 if (pCtx->iArgc < 1)4112 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,4113 "Must specify at least a PID to close");4114 4115 4294 static const RTGETOPTDEF s_aOptions[] = 4116 4295 { 4296 GCTLCMD_COMMON_OPTION_DEFS() 4117 4297 { "--session-id", 'i', RTGETOPT_REQ_UINT32 }, 4118 4298 { "--session-name", 'n', RTGETOPT_REQ_STRING } … … 4122 4302 RTGETOPTUNION ValueUnion; 4123 4303 RTGETOPTSTATE GetState; 4124 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv,4125 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);4304 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 4305 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 4126 4306 4127 4307 std::vector < uint32_t > vecPID; … … 4129 4309 Utf8Str strSessionName; 4130 4310 4131 int vrc = VINF_SUCCESS; 4132 4133 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 4134 && RT_SUCCESS(vrc)) 4311 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0) 4135 4312 { 4136 4313 /* For options that require an argument, ValueUnion has received the value. */ 4137 4314 switch (ch) 4138 4315 { 4316 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 4317 4139 4318 case 'n': /* Session name (or pattern) */ 4140 4319 strSessionName = ValueUnion.psz; … … 4146 4325 4147 4326 case VINF_GETOPT_NOT_OPTION: 4148 if (pCtx->iArgc == GetState.iNext) 4327 { 4328 /* Treat every else specified as a PID to kill. */ 4329 uint32_t uPid; 4330 int rc = RTStrToUInt32Ex(ValueUnion.psz, NULL, 0, &uPid); 4331 if ( RT_SUCCESS(rc) 4332 && rc != VWRN_TRAILING_CHARS 4333 && rc != VWRN_NUMBER_TOO_BIG 4334 && rc != VWRN_NEGATIVE_UNSIGNED) 4149 4335 { 4150 /* Treat every else specified as a PID to kill. */ 4151 try 4336 if (uPid != 0) 4152 4337 { 4153 uint32_t uPID = RTStrToUInt32(ValueUnion.psz); 4154 if (uPID) /** @todo Is this what we want? If specifying PID 0 4155 this is not going to work on most systems anyway. */ 4156 vecPID.push_back(uPID); 4157 else 4158 vrc = VERR_INVALID_PARAMETER; 4338 try 4339 { 4340 vecPID.push_back(uPid); 4341 } 4342 catch (std::bad_alloc &) 4343 { 4344 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Out of memory"); 4345 } 4159 4346 } 4160 catch(std::bad_alloc &) 4161 { 4162 vrc = VERR_NO_MEMORY; 4163 } 4347 else 4348 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS, "Invalid PID value: 0"); 4164 4349 } 4350 else 4351 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS, 4352 "Error parsing PID value: %Rrc", rc); 4165 4353 break; 4354 } 4166 4355 4167 4356 default: 4168 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ PROCESS, ch, &ValueUnion);4357 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS, ch, &ValueUnion); 4169 4358 } 4170 4359 } 4171 4360 4172 4361 if (vecPID.empty()) 4173 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ PROCESS,4362 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS, 4174 4363 "At least one PID must be specified to kill!"); 4175 4364 4176 4365 if ( strSessionName.isEmpty() 4177 4366 && ulSessionID == UINT32_MAX) 4178 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS, 4179 "No session ID specified!"); 4180 4181 if ( !strSessionName.isEmpty() 4367 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS, "No session ID specified!"); 4368 4369 if ( strSessionName.isNotEmpty() 4182 4370 && ulSessionID != UINT32_MAX) 4183 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ PROCESS,4371 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS, 4184 4372 "Either session ID or name (pattern) must be specified"); 4185 4373 4186 if (RT_FAILURE(vrc))4187 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,4188 "Invalid parameters specified");4374 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 4375 if (rcExit != RTEXITCODE_SUCCESS) 4376 return rcExit; 4189 4377 4190 4378 HRESULT rc = S_OK; … … 4249 4437 if (fProcFound) 4250 4438 { 4251 if (pCtx-> fVerbose)4439 if (pCtx->cVerbose > 1) 4252 4440 RTPrintf("Terminating process (PID %RU32) (session ID %RU32) ...\n", 4253 4441 uPID, uID); … … 4284 4472 } 4285 4473 4286 static DECLCALLBACK(RTEXITCODE) handleCtrlProcess(PGCTLCMDCTX pCtx) 4474 4475 static DECLCALLBACK(RTEXITCODE) gctlHandleCloseSession(PGCTLCMDCTX pCtx) 4287 4476 { 4288 4477 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 4289 4478 4290 if (pCtx->iArgc < 1) 4291 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS, 4292 "Must specify an action"); 4293 4294 /** Use RTGetOpt here when handling command line args gets more complex. */ 4295 4296 if ( !RTStrICmp(pCtx->ppaArgv[0], "close") 4297 || !RTStrICmp(pCtx->ppaArgv[0], "kill") 4298 || !RTStrICmp(pCtx->ppaArgv[0], "terminate")) 4299 { 4300 pCtx->iFirstArgc++; /* Skip process action. */ 4301 return handleCtrlProcessClose(pCtx); 4302 } 4303 4304 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS, 4305 "Invalid process action '%s'", pCtx->ppaArgv[0]); 4306 } 4307 4308 static DECLCALLBACK(RTEXITCODE) handleCtrlSessionClose(PGCTLCMDCTX pCtx) 4309 { 4310 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 4311 4312 if (pCtx->iArgc < 1) 4313 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION, 4314 "Must specify at least a session to close"); 4315 4479 enum GETOPTDEF_SESSIONCLOSE 4480 { 4481 GETOPTDEF_SESSIONCLOSE_ALL = 2000 4482 }; 4316 4483 static const RTGETOPTDEF s_aOptions[] = 4317 4484 { 4485 GCTLCMD_COMMON_OPTION_DEFS() 4318 4486 { "--all", GETOPTDEF_SESSIONCLOSE_ALL, RTGETOPT_REQ_NOTHING }, 4319 4487 { "--session-id", 'i', RTGETOPT_REQ_UINT32 }, … … 4324 4492 RTGETOPTUNION ValueUnion; 4325 4493 RTGETOPTSTATE GetState; 4326 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv,4327 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);4494 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 4495 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 4328 4496 4329 4497 ULONG ulSessionID = UINT32_MAX; … … 4335 4503 switch (ch) 4336 4504 { 4505 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 4506 4337 4507 case 'n': /* Session name pattern */ 4338 4508 strSessionName = ValueUnion.psz; … … 4348 4518 4349 4519 case VINF_GETOPT_NOT_OPTION: 4350 /** @todo Supply a CSV list of IDs or patterns to close? */ 4351 break; 4352 4520 /** @todo Supply a CSV list of IDs or patterns to close? 4521 * break; */ 4353 4522 default: 4354 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ SESSION, ch, &ValueUnion);4523 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSESESSION, ch, &ValueUnion); 4355 4524 } 4356 4525 } … … 4358 4527 if ( strSessionName.isEmpty() 4359 4528 && ulSessionID == UINT32_MAX) 4360 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ SESSION,4529 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSESESSION, 4361 4530 "No session ID specified!"); 4362 4531 4363 4532 if ( !strSessionName.isEmpty() 4364 4533 && ulSessionID != UINT32_MAX) 4365 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ SESSION,4534 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSESESSION, 4366 4535 "Either session ID or name (pattern) must be specified"); 4536 4537 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 4538 if (rcExit != RTEXITCODE_SUCCESS) 4539 return rcExit; 4367 4540 4368 4541 HRESULT rc = S_OK; … … 4403 4576 4404 4577 Assert(!pSession.isNull()); 4405 if (pCtx-> fVerbose)4578 if (pCtx->cVerbose > 1) 4406 4579 RTPrintf("Closing guest session ID=#%RU32 \"%s\" ...\n", 4407 4580 uID, strNameUtf8.c_str()); 4408 4581 CHECK_ERROR_BREAK(pSession, Close()); 4409 if (pCtx-> fVerbose)4582 if (pCtx->cVerbose > 1) 4410 4583 RTPrintf("Guest session successfully closed\n"); 4411 4584 … … 4425 4598 } 4426 4599 4427 static DECLCALLBACK(RTEXITCODE) handleCtrlSession(PGCTLCMDCTX pCtx) 4428 { 4429 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 4430 4431 if (pCtx->iArgc < 1) 4432 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION, 4433 "Must specify an action"); 4434 4435 /** Use RTGetOpt here when handling command line args gets more complex. */ 4436 4437 if ( !RTStrICmp(pCtx->ppaArgv[0], "close") 4438 || !RTStrICmp(pCtx->ppaArgv[0], "kill") 4439 || !RTStrICmp(pCtx->ppaArgv[0], "terminate")) 4440 { 4441 pCtx->iFirstArgc++; /* Skip session action. */ 4442 return handleCtrlSessionClose(pCtx); 4443 } 4444 4445 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION, 4446 "Invalid session action '%s'", pCtx->ppaArgv[0]); 4447 } 4448 4449 static DECLCALLBACK(RTEXITCODE) handleCtrlWatch(PGCTLCMDCTX pCtx) 4600 4601 static DECLCALLBACK(RTEXITCODE) gctlHandleWatch(PGCTLCMDCTX pCtx) 4450 4602 { 4451 4603 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 4454 4606 * Parse arguments. 4455 4607 */ 4456 static const RTGETOPTDEF s_aOptions[] = { { 0 } }; 4608 static const RTGETOPTDEF s_aOptions[] = 4609 { 4610 GCTLCMD_COMMON_OPTION_DEFS() 4611 }; 4457 4612 4458 4613 int ch; 4459 4614 RTGETOPTUNION ValueUnion; 4460 4615 RTGETOPTSTATE GetState; 4461 RTGetOptInit(&GetState, pCtx-> iArgc, pCtx->ppaArgv,4462 NULL /*s_aOptions*/, 0 /*RT_ELEMENTS(s_aOptions)*/, pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);4616 RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 4617 2, RTGETOPTINIT_FLAGS_OPTS_FIRST); 4463 4618 4464 4619 while ((ch = RTGetOpt(&GetState, &ValueUnion))) … … 4467 4622 switch (ch) 4468 4623 { 4624 GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion); 4625 4469 4626 case VINF_GETOPT_NOT_OPTION: 4470 break;4471 4472 4627 default: 4473 4628 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_WATCH, ch, &ValueUnion); … … 4477 4632 /** @todo Specify categories to watch for. */ 4478 4633 /** @todo Specify a --timeout for waiting only for a certain amount of time? */ 4634 4635 RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx); 4636 if (rcExit != RTEXITCODE_SUCCESS) 4637 return rcExit; 4479 4638 4480 4639 HRESULT rc; … … 4502 4661 } while (0); 4503 4662 4504 if (pCtx-> fVerbose)4663 if (pCtx->cVerbose > 1) 4505 4664 RTPrintf("Waiting for events ...\n"); 4506 4665 … … 4511 4670 } 4512 4671 4513 if (pCtx-> fVerbose)4672 if (pCtx->cVerbose > 1) 4514 4673 RTPrintf("Signal caught, exiting ...\n"); 4515 4674 … … 4547 4706 #endif 4548 4707 4549 /* pArg->argv[0] contains the VM name. */ 4550 /* pArg->argv[1] contains the guest control command. */ 4551 if (pArg->argc < 2) 4552 return errorSyntax(USAGE_GUESTCONTROL, "No sub command specified!"); 4553 4554 uint32_t uCmdCtxFlags = 0; 4555 uint32_t uUsage; 4556 GCTLCMD gctlCmd; 4557 if ( !RTStrICmp(pArg->argv[1], "exec") 4558 || !RTStrICmp(pArg->argv[1], "execute")) 4559 { 4560 gctlCmd.pfnHandler = handleCtrlProcessExecDeprecated; 4561 uUsage = USAGE_GSTCTRL_EXEC; 4562 } 4563 else if (!strcmp(pArg->argv[1], "run")) 4564 { 4565 gctlCmd.pfnHandler = handleCtrlProcessRun; 4566 uUsage = USAGE_GSTCTRL_RUN; 4567 } 4568 else if (!strcmp(pArg->argv[1], "start")) 4569 { 4570 gctlCmd.pfnHandler = handleCtrlProcessStart; 4571 uUsage = USAGE_GSTCTRL_START; 4572 } 4573 else if (!RTStrICmp(pArg->argv[1], "copyfrom")) 4574 { 4575 gctlCmd.pfnHandler = handleCtrlCopyFrom; 4576 uUsage = USAGE_GSTCTRL_COPYFROM; 4577 } 4578 else if ( !RTStrICmp(pArg->argv[1], "copyto") 4579 || !RTStrICmp(pArg->argv[1], "cp")) 4580 { 4581 gctlCmd.pfnHandler = handleCtrlCopyTo; 4582 uUsage = USAGE_GSTCTRL_COPYTO; 4583 } 4584 else if ( !RTStrICmp(pArg->argv[1], "createdirectory") 4585 || !RTStrICmp(pArg->argv[1], "createdir") 4586 || !RTStrICmp(pArg->argv[1], "mkdir") 4587 || !RTStrICmp(pArg->argv[1], "md")) 4588 { 4589 gctlCmd.pfnHandler = handleCtrlCreateDirectory; 4590 uUsage = USAGE_GSTCTRL_CREATEDIR; 4591 } 4592 else if ( !RTStrICmp(pArg->argv[1], "removedirectory") 4593 || !RTStrICmp(pArg->argv[1], "removedir") 4594 || !RTStrICmp(pArg->argv[1], "rmdir")) 4595 { 4596 gctlCmd.pfnHandler = handleCtrlRemoveDirectory; 4597 uUsage = USAGE_GSTCTRL_REMOVEDIR; 4598 } 4599 else if ( !RTStrICmp(pArg->argv[1], "rm") 4600 || !RTStrICmp(pArg->argv[1], "removefile")) 4601 { 4602 gctlCmd.pfnHandler = handleCtrlRemoveFile; 4603 uUsage = USAGE_GSTCTRL_REMOVEFILE; 4604 } 4605 else if ( !RTStrICmp(pArg->argv[1], "ren") 4606 || !RTStrICmp(pArg->argv[1], "rename") 4607 || !RTStrICmp(pArg->argv[1], "mv")) 4608 { 4609 gctlCmd.pfnHandler = handleCtrlRename; 4610 uUsage = USAGE_GSTCTRL_RENAME; 4611 } 4612 else if ( !RTStrICmp(pArg->argv[1], "createtemporary") 4613 || !RTStrICmp(pArg->argv[1], "createtemp") 4614 || !RTStrICmp(pArg->argv[1], "mktemp")) 4615 { 4616 gctlCmd.pfnHandler = handleCtrlCreateTemp; 4617 uUsage = USAGE_GSTCTRL_CREATETEMP; 4618 } 4619 else if ( !RTStrICmp(pArg->argv[1], "kill") /* Linux. */ 4620 || !RTStrICmp(pArg->argv[1], "pkill") /* Solaris / *BSD. */ 4621 || !RTStrICmp(pArg->argv[1], "pskill")) /* SysInternals version. */ 4622 { 4623 /** @todo What about "taskkill" on Windows? */ 4624 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 4625 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 4626 gctlCmd.pfnHandler = handleCtrlProcessClose; 4627 uUsage = USAGE_GSTCTRL_KILL; 4628 } 4629 /** @todo Implement "killall"? */ 4630 else if ( !RTStrICmp(pArg->argv[1], "stat")) 4631 { 4632 gctlCmd.pfnHandler = handleCtrlStat; 4633 uUsage = USAGE_GSTCTRL_STAT; 4634 } 4635 else if ( !RTStrICmp(pArg->argv[1], "updateadditions") 4636 || !RTStrICmp(pArg->argv[1], "updateadds")) 4637 { 4638 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 4639 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 4640 gctlCmd.pfnHandler = handleCtrlUpdateAdditions; 4641 uUsage = USAGE_GSTCTRL_UPDATEADDS; 4642 } 4643 else if ( !RTStrICmp(pArg->argv[1], "list")) 4644 { 4645 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 4646 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 4647 gctlCmd.pfnHandler = handleCtrlList; 4648 uUsage = USAGE_GSTCTRL_LIST; 4649 } 4650 else if ( !RTStrICmp(pArg->argv[1], "session")) 4651 { 4652 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 4653 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 4654 gctlCmd.pfnHandler = handleCtrlSession; 4655 uUsage = USAGE_GSTCTRL_SESSION; 4656 } 4657 else if ( !RTStrICmp(pArg->argv[1], "process")) 4658 { 4659 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 4660 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 4661 gctlCmd.pfnHandler = handleCtrlProcess; 4662 uUsage = USAGE_GSTCTRL_PROCESS; 4663 } 4664 else if ( !RTStrICmp(pArg->argv[1], "watch")) 4665 { 4666 uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS 4667 | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER; 4668 gctlCmd.pfnHandler = handleCtrlWatch; 4669 uUsage = USAGE_GSTCTRL_WATCH; 4670 } 4671 else 4672 return errorSyntax(USAGE_GUESTCONTROL, "Unknown sub command '%s' specified!", pArg->argv[1]); 4673 4674 GCTLCMDCTX cmdCtx; 4675 RT_ZERO(cmdCtx); 4676 4677 RTEXITCODE rcExit = ctrlInitVM(pArg, &cmdCtx, uCmdCtxFlags, uUsage); 4678 if (rcExit == RTEXITCODE_SUCCESS) 4679 { 4680 /* Kick off the actual command handler. */ 4681 rcExit = gctlCmd.pfnHandler(&cmdCtx); 4682 4683 ctrlUninitVM(&cmdCtx, cmdCtx.uFlags); 4684 return rcExit; 4685 } 4686 4687 return rcExit; 4708 /* 4709 * Command definitions. 4710 */ 4711 static const GCTLCMDDEF s_aCmdDefs[] = 4712 { 4713 { "exec", gctlHandleProcessExecDeprecated,USAGE_GSTCTRL_EXEC, 0, }, 4714 { "execute", gctlHandleProcessExecDeprecated,USAGE_GSTCTRL_EXEC, 0, }, 4715 { "run", gctlHandleRun, USAGE_GSTCTRL_RUN, 0, }, 4716 { "start", gctlHandleStart, USAGE_GSTCTRL_START, 0, }, 4717 { "copyfrom", gctlHandleCopyFrom, USAGE_GSTCTRL_COPYFROM, 0, }, 4718 { "copyto", gctlHandleCopyTo, USAGE_GSTCTRL_COPYTO, 0, }, 4719 { "cp", gctlHandleCopyTo, USAGE_GSTCTRL_COPYTO, 0, }, 4720 4721 { "mkdir", handleCtrtMkDir, USAGE_GSTCTRL_MKDIR, 0, }, 4722 { "md", handleCtrtMkDir, USAGE_GSTCTRL_MKDIR, 0, }, 4723 { "createdirectory", handleCtrtMkDir, USAGE_GSTCTRL_MKDIR, 0, }, 4724 { "createdir", handleCtrtMkDir, USAGE_GSTCTRL_MKDIR, 0, }, 4725 4726 { "rmdir", gctlHandleRmDir, USAGE_GSTCTRL_RMDIR, 0, }, 4727 { "removedir", gctlHandleRmDir, USAGE_GSTCTRL_RMDIR, 0, }, 4728 { "removedirectory", gctlHandleRmDir, USAGE_GSTCTRL_RMDIR, 0, }, 4729 4730 { "rm", gctlHandleRm, USAGE_GSTCTRL_RM, 0, }, 4731 { "removefile", gctlHandleRm, USAGE_GSTCTRL_RM, 0, }, 4732 { "erase", gctlHandleRm, USAGE_GSTCTRL_RM, 0, }, 4733 { "del", gctlHandleRm, USAGE_GSTCTRL_RM, 0, }, 4734 { "delete", gctlHandleRm, USAGE_GSTCTRL_RM, 0, }, 4735 4736 { "mv", gctlHandleMv, USAGE_GSTCTRL_MV, 0, }, 4737 { "move", gctlHandleMv, USAGE_GSTCTRL_MV, 0, }, 4738 { "ren", gctlHandleMv, USAGE_GSTCTRL_MV, 0, }, 4739 { "rename", gctlHandleMv, USAGE_GSTCTRL_MV, 0, }, 4740 4741 { "mktemp", gctlHandleMkTemp, USAGE_GSTCTRL_MKTEMP, 0, }, 4742 { "createtemp", gctlHandleMkTemp, USAGE_GSTCTRL_MKTEMP, 0, }, 4743 { "createtemporary", gctlHandleMkTemp, USAGE_GSTCTRL_MKTEMP, 0, }, 4744 4745 { "stat", gctlHandleStat, USAGE_GSTCTRL_STAT, 0, }, 4746 4747 /** @todo r=bird: these just work on processes we created, would be better to 4748 * use some different command names here and leave the standard unix 4749 * kill commands for killing/signalling ANY guest process, unix style. */ 4750 { "closeprocess", gctlHandleCloseProcess, USAGE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4751 { "kill", gctlHandleCloseProcess, USAGE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4752 { "pkill", gctlHandleCloseProcess, USAGE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4753 { "pskill", gctlHandleCloseProcess, USAGE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4754 4755 { "closesession", gctlHandleCloseSession, USAGE_GSTCTRL_CLOSESESSION, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4756 { "list", gctlHandleList, USAGE_GSTCTRL_LIST, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4757 { "watch", gctlHandleWatch, USAGE_GSTCTRL_WATCH, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4758 4759 {"updateguestadditions",gctlHandleUpdateAdditions, USAGE_GSTCTRL_UPDATEGA, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4760 { "updateadditions", gctlHandleUpdateAdditions, USAGE_GSTCTRL_UPDATEGA, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4761 { "updatega", gctlHandleUpdateAdditions, USAGE_GSTCTRL_UPDATEGA, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, }, 4762 }; 4763 4764 /* 4765 * Lookup the command and invoke the handler. 4766 * 4767 * Our Argument expectations: 4768 * argv[0] is the VM name. 4769 * argv[1] is the guest control command. 4770 */ 4771 if (pArg->argc >= 2) 4772 { 4773 const char *pszCmd = pArg->argv[1]; 4774 uint32_t iCmd; 4775 for (iCmd = 0; iCmd < RT_ELEMENTS(s_aCmdDefs); iCmd++) 4776 if (strcmp(s_aCmdDefs[iCmd].pszName, pszCmd) == 0) 4777 { 4778 GCTLCMDCTX CmdCtx; 4779 RTEXITCODE rcExit = gctrCmdCtxInit(&CmdCtx, pArg, &s_aCmdDefs[iCmd]); 4780 if (rcExit == RTEXITCODE_SUCCESS) 4781 { 4782 rcExit = s_aCmdDefs[iCmd].pfnHandler(&CmdCtx); 4783 4784 gctlCtxTerm(&CmdCtx); 4785 } 4786 return rcExit; 4787 } 4788 4789 return errorSyntax(USAGE_GUESTCONTROL, "Unknown sub-command: '%s'", pszCmd); 4790 } 4791 return errorSyntax(USAGE_GUESTCONTROL, "Missing sub-command"); 4688 4792 } 4689 4793 #endif /* !VBOX_ONLY_DOCS */ -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.h
r49181 r55604 5 5 6 6 /* 7 * Copyright (C) 2013 Oracle Corporation7 * Copyright (C) 2013-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 29 29 #include <map> 30 30 31 const char * ctrlFileStatusToText(FileStatus_T enmStatus);32 const char * ctrlProcessStatusToText(ProcessStatus_T enmStatus);33 const char * ctrlSessionStatusToText(GuestSessionStatus_T enmStatus);31 const char *gctlFileStatusToText(FileStatus_T enmStatus); 32 const char *gctlProcessStatusToText(ProcessStatus_T enmStatus); 33 const char *gctlGuestSessionStatusToText(GuestSessionStatus_T enmStatus); 34 34 35 35 using namespace com; -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrlListener.cpp
r49181 r55604 5 5 6 6 /* 7 * Copyright (C) 2013 Oracle Corporation7 * Copyright (C) 2013-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 34 34 #include <vector> 35 35 36 37 38 /* 39 * GuestListenerBase 40 * GuestListenerBase 41 * GuestListenerBase 42 */ 43 36 44 GuestListenerBase::GuestListenerBase(void) 37 45 : mfVerbose(false) … … 49 57 } 50 58 59 60 61 /* 62 * GuestFileEventListener 63 * GuestFileEventListener 64 * GuestFileEventListener 65 */ 51 66 52 67 GuestFileEventListener::GuestFileEventListener(void) … … 86 101 87 102 RTPrintf("File ID=%RU32 \"%s\" changed status to [%s]\n", 88 uID, Utf8Str(strPath).c_str(), 89 ctrlFileStatusToText(fileSts)); 103 uID, Utf8Str(strPath).c_str(), gctlFileStatusToText(fileSts)); 90 104 91 105 } while (0); … … 99 113 return S_OK; 100 114 } 115 116 117 /* 118 * GuestProcessEventListener 119 * GuestProcessEventListener 120 * GuestProcessEventListener 121 */ 101 122 102 123 GuestProcessEventListener::GuestProcessEventListener(void) … … 136 157 137 158 RTPrintf("Process PID=%RU32 \"%s\" changed status to [%s]\n", 138 uPID, Utf8Str(strPath).c_str(), 139 ctrlProcessStatusToText(procSts)); 159 uPID, Utf8Str(strPath).c_str(), gctlProcessStatusToText(procSts)); 140 160 141 161 } while (0); … … 149 169 return S_OK; 150 170 } 171 172 173 /* 174 * GuestSessionEventListener 175 * GuestSessionEventListener 176 * GuestSessionEventListener 177 */ 151 178 152 179 GuestSessionEventListener::GuestSessionEventListener(void) … … 356 383 357 384 RTPrintf("Session ID=%RU32 \"%s\" changed status to [%s]\n", 358 uID, Utf8Str(strName).c_str(), 359 ctrlSessionStatusToText(sessSts)); 385 uID, Utf8Str(strName).c_str(), gctlGuestSessionStatusToText(sessSts)); 360 386 361 387 } while (0); … … 369 395 return S_OK; 370 396 } 397 398 399 /* 400 * GuestEventListener 401 * GuestEventListener 402 * GuestEventListener 403 */ 371 404 372 405 GuestEventListener::GuestEventListener(void) … … 481 514 return S_OK; 482 515 } 516 483 517 #endif /* !VBOX_ONLY_DOCS */ 484 518
Note:
See TracChangeset
for help on using the changeset viewer.