Changeset 47625 in vbox
- Timestamp:
- Aug 9, 2013 8:15:22 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r47560 r47625 42 42 #include <iprt/list.h> 43 43 #include <iprt/path.h> 44 #include <iprt/process.h> /* For RTProcSelf(). */ 44 45 #include <iprt/thread.h> 45 46 … … 657 658 658 659 /* <Missing documentation> */ 659 static RTEXITCODE handleCtrl ExecProgram(ComPtr<IGuest> pGuest, HandlerArg *pArg)660 static RTEXITCODE handleCtrlProcessExec(ComPtr<IGuest> pGuest, HandlerArg *pArg) 660 661 { 661 662 AssertPtrReturn(pArg, RTEXITCODE_SYNTAX); … … 689 690 RTGetOptInit(&GetState, pArg->argc, pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0); 690 691 691 Utf8Str strCmd;692 Utf8Str strCmd; 692 693 com::SafeArray<ProcessCreateFlag_T> aCreateFlags; 693 694 com::SafeArray<ProcessWaitForFlag_T> aWaitFlags; … … 699 700 RTMSINTERVAL cMsTimeout = 0; 700 701 OUTPUTTYPE eOutputType = OUTPUTTYPE_UNDEFINED; 701 bool f WaitForExit = false;702 bool fDetached = true; 702 703 bool fVerbose = false; 703 704 int vrc = VINF_SUCCESS; 704 705 705 /* Wait for process start in any case. This is useful for scripting VBoxManage 706 * when relying on its overall exit code. */ 707 aWaitFlags.push_back(ProcessWaitForFlag_Start); 708 709 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 710 && RT_SUCCESS(vrc)) 711 { 712 /* For options that require an argument, ValueUnion has received the value. */ 713 switch (ch) 706 try 707 { 708 /* Wait for process start in any case. This is useful for scripting VBoxManage 709 * when relying on its overall exit code. */ 710 aWaitFlags.push_back(ProcessWaitForFlag_Start); 711 712 while ( (ch = RTGetOpt(&GetState, &ValueUnion)) 713 && RT_SUCCESS(vrc)) 714 714 { 715 case GETOPTDEF_EXEC_DOS2UNIX: 716 if (eOutputType != OUTPUTTYPE_UNDEFINED) 717 return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!"); 718 eOutputType = OUTPUTTYPE_DOS2UNIX; 719 break; 720 721 case 'e': /* Environment */ 722 { 723 char **papszArg; 724 int cArgs; 725 726 vrc = RTGetOptArgvFromString(&papszArg, &cArgs, ValueUnion.psz, NULL); 727 if (RT_FAILURE(vrc)) 728 return errorSyntax(USAGE_GUESTCONTROL, "Failed to parse environment value, rc=%Rrc", vrc); 729 for (int j = 0; j < cArgs; j++) 730 aEnv.push_back(Bstr(papszArg[j]).raw()); 731 732 RTGetOptArgvFree(papszArg); 733 break; 734 } 735 736 case GETOPTDEF_EXEC_IGNOREORPHANEDPROCESSES: 737 aCreateFlags.push_back(ProcessCreateFlag_IgnoreOrphanedProcesses); 738 break; 739 740 case GETOPTDEF_EXEC_NO_PROFILE: 741 aCreateFlags.push_back(ProcessCreateFlag_NoProfile); 742 break; 743 744 case 'i': 745 strCmd = ValueUnion.psz; 746 break; 747 748 /** @todo Add a hidden flag. */ 749 750 case 'u': /* User name */ 751 strUsername = ValueUnion.psz; 752 break; 753 754 case GETOPTDEF_EXEC_PASSWORD: /* Password */ 755 strPassword = ValueUnion.psz; 756 break; 757 758 case 'p': /* Password file */ 759 { 760 RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword); 761 if (rcExit != RTEXITCODE_SUCCESS) 762 return rcExit; 763 break; 764 } 765 766 case 'd': /* domain */ 767 strDomain = ValueUnion.psz; 768 break; 769 770 case 't': /* Timeout */ 771 cMsTimeout = ValueUnion.u32; 772 break; 773 774 case GETOPTDEF_EXEC_UNIX2DOS: 775 if (eOutputType != OUTPUTTYPE_UNDEFINED) 776 return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!"); 777 eOutputType = OUTPUTTYPE_UNIX2DOS; 778 break; 779 780 case 'v': /* Verbose */ 781 fVerbose = true; 782 break; 783 784 case GETOPTDEF_EXEC_WAITFOREXIT: 785 aWaitFlags.push_back(ProcessWaitForFlag_Terminate); 786 fWaitForExit = true; 787 break; 788 789 case GETOPTDEF_EXEC_WAITFORSTDOUT: 790 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut); 791 aWaitFlags.push_back(ProcessWaitForFlag_StdOut); 792 fWaitForExit = true; 793 break; 794 795 case GETOPTDEF_EXEC_WAITFORSTDERR: 796 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr); 797 aWaitFlags.push_back(ProcessWaitForFlag_StdErr); 798 fWaitForExit = true; 799 break; 800 801 case VINF_GETOPT_NOT_OPTION: 802 { 803 if (aArgs.size() == 0 && strCmd.isEmpty()) 715 /* For options that require an argument, ValueUnion has received the value. */ 716 switch (ch) 717 { 718 case GETOPTDEF_EXEC_DOS2UNIX: 719 if (eOutputType != OUTPUTTYPE_UNDEFINED) 720 return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!"); 721 eOutputType = OUTPUTTYPE_DOS2UNIX; 722 break; 723 724 case 'e': /* Environment */ 725 { 726 char **papszArg; 727 int cArgs; 728 729 vrc = RTGetOptArgvFromString(&papszArg, &cArgs, ValueUnion.psz, NULL); 730 if (RT_FAILURE(vrc)) 731 return errorSyntax(USAGE_GUESTCONTROL, "Failed to parse environment value, rc=%Rrc", vrc); 732 for (int j = 0; j < cArgs; j++) 733 aEnv.push_back(Bstr(papszArg[j]).raw()); 734 735 RTGetOptArgvFree(papszArg); 736 break; 737 } 738 739 case GETOPTDEF_EXEC_IGNOREORPHANEDPROCESSES: 740 aCreateFlags.push_back(ProcessCreateFlag_IgnoreOrphanedProcesses); 741 break; 742 743 case GETOPTDEF_EXEC_NO_PROFILE: 744 aCreateFlags.push_back(ProcessCreateFlag_NoProfile); 745 break; 746 747 case 'i': 804 748 strCmd = ValueUnion.psz; 805 else 806 aArgs.push_back(Bstr(ValueUnion.psz).raw()); 807 break; 808 } 809 810 default: 811 return RTGetOptPrintError(ch, &ValueUnion); 812 } 813 } 749 break; 750 751 /** @todo Add a hidden flag. */ 752 753 case 'u': /* User name */ 754 strUsername = ValueUnion.psz; 755 break; 756 757 case GETOPTDEF_EXEC_PASSWORD: /* Password */ 758 strPassword = ValueUnion.psz; 759 break; 760 761 case 'p': /* Password file */ 762 { 763 RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword); 764 if (rcExit != RTEXITCODE_SUCCESS) 765 return rcExit; 766 break; 767 } 768 769 case 'd': /* domain */ 770 strDomain = ValueUnion.psz; 771 break; 772 773 case 't': /* Timeout */ 774 cMsTimeout = ValueUnion.u32; 775 break; 776 777 case GETOPTDEF_EXEC_UNIX2DOS: 778 if (eOutputType != OUTPUTTYPE_UNDEFINED) 779 return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!"); 780 eOutputType = OUTPUTTYPE_UNIX2DOS; 781 break; 782 783 case 'v': /* Verbose */ 784 fVerbose = true; 785 break; 786 787 case GETOPTDEF_EXEC_WAITFOREXIT: 788 aWaitFlags.push_back(ProcessWaitForFlag_Terminate); 789 fDetached = false; 790 break; 791 792 case GETOPTDEF_EXEC_WAITFORSTDOUT: 793 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut); 794 aWaitFlags.push_back(ProcessWaitForFlag_StdOut); 795 fDetached = false; 796 break; 797 798 case GETOPTDEF_EXEC_WAITFORSTDERR: 799 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr); 800 aWaitFlags.push_back(ProcessWaitForFlag_StdErr); 801 fDetached = false; 802 break; 803 804 case VINF_GETOPT_NOT_OPTION: 805 { 806 if (aArgs.size() == 0 && strCmd.isEmpty()) 807 strCmd = ValueUnion.psz; 808 else 809 aArgs.push_back(Bstr(ValueUnion.psz).raw()); 810 break; 811 } 812 813 default: 814 return RTGetOptPrintError(ch, &ValueUnion); 815 816 } /* switch */ 817 } /* while RTGetOpt */ 818 } 819 catch (std::bad_alloc &) 820 { 821 vrc = VERR_NO_MEMORY; 822 } 823 824 if (RT_FAILURE(vrc)) 825 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize, rc=%Rrc\n", vrc); 814 826 815 827 if (strCmd.isEmpty()) … … 819 831 return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!"); 820 832 821 /* Any output conversion not supported yet! */833 /** @todo Any output conversion not supported yet! */ 822 834 if (eOutputType != OUTPUTTYPE_UNDEFINED) 823 835 return errorSyntax(USAGE_GUESTCONTROL, "Output conversion not implemented yet!"); … … 830 842 RTPrintf("Opening guest session as user '%s' ...\n", strUsername.c_str()); 831 843 844 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 845 832 846 /** @todo This eventually needs a bit of revamping so that a valid session gets passed 833 847 * into this function already so that we don't need to mess around with closing … … 835 849 836 850 ComPtr<IGuestSession> pGuestSession; 837 rc = pGuest->CreateSession(Bstr(strUsername).raw(), 838 Bstr(strPassword).raw(), 839 Bstr(strDomain).raw(), 840 Bstr("VBoxManage Guest Control").raw(), 841 pGuestSession.asOutParam()); 842 if (FAILED(rc)) 843 { 844 ctrlPrintError(pGuest, COM_IIDOF(IGuest)); 845 return RTEXITCODE_FAILURE; 846 } 847 848 /* Adjust process creation flags if we don't want to wait for process termination. */ 849 if (!fWaitForExit) 850 aCreateFlags.push_back(ProcessCreateFlag_WaitForProcessStartOnly); 851 852 /* Get current time stamp to later calculate rest of timeout left. */ 853 uint64_t u64StartMS = RTTimeMilliTS(); 854 855 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 856 do 857 { 858 /* 859 * Wait for guest session to start. 860 */ 861 if (fVerbose) 851 try 852 { 853 do 862 854 { 863 if (cMsTimeout == 0) 864 RTPrintf("Waiting for guest session to start ...\n"); 855 Utf8Str strVBoxManage; 856 strVBoxManage.printf("VBoxManage Guest Control (PID %RU32)", RTProcSelf()); 857 858 CHECK_ERROR_BREAK(pGuest, CreateSession(Bstr(strUsername).raw(), 859 Bstr(strPassword).raw(), 860 Bstr(strDomain).raw(), 861 Bstr(strVBoxManage).raw(), 862 pGuestSession.asOutParam())); 863 864 /* Adjust process creation flags if we don't want to wait for process termination. */ 865 if (fDetached) 866 aCreateFlags.push_back(ProcessCreateFlag_WaitForProcessStartOnly); 867 868 /* Get current time stamp to later calculate rest of timeout left. */ 869 uint64_t u64StartMS = RTTimeMilliTS(); 870 871 /* 872 * Wait for guest session to start. 873 */ 874 if (fVerbose) 875 { 876 if (cMsTimeout == 0) 877 RTPrintf("Waiting for guest session to start ...\n"); 878 else 879 RTPrintf("Waiting for guest session to start (within %ums)\n", cMsTimeout); 880 } 881 882 com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags; 883 aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start); 884 GuestSessionWaitResult_T sessionWaitResult; 885 CHECK_ERROR_BREAK(pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags), cMsTimeout, &sessionWaitResult)); 886 ULONG uSessionID; 887 CHECK_ERROR_BREAK(pGuestSession, COMGETTER(Id)(&uSessionID)); 888 889 if ( sessionWaitResult == GuestSessionWaitResult_Start 890 /* Note: This might happen when Guest Additions < 4.3 are installed which don't 891 * support dedicated guest sessions. */ 892 || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported) 893 { 894 if (fVerbose) 895 RTPrintf("Guest session (ID %RU32) has been started\n", uSessionID); 896 } 865 897 else 866 RTPrintf("Waiting for guest session to start (within %ums)\n", cMsTimeout); 867 } 868 869 com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags; 870 aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start); 871 GuestSessionWaitResult_T sessionWaitResult; 872 rc = pGuestSession->WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags), cMsTimeout, &sessionWaitResult); 873 if (FAILED(rc)) 874 { 875 ctrlPrintError(pGuestSession, COM_IIDOF(IGuestSession)); 876 877 rcExit = RTEXITCODE_FAILURE; 878 break; 879 } 880 881 Assert( sessionWaitResult == GuestSessionWaitResult_Start 882 /* Note: This might happen when Guest Additions < 4.3 are installed which don't 883 * support dedicated guest sessions. */ 884 || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported); 885 if (fVerbose) 886 RTPrintf("Guest session has been started\n"); 887 888 if (fVerbose) 889 { 890 if (cMsTimeout == 0) 891 RTPrintf("Waiting for guest process to start ...\n"); 892 else 893 RTPrintf("Waiting for guest process to start (within %ums)\n", cMsTimeout); 894 } 895 896 /* 897 * Execute the process. 898 */ 899 ComPtr<IGuestProcess> pProcess; 900 rc = pGuestSession->ProcessCreate(Bstr(strCmd).raw(), 901 ComSafeArrayAsInParam(aArgs), 902 ComSafeArrayAsInParam(aEnv), 903 ComSafeArrayAsInParam(aCreateFlags), 904 cMsTimeout, 905 pProcess.asOutParam()); 906 if (FAILED(rc)) 907 { 908 ctrlPrintError(pGuestSession, COM_IIDOF(IGuestSession)); 909 910 rcExit = RTEXITCODE_FAILURE; 911 break; 912 } 913 914 /** @todo does this need signal handling? there's no progress object etc etc */ 915 916 vrc = RTStrmSetMode(g_pStdOut, 1 /* Binary mode */, -1 /* Code set, unchanged */); 917 if (RT_FAILURE(vrc)) 918 RTMsgError("Unable to set stdout's binary mode, rc=%Rrc\n", vrc); 919 vrc = RTStrmSetMode(g_pStdErr, 1 /* Binary mode */, -1 /* Code set, unchanged */); 920 if (RT_FAILURE(vrc)) 921 RTMsgError("Unable to set stderr's binary mode, rc=%Rrc\n", vrc); 922 923 /* Wait for process to exit ... */ 924 RTMSINTERVAL cMsTimeLeft = 1; 925 bool fReadStdOut, fReadStdErr; 926 fReadStdOut = fReadStdErr = false; 927 bool fCompleted = false; 928 while (!fCompleted && cMsTimeLeft != 0) 929 { 930 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout); 931 ProcessWaitResult_T waitResult; 932 rc = pProcess->WaitForArray(ComSafeArrayAsInParam(aWaitFlags), cMsTimeLeft, &waitResult); 933 if (FAILED(rc)) 934 { 935 ctrlPrintError(pProcess, COM_IIDOF(IProcess)); 936 937 rcExit = RTEXITCODE_FAILURE; 938 break; 939 } 940 941 switch (waitResult) 942 { 943 case ProcessWaitResult_Start: 898 { 899 RTPrintf("Error starting guest session\n"); 900 break; 901 } 902 903 if (fVerbose) 904 { 905 if (cMsTimeout == 0) 906 RTPrintf("Waiting for guest process to start ...\n"); 907 else 908 RTPrintf("Waiting for guest process to start (within %ums)\n", cMsTimeout); 909 } 910 911 /* 912 * Execute the process. 913 */ 914 ComPtr<IGuestProcess> pProcess; 915 CHECK_ERROR_BREAK(pGuestSession, ProcessCreate(Bstr(strCmd).raw(), 916 ComSafeArrayAsInParam(aArgs), 917 ComSafeArrayAsInParam(aEnv), 918 ComSafeArrayAsInParam(aCreateFlags), 919 cMsTimeout, 920 pProcess.asOutParam())); 921 922 /** @todo does this need signal handling? there's no progress object etc etc */ 923 924 vrc = RTStrmSetMode(g_pStdOut, 1 /* Binary mode */, -1 /* Code set, unchanged */); 925 if (RT_FAILURE(vrc)) 926 RTMsgError("Unable to set stdout's binary mode, rc=%Rrc\n", vrc); 927 vrc = RTStrmSetMode(g_pStdErr, 1 /* Binary mode */, -1 /* Code set, unchanged */); 928 if (RT_FAILURE(vrc)) 929 RTMsgError("Unable to set stderr's binary mode, rc=%Rrc\n", vrc); 930 931 /* Wait for process to exit ... */ 932 RTMSINTERVAL cMsTimeLeft = 1; 933 bool fReadStdOut, fReadStdErr; 934 fReadStdOut = fReadStdErr = false; 935 936 bool fCompleted = false; 937 while (!fCompleted && cMsTimeLeft != 0) 938 { 939 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout); 940 ProcessWaitResult_T waitResult; 941 CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags), 942 cMsTimeLeft, &waitResult)); 943 switch (waitResult) 944 944 { 945 ULONG uPID = 0; 946 rc = pProcess->COMGETTER(PID)(&uPID); 947 if (FAILED(rc)) 945 case ProcessWaitResult_Start: 948 946 { 949 ctrlPrintError(pProcess, COM_IIDOF(IProcess)); 950 951 rcExit = RTEXITCODE_FAILURE; 947 ULONG uPID = 0; 948 CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID)); 949 if (fVerbose) 950 { 951 RTPrintf("Process '%s' (PID %RU32) started\n", 952 strCmd.c_str(), uPID); 953 } 954 else /** @todo Introduce a --quiet option for not printing this. */ 955 { 956 /* Just print plain PID to make it easier for scripts 957 * invoking VBoxManage. */ 958 RTPrintf("%RU32, session ID %RU32\n", uPID, uSessionID); 959 } 960 961 /* We're done here if we don't want to wait for termination. */ 962 if (fDetached) 963 fCompleted = true; 964 952 965 break; 953 966 } 954 967 case ProcessWaitResult_StdOut: 968 fReadStdOut = true; 969 break; 970 case ProcessWaitResult_StdErr: 971 fReadStdErr = true; 972 break; 973 case ProcessWaitResult_Terminate: 974 /* Process terminated, we're done */ 975 fCompleted = true; 976 break; 977 case ProcessWaitResult_WaitFlagNotSupported: 978 { 979 /* The guest does not support waiting for stdout/err, so 980 * yield to reduce the CPU load due to busy waiting. */ 981 RTThreadYield(); /* Optional, don't check rc. */ 982 983 /* Try both, stdout + stderr. */ 984 fReadStdOut = fReadStdErr = true; 985 break; 986 } 987 default: 988 /* Ignore all other results, let the timeout expire */ 989 break; 990 } 991 992 if (FAILED(rc)) 993 break; 994 995 if (fReadStdOut) /* Do we need to fetch stdout data? */ 996 { 997 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout); 998 vrc = ctrlExecPrintOutput(pProcess, g_pStdOut, 999 1 /* StdOut */, cMsTimeLeft); 1000 fReadStdOut = false; 1001 } 1002 1003 if (fReadStdErr) /* Do we need to fetch stdout data? */ 1004 { 1005 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout); 1006 vrc = ctrlExecPrintOutput(pProcess, g_pStdErr, 1007 2 /* StdErr */, cMsTimeLeft); 1008 fReadStdErr = false; 1009 } 1010 1011 if (RT_FAILURE(vrc)) 1012 break; 1013 1014 /* Did we run out of time? */ 1015 if ( cMsTimeout 1016 && RTTimeMilliTS() - u64StartMS > cMsTimeout) 1017 break; 1018 1019 NativeEventQueue::getMainEventQueue()->processEventQueue(0); 1020 1021 } /* while */ 1022 1023 /* Report status back to the user. */ 1024 if (fCompleted) 1025 { 1026 ProcessStatus_T procStatus; 1027 CHECK_ERROR_BREAK(pProcess, COMGETTER(Status)(&procStatus)); 1028 if ( procStatus == ProcessStatus_TerminatedNormally 1029 || procStatus == ProcessStatus_TerminatedAbnormally 1030 || procStatus == ProcessStatus_TerminatedSignal) 1031 { 1032 LONG exitCode; 1033 CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&exitCode)); 955 1034 if (fVerbose) 956 { 957 RTPrintf("Process '%s' (PID: %ld) %s\n", 958 strCmd.c_str(), uPID, 959 fWaitForExit ? "started" : "started (detached)"); 960 } 961 else /** @todo Introduce a --quiet option for not printing this. */ 962 { 963 /* Just print plain PID to make it easier for scripts 964 * invoking VBoxManage. */ 965 RTPrintf("%ld\n", uPID); 966 } 967 968 /* We're done here if we don't want to wait for termination. */ 969 if (!fWaitForExit) 970 fCompleted = true; 971 972 break; 1035 RTPrintf("Exit code=%u (Status=%u [%s])\n", 1036 exitCode, procStatus, ctrlExecProcessStatusToText(procStatus)); 1037 1038 rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCode(procStatus, exitCode); 973 1039 } 974 case ProcessWaitResult_StdOut: 975 fReadStdOut = true; 976 break; 977 case ProcessWaitResult_StdErr: 978 fReadStdErr = true; 979 break; 980 case ProcessWaitResult_Terminate: 981 /* Process terminated, we're done */ 982 fCompleted = true; 983 break; 984 case ProcessWaitResult_WaitFlagNotSupported: 985 { 986 /* The guest does not support waiting for stdout/err, so 987 * yield to reduce the CPU load due to busy waiting. */ 988 RTThreadYield(); /* Optional, don't check rc. */ 989 990 /* Try both, stdout + stderr. */ 991 fReadStdOut = fReadStdErr = true; 992 break; 993 } 994 default: 995 /* Ignore all other results, let the timeout expire */ 996 break; 997 } 998 999 if (FAILED(rc)) 1000 break; 1001 1002 if (fReadStdOut) /* Do we need to fetch stdout data? */ 1003 { 1004 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout); 1005 vrc = ctrlExecPrintOutput(pProcess, g_pStdOut, 1006 1 /* StdOut */, cMsTimeLeft); 1007 fReadStdOut = false; 1008 } 1009 1010 if (fReadStdErr) /* Do we need to fetch stdout data? */ 1011 { 1012 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout); 1013 vrc = ctrlExecPrintOutput(pProcess, g_pStdErr, 1014 2 /* StdErr */, cMsTimeLeft); 1015 fReadStdErr = false; 1016 } 1017 1018 if (RT_FAILURE(vrc)) 1019 break; 1020 1021 /* Did we run out of time? */ 1022 if ( cMsTimeout 1023 && RTTimeMilliTS() - u64StartMS > cMsTimeout) 1024 break; 1025 1026 NativeEventQueue::getMainEventQueue()->processEventQueue(0); 1027 1028 } /* while */ 1029 1030 /* Report status back to the user. */ 1031 if (fCompleted) 1032 { 1033 ProcessStatus_T status; 1034 rc = pProcess->COMGETTER(Status)(&status); 1035 if (FAILED(rc)) 1036 { 1037 ctrlPrintError(pProcess, COM_IIDOF(IProcess)); 1038 1039 rcExit = RTEXITCODE_FAILURE; 1040 else if (fVerbose) 1041 RTPrintf("Process now is in status [%s]\n", ctrlExecProcessStatusToText(procStatus)); 1040 1042 } 1041 1043 else 1042 1044 { 1043 LONG exitCode; 1044 rc = pProcess->COMGETTER(ExitCode)(&exitCode); 1045 if (FAILED(rc)) 1046 { 1047 ctrlPrintError(pProcess, COM_IIDOF(IProcess)); 1048 1049 rcExit = RTEXITCODE_FAILURE; 1050 } 1051 else 1052 { 1053 if (fVerbose) 1054 RTPrintf("Exit code=%u (Status=%u [%s])\n", exitCode, status, ctrlExecProcessStatusToText(status)); 1055 1056 rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCode(status, exitCode); 1057 } 1058 } 1059 } 1060 else 1061 { 1062 if (fVerbose) 1063 RTPrintf("Process execution aborted!\n"); 1064 1065 rcExit = (RTEXITCODE)EXITCODEEXEC_TERM_ABEND; 1066 } 1067 } while (0); 1068 1069 /* 1070 * Only close the guest session if we waited for the guest 1071 * process to exit. Otherwise we wouldn't have any chance to 1072 * access and/or kill detached guest process lateron. 1073 */ 1074 if ( fWaitForExit 1075 || rcExit != RTEXITCODE_SUCCESS) 1045 if (fVerbose) 1046 RTPrintf("Process execution aborted!\n"); 1047 1048 rcExit = (RTEXITCODE)EXITCODEEXEC_TERM_ABEND; 1049 } 1050 1051 } while (0); 1052 } 1053 catch (std::bad_alloc) 1054 { 1055 rc = E_OUTOFMEMORY; 1056 } 1057 1058 bool fCloseSession = false; 1059 if (SUCCEEDED(rc)) 1060 { 1061 /* 1062 * Only close the guest session if we waited for the guest 1063 * process to exit. Otherwise we wouldn't have any chance to 1064 * access and/or kill detached guest process lateron. 1065 */ 1066 fCloseSession = !fDetached; 1067 } 1068 else /* Close session on error. */ 1069 fCloseSession = true; 1070 1071 if ( fCloseSession 1072 && !pGuestSession.isNull()) 1076 1073 { 1077 1074 if (fVerbose) 1078 1075 RTPrintf("Closing guest session ...\n"); 1079 1076 rc = pGuestSession->Close(); 1080 if (FAILED(rc)) 1081 { 1082 ctrlPrintError(pGuestSession, COM_IIDOF(ISession)); 1083 1084 if (rcExit == RTEXITCODE_SUCCESS) 1085 rcExit = RTEXITCODE_FAILURE; 1086 } 1087 } 1088 else if (fVerbose) 1077 } 1078 else if (!fCloseSession && fVerbose) 1089 1079 RTPrintf("Guest session detached\n"); 1080 1081 if ( rcExit == RTEXITCODE_SUCCESS 1082 && FAILED(rc)) 1083 { 1084 /* Make sure an appropriate exit code is set on error. */ 1085 rcExit = RTEXITCODE_FAILURE; 1086 } 1090 1087 1091 1088 return rcExit; … … 3106 3103 { 3107 3104 if (fVerbose) 3108 RTPrintf("Terminating process PID=%RU32 (session ID=%RU32) ...\n",3105 RTPrintf("Terminating process (PID %RU32) (session ID %RU32) ...\n", 3109 3106 uPID, uID); 3110 3107 CHECK_ERROR_BREAK(pProcess, Terminate()); … … 3114 3111 { 3115 3112 if (ulSessionID != UINT32_MAX) 3116 RTPrintf("No matching process(es) for session %RU32 found\n",3113 RTPrintf("No matching process(es) for session ID %RU32 found\n", 3117 3114 ulSessionID); 3118 3115 } … … 3343 3340 else if ( !RTStrICmp(pArg->argv[1], "exec") 3344 3341 || !RTStrICmp(pArg->argv[1], "execute")) 3345 rcExit = handleCtrl ExecProgram(guest, &arg);3342 rcExit = handleCtrlProcessExec(guest, &arg); 3346 3343 else if (!RTStrICmp(pArg->argv[1], "copyfrom")) 3347 3344 rcExit = handleCtrlCopy(guest, &arg, false /* Guest to host */);
Note:
See TracChangeset
for help on using the changeset viewer.