Changeset 55535 in vbox
- Timestamp:
- Apr 30, 2015 2:13:56 AM (9 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 11 edited
-
Additions/common/VBoxService/VBoxServiceControlProcess.cpp (modified) (1 diff)
-
Frontends/VBoxManage/VBoxManage.h (modified) (1 diff)
-
Frontends/VBoxManage/VBoxManageGuestCtrl.cpp (modified) (30 diffs)
-
Main/idl/VirtualBox.xidl (modified) (7 diffs)
-
Main/include/GuestCtrlImplPrivate.h (modified) (1 diff)
-
Main/include/GuestSessionImpl.h (modified) (2 diffs)
-
Main/src-client/GuestDirectoryImpl.cpp (modified) (1 diff)
-
Main/src-client/GuestProcessImpl.cpp (modified) (14 diffs)
-
Main/src-client/GuestSessionImpl.cpp (modified) (12 diffs)
-
Main/src-client/GuestSessionImplTasks.cpp (modified) (9 diffs)
-
ValidationKit/tests/additions/tdAddGuestCtrl.py (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp
r55531 r55535 1500 1500 * Prepare environment variables list. 1501 1501 */ 1502 /** @todo r=bird: you don't need to prepare this, do you? Why don't you replace 1503 * the brilliant RTStrAPrintf call with RTEnvPutEx and drop the papszEnv related code? */ 1502 1504 char **papszEnv = NULL; 1503 1505 uint32_t uNumEnvVars = 0; /* Initialize in case of failing ... */ -
trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h
r55182 r55535 111 111 112 112 #ifdef VBOX_WITH_GUEST_CONTROL 113 # define USAGE_GSTCTRL_EXEC RT_BIT(0) 114 # define USAGE_GSTCTRL_COPYFROM RT_BIT(1) 115 # define USAGE_GSTCTRL_COPYTO RT_BIT(2) 116 # define USAGE_GSTCTRL_CREATEDIR RT_BIT(3) 117 # define USAGE_GSTCTRL_REMOVEDIR RT_BIT(4) 118 # define USAGE_GSTCTRL_REMOVEFILE RT_BIT(5) 119 # define USAGE_GSTCTRL_RENAME RT_BIT(6) 120 # define USAGE_GSTCTRL_CREATETEMP RT_BIT(7) 121 # define USAGE_GSTCTRL_LIST RT_BIT(8) 122 # define USAGE_GSTCTRL_PROCESS RT_BIT(9) 123 # define USAGE_GSTCTRL_KILL RT_BIT(10) 124 # define USAGE_GSTCTRL_SESSION RT_BIT(11) 125 # define USAGE_GSTCTRL_STAT RT_BIT(12) 126 # define USAGE_GSTCTRL_UPDATEADDS RT_BIT(13) 127 # define USAGE_GSTCTRL_WATCH RT_BIT(14) 113 # define USAGE_GSTCTRL_RUN RT_BIT(0) 114 # define USAGE_GSTCTRL_START RT_BIT(1) 115 # define USAGE_GSTCTRL_COPYFROM RT_BIT(2) 116 # define USAGE_GSTCTRL_COPYTO RT_BIT(3) 117 # define USAGE_GSTCTRL_CREATEDIR RT_BIT(4) 118 # define USAGE_GSTCTRL_REMOVEDIR RT_BIT(5) 119 # define USAGE_GSTCTRL_REMOVEFILE RT_BIT(6) 120 # define USAGE_GSTCTRL_RENAME RT_BIT(7) 121 # define USAGE_GSTCTRL_CREATETEMP RT_BIT(8) 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) 129 # define USAGE_GSTCTRL_EXEC RT_BIT(31) /**< @deprecated Remember to remove. */ 128 130 #endif 129 131 -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r55532 r55535 46 46 #include <iprt/process.h> /* For RTProcSelf(). */ 47 47 #include <iprt/thread.h> 48 #include <iprt/vfs.h> 48 49 49 50 #include <map> … … 218 219 typedef std::map< Utf8Str, std::vector<DESTFILEENTRY> >::iterator DESTDIRMAPITER, *PDESTDIRMAPITER; 219 220 220 /**221 * Special exit codes for returning errors/information of a222 * started guest process to the command line VBoxManage was started from.223 * Useful for e.g. scripting.224 *225 * @note These are frozen as of 4.1.0.226 */227 enum EXITCODEEXEC228 {229 EXITCODEEXEC_SUCCESS = RTEXITCODE_SUCCESS,230 /* Process exited normally but with an exit code <> 0. */231 EXITCODEEXEC_CODE = 16,232 EXITCODEEXEC_FAILED = 17,233 EXITCODEEXEC_TERM_SIGNAL = 18,234 EXITCODEEXEC_TERM_ABEND = 19,235 EXITCODEEXEC_TIMEOUT = 20,236 EXITCODEEXEC_DOWN = 21,237 EXITCODEEXEC_CANCELED = 22238 };239 221 240 222 /* … … 245 227 { 246 228 GETOPTDEF_COMMON_PASSWORD = 1000 229 }; 230 231 /** 232 * Long option IDs for the guestcontrol run command. 233 */ 234 enum kGstCtrlRunOpt 235 { 236 kGstCtrlRunOpt_IgnoreOrphanedProcesses = 1000, 237 kGstCtrlRunOpt_NoProfile, 238 kGstCtrlRunOpt_Dos2Unix, 239 kGstCtrlRunOpt_Unix2Dos, 240 kGstCtrlRunOpt_WaitForStdOut, 241 kGstCtrlRunOpt_NoWaitForStdOut, 242 kGstCtrlRunOpt_WaitForStdErr, 243 kGstCtrlRunOpt_NoWaitForStdErr 247 244 }; 248 245 … … 290 287 }; 291 288 292 enum OUTPUTTYPE293 { 294 OUTPUTTYPE_UNDEFINED= 0,295 OUTPUTTYPE_DOS2UNIX = 10,296 OUTPUTTYPE_UNIX2DOS = 20289 enum kStreamTransform 290 { 291 kStreamTransform_None = 0, 292 kStreamTransform_Dos2Unix, 293 kStreamTransform_Unix2Dos 297 294 }; 298 295 … … 307 304 pcszSep1, pcszSep2, 308 305 uSubCmd == ~0U ? "\n" : ""); 309 if (uSubCmd & USAGE_GSTCTRL_ EXEC)306 if (uSubCmd & USAGE_GSTCTRL_RUN) 310 307 RTStrmPrintf(pStrm, 311 " exec[ute]\n" 312 " --image <path to program> --username <name>\n" 313 " [--passwordfile <file> | --password <password>]\n" 314 " [--domain <domain>] [--verbose] [--timeout <msec>]\n" 315 " [--environment \"<NAME>=<VALUE> [<NAME>=<VALUE>]\"]\n" 316 " [--wait-exit] [--wait-stdout] [--wait-stderr]\n" 317 " [--dos2unix] [--unquoted-args] [--unix2dos]\n" 318 " [-- [<argument1>] ... [<argumentN>]]\n" 308 " run\n" 309 " [--image <path to executable>] --username <name>\n" 310 " [--passwordfile <file> | --password <password>]\n" 311 " [--domain <domain>] [--verbose] [--timeout <msec>]\n" 312 " [--setenv <NAME>=<VALUE>] [--unset <NAME>]\n" 313 " [--unquoted-args] [--no-wait-stdout|--wait-stdout]\n" 314 " [--no-wait-stderr|--wait-stderr]\n" 315 " [--dos2unix] [--unix2dos]\n" 316 " [--] <program/arg0> [argument1] ... [argumentN]]\n" 317 "\n"); 318 if (uSubCmd & USAGE_GSTCTRL_START) 319 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" 324 " [--setenv <NAME>=<VALUE>] [--unset <NAME>]\n" 325 " [--unquoted-args] [--dos2unix] [--unix2dos]\n" 326 " [--] <program/arg0> [argument1] ... [argumentN]]\n" 327 "\n"); 328 if (uSubCmd == USAGE_GSTCTRL_EXEC) 329 RTStrmPrintf(pStrm, 330 " {DEPRECATED} exec[ute]\n" 331 " {DEPRECATED} --image <path to program> --username <name>\n" 332 " {DEPRECATED} [--passwordfile <file> | --password <password>]\n" 333 " {DEPRECATED} [--domain <domain>] [--verbose] [--timeout <msec>]\n" 334 " {DEPRECATED} [--environment \"<NAME>=<VALUE> [<NAME>=<VALUE>]\"]\n" 335 " {DEPRECATED} [--wait-exit] [--wait-stdout] [--wait-stderr]\n" 336 " {DEPRECATED} [--dos2unix] [--unquoted-args] [--unix2dos]\n" 337 " {DEPRECATED} [-- [<argument1>] ... [<argumentN>]]\n" 319 338 "\n"); 320 339 if (uSubCmd & USAGE_GSTCTRL_COPYFROM) … … 537 556 } 538 557 539 static int ctrlExecProcessStatusToExitCode(ProcessStatus_T enmStatus, ULONG uExitCode) 540 { 541 int vrc = EXITCODEEXEC_SUCCESS; 558 const char *ctrlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult) 559 { 560 switch (enmWaitResult) 561 { 562 case ProcessWaitResult_Start: 563 return "started"; 564 case ProcessWaitResult_Terminate: 565 return "terminated"; 566 case ProcessWaitResult_Status: 567 return "status changed"; 568 case ProcessWaitResult_Error: 569 return "error"; 570 case ProcessWaitResult_Timeout: 571 return "timed out"; 572 case ProcessWaitResult_StdIn: 573 return "stdin ready"; 574 case ProcessWaitResult_StdOut: 575 return "data on stdout"; 576 case ProcessWaitResult_StdErr: 577 return "data on stderr"; 578 case ProcessWaitResult_WaitFlagNotSupported: 579 return "waiting flag not supported"; 580 default: 581 break; 582 } 583 return "unknown"; 584 } 585 586 /** 587 * Translates a guest session status to a human readable 588 * string. 589 */ 590 const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus) 591 { 542 592 switch (enmStatus) 543 593 { 594 case GuestSessionStatus_Starting: 595 return "starting"; 596 case GuestSessionStatus_Started: 597 return "started"; 598 case GuestSessionStatus_Terminating: 599 return "terminating"; 600 case GuestSessionStatus_Terminated: 601 return "terminated"; 602 case GuestSessionStatus_TimedOutKilled: 603 return "timed out"; 604 case GuestSessionStatus_TimedOutAbnormally: 605 return "timed out, hanging"; 606 case GuestSessionStatus_Down: 607 return "killed"; 608 case GuestSessionStatus_Error: 609 return "error"; 610 default: 611 break; 612 } 613 return "unknown"; 614 } 615 616 /** 617 * Translates a guest file status to a human readable 618 * string. 619 */ 620 const char *ctrlFileStatusToText(FileStatus_T enmStatus) 621 { 622 switch (enmStatus) 623 { 624 case FileStatus_Opening: 625 return "opening"; 626 case FileStatus_Open: 627 return "open"; 628 case FileStatus_Closing: 629 return "closing"; 630 case FileStatus_Closed: 631 return "closed"; 632 case FileStatus_Down: 633 return "killed"; 634 case FileStatus_Error: 635 return "error"; 636 default: 637 break; 638 } 639 return "unknown"; 640 } 641 642 static int ctrlPrintError(com::ErrorInfo &errorInfo) 643 { 644 if ( errorInfo.isFullAvailable() 645 || errorInfo.isBasicAvailable()) 646 { 647 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way 648 * because it contains more accurate info about what went wrong. */ 649 if (errorInfo.getResultCode() == VBOX_E_IPRT_ERROR) 650 RTMsgError("%ls.", errorInfo.getText().raw()); 651 else 652 { 653 RTMsgError("Error details:"); 654 GluePrintErrorInfo(errorInfo); 655 } 656 return VERR_GENERAL_FAILURE; /** @todo */ 657 } 658 AssertMsgFailedReturn(("Object has indicated no error (%Rhrc)!?\n", errorInfo.getResultCode()), 659 VERR_INVALID_PARAMETER); 660 } 661 662 static int ctrlPrintError(IUnknown *pObj, const GUID &aIID) 663 { 664 com::ErrorInfo ErrInfo(pObj, aIID); 665 return ctrlPrintError(ErrInfo); 666 } 667 668 static int ctrlPrintProgressError(ComPtr<IProgress> pProgress) 669 { 670 int vrc = VINF_SUCCESS; 671 HRESULT rc; 672 673 do 674 { 675 BOOL fCanceled; 676 CHECK_ERROR_BREAK(pProgress, COMGETTER(Canceled)(&fCanceled)); 677 if (!fCanceled) 678 { 679 LONG rcProc; 680 CHECK_ERROR_BREAK(pProgress, COMGETTER(ResultCode)(&rcProc)); 681 if (FAILED(rcProc)) 682 { 683 com::ProgressErrorInfo ErrInfo(pProgress); 684 vrc = ctrlPrintError(ErrInfo); 685 } 686 } 687 688 } while(0); 689 690 AssertMsgStmt(SUCCEEDED(rc), ("Could not lookup progress information\n"), vrc = VERR_COM_UNEXPECTED); 691 692 return vrc; 693 } 694 695 /** 696 * Un-initializes the VM after guest control usage. 697 * @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 707 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 } 915 916 /* 917 * Check for mandatory stuff. 918 */ 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 } 1026 1027 1028 /** @name EXITCODEEXEC_XXX - Special run exit codes. 1029 * 1030 * Special exit codes for returning errors/information of a started guest 1031 * process to the command line VBoxManage was started from. Useful for e.g. 1032 * scripting. 1033 * 1034 * ASSUMING that all platforms have at least 7-bits for the exit code we can do 1035 * the following mapping: 1036 * - Guest exit code 0 is mapped to 0 on the host. 1037 * - Guest exit codes 1 thru 93 (0x5d) are displaced by 32, so that 1 1038 * becomes 33 (0x21) on the host and 93 becomes 125 (0x7d) on the host. 1039 * - Guest exit codes 94 (0x5e) and above are mapped to 126 (0x5e). 1040 * 1041 * We ASSUME that all VBoxManage status codes are in the range 0 thru 32. 1042 * 1043 * @note These are frozen as of 4.1.0. 1044 * @note The guest exit code mappings was introduced with 5.0 and the 'run' 1045 * command, they are/was not supported by 'exec'. 1046 * @sa ctrlRunCalculateExitCode 1047 */ 1048 /** Process exited normally but with an exit code <> 0. */ 1049 #define EXITCODEEXEC_CODE ((RTEXITCODE)16) 1050 #define EXITCODEEXEC_FAILED ((RTEXITCODE)17) 1051 #define EXITCODEEXEC_TERM_SIGNAL ((RTEXITCODE)18) 1052 #define EXITCODEEXEC_TERM_ABEND ((RTEXITCODE)19) 1053 #define EXITCODEEXEC_TIMEOUT ((RTEXITCODE)20) 1054 #define EXITCODEEXEC_DOWN ((RTEXITCODE)21) 1055 /** Execution was interrupt by user (ctrl-c). */ 1056 #define EXITCODEEXEC_CANCELED ((RTEXITCODE)22) 1057 /** The first mapped guest (non-zero) exit code. */ 1058 #define EXITCODEEXEC_MAPPED_FIRST 33 1059 /** The last mapped guest (non-zero) exit code value (inclusive). */ 1060 #define EXITCODEEXEC_MAPPED_LAST 125 1061 /** The number of exit codes from EXITCODEEXEC_MAPPED_FIRST to 1062 * EXITCODEEXEC_MAPPED_LAST. This is also the highest guest exit code number 1063 * we're able to map. */ 1064 #define EXITCODEEXEC_MAPPED_RANGE (93) 1065 /** The guest exit code displacement value. */ 1066 #define EXITCODEEXEC_MAPPED_DISPLACEMENT 32 1067 /** The guest exit code was too big to be mapped. */ 1068 #define EXITCODEEXEC_MAPPED_BIG ((RTEXITCODE)126) 1069 /** @} */ 1070 1071 /** 1072 * Calculates the exit code of VBoxManage. 1073 * 1074 * @returns The exit code to return. 1075 * @param enmStatus The guest process status. 1076 * @param uExitCode The associated guest process exit code (where 1077 * applicable). 1078 * @param fReturnExitCodes Set if we're to use the 32-126 range for guest 1079 * exit codes. 1080 */ 1081 static RTEXITCODE ctrlRunCalculateExitCode(ProcessStatus_T enmStatus, ULONG uExitCode, bool fReturnExitCodes) 1082 { 1083 int vrc = RTEXITCODE_SUCCESS; 1084 switch (enmStatus) 1085 { 1086 case ProcessStatus_TerminatedNormally: 1087 if (uExitCode == 0) 1088 return RTEXITCODE_SUCCESS; 1089 if (!fReturnExitCodes) 1090 return EXITCODEEXEC_CODE; 1091 if (uExitCode <= EXITCODEEXEC_MAPPED_RANGE) 1092 return (RTEXITCODE) (uExitCode + EXITCODEEXEC_MAPPED_DISPLACEMENT); 1093 return EXITCODEEXEC_MAPPED_BIG; 1094 1095 case ProcessStatus_TerminatedAbnormally: 1096 return EXITCODEEXEC_TERM_ABEND; 1097 case ProcessStatus_TerminatedSignal: 1098 return EXITCODEEXEC_TERM_SIGNAL; 1099 1100 #if 0 /* see caller! */ 1101 case ProcessStatus_TimedOutKilled: 1102 return EXITCODEEXEC_TIMEOUT; 1103 case ProcessStatus_Down: 1104 return EXITCODEEXEC_DOWN; /* Service/OS is stopping, process was killed. */ 1105 case ProcessStatus_Error: 1106 return EXITCODEEXEC_FAILED; 1107 1108 /* The following is probably for detached? */ 544 1109 case ProcessStatus_Starting: 545 vrc = EXITCODEEXEC_SUCCESS; 1110 return RTEXITCODE_SUCCESS; 1111 case ProcessStatus_Started: 1112 return RTEXITCODE_SUCCESS; 1113 case ProcessStatus_Paused: 1114 return RTEXITCODE_SUCCESS; 1115 case ProcessStatus_Terminating: 1116 return RTEXITCODE_SUCCESS; /** @todo ???? */ 1117 #endif 1118 1119 default: 1120 AssertMsgFailed(("Unknown exit status (%u/%u) from guest process returned!\n", enmStatus, uExitCode)); 1121 return RTEXITCODE_FAILURE; 1122 } 1123 } 1124 1125 1126 /** 1127 * Pumps guest output to the host. 1128 * 1129 * @return IPRT status code. 1130 * @param pProcess Pointer to appropriate process object. 1131 * @param hVfsIosDst Where to write the data. 1132 * @param uHandle Handle where to read the data from. 1133 * @param cMsTimeout Timeout (in ms) to wait for the operation to 1134 * complete. 1135 */ 1136 static int ctrlRunPumpOutput(IProcess *pProcess, RTVFSIOSTREAM hVfsIosDst, ULONG uHandle, RTMSINTERVAL cMsTimeout) 1137 { 1138 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 1139 Assert(hVfsIosDst != NIL_RTVFSIOSTREAM); 1140 1141 int vrc; 1142 1143 SafeArray<BYTE> aOutputData; 1144 HRESULT hrc = pProcess->Read(uHandle, _64K, RT_MAX(cMsTimeout, 1), ComSafeArrayAsOutParam(aOutputData)); 1145 if (SUCCEEDED(hrc)) 1146 { 1147 size_t cbOutputData = aOutputData.size(); 1148 if (cbOutputData == 0) 1149 vrc = VINF_SUCCESS; 1150 else 1151 { 1152 BYTE const *pbBuf = aOutputData.raw(); 1153 AssertPtr(pbBuf); 1154 1155 vrc = RTVfsIoStrmWrite(hVfsIosDst, pbBuf, cbOutputData, true /*fBlocking*/, NULL); 1156 if (RT_FAILURE(vrc)) 1157 RTMsgError("Unable to write output, rc=%Rrc\n", vrc); 1158 } 1159 } 1160 else 1161 vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess)); 1162 return vrc; 1163 } 1164 1165 1166 /** 1167 * Configures a host handle for pumping guest bits. 1168 * 1169 * @returns true if enabled and we successfully configured it. 1170 * @param fEnabled Whether pumping this pipe is configured. 1171 * @param enmHandle The IPRT standard handle designation. 1172 * @param pszName The name for user messages. 1173 * @param enmTransformation The transformation to apply. 1174 * @param phVfsIos Where to return the resulting I/O stream handle. 1175 */ 1176 static bool ctrlRunSetupHandle(bool fEnabled, RTHANDLESTD enmHandle, const char *pszName, 1177 kStreamTransform enmTransformation, PRTVFSIOSTREAM phVfsIos) 1178 { 1179 if (fEnabled) 1180 { 1181 int vrc = RTVfsIoStrmFromStdHandle(enmHandle, 0, true /*fLeaveOpen*/, phVfsIos); 1182 if (RT_SUCCESS(vrc)) 1183 { 1184 if (enmTransformation != kStreamTransform_None) 1185 { 1186 RTMsgWarning("Unsupported %s line ending conversion", pszName); 1187 /** @todo Implement dos2unix and unix2dos stream filters. */ 1188 } 1189 return true; 1190 } 1191 RTMsgWarning("Error getting %s handle: %Rrc", pszName, vrc); 1192 } 1193 return false; 1194 } 1195 1196 1197 /** 1198 * Returns the remaining time (in ms) based on the start time and a set 1199 * timeout value. Returns RT_INDEFINITE_WAIT if no timeout was specified. 1200 * 1201 * @return RTMSINTERVAL Time left (in ms). 1202 * @param u64StartMs Start time (in ms). 1203 * @param cMsTimeout Timeout value (in ms). 1204 */ 1205 static RTMSINTERVAL ctrlExecGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout) 1206 { 1207 if (!cMsTimeout || cMsTimeout == RT_INDEFINITE_WAIT) /* If no timeout specified, wait forever. */ 1208 return RT_INDEFINITE_WAIT; 1209 1210 uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs; 1211 if (u64ElapsedMs >= cMsTimeout) 1212 return 0; 1213 1214 return cMsTimeout - (RTMSINTERVAL)u64ElapsedMs; 1215 } 1216 1217 /** 1218 * Common handler for the 'run' and 'start' commands. 1219 * 1220 * @returns Command exit code. 1221 * @param pCtx Guest session context. 1222 * @param fRunCmd Set if it's 'run' clear if 'start'. 1223 * @param fHelp The help flag for the command. 1224 */ 1225 static RTEXITCODE handleCtrlProcessRunCommon(PGCTLCMDCTX pCtx, bool fRunCmd, uint32_t fHelp) 1226 { 1227 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); 1228 1229 /* 1230 * Parse arguments. 1231 */ 1232 static const RTGETOPTDEF s_aOptions[] = 1233 { 1234 { "--environment", 'E', RTGETOPT_REQ_STRING }, 1235 { "--executable", 'e', RTGETOPT_REQ_STRING }, 1236 { "--timeout", 't', RTGETOPT_REQ_UINT32 }, 1237 { "--unquoted-args", 'u', RTGETOPT_REQ_NOTHING }, 1238 { "--ignore-operhaned-processes", kGstCtrlRunOpt_IgnoreOrphanedProcesses, RTGETOPT_REQ_NOTHING }, 1239 { "--no-profile", kGstCtrlRunOpt_NoProfile, RTGETOPT_REQ_NOTHING }, 1240 { "--dos2unix", kGstCtrlRunOpt_Dos2Unix, RTGETOPT_REQ_NOTHING }, 1241 { "--unix2dos", kGstCtrlRunOpt_Unix2Dos, RTGETOPT_REQ_NOTHING }, 1242 { "--no-wait-stdout", kGstCtrlRunOpt_NoWaitForStdOut, RTGETOPT_REQ_NOTHING }, 1243 { "--wait-stdout", kGstCtrlRunOpt_WaitForStdOut, RTGETOPT_REQ_NOTHING }, 1244 { "--no-wait-stderr", kGstCtrlRunOpt_NoWaitForStdErr, RTGETOPT_REQ_NOTHING }, 1245 { "--wait-stderr", kGstCtrlRunOpt_WaitForStdErr, RTGETOPT_REQ_NOTHING }, 1246 }; 1247 1248 int ch; 1249 RTGETOPTUNION ValueUnion; 1250 RTGETOPTSTATE GetState; 1251 RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions), 1252 pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST); 1253 1254 com::SafeArray<ProcessCreateFlag_T> aCreateFlags; 1255 com::SafeArray<ProcessWaitForFlag_T> aWaitFlags; 1256 com::SafeArray<IN_BSTR> aArgs; 1257 com::SafeArray<IN_BSTR> aEnv; 1258 const char * pszImage = NULL; 1259 bool fDetached = false; 1260 bool fWaitForStdOut = true; 1261 bool fWaitForStdErr = true; 1262 RTVFSIOSTREAM hVfsStdOut = NIL_RTVFSIOSTREAM; 1263 RTVFSIOSTREAM hVfsStdErr = NIL_RTVFSIOSTREAM; 1264 enum kStreamTransform enmStdOutTransform = kStreamTransform_None; 1265 enum kStreamTransform enmStdErrTransform = kStreamTransform_None; 1266 RTMSINTERVAL cMsTimeout = 0; 1267 1268 try 1269 { 1270 /* Wait for process start in any case. This is useful for scripting VBoxManage 1271 * when relying on its overall exit code. */ 1272 aWaitFlags.push_back(ProcessWaitForFlag_Start); 1273 1274 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0) 1275 { 1276 /* For options that require an argument, ValueUnion has received the value. */ 1277 switch (ch) 1278 { 1279 case 'E': 1280 if ( ValueUnion.psz[0] == '\0' 1281 || ValueUnion.psz[0] == '=' 1282 || strchr(ValueUnion.psz, '=') == NULL) 1283 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, 1284 "Invalid argument variable=value pair: '%s'", ValueUnion.psz); 1285 aEnv.push_back(Bstr(ValueUnion.psz).raw()); 1286 break; 1287 1288 case kGstCtrlRunOpt_IgnoreOrphanedProcesses: 1289 aCreateFlags.push_back(ProcessCreateFlag_IgnoreOrphanedProcesses); 1290 break; 1291 1292 case kGstCtrlRunOpt_NoProfile: 1293 aCreateFlags.push_back(ProcessCreateFlag_NoProfile); 1294 break; 1295 1296 case 'i': 1297 pszImage = ValueUnion.psz; 1298 break; 1299 1300 case 'u': 1301 aCreateFlags.push_back(ProcessCreateFlag_UnquotedArguments); 1302 break; 1303 1304 /** @todo Add a hidden flag. */ 1305 1306 case 't': /* Timeout */ 1307 cMsTimeout = ValueUnion.u32; 1308 break; 1309 1310 case kGstCtrlRunOpt_Dos2Unix: 1311 enmStdErrTransform = enmStdOutTransform = kStreamTransform_Dos2Unix; 1312 break; 1313 case kGstCtrlRunOpt_Unix2Dos: 1314 enmStdErrTransform = enmStdOutTransform = kStreamTransform_Unix2Dos; 1315 break; 1316 1317 case kGstCtrlRunOpt_WaitForStdOut: 1318 if (!fRunCmd) 1319 return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --wait-for-stdout"); 1320 fWaitForStdOut = true; 1321 break; 1322 case kGstCtrlRunOpt_NoWaitForStdOut: 1323 if (!fRunCmd) 1324 return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --no-wait-for-stdout"); 1325 fWaitForStdOut = false; 1326 break; 1327 1328 case kGstCtrlRunOpt_WaitForStdErr: 1329 if (!fRunCmd) 1330 return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --wait-for-stderr"); 1331 fWaitForStdErr = true; 1332 break; 1333 case kGstCtrlRunOpt_NoWaitForStdErr: 1334 if (!fRunCmd) 1335 return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --wait-for-stderr"); 1336 fWaitForStdErr = false; 1337 break; 1338 1339 case VINF_GETOPT_NOT_OPTION: 1340 aArgs.push_back(Bstr(ValueUnion.psz).raw()); 1341 if (!pszImage) 1342 { 1343 Assert(aArgs.size() == 1); 1344 pszImage = ValueUnion.psz; 1345 } 1346 break; 1347 1348 default: 1349 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, ch, &ValueUnion); 1350 1351 } /* switch */ 1352 } /* while RTGetOpt */ 1353 1354 /* Must have something to execute. */ 1355 if (!pszImage || *pszImage) 1356 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, "No executable specified!"); 1357 1358 /* 1359 * Finalize process creation and wait flags and input/output streams. 1360 */ 1361 if (!fRunCmd) 1362 { 1363 aCreateFlags.push_back(ProcessCreateFlag_WaitForProcessStartOnly); 1364 Assert(!fWaitForStdOut); 1365 Assert(!fWaitForStdErr); 1366 } 1367 else 1368 { 1369 aWaitFlags.push_back(ProcessWaitForFlag_Terminate); 1370 fWaitForStdOut = ctrlRunSetupHandle(fWaitForStdOut, RTHANDLESTD_OUTPUT, "stdout", enmStdOutTransform, &hVfsStdOut); 1371 if (fWaitForStdOut) 1372 { 1373 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut); 1374 aWaitFlags.push_back(ProcessWaitForFlag_StdOut); 1375 } 1376 fWaitForStdErr = ctrlRunSetupHandle(fWaitForStdErr, RTHANDLESTD_ERROR, "stderr", enmStdErrTransform, &hVfsStdErr); 1377 if (fWaitForStdErr) 1378 { 1379 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr); 1380 aWaitFlags.push_back(ProcessWaitForFlag_StdErr); 1381 } 1382 } 1383 } 1384 catch (std::bad_alloc &) 1385 { 1386 return RTMsgErrorExit(RTEXITCODE_FAILURE, "VERR_NO_MEMORY\n"); 1387 } 1388 1389 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 1390 HRESULT rc; 1391 1392 try 1393 { 1394 do 1395 { 1396 /* Get current time stamp to later calculate rest of timeout left. */ 1397 uint64_t msStart = RTTimeMilliTS(); 1398 1399 /* 1400 * Create the process. 1401 */ 1402 if (pCtx->fVerbose) 1403 { 1404 if (cMsTimeout == 0) 1405 RTPrintf("Starting guest process ...\n"); 1406 else 1407 RTPrintf("Starting guest process (within %ums)\n", cMsTimeout); 1408 } 1409 ComPtr<IGuestProcess> pProcess; 1410 CHECK_ERROR_BREAK(pCtx->pGuestSession, ProcessCreate(Bstr(pszImage).raw(), 1411 ComSafeArrayAsInParam(aArgs), 1412 ComSafeArrayAsInParam(aEnv), 1413 ComSafeArrayAsInParam(aCreateFlags), 1414 ctrlExecGetRemainingTime(msStart, cMsTimeout), 1415 pProcess.asOutParam())); 1416 1417 /* 1418 * Explicitly wait for the guest process to be in a started state. 1419 */ 1420 com::SafeArray<ProcessWaitForFlag_T> aWaitStartFlags; 1421 aWaitStartFlags.push_back(ProcessWaitForFlag_Start); 1422 ProcessWaitResult_T waitResult; 1423 CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitStartFlags), 1424 ctrlExecGetRemainingTime(msStart, cMsTimeout), &waitResult)); 1425 1426 ULONG uPID = 0; 1427 CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID)); 1428 if (fRunCmd && pCtx->fVerbose) 1429 RTPrintf("Process '%s' (PID %RU32) started\n", pszImage, uPID); 1430 else if (!fRunCmd) /** @todo Introduce a --quiet option for not printing this. */ 1431 { 1432 /* Just print plain PID to make it easier for scripts 1433 * invoking VBoxManage. */ 1434 RTPrintf("[%RU32 - Session %RU32]\n", uPID, pCtx->uSessionID); 1435 } 1436 1437 /* 1438 * Wait for process to exit/start... 1439 */ 1440 RTMSINTERVAL cMsTimeLeft = 1; /* Will be calculated. */ 1441 bool fReadStdOut = false; 1442 bool fReadStdErr = false; 1443 bool fCompleted = false; 1444 bool fCompletedStartCmd = false; 1445 int vrc = VINF_SUCCESS; 1446 1447 while ( !fCompleted 1448 && cMsTimeLeft > 0) 1449 { 1450 cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout); 1451 CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags), 1452 RT_MIN(500 /*ms*/, RT_MAX(cMsTimeLeft, 1 /*ms*/)), 1453 &waitResult)); 1454 switch (waitResult) 1455 { 1456 case ProcessWaitResult_Start: 1457 fCompletedStartCmd = fCompleted = !fRunCmd; /* Only wait for startup if the 'start' command. */ 1458 break; 1459 case ProcessWaitResult_StdOut: 1460 fReadStdOut = true; 1461 break; 1462 case ProcessWaitResult_StdErr: 1463 fReadStdErr = true; 1464 break; 1465 case ProcessWaitResult_Terminate: 1466 if (pCtx->fVerbose) 1467 RTPrintf("Process terminated\n"); 1468 /* Process terminated, we're done. */ 1469 fCompleted = true; 1470 break; 1471 case ProcessWaitResult_WaitFlagNotSupported: 1472 /* The guest does not support waiting for stdout/err, so 1473 * yield to reduce the CPU load due to busy waiting. */ 1474 RTThreadYield(); 1475 fReadStdOut = fReadStdErr = true; 1476 break; 1477 case ProcessWaitResult_Timeout: 1478 { 1479 /** @todo It is really unclear whether we will get stuck with the timeout 1480 * result here if the guest side times out the process and fails to 1481 * kill the process... To be on the save side, double the IPC and 1482 * check the process status every time we time out. */ 1483 ProcessStatus_T enmProcStatus; 1484 CHECK_ERROR_BREAK(pProcess, COMGETTER(Status)(&enmProcStatus)); 1485 if ( enmProcStatus == ProcessStatus_TimedOutKilled 1486 || enmProcStatus == ProcessStatus_TimedOutAbnormally) 1487 fCompleted = true; 1488 fReadStdOut = fReadStdErr = true; 1489 break; 1490 } 1491 case ProcessWaitResult_Status: 1492 /* ignore. */ 1493 break; 1494 case ProcessWaitResult_Error: 1495 /* waitFor is dead in the water, I think, so better leave the loop. */ 1496 vrc = VERR_CALLBACK_RETURN; 1497 break; 1498 1499 case ProcessWaitResult_StdIn: AssertFailed(); /* did ask for this! */ break; 1500 case ProcessWaitResult_None: AssertFailed(); /* used. */ break; 1501 default: AssertFailed(); /* huh? */ break; 1502 } 1503 1504 if (g_fGuestCtrlCanceled) 1505 break; 1506 1507 /* 1508 * Pump output as needed. 1509 */ 1510 if (fReadStdOut) 1511 { 1512 cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout); 1513 int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdOut, 1 /* StdOut */, cMsTimeLeft); 1514 if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc)) 1515 vrc = vrc2; 1516 fReadStdOut = false; 1517 } 1518 if (fReadStdErr) 1519 { 1520 cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout); 1521 int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdErr, 2 /* StdErr */, cMsTimeLeft); 1522 if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc)) 1523 vrc = vrc2; 1524 fReadStdErr = false; 1525 } 1526 if ( RT_FAILURE(vrc) 1527 || g_fGuestCtrlCanceled) 1528 break; 1529 1530 /* 1531 * Process events before looping. 1532 */ 1533 NativeEventQueue::getMainEventQueue()->processEventQueue(0); 1534 } /* while */ 1535 1536 /* 1537 * Report status back to the user. 1538 */ 1539 if (g_fGuestCtrlCanceled) 1540 { 1541 if (pCtx->fVerbose) 1542 RTPrintf("Process execution aborted!\n"); 1543 rcExit = EXITCODEEXEC_CANCELED; 1544 } 1545 else if (fCompletedStartCmd) 1546 { 1547 if (pCtx->fVerbose) 1548 RTPrintf("Process successfully started!\n"); 1549 rcExit = RTEXITCODE_SUCCESS; 1550 } 1551 else if (fCompleted) 1552 { 1553 ProcessStatus_T procStatus; 1554 CHECK_ERROR_BREAK(pProcess, COMGETTER(Status)(&procStatus)); 1555 if ( procStatus == ProcessStatus_TerminatedNormally 1556 || procStatus == ProcessStatus_TerminatedAbnormally 1557 || procStatus == ProcessStatus_TerminatedSignal) 1558 { 1559 LONG lExitCode; 1560 CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&lExitCode)); 1561 if (pCtx->fVerbose) 1562 RTPrintf("Exit code=%u (Status=%u [%s])\n", 1563 lExitCode, procStatus, ctrlProcessStatusToText(procStatus)); 1564 1565 rcExit = ctrlRunCalculateExitCode(procStatus, lExitCode, true /*fReturnExitCodes*/); 1566 } 1567 else if ( procStatus == ProcessStatus_TimedOutKilled 1568 || procStatus == ProcessStatus_TimedOutAbnormally) 1569 { 1570 if (pCtx->fVerbose) 1571 RTPrintf("Process timed out (guest side) and\n", 1572 procStatus == ProcessStatus_TimedOutAbnormally 1573 ? " failed to terminate so far" : " was terminated"); 1574 rcExit = EXITCODEEXEC_TIMEOUT; 1575 } 1576 else 1577 { 1578 if (pCtx->fVerbose) 1579 RTPrintf("Process now is in status [%s] (unexpected)\n", ctrlProcessStatusToText(procStatus)); 1580 rcExit = RTEXITCODE_FAILURE; 1581 } 1582 } 1583 else if (RT_FAILURE_NP(vrc)) 1584 { 1585 if (pCtx->fVerbose) 1586 RTPrintf("Process monitor loop quit with vrc=%Rrc\n", vrc); 1587 rcExit = RTEXITCODE_FAILURE; 1588 } 1589 else 1590 { 1591 if (pCtx->fVerbose) 1592 RTPrintf("Process monitor loop timed out\n"); 1593 rcExit = EXITCODEEXEC_TIMEOUT; 1594 } 1595 1596 } while (0); 1597 } 1598 catch (std::bad_alloc) 1599 { 1600 rc = E_OUTOFMEMORY; 1601 } 1602 1603 /* 1604 * Decide what to do with the guest session. 1605 * 1606 * If it's the 'start' command where detach the guest process after 1607 * starting, don't close the guest session it is part of, except on 1608 * failure or ctrl-c. 1609 * 1610 * For the 'run' command the guest process quits with us. 1611 */ 1612 if (!fRunCmd && SUCCEEDED(rc) && !g_fGuestCtrlCanceled) 1613 pCtx->uFlags |= CTLCMDCTX_FLAGS_SESSION_DETACH; 1614 1615 /* Make sure we return failure on failure. */ 1616 if (FAILED(rc) && rcExit == RTEXITCODE_SUCCESS) 1617 rcExit = RTEXITCODE_FAILURE; 1618 return rcExit; 1619 } 1620 1621 1622 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessRun(PGCTLCMDCTX pCtx) 1623 { 1624 return handleCtrlProcessRunCommon(pCtx, true /*fRunCmd*/, USAGE_GSTCTRL_RUN); 1625 } 1626 1627 1628 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessStart(PGCTLCMDCTX pCtx) 1629 { 1630 return handleCtrlProcessRunCommon(pCtx, false /*fRunCmd*/, USAGE_GSTCTRL_START); 1631 } 1632 1633 #if 1 /* Old exec code. */ 1634 1635 static int ctrlExecProcessStatusToExitCodeDeprecated(ProcessStatus_T enmStatus, ULONG uExitCode) 1636 { 1637 int vrc = RTEXITCODE_SUCCESS; 1638 switch (enmStatus) 1639 { 1640 case ProcessStatus_Starting: 1641 vrc = RTEXITCODE_SUCCESS; 546 1642 break; 547 1643 case ProcessStatus_Started: 548 vrc = EXITCODEEXEC_SUCCESS;1644 vrc = RTEXITCODE_SUCCESS; 549 1645 break; 550 1646 case ProcessStatus_Paused: 551 vrc = EXITCODEEXEC_SUCCESS;1647 vrc = RTEXITCODE_SUCCESS; 552 1648 break; 553 1649 case ProcessStatus_Terminating: 554 vrc = EXITCODEEXEC_SUCCESS;1650 vrc = RTEXITCODE_SUCCESS; 555 1651 break; 556 1652 case ProcessStatus_TerminatedNormally: 557 vrc = !uExitCode ? EXITCODEEXEC_SUCCESS : EXITCODEEXEC_CODE;1653 vrc = !uExitCode ? RTEXITCODE_SUCCESS : EXITCODEEXEC_CODE; 558 1654 break; 559 1655 case ProcessStatus_TerminatedSignal: … … 584 1680 } 585 1681 586 const char *ctrlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult)587 {588 switch (enmWaitResult)589 {590 case ProcessWaitResult_Start:591 return "started";592 case ProcessWaitResult_Terminate:593 return "terminated";594 case ProcessWaitResult_Status:595 return "status changed";596 case ProcessWaitResult_Error:597 return "error";598 case ProcessWaitResult_Timeout:599 return "timed out";600 case ProcessWaitResult_StdIn:601 return "stdin ready";602 case ProcessWaitResult_StdOut:603 return "data on stdout";604 case ProcessWaitResult_StdErr:605 return "data on stderr";606 case ProcessWaitResult_WaitFlagNotSupported:607 return "waiting flag not supported";608 default:609 break;610 }611 return "unknown";612 }613 614 /**615 * Translates a guest session status to a human readable616 * string.617 */618 const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus)619 {620 switch (enmStatus)621 {622 case GuestSessionStatus_Starting:623 return "starting";624 case GuestSessionStatus_Started:625 return "started";626 case GuestSessionStatus_Terminating:627 return "terminating";628 case GuestSessionStatus_Terminated:629 return "terminated";630 case GuestSessionStatus_TimedOutKilled:631 return "timed out";632 case GuestSessionStatus_TimedOutAbnormally:633 return "timed out, hanging";634 case GuestSessionStatus_Down:635 return "killed";636 case GuestSessionStatus_Error:637 return "error";638 default:639 break;640 }641 return "unknown";642 }643 644 /**645 * Translates a guest file status to a human readable646 * string.647 */648 const char *ctrlFileStatusToText(FileStatus_T enmStatus)649 {650 switch (enmStatus)651 {652 case FileStatus_Opening:653 return "opening";654 case FileStatus_Open:655 return "open";656 case FileStatus_Closing:657 return "closing";658 case FileStatus_Closed:659 return "closed";660 case FileStatus_Down:661 return "killed";662 case FileStatus_Error:663 return "error";664 default:665 break;666 }667 return "unknown";668 }669 670 static int ctrlPrintError(com::ErrorInfo &errorInfo)671 {672 if ( errorInfo.isFullAvailable()673 || errorInfo.isBasicAvailable())674 {675 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way676 * because it contains more accurate info about what went wrong. */677 if (errorInfo.getResultCode() == VBOX_E_IPRT_ERROR)678 RTMsgError("%ls.", errorInfo.getText().raw());679 else680 {681 RTMsgError("Error details:");682 GluePrintErrorInfo(errorInfo);683 }684 return VERR_GENERAL_FAILURE; /** @todo */685 }686 AssertMsgFailedReturn(("Object has indicated no error (%Rhrc)!?\n", errorInfo.getResultCode()),687 VERR_INVALID_PARAMETER);688 }689 690 static int ctrlPrintError(IUnknown *pObj, const GUID &aIID)691 {692 com::ErrorInfo ErrInfo(pObj, aIID);693 return ctrlPrintError(ErrInfo);694 }695 696 static int ctrlPrintProgressError(ComPtr<IProgress> pProgress)697 {698 int vrc = VINF_SUCCESS;699 HRESULT rc;700 701 do702 {703 BOOL fCanceled;704 CHECK_ERROR_BREAK(pProgress, COMGETTER(Canceled)(&fCanceled));705 if (!fCanceled)706 {707 LONG rcProc;708 CHECK_ERROR_BREAK(pProgress, COMGETTER(ResultCode)(&rcProc));709 if (FAILED(rcProc))710 {711 com::ProgressErrorInfo ErrInfo(pProgress);712 vrc = ctrlPrintError(ErrInfo);713 }714 }715 716 } while(0);717 718 AssertMsgStmt(SUCCEEDED(rc), ("Could not lookup progress information\n"), vrc = VERR_COM_UNEXPECTED);719 720 return vrc;721 }722 723 /**724 * Un-initializes the VM after guest control usage.725 * @param pCmdCtx Pointer to command context.726 * @param uFlags Command context flags.727 */728 static void ctrlUninitVM(PGCTLCMDCTX pCtx, uint32_t uFlags)729 {730 AssertPtrReturnVoid(pCtx);731 732 if (!(pCtx->uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))733 ctrlSignalHandlerUninstall();734 735 HRESULT rc;736 737 do738 {739 if (!pCtx->pGuestSession.isNull())740 {741 if ( !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)742 && !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH))743 {744 if (pCtx->fVerbose)745 RTPrintf("Closing guest session ...\n");746 747 CHECK_ERROR(pCtx->pGuestSession, Close());748 /* Keep going - don't break here. Try to unlock the749 * machine down below. */750 }751 else if ( (pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH)752 && pCtx->fVerbose)753 RTPrintf("Guest session detached\n");754 755 pCtx->pGuestSession.setNull();756 }757 758 if (pCtx->handlerArg.session)759 CHECK_ERROR(pCtx->handlerArg.session, UnlockMachine());760 761 } while (0);762 763 for (int i = 0; i < pCtx->iArgc; i++)764 RTStrFree(pCtx->ppaArgv[i]);765 RTMemFree(pCtx->ppaArgv);766 pCtx->iArgc = 0;767 }768 769 /**770 * Initializes the VM for IGuest operations.771 *772 * That is, checks whether it's up and running, if it can be locked (shared773 * only) and returns a valid IGuest pointer on success. Also, it does some774 * basic command line processing and opens a guest session, if required.775 *776 * @return RTEXITCODE status code.777 * @param pArg Pointer to command line argument structure.778 * @param pCmdCtx Pointer to command context.779 * @param uFlags Command context flags.780 */781 static RTEXITCODE ctrlInitVM(HandlerArg *pArg,782 PGCTLCMDCTX pCtx, uint32_t uFlags, uint32_t uUsage)783 {784 AssertPtrReturn(pArg, RTEXITCODE_FAILURE);785 AssertReturn(pArg->argc > 1, RTEXITCODE_FAILURE);786 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);787 788 #ifdef DEBUG_andy789 RTPrintf("Original argv:\n");790 for (int i=0; i<pArg->argc;i++)791 RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);792 #endif793 794 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;795 796 const char *pszNameOrId = pArg->argv[0];797 const char *pszCmd = pArg->argv[1];798 799 /* Lookup VM. */800 ComPtr<IMachine> machine;801 /* Assume it's an UUID. */802 HRESULT rc;803 CHECK_ERROR(pArg->virtualBox, FindMachine(Bstr(pszNameOrId).raw(),804 machine.asOutParam()));805 if (SUCCEEDED(rc))806 {807 /* Machine is running? */808 MachineState_T machineState;809 CHECK_ERROR(machine, COMGETTER(State)(&machineState));810 if ( SUCCEEDED(rc)811 && (machineState != MachineState_Running))812 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine \"%s\" is not running (currently %s)!\n",813 pszNameOrId, machineStateToName(machineState, false));814 }815 else816 rcExit = RTEXITCODE_FAILURE;817 818 if (rcExit == RTEXITCODE_SUCCESS)819 {820 /*821 * Process standard options which are served by all commands.822 */823 static const RTGETOPTDEF s_aOptions[] =824 {825 { "--username", 'u', RTGETOPT_REQ_STRING },826 { "--passwordfile", 'p', RTGETOPT_REQ_STRING },827 { "--password", GETOPTDEF_COMMON_PASSWORD, RTGETOPT_REQ_STRING },828 { "--domain", 'd', RTGETOPT_REQ_STRING },829 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }830 };831 832 /*833 * Allocate per-command argv. This then only contains the specific arguments834 * the command needs.835 */836 pCtx->ppaArgv = (char**)RTMemAlloc(pArg->argc * sizeof(char*) + 1);837 if (!pCtx->ppaArgv)838 {839 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Not enough memory for per-command argv\n");840 }841 else842 {843 pCtx->iArgc = 0;844 845 int iArgIdx = 2; /* Skip VM name and guest control command */846 int ch;847 RTGETOPTUNION ValueUnion;848 RTGETOPTSTATE GetState;849 RTGetOptInit(&GetState, pArg->argc, pArg->argv,850 s_aOptions, RT_ELEMENTS(s_aOptions),851 iArgIdx, 0);852 853 while ( (ch = RTGetOpt(&GetState, &ValueUnion))854 && (rcExit == RTEXITCODE_SUCCESS))855 {856 /* For options that require an argument, ValueUnion has received the value. */857 switch (ch)858 {859 case 'u': /* User name */860 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))861 pCtx->strUsername = ValueUnion.psz;862 iArgIdx = GetState.iNext;863 break;864 865 case GETOPTDEF_COMMON_PASSWORD: /* Password */866 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))867 {868 if (pCtx->strPassword.isEmpty())869 pCtx->strPassword = ValueUnion.psz;870 }871 iArgIdx = GetState.iNext;872 break;873 874 case 'p': /* Password file */875 {876 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))877 rcExit = readPasswordFile(ValueUnion.psz, &pCtx->strPassword);878 iArgIdx = GetState.iNext;879 break;880 }881 882 case 'd': /* domain */883 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))884 pCtx->strDomain = ValueUnion.psz;885 iArgIdx = GetState.iNext;886 break;887 888 case 'v': /* Verbose */889 pCtx->fVerbose = true;890 iArgIdx = GetState.iNext;891 break;892 893 case 'h': /* Help */894 errorGetOptEx(USAGE_GUESTCONTROL, uUsage, ch, &ValueUnion);895 return RTEXITCODE_SYNTAX;896 897 default:898 /* Simply skip; might be handled in a specific command899 * handler later. */900 break;901 902 } /* switch */903 904 int iArgDiff = GetState.iNext - iArgIdx;905 if (iArgDiff)906 {907 #ifdef DEBUG_andy908 RTPrintf("Not handled (iNext=%d, iArgsCur=%d):\n", GetState.iNext, iArgIdx);909 #endif910 for (int i = iArgIdx; i < GetState.iNext; i++)911 {912 char *pszArg = RTStrDup(pArg->argv[i]);913 if (!pszArg)914 {915 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,916 "Not enough memory for command line handling\n");917 break;918 }919 pCtx->ppaArgv[pCtx->iArgc] = pszArg;920 pCtx->iArgc++;921 #ifdef DEBUG_andy922 RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);923 #endif924 }925 926 iArgIdx = GetState.iNext;927 }928 929 } /* while RTGetOpt */930 }931 }932 933 /*934 * Check for mandatory stuff.935 */936 if (rcExit == RTEXITCODE_SUCCESS)937 {938 #if 0939 RTPrintf("argc=%d\n", pCtx->iArgc);940 for (int i = 0; i < pCtx->iArgc; i++)941 RTPrintf("argv[%d]=%s\n", i, pCtx->ppaArgv[i]);942 #endif943 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))944 {945 if (pCtx->strUsername.isEmpty())946 rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, uUsage, "No user name specified!");947 }948 }949 950 if (rcExit == RTEXITCODE_SUCCESS)951 {952 /*953 * Build up a reasonable guest session name. Useful for identifying954 * a specific session when listing / searching for them.955 */956 char *pszSessionName;957 if (0 >= RTStrAPrintf(&pszSessionName,958 "[%RU32] VBoxManage Guest Control [%s] - %s",959 RTProcSelf(), pszNameOrId, pszCmd))960 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name\n");961 962 do963 {964 /* Open a session for the VM. */965 CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared));966 /* Get the associated console. */967 ComPtr<IConsole> console;968 CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam()));969 /* ... and session machine. */970 ComPtr<IMachine> sessionMachine;971 CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam()));972 /* Get IGuest interface. */973 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pCtx->pGuest.asOutParam()));974 if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))975 {976 if (pCtx->fVerbose)977 RTPrintf("Opening guest session as user '%s' ...\n", pCtx->strUsername.c_str());978 979 /* Open a guest session. */980 Assert(!pCtx->pGuest.isNull());981 CHECK_ERROR_BREAK(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(),982 Bstr(pCtx->strPassword).raw(),983 Bstr(pCtx->strDomain).raw(),984 Bstr(pszSessionName).raw(),985 pCtx->pGuestSession.asOutParam()));986 987 /*988 * Wait for guest session to start.989 */990 if (pCtx->fVerbose)991 RTPrintf("Waiting for guest session to start ...\n");992 993 com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;994 aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);995 GuestSessionWaitResult_T sessionWaitResult;996 CHECK_ERROR_BREAK(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags),997 /** @todo Make session handling timeouts configurable. */998 30 * 1000, &sessionWaitResult));999 1000 if ( sessionWaitResult == GuestSessionWaitResult_Start1001 /* Note: This might happen when Guest Additions < 4.3 are installed which don't1002 * support dedicated guest sessions. */1003 || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported)1004 {1005 CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID));1006 if (pCtx->fVerbose)1007 RTPrintf("Guest session (ID %RU32) has been started\n", pCtx->uSessionID);1008 }1009 else1010 {1011 GuestSessionStatus_T sessionStatus;1012 CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Status)(&sessionStatus));1013 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error starting guest session (current status is: %s)\n",1014 ctrlSessionStatusToText(sessionStatus));1015 break;1016 }1017 }1018 1019 if ( SUCCEEDED(rc)1020 && !(uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))1021 {1022 ctrlSignalHandlerInstall();1023 }1024 1025 } while (0);1026 1027 if (FAILED(rc))1028 rcExit = RTEXITCODE_FAILURE;1029 1030 RTStrFree(pszSessionName);1031 }1032 1033 if (rcExit == RTEXITCODE_SUCCESS)1034 {1035 pCtx->handlerArg = *pArg;1036 pCtx->uFlags = uFlags;1037 }1038 else /* Clean up on failure. */1039 ctrlUninitVM(pCtx, uFlags);1040 1041 return rcExit;1042 }1043 1682 1044 1683 /** … … 1049 1688 * @param pStrmOutput Where to write the data. 1050 1689 * @param uHandle Handle where to read the data from. 1051 * @param uTimeoutMS Timeout (in ms) to wait for the operation to complete. 1690 * @param cMsTimeout Timeout (in ms) to wait for the operation to 1691 * complete. 1692 * @remarks Obsolete. 1052 1693 */ 1053 static int ctrlExecPrintOutput (IProcess *pProcess, PRTSTREAM pStrmOutput,1054 ULONG uHandle, ULONG uTimeoutMS)1694 static int ctrlExecPrintOutputDeprecated(IProcess *pProcess, PRTSTREAM pStrmOutput, 1695 ULONG uHandle, RTMSINTERVAL cMsTimeout) 1055 1696 { 1056 1697 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); … … 1060 1701 1061 1702 SafeArray<BYTE> aOutputData; 1062 HRESULT rc = pProcess->Read(uHandle, _64K, uTimeoutMS,1703 HRESULT rc = pProcess->Read(uHandle, _64K, cMsTimeout, 1063 1704 ComSafeArrayAsOutParam(aOutputData)); 1064 if (FAILED(rc)) 1065 vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess)); 1066 else 1705 if (SUCCEEDED(rc)) 1067 1706 { 1068 1707 size_t cbOutputData = aOutputData.size(); … … 1072 1711 AssertPtr(pBuf); 1073 1712 pBuf[cbOutputData - 1] = 0; /* Properly terminate buffer. */ 1074 1075 /** @todo implement the dos2unix/unix2dos conversions */1076 1713 1077 1714 /* … … 1088 1725 cbOutputData = strlen(pszBufUTF8); 1089 1726 1090 ULONG cbOutputDataPrint = cbOutputData;1727 ULONG cbOutputDataPrint = (ULONG)cbOutputData; 1091 1728 for (char *s = pszBufUTF8, *d = s; 1092 1729 s - pszBufUTF8 < (ssize_t)cbOutputData; … … 1113 1750 } 1114 1751 } 1115 1752 else 1753 vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess)); 1116 1754 return vrc; 1117 1755 } 1118 1756 1119 /** 1120 * Returns the remaining time (in ms) based on the start time and a set 1121 * timeout value. Returns RT_INDEFINITE_WAIT if no timeout was specified. 1122 * 1123 * @return RTMSINTERVAL Time left (in ms). 1124 * @param u64StartMs Start time (in ms). 1125 * @param cMsTimeout Timeout value (in ms). 1126 */ 1127 inline RTMSINTERVAL ctrlExecGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout) 1128 { 1129 if (!cMsTimeout || cMsTimeout == RT_INDEFINITE_WAIT) /* If no timeout specified, wait forever. */ 1130 return RT_INDEFINITE_WAIT; 1131 1132 uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs; 1133 if (u64ElapsedMs >= cMsTimeout) 1134 return 0; 1135 1136 return cMsTimeout - (RTMSINTERVAL)u64ElapsedMs; 1137 } 1138 1139 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExec(PGCTLCMDCTX pCtx) 1757 1758 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExecDeprecated(PGCTLCMDCTX pCtx) 1140 1759 { 1141 1760 AssertPtrReturn(pCtx, RTEXITCODE_FAILURE); … … 1175 1794 com::SafeArray<ProcessCreateFlag_T> aCreateFlags; 1176 1795 com::SafeArray<ProcessWaitForFlag_T> aWaitFlags; 1177 com::SafeArray<IN_BSTR> aArgs; 1796 com::SafeArray<IN_BSTR> aArgsWithout0; 1797 com::SafeArray<IN_BSTR> aArgsWith0; 1178 1798 com::SafeArray<IN_BSTR> aEnv; 1179 1799 RTMSINTERVAL cMsTimeout = 0; 1180 OUTPUTTYPE eOutputType = OUTPUTTYPE_UNDEFINED;1181 1800 bool fDetached = true; 1182 1801 int vrc = VINF_SUCCESS; … … 1194 1813 switch (ch) 1195 1814 { 1196 case GETOPTDEF_EXEC_DOS2UNIX:1197 if (eOutputType != OUTPUTTYPE_UNDEFINED)1198 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,1199 "More than one output type (dos2unix/unix2dos) specified!");1200 eOutputType = OUTPUTTYPE_DOS2UNIX;1201 break;1202 1203 1815 case 'e': /* Environment */ 1204 1816 { … … 1208 1820 vrc = RTGetOptArgvFromString(&papszArg, &cArgs, ValueUnion.psz, NULL); 1209 1821 if (RT_FAILURE(vrc)) 1210 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ EXEC,1822 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, 1211 1823 "Failed to parse environment value, rc=%Rrc", vrc); 1212 1824 for (int j = 0; j < cArgs; j++) … … 1240 1852 1241 1853 case GETOPTDEF_EXEC_UNIX2DOS: 1242 if (eOutputType != OUTPUTTYPE_UNDEFINED) 1243 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC, 1244 "More than one output type (dos2unix/unix2dos) specified!"); 1245 eOutputType = OUTPUTTYPE_UNIX2DOS; 1246 break; 1854 case GETOPTDEF_EXEC_DOS2UNIX: 1855 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, 1856 "Output conversion not implemented yet!"); 1247 1857 1248 1858 case GETOPTDEF_EXEC_WAITFOREXIT: … … 1264 1874 1265 1875 case VINF_GETOPT_NOT_OPTION: 1266 if (aArgs .size() == 0 && strCmd.isEmpty())1876 if (aArgsWithout0.size() == 0 && strCmd.isEmpty()) 1267 1877 strCmd = ValueUnion.psz; 1268 1878 else 1269 aArgs .push_back(Bstr(ValueUnion.psz).raw());1879 aArgsWithout0.push_back(Bstr(ValueUnion.psz).raw()); 1270 1880 break; 1271 1881 … … 1274 1884 * contain a single dash, e.g. "-- foo.exe -s". */ 1275 1885 if (GetState.argc == GetState.iNext) 1276 aArgs .push_back(Bstr(ValueUnion.psz).raw());1886 aArgsWithout0.push_back(Bstr(ValueUnion.psz).raw()); 1277 1887 else 1278 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ EXEC, ch, &ValueUnion);1888 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, ch, &ValueUnion); 1279 1889 break; 1280 1890 1281 1891 } /* switch */ 1282 1892 } /* while RTGetOpt */ 1893 1894 /* Create aArgsWith0 from strCmd and aArgsWithout0. */ 1895 aArgsWith0.push_back(Bstr(strCmd).raw()); 1896 for (size_t i = 0; i < aArgsWithout0.size(); i++) 1897 aArgsWith0.push_back(aArgsWithout0[i]); 1283 1898 } 1284 1899 catch (std::bad_alloc &) … … 1291 1906 1292 1907 if (strCmd.isEmpty()) 1293 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_ EXEC,1908 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, 1294 1909 "No command to execute specified!"); 1295 1296 /** @todo Any output conversion not supported yet! */1297 if (eOutputType != OUTPUTTYPE_UNDEFINED)1298 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,1299 "Output conversion not implemented yet!");1300 1910 1301 1911 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; … … 1326 1936 ComPtr<IGuestProcess> pProcess; 1327 1937 CHECK_ERROR_BREAK(pCtx->pGuestSession, ProcessCreate(Bstr(strCmd).raw(), 1328 ComSafeArrayAsInParam(aArgs ),1938 ComSafeArrayAsInParam(aArgsWith0), 1329 1939 ComSafeArrayAsInParam(aEnv), 1330 1940 ComSafeArrayAsInParam(aCreateFlags), … … 1421 2031 { 1422 2032 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout); 1423 vrc = ctrlExecPrintOutput (pProcess, g_pStdOut,1424 1 /* StdOut */, cMsTimeLeft);2033 vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdOut, 2034 1 /* StdOut */, cMsTimeLeft); 1425 2035 fReadStdOut = false; 1426 2036 } … … 1429 2039 { 1430 2040 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout); 1431 vrc = ctrlExecPrintOutput (pProcess, g_pStdErr,1432 2 /* StdErr */, cMsTimeLeft);2041 vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdErr, 2042 2 /* StdErr */, cMsTimeLeft); 1433 2043 fReadStdErr = false; 1434 2044 } … … 1467 2077 exitCode, procStatus, ctrlProcessStatusToText(procStatus)); 1468 2078 1469 rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCode (procStatus, exitCode);2079 rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCodeDeprecated(procStatus, exitCode); 1470 2080 } 1471 2081 else if (pCtx->fVerbose) … … 1526 2136 return rcExit; 1527 2137 } 2138 2139 #endif /* Old exec code. */ 1528 2140 1529 2141 /** … … 2718 3330 } 2719 3331 2720 uint32_t cDirs = mapDirs.size();3332 size_t cDirs = mapDirs.size(); 2721 3333 if (!cDirs) 2722 3334 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATEDIR, … … 2781 3393 } 2782 3394 2783 uint32_t cDirs = mapDirs.size();3395 size_t cDirs = mapDirs.size(); 2784 3396 if (!cDirs) 2785 3397 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEDIR, … … 2864 3476 } 2865 3477 2866 uint32_t cFiles = mapDirs.size();3478 size_t cFiles = mapDirs.size(); 2867 3479 if (!cFiles) 2868 3480 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEFILE, … … 2942 3554 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize, rc=%Rrc\n", vrc); 2943 3555 2944 uint32_t cSources = vecSources.size();3556 size_t cSources = vecSources.size(); 2945 3557 if (!cSources) 2946 3558 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RENAME, … … 3179 3791 } 3180 3792 3181 uint32_t cObjs = mapObjs.size();3793 size_t cObjs = mapObjs.size(); 3182 3794 if (!cObjs) 3183 3795 return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_STAT, … … 3948 4560 || !RTStrICmp(pArg->argv[1], "execute")) 3949 4561 { 3950 gctlCmd.pfnHandler = handleCtrlProcessExec ;4562 gctlCmd.pfnHandler = handleCtrlProcessExecDeprecated; 3951 4563 uUsage = USAGE_GSTCTRL_EXEC; 4564 } 4565 else if (!strcmp(pArg->argv[1], "run")) 4566 { 4567 gctlCmd.pfnHandler = handleCtrlProcessRun; 4568 uUsage = USAGE_GSTCTRL_RUN; 4569 } 4570 else if (!strcmp(pArg->argv[1], "start")) 4571 { 4572 gctlCmd.pfnHandler = handleCtrlProcessStart; 4573 uUsage = USAGE_GSTCTRL_START; 3952 4574 } 3953 4575 else if (!RTStrICmp(pArg->argv[1], "copyfrom")) -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r55531 r55535 10079 10079 To wait for a guest process to terminate after it has been 10080 10080 created by <link to="IGuestSession::processCreate"/> or <link to="IGuestSession::processCreateEx"/> 10081 one would specify ProcessWait Result_Terminate.10081 one would specify ProcessWaitFor_Terminate. 10082 10082 10083 10083 If a guest process has been started with ProcessCreateFlag_WaitForStdOut … … 10107 10107 <const name="Timeout" value="5"> 10108 10108 <desc> 10109 The waiting operation timed out. This also will happen 10110 when no event has been occurred matching the 10111 current waiting flags in a <link to="IProcess::waitFor"/> call. 10109 The waiting operation timed out. Also use if the guest process has 10110 timed out on the guest side (kill attempted). 10112 10111 </desc> 10113 10112 </const> 10114 10113 <const name="StdIn" value="6"> 10115 <desc> 10116 The process signalled that stdin became available for writing 10117 and that the process awaits input now.</desc> 10114 <desc>The process signalled that stdin became available for writing.</desc> 10118 10115 </const> 10119 10116 <const name="StdOut" value="7"> … … 10213 10210 <enum 10214 10211 name="ProcessCreateFlag" 10215 uuid=" 35192799-bfde-405d-9bea-c735ab9998e4"10212 uuid="be8c8dbd-4a76-e9ac-20df-468e86edf383" 10216 10213 > 10217 10214 <desc> … … 10786 10783 <interface 10787 10784 name="IGuestSession" extends="$unknown" 10788 uuid=" 5b28703c-07b6-4fcb-afba-ac199b309752"10785 uuid="c899776d-41f7-7aee-7056-4bac979d58b7" 10789 10786 wsmap="managed" 10790 10787 > … … 11431 11428 appropriate error message. 11432 11429 11433 If ProcessCreateFlag_WaitForStdOut and / or respectivelyProcessCreateFlag_WaitForStdErr11434 is /are set, the guest process will not exit until all data from the specified11435 stream (s) is /are read out.11430 If ProcessCreateFlag_WaitForStdOut and/or ProcessCreateFlag_WaitForStdErr 11431 are set, the guest process will not exit until all data from the specified 11432 streams are read out. 11436 11433 </note> 11437 11434 … … 11440 11437 </result> 11441 11438 </desc> 11442 <param name="command" type="wstring" dir="in"> 11443 <desc> 11444 Full path name of the command to execute on the guest; the 11445 commands has to exists in the guest VM in order to be executed. 11439 <param name="executable" type="wstring" dir="in"> 11440 <desc> 11441 Full path name of the file to execute on the guest. The file has to 11442 exists in the guest VM with executable right to the session user in 11443 order to be executed. If empty/null, the first entry in the 11444 @a arguments array will be used in stead (i.e. argv[0]). 11446 11445 </desc> 11447 11446 </param> 11448 11447 <param name="arguments" type="wstring" dir="in" safearray="yes"> 11449 <desc>Array of arguments passed to the execution command.</desc> 11448 <desc>Array of arguments passed to the new process. 11449 <note> 11450 Starting with VirtualBox 5.0 this array starts with argument 0 11451 instead of argument 1 as in previous versions. Whether the zeroth 11452 argument can be passed to the guest depends on the VBoxService 11453 version running there. 11454 </note> 11455 </desc> 11450 11456 </param> 11451 11457 <param name="environment" type="wstring" dir="in" safearray="yes"> 11452 11458 <desc> 11453 Environment variables that can be set while the command is being 11454 executed, in form of "NAME=VALUE"; one pair per entry. To unset a 11455 variable just set its name ("NAME") without a value. 11456 11457 This parameter can be used to override environment variables set by 11458 the guest session, which will be applied to the newly started process 11459 in any case. 11459 Environment variables to set or unset for the guest process, 11460 relative to the environment of the guest session. 11461 11462 The variables are in the traditional "NAME=VALUE" form with one pair 11463 per array entry. To unset a variable just leave out the equal sign 11464 and the value ("NAME"). 11460 11465 </desc> 11461 11466 </param> … … 11486 11491 See <link to="IGuestSession::processCreate"/> for more information. 11487 11492 </desc> 11488 <param name="command" type="wstring" dir="in"> 11489 <desc> 11490 Full path name of the command to execute on the guest; the 11491 commands has to exists in the guest VM in order to be executed. 11493 <param name="executable" type="wstring" dir="in"> 11494 <desc> 11495 Full path name of the file to execute on the guest. The file has to 11496 exists in the guest VM with executable right to the session user in 11497 order to be executed. If empty/null, the first entry in the 11498 @a arguments array will be used in stead (i.e. argv[0]). 11492 11499 </desc> 11493 11500 </param> 11494 11501 <param name="arguments" type="wstring" dir="in" safearray="yes"> 11495 <desc>Array of arguments passed to the execution command.</desc> 11502 <desc>Array of arguments passed to the new process. 11503 <note> 11504 Starting with VirtualBox 5.0 this array starts with argument 0 11505 instead of argument 1 as in previous versions. Whether the zeroth 11506 argument can be passed to the guest depends on the VBoxService 11507 version running there. 11508 </note> 11509 </desc> 11496 11510 </param> 11497 11511 <param name="environment" type="wstring" dir="in" safearray="yes"> 11498 11512 <desc> 11499 Environment variables that can be set while the command is being 11500 executed, in form of "NAME=VALUE"; one pair per entry. To unset a 11501 variable just set its name ("NAME") without a value. 11502 11503 This parameter can be used to override environment variables set by 11504 the guest session, which will be applied to the newly started process 11505 in any case. 11513 Environment variables to set or unset for the guest process, 11514 relative to the environment of the guest session. 11515 11516 The variables are in the traditional "NAME=VALUE" form with one pair 11517 per array entry. To unset a variable just leave out the equal sign 11518 and the value ("NAME"). 11506 11519 </desc> 11507 11520 </param> -
trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
r55401 r55535 221 221 /** The process' friendly name. */ 222 222 Utf8Str mName; 223 /** The actual command to execute. */ 224 Utf8Str mCommand; 223 /** The executable. */ 224 Utf8Str mExecutable; 225 /** Arguments vector (starting with argument \#0). */ 225 226 ProcessArguments mArguments; 226 227 GuestEnvironment mEnvironment; -
trunk/src/VBox/Main/include/GuestSessionImpl.h
r51321 r55535 204 204 mProcInfo(startupInfo) 205 205 { 206 mProcInfo.m Command= strDest;206 mProcInfo.mExecutable = strDest; 207 207 if (mProcInfo.mName.isEmpty()) 208 208 mProcInfo.mName = strDest; … … 432 432 int *pGuestRc); 433 433 int i_processRemoveFromList(GuestProcess *pProcess); 434 int i_processCreateExInter al(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProgress);434 int i_processCreateExInternal(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProgress); 435 435 inline bool i_processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess); 436 436 inline int i_processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess); -
trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp
r53127 r55535 91 91 GuestProcessStartupInfo procInfo; 92 92 procInfo.mName = Utf8StrFmt(tr("Reading directory \"%s\""), openInfo.mPath.c_str()); 93 procInfo.m Command= Utf8Str(VBOXSERVICE_TOOL_LS);93 procInfo.mExecutable= Utf8Str(VBOXSERVICE_TOOL_LS); 94 94 procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */ 95 95 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; -
trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
r55491 r55535 266 266 267 267 #ifdef VBOX_WITH_GUEST_CONTROL 268 LogFlowThisFunc(("mCmd=%s, PID=%RU32\n", 269 mData.mProcess.mCommand.c_str(), mData.mPID)); 268 LogFlowThisFunc(("mExe=%s, PID=%RU32\n", mData.mProcess.mExecutable.c_str(), mData.mPID)); 270 269 271 270 /* Terminate process if not already done yet. */ … … 334 333 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 335 334 336 aExecutablePath = mData.mProcess.m Command;335 aExecutablePath = mData.mProcess.mExecutable; 337 336 338 337 return S_OK; … … 987 986 int GuestProcess::i_startProcess(uint32_t uTimeoutMS, int *pGuestRc) 988 987 { 989 LogFlowThisFunc(("uTimeoutMS=%RU32, proc Cmd=%s, procTimeoutMS=%RU32, procFlags=%x, sessionID=%RU32\n",990 uTimeoutMS, mData.mProcess.m Command.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags,988 LogFlowThisFunc(("uTimeoutMS=%RU32, procExe=%s, procTimeoutMS=%RU32, procFlags=%x, sessionID=%RU32\n", 989 uTimeoutMS, mData.mProcess.mExecutable.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags, 991 990 mSession->i_getId())); 992 991 … … 1017 1016 GuestSession *pSession = mSession; 1018 1017 AssertPtr(pSession); 1018 uint32_t const uProtocol = pSession->i_getProtocolVersion(); 1019 1019 1020 1020 const GuestCredentials &sessionCreds = pSession->i_getCredentials(); 1021 1021 1022 1022 1023 /* Prepare arguments. */ … … 1029 1030 && cArgs) 1030 1031 { 1031 char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));1032 char const **papszArgv = (char const **)RTMemAlloc((cArgs + 1) * sizeof(papszArgv[0])); 1032 1033 AssertReturn(papszArgv, VERR_NO_MEMORY); 1033 1034 1034 for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++) 1035 { 1036 const char *pszCurArg = mData.mProcess.mArguments[i].c_str(); 1037 AssertPtr(pszCurArg); 1038 vrc = RTStrDupEx(&papszArgv[i], pszCurArg); 1035 for (size_t i = 0; i < cArgs; i++) 1036 { 1037 papszArgv[i] = mData.mProcess.mArguments[i].c_str(); 1038 AssertPtr(papszArgv[i]); 1039 1039 } 1040 1040 papszArgv[cArgs] = NULL; 1041 1041 1042 if (RT_SUCCESS(vrc)) 1042 if (uProtocol < UINT32_C(0xdeadbeef) ) /** @todo implement a way of sending argv[0], best idea is a new command. */ 1043 vrc = RTGetOptArgvToString(&pszArgs, papszArgv + 1, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH); 1044 else 1043 1045 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH); 1044 1046 1045 if (papszArgv) 1046 { 1047 size_t i = 0; 1048 while (papszArgv[i]) 1049 RTStrFree(papszArgv[i++]); 1050 RTMemFree(papszArgv); 1051 } 1047 RTMemFree(papszArgv); 1052 1048 } 1053 1049 … … 1065 1061 if (RT_SUCCESS(vrc)) 1066 1062 { 1067 AssertPtr(mSession);1068 uint32_t uProtocol = mSession->i_getProtocolVersion();1069 1070 1063 /* Prepare HGCM call. */ 1071 1064 VBOXHGCMSVCPARM paParms[16]; 1072 1065 int i = 0; 1073 1066 paParms[i++].setUInt32(pEvent->ContextID()); 1074 paParms[i++].setPointer((void*)mData.mProcess.m Command.c_str(),1075 (ULONG)mData.mProcess.m Command.length() + 1);1067 paParms[i++].setPointer((void*)mData.mProcess.mExecutable.c_str(), 1068 (ULONG)mData.mProcess.mExecutable.length() + 1); 1076 1069 paParms[i++].setUInt32(mData.mProcess.mFlags); 1077 1070 paParms[i++].setUInt32((uint32_t)mData.mProcess.mArguments.size()); … … 1764 1757 hr = setError(VBOX_E_IPRT_ERROR, 1765 1758 tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"), 1766 mData.mProcess.m Command.c_str(), mData.mPID, vrc);1759 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc); 1767 1760 break; 1768 1761 } … … 1798 1791 hr = setError(VBOX_E_IPRT_ERROR, 1799 1792 tr("Terminating process \"%s\" (PID %RU32) not supported by installed Guest Additions"), 1800 mData.mProcess.m Command.c_str(), mData.mPID);1793 mData.mProcess.mExecutable.c_str(), mData.mPID); 1801 1794 break; 1802 1795 … … 1804 1797 hr = setError(VBOX_E_IPRT_ERROR, 1805 1798 tr("Terminating process \"%s\" (PID %RU32) failed: %Rrc"), 1806 mData.mProcess.m Command.c_str(), mData.mPID, vrc);1799 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc); 1807 1800 break; 1808 1801 } … … 1834 1827 HRESULT hr = S_OK; 1835 1828 1836 int guestRc; ProcessWaitResult_T waitResult; 1829 int guestRc; 1830 ProcessWaitResult_T waitResult; 1837 1831 int vrc = i_waitFor(aWaitFor, aTimeoutMS, waitResult, &guestRc); 1838 1832 if (RT_SUCCESS(vrc)) … … 1855 1849 hr = setError(VBOX_E_IPRT_ERROR, 1856 1850 tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"), 1857 mData.mProcess.m Command.c_str(), mData.mPID, vrc);1851 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc); 1858 1852 break; 1859 1853 } … … 1907 1901 hr = setError(VBOX_E_IPRT_ERROR, 1908 1902 tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"), 1909 mData.mProcess.m Command.c_str(), mData.mPID, vrc);1903 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc); 1910 1904 break; 1911 1905 } … … 1956 1950 bool fAsync, int *pGuestRc) 1957 1951 { 1958 LogFlowThisFunc(("pGuestSession=%p, szCmd=%s, fAsync=%RTbool\n",1959 pGuestSession, startupInfo.m Command.c_str(), fAsync));1952 LogFlowThisFunc(("pGuestSession=%p, exe=%s, fAsync=%RTbool\n", 1953 pGuestSession, startupInfo.mExecutable.c_str(), fAsync)); 1960 1954 1961 1955 AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER); … … 1967 1961 mStartupInfo.mFlags |= ProcessCreateFlag_Hidden; 1968 1962 1969 int vrc = pSession->i_processCreateExInter al(mStartupInfo, pProcess);1963 int vrc = pSession->i_processCreateExInternal(mStartupInfo, pProcess); 1970 1964 if (RT_SUCCESS(vrc)) 1971 1965 vrc = fAsync -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r54009 r55535 661 661 662 662 GuestProcessStartupInfo procInfo; 663 procInfo.m Command= Utf8Str(VBOXSERVICE_TOOL_MKDIR);664 procInfo.mFlags = ProcessCreateFlag_Hidden;663 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKDIR); 664 procInfo.mFlags = ProcessCreateFlag_Hidden; 665 665 666 666 try … … 816 816 817 817 GuestProcessStartupInfo procInfo; 818 procInfo.m Command= Utf8Str(VBOXSERVICE_TOOL_MKTEMP);819 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;818 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKTEMP); 819 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; 820 820 821 821 try … … 1217 1217 GuestProcessStream streamOut; 1218 1218 1219 procInfo.m Command= Utf8Str(VBOXSERVICE_TOOL_RM);1220 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;1219 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_RM); 1220 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; 1221 1221 1222 1222 try … … 1374 1374 /** @todo Merge this with IGuestFile::queryInfo(). */ 1375 1375 GuestProcessStartupInfo procInfo; 1376 procInfo.m Command= Utf8Str(VBOXSERVICE_TOOL_STAT);1377 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;1376 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_STAT); 1377 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut; 1378 1378 1379 1379 try … … 1837 1837 1838 1838 /** 1839 * Creates but does *not* start the process yet. See GuestProcess::startProcess() or 1840 * GuestProcess::startProcessAsync() for that. 1839 * Creates but does *not* start the process yet. 1840 * 1841 * See GuestProcess::startProcess() or GuestProcess::startProcessAsync() for 1842 * starting the process. 1841 1843 * 1842 1844 * @return IPRT status code. … … 1844 1846 * @param pProcess 1845 1847 */ 1846 int GuestSession::i_processCreateExInter al(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)1847 { 1848 LogFlowFunc(("m Cmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",1849 procInfo.m Command.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));1848 int GuestSession::i_processCreateExInternal(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess) 1849 { 1850 LogFlowFunc(("mExe=%s, mFlags=%x, mTimeoutMS=%RU32\n", 1851 procInfo.mExecutable.c_str(), procInfo.mFlags, procInfo.mTimeoutMS)); 1850 1852 #ifdef DEBUG 1851 1853 if (procInfo.mArguments.size()) … … 3308 3310 } 3309 3311 3310 HRESULT GuestSession::processCreate(const com::Utf8Str &a Command, const std::vector<com::Utf8Str> &aArguments,3312 HRESULT GuestSession::processCreate(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments, 3311 3313 const std::vector<com::Utf8Str> &aEnvironment, 3312 3314 const std::vector<ProcessCreateFlag_T> &aFlags, … … 3320 3322 std::vector<LONG> affinityIgnored; 3321 3323 3322 return processCreateEx(a Command, aArguments, aEnvironment, aFlags, aTimeoutMS, ProcessPriority_Default,3324 return processCreateEx(aExecutable, aArguments, aEnvironment, aFlags, aTimeoutMS, ProcessPriority_Default, 3323 3325 affinityIgnored, aGuestProcess); 3324 3326 #endif /* VBOX_WITH_GUEST_CONTROL */ 3325 3327 } 3326 3328 3327 HRESULT GuestSession::processCreateEx(const com::Utf8Str &a Command, const std::vector<com::Utf8Str> &aArguments,3329 HRESULT GuestSession::processCreateEx(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments, 3328 3330 const std::vector<com::Utf8Str> &aEnvironment, 3329 3331 const std::vector<ProcessCreateFlag_T> &aFlags, ULONG aTimeoutMS, … … 3336 3338 LogFlowThisFuncEnter(); 3337 3339 3338 if (RT_UNLIKELY((aCommand.c_str()) == NULL || *(aCommand.c_str()) == '\0')) 3339 return setError(E_INVALIDARG, tr("No command to execute specified")); 3340 3340 /* 3341 * Must have an executable to execute. If none is given, we try use the 3342 * zero'th argument. 3343 */ 3344 const char *pszExecutable = aExecutable.c_str(); 3345 if (RT_UNLIKELY(pszExecutable == NULL || *pszExecutable == '\0')) 3346 { 3347 if (aArguments.size() > 0) 3348 pszExecutable = aArguments[0].c_str(); 3349 if (pszExecutable == NULL || *pszExecutable == '\0') 3350 return setError(E_INVALIDARG, tr("No command to execute specified")); 3351 } 3352 3353 /* 3354 * Check the session. 3355 */ 3341 3356 HRESULT hr = i_isReadyExternal(); 3342 3357 if (FAILED(hr)) 3343 3358 return hr; 3344 3359 3360 /* 3361 * Build the process startup info. 3362 */ 3345 3363 GuestProcessStartupInfo procInfo; 3346 procInfo.mCommand = aCommand; 3347 3364 3365 /* Executable and arguments. */ 3366 procInfo.mExecutable = pszExecutable; 3348 3367 if (aArguments.size()) 3349 3368 for (size_t i = 0; i < aArguments.size(); i++) 3350 3369 procInfo.mArguments.push_back(aArguments[i]); 3351 3352 int rc = VINF_SUCCESS;3353 3370 3354 3371 /* … … 3360 3377 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */ 3361 3378 3379 int rc = VINF_SUCCESS; 3362 3380 if (aEnvironment.size()) 3363 3381 for (size_t i = 0; i < aEnvironment.size() && RT_SUCCESS(rc); i++) 3382 { 3383 /** @todo r=bird: What ARE you trying to do here??? The documentation is crystal 3384 * clear on that each entry contains ONE pair, however, 3385 * GuestEnvironment::Set(const Utf8Str &) here will split up the input 3386 * into any number of pairs, from what I can tell. Such that for e.g. 3387 * "VBOX_LOG_DEST=file=/tmp/foobared.log" becomes "VBOX_LOG_DEST=file" 3388 * and "/tmp/foobared.log" - which I obviously don't want! */ 3364 3389 rc = procInfo.mEnvironment.Set(aEnvironment[i]); 3390 } 3365 3391 3366 3392 if (RT_SUCCESS(rc)) 3367 3393 { 3394 /* Convert the flag array into a mask. */ 3368 3395 if (aFlags.size()) 3369 3396 for (size_t i = 0; i < aFlags.size(); i++) … … 3372 3399 procInfo.mTimeoutMS = aTimeoutMS; 3373 3400 3401 /** @todo use RTCPUSET instead of archaic 64-bit variables! */ 3374 3402 if (aAffinity.size()) 3375 3403 for (size_t i = 0; i < aAffinity.size(); i++) … … 3379 3407 procInfo.mPriority = aPriority; 3380 3408 3409 /* 3410 * Create a guest process object. 3411 */ 3381 3412 ComObjPtr<GuestProcess> pProcess; 3382 rc = i_processCreateExInter al(procInfo, pProcess);3413 rc = i_processCreateExInternal(procInfo, pProcess); 3383 3414 if (RT_SUCCESS(rc)) 3384 3415 { 3385 3416 /* Return guest session to the caller. */ 3386 3417 HRESULT hr2 = pProcess.queryInterfaceTo(aGuestProcess.asOutParam()); 3387 if (FAILED(hr2)) 3418 if (SUCCEEDED(hr2)) 3419 { 3420 /* 3421 * Start the process. 3422 */ 3423 rc = pProcess->i_startProcessAsync(); 3424 if (RT_FAILURE(rc)) 3425 { 3426 /** @todo r=bird: What happens to the interface that *aGuestProcess points to 3427 * now? Looks like a leak or an undocument hack of sorts... */ 3428 } 3429 } 3430 else 3388 3431 rc = VERR_COM_OBJECT_NOT_FOUND; 3389 3390 if (RT_SUCCESS(rc))3391 rc = pProcess->i_startProcessAsync(); 3392 }3393 }3394 3432 } 3433 } 3434 3435 /** @todo you're better off doing this is 'else if (rc == xxx') statements, 3436 * since there is just one place where you'll get 3437 * VERR_MAX_PROCS_REACHED in the above code. */ 3395 3438 if (RT_FAILURE(rc)) 3396 3439 { -
trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
r53873 r55535 309 309 310 310 GuestProcessStartupInfo procInfo; 311 procInfo.m Command= Utf8Str(VBOXSERVICE_TOOL_CAT);312 procInfo.mFlags = ProcessCreateFlag_Hidden;311 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT); 312 procInfo.mFlags = ProcessCreateFlag_Hidden; 313 313 314 314 /* Set arguments.*/ … … 318 318 ComObjPtr<GuestProcess> pProcess; int guestRc; 319 319 if (RT_SUCCESS(rc)) 320 rc = pSession->i_processCreateExInter al(procInfo, pProcess);320 rc = pSession->i_processCreateExInternal(procInfo, pProcess); 321 321 if (RT_SUCCESS(rc)) 322 322 { … … 637 637 procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"), 638 638 mSource.c_str(), mDest.c_str(), objData.mObjectSize); 639 procInfo.m Command= Utf8Str(VBOXSERVICE_TOOL_CAT);640 procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;639 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT); 640 procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut; 641 641 642 642 /* Set arguments.*/ … … 645 645 /* Startup process. */ 646 646 ComObjPtr<GuestProcess> pProcess; 647 rc = pSession->i_processCreateExInter al(procInfo, pProcess);647 rc = pSession->i_processCreateExInternal(procInfo, pProcess); 648 648 if (RT_SUCCESS(rc)) 649 649 rc = pProcess->i_startProcess(30 * 1000 /* 30s timeout */, … … 1040 1040 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1041 1041 Utf8StrFmt(GuestSession::tr("Running update file \"%s\" on guest terminated with exit code %ld"), 1042 procInfo.m Command.c_str(), exitCode));1042 procInfo.mExecutable.c_str(), exitCode)); 1043 1043 break; 1044 1044 … … 1051 1051 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1052 1052 Utf8StrFmt(GuestSession::tr("Update file \"%s\" reported invalid running state"), 1053 procInfo.m Command.c_str()));1053 procInfo.mExecutable.c_str())); 1054 1054 break; 1055 1055 … … 1057 1057 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1058 1058 Utf8StrFmt(GuestSession::tr("Error while running update file \"%s\" on guest: %Rrc"), 1059 procInfo.m Command.c_str(), vrc));1059 procInfo.mExecutable.c_str(), vrc)); 1060 1060 break; 1061 1061 } … … 1413 1413 * calculate the specific percentage step of each copied file. */ 1414 1414 uint8_t uOffset = 20; /* Start at 20%. */ 1415 uint8_t uStep = 40 / mFiles.size();1415 uint8_t uStep = 40 / (uint8_t)mFiles.size(); Assert(mFiles.size() <= 10); 1416 1416 1417 1417 LogRel(("Copying over Guest Additions update files to the guest ...\n")); … … 1453 1453 * calculate the specific percentage step of each copied file. */ 1454 1454 uint8_t uOffset = 60; /* Start at 60%. */ 1455 uint8_t uStep = 35 / mFiles.size();1455 uint8_t uStep = 35 / (uint8_t)mFiles.size(); Assert(mFiles.size() <= 10); 1456 1456 1457 1457 LogRel(("Executing Guest Additions update files ...\n")); -
trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py
r52776 r55535 9 9 __copyright__ = \ 10 10 """ 11 Copyright (C) 2010-201 4Oracle Corporation11 Copyright (C) 2010-2015 Oracle Corporation 12 12 13 13 This file is part of VirtualBox Open Source Edition (OSE), as … … 262 262 self.oCreds = tdCtxCreds(sUser, sPassword, sDomain); 263 263 self.sCmd = sCmd; 264 self.aArgs = aArgs ;264 self.aArgs = aArgs if aArgs is not None else [sCmd,]; 265 265 self.aEnv = aEnv; 266 266 self.aFlags = aFlags or []; … … 998 998 oTest.aArgs, oTest.aEnv)); 999 999 try: 1000 curProc = oGuestSession.processCreate(oTest.sCmd, \1001 oTest.aArgs , oTest.aEnv, \1002 oTest.a Flags, oTest.timeoutMS);1000 curProc = oGuestSession.processCreate(oTest.sCmd, 1001 oTest.aArgs if self.oTstDrv.fpApiVer >= 5.0 else oTest.aArgs[1:], 1002 oTest.aEnv, oTest.aFlags, oTest.timeoutMS); 1003 1003 if curProc is not None: 1004 1004 reporter.log2('Process start requested, waiting for start (%ldms) ...' % (oTest.timeoutMS,)); … … 1511 1511 sDomain = ""; 1512 1512 sCmd = "C:\\windows\\system32\\cmd.exe"; 1513 sArgs = [];1513 aArgs = [sCmd,]; 1514 1514 1515 1515 # Number of stale guest processes to create. … … 1542 1542 for i in range(0, cStaleProcs): 1543 1543 try: 1544 oGuestSession.processCreate(sCmd, \1545 sArgs, [], \1544 oGuestSession.processCreate(sCmd, 1545 aArgs if self.oTstDrv.fpApiVer >= 5.0 else aArgs[1:], [], 1546 1546 [ vboxcon.ProcessCreateFlag_WaitForStdOut ], \ 1547 1547 30 * 1000); … … 1565 1565 # 1566 1566 if oTestVm.isWindows(): 1567 sArgs = ['/C', 'dir', '/S', 'C:\\Windows\\system'];1567 aArgs = [ sCmd, '/C', 'dir', '/S', 'C:\\Windows\\system']; 1568 1568 reporter.log2('Starting non-stale processes'); 1569 1569 aaProcs = []; 1570 1570 for i in range(0, cStaleProcs): 1571 1571 try: 1572 oCurProc = oGuestSession.processCreate(sCmd, \ 1573 sArgs, [], \ 1574 [], \ 1575 0); # Infinite timeout. 1572 oCurProc = oGuestSession.processCreate(sCmd, aArgs if self.oTstDrv.fpApiVer >= 5.0 else aArgs[1:], 1573 [], [], 0); # Infinite timeout. 1576 1574 aaProcs.append(oCurProc); 1577 1575 except: … … 1617 1615 # Fire off blocking processes which are terminated via terminate(). 1618 1616 if oTestVm.isWindows(): 1619 sArgs = ['/C', 'dir', '/S', 'C:\\Windows'];1617 aArgs = [ sCmd, '/C', 'dir', '/S', 'C:\\Windows']; 1620 1618 reporter.log2('Starting blocking processes'); 1621 1619 aaProcs = []; 1622 1620 for i in range(0, cStaleProcs): 1623 1621 try: 1624 oCurProc = oGuestSession.processCreate(sCmd, \ 1625 sArgs, [], \ 1626 [], 30 * 1000); 1622 oCurProc = oGuestSession.processCreate(sCmd, aArgs if self.oTstDrv.fpApiVer >= 5.0 else aArgs[1:], 1623 [], [], 30 * 1000); 1627 1624 # Note: Use a timeout in the call above for not letting the stale processes 1628 1625 # hanging around forever. This can happen if the installed Guest Additions … … 1698 1695 1699 1696 if oTestVm.isWindows(): 1697 sVBoxControl = "C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\VBoxControl.exe"; 1700 1698 aaExec = [ 1701 1699 # Basic executon. 1702 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],1700 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ], 1703 1701 sUser = sUser, sPassword = sPassword), 1704 1702 tdTestResultExec(fRc = True) ], 1705 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32\\kernel32.dll' ],1703 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32\\kernel32.dll' ], 1706 1704 sUser = sUser, sPassword = sPassword), 1707 1705 tdTestResultExec(fRc = True) ], 1708 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32\\nonexist.dll' ],1706 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32\\nonexist.dll' ], 1709 1707 sUser = sUser, sPassword = sPassword), 1710 1708 tdTestResultExec(fRc = True, iExitCode = 1) ], 1711 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', '/wrongparam' ],1709 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ], 1712 1710 sUser = sUser, sPassword = sPassword), 1713 1711 tdTestResultExec(fRc = True, iExitCode = 1) ], 1714 1712 # Paths with spaces. 1715 1713 ## @todo Get path of installed Guest Additions. Later. 1716 [ tdTestExec(sCmd = "C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\VBoxControl.exe", 1717 aArgs = [ 'version' ], 1714 [ tdTestExec(sCmd = sVBoxControl, aArgs = [ sVBoxControl, 'version' ], 1718 1715 sUser = sUser, sPassword = sPassword), 1719 1716 tdTestResultExec(fRc = True) ], 1720 1717 # StdOut. 1721 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],1718 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ], 1722 1719 sUser = sUser, sPassword = sPassword), 1723 1720 tdTestResultExec(fRc = True) ], 1724 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'stdout-non-existing' ],1721 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ], 1725 1722 sUser = sUser, sPassword = sPassword), 1726 1723 tdTestResultExec(fRc = True, iExitCode = 1) ], 1727 1724 # StdErr. 1728 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],1725 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ], 1729 1726 sUser = sUser, sPassword = sPassword), 1730 1727 tdTestResultExec(fRc = True) ], 1731 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'stderr-non-existing' ],1728 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ], 1732 1729 sUser = sUser, sPassword = sPassword), 1733 1730 tdTestResultExec(fRc = True, iExitCode = 1) ], 1734 1731 # StdOut + StdErr. 1735 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],1732 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ], 1736 1733 sUser = sUser, sPassword = sPassword), 1737 1734 tdTestResultExec(fRc = True) ], 1738 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'stdouterr-non-existing' ],1735 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ], 1739 1736 sUser = sUser, sPassword = sPassword), 1740 1737 tdTestResultExec(fRc = True, iExitCode = 1) ] 1741 1738 # FIXME: Failing tests. 1742 1739 # Environment variables. 1743 # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'TEST_NONEXIST' ],1740 # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ], 1744 1741 # sUser = sUser, sPassword = sPassword), 1745 1742 # tdTestResultExec(fRc = True, iExitCode = 1) ] 1746 # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'windir' ],1743 # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'windir' ], 1747 1744 # sUser = sUser, sPassword = sPassword, 1748 1745 # aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]), 1749 1746 # tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ], 1750 # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'TEST_FOO' ],1747 # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ], 1751 1748 # sUser = sUser, sPassword = sPassword, 1752 1749 # aEnv = [ 'TEST_FOO=BAR' ], 1753 1750 # aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]), 1754 1751 # tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ], 1755 # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'TEST_FOO' ],1752 # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ], 1756 1753 # sUser = sUser, sPassword = sPassword, 1757 1754 # aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ], … … 1765 1762 # Manual test, not executed automatically. 1766 1763 aaManual = [ 1767 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir /S C:\\Windows' ],1764 [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir /S C:\\Windows' ], 1768 1765 sUser = sUser, sPassword = sPassword, 1769 1766 aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]), … … 1922 1919 aaTests.extend([ 1923 1920 # Simple. 1924 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'wrongcommand' ],1921 [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'wrongcommand' ], 1925 1922 sUser = sUser, sPassword = sPassword), 1926 1923 tdTestResultExec(fRc = True, iExitCode = 1) ], 1927 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'exit', '22' ],1924 [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'exit', '22' ], 1928 1925 sUser = sUser, sPassword = sPassword), 1929 1926 tdTestResultExec(fRc = True, iExitCode = 22) ], 1930 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'set', 'ERRORLEVEL=234' ],1927 [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'set', 'ERRORLEVEL=234' ], 1931 1928 sUser = sUser, sPassword = sPassword), 1932 1929 tdTestResultExec(fRc = True, iExitCode = 0) ], 1933 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'echo', '%WINDIR%' ],1930 [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'echo', '%WINDIR%' ], 1934 1931 sUser = sUser, sPassword = sPassword), 1935 1932 tdTestResultExec(fRc = True, iExitCode = 0) ], 1936 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'set', 'ERRORLEVEL=0' ],1933 [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'set', 'ERRORLEVEL=0' ], 1937 1934 sUser = sUser, sPassword = sPassword), 1938 1935 tdTestResultExec(fRc = True, iExitCode = 0) ], 1939 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],1936 [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ], 1940 1937 sUser = sUser, sPassword = sPassword), 1941 1938 tdTestResultExec(fRc = True, iExitCode = 0) ], 1942 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32\\kernel32.dll' ],1939 [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32\\kernel32.dll' ], 1943 1940 sUser = sUser, sPassword = sPassword), 1944 1941 tdTestResultExec(fRc = True, iExitCode = 0) ], 1945 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],1942 [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ], 1946 1943 sUser = sUser, sPassword = sPassword), 1947 1944 tdTestResultExec(fRc = True, iExitCode = 1) ], 1948 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],1945 [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ], 1949 1946 sUser = sUser, sPassword = sPassword), 1950 1947 tdTestResultExec(fRc = True, iExitCode = 1) ] 1951 1948 # FIXME: Failing tests. 1952 1949 # With stdout. 1953 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],1950 # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ], 1954 1951 # sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut ]), 1955 1952 # tdTestResultExec(fRc = True, iExitCode = 0) ], 1956 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],1953 # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ], 1957 1954 # sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut ]), 1958 1955 # tdTestResultExec(fRc = True, iExitCode = 1) ], 1959 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],1956 # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ], 1960 1957 # sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut ]), 1961 1958 # tdTestResultExec(fRc = True, iExitCode = 1) ], 1962 1959 # With stderr. 1963 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],1960 # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ], 1964 1961 # sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdErr ]), 1965 1962 # tdTestResultExec(fRc = True, iExitCode = 0) ], 1966 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],1963 # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ], 1967 1964 # sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdErr ]), 1968 1965 # tdTestResultExec(fRc = True, iExitCode = 1) ], 1969 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],1966 # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ], 1970 1967 # sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdErr ]), 1971 1968 # tdTestResultExec(fRc = True, iExitCode = 1) ], 1972 1969 # With stdout/stderr. 1973 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],1970 # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ], 1974 1971 # sUser = sUser, sPassword = sPassword, 1975 1972 # aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]), 1976 1973 # tdTestResultExec(fRc = True, iExitCode = 0) ], 1977 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],1974 # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ], 1978 1975 # sUser = sUser, sPassword = sPassword, 1979 1976 # aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]), 1980 1977 # tdTestResultExec(fRc = True, iExitCode = 1) ], 1981 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],1978 # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ], 1982 1979 # sUser = sUser, sPassword = sPassword, 1983 1980 # aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]), … … 2031 2028 # waiting for termination. 2032 2029 try: 2033 curProc = oGuestSession.processCreate(sImage, [ ], \2030 curProc = oGuestSession.processCreate(sImage, [sImage,] if self.oTstDrv.fpApiVer >= 5.0 else [], \ 2034 2031 [], [], 30 * 1000); 2035 2032 reporter.log('Waiting for process 1 being started ...'); … … 2062 2059 if fRc: 2063 2060 try: 2064 curProc = oGuestSession.processCreate(sImage, [ ], \2061 curProc = oGuestSession.processCreate(sImage, [sImage,] if self.oTstDrv.fpApiVer >= 5.0 else [], \ 2065 2062 [], [], 5 * 1000); 2066 2063 reporter.log('Waiting for process 2 being started ...'); … … 3282 3279 3283 3280 sCmd = 'c:\\windows\\system32\\cmd.exe'; 3284 aArgs = [ '/C', 'dir', '/S', 'c:\\windows' ];3281 aArgs = [ sCmd, '/C', 'dir', '/S', 'c:\\windows' ]; 3285 3282 aEnv = []; 3286 3283 aFlags = []; 3287 3284 3288 3285 for _ in range(100): 3289 oProc = oGuestSession.processCreate(sCmd, 3290 aArgs, aEnv, 3291 aFlags, 30 * 1000); 3286 oProc = oGuestSession.processCreate(sCmd, aArgs if self.fpApiVer >= 5.0 else aArgs[1:], 3287 aEnv, aFlags, 30 * 1000); 3292 3288 3293 3289 aWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate ];
Note:
See TracChangeset
for help on using the changeset viewer.

